2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler, axeld@pinc-software.de
16 #include <sys/socket.h>
17 #include <sys/sockio.h>
20 #include <net/if_dl.h>
21 #include <net/if_types.h>
30 * Private data for capturing on Haiku sockets.
33 struct pcap_stat stat
;
34 char *device
; /* device name */
39 prepare_request(struct ifreq
*request
, const char* name
)
41 if (strlen(name
) >= IF_NAMESIZE
)
44 strcpy(request
->ifr_name
, name
);
50 pcap_read_haiku(pcap_t
* handle
, int maxPackets _U_
, pcap_handler callback
,
53 // Receive a single packet
55 u_char
* buffer
= handle
->buffer
+ handle
->offset
;
56 struct sockaddr_dl from
;
57 ssize_t bytesReceived
;
59 if (handle
->break_loop
) {
60 // Clear the break loop flag, and return -2 to indicate our
62 handle
->break_loop
= 0;
66 socklen_t fromLength
= sizeof(from
);
67 bytesReceived
= recvfrom(handle
->fd
, buffer
, handle
->bufsize
, MSG_TRUNC
,
68 (struct sockaddr
*)&from
, &fromLength
);
69 } while (bytesReceived
< 0 && errno
== B_INTERRUPTED
);
71 if (bytesReceived
< 0) {
72 if (errno
== B_WOULD_BLOCK
) {
73 // there is no packet for us
77 snprintf(handle
->errbuf
, sizeof(handle
->errbuf
),
78 "recvfrom: %s", strerror(errno
));
82 int32_t captureLength
= bytesReceived
;
83 if (captureLength
> handle
->snapshot
)
84 captureLength
= handle
->snapshot
;
86 // run the packet filter
87 if (handle
->fcode
.bf_insns
) {
88 if (pcap_filter(handle
->fcode
.bf_insns
, buffer
, bytesReceived
,
89 captureLength
) == 0) {
90 // packet got rejected
95 // fill in pcap_header
96 struct pcap_pkthdr header
;
97 header
.caplen
= captureLength
;
98 header
.len
= bytesReceived
;
99 header
.ts
.tv_usec
= system_time() % 1000000;
100 header
.ts
.tv_sec
= system_time() / 1000000;
101 // TODO: get timing from packet!!!
103 /* Call the user supplied callback function */
104 callback(userdata
, &header
, buffer
);
110 pcap_inject_haiku(pcap_t
*handle
, const void *buffer _U_
, int size _U_
)
112 // we don't support injecting packets yet
113 // TODO: use the AF_LINK protocol (we need another socket for this) to
114 // inject the packets
115 strlcpy(handle
->errbuf
, "Sending packets isn't supported yet",
122 pcap_stats_haiku(pcap_t
*handle
, struct pcap_stat
*stats
)
124 struct pcap_haiku
* handlep
= (struct pcap_haiku
*)handle
->priv
;
125 struct ifreq request
;
126 int pcapSocket
= socket(AF_INET
, SOCK_DGRAM
, 0);
127 if (pcapSocket
< 0) {
130 prepare_request(&request
, handlep
->device
);
131 if (ioctl(pcapSocket
, SIOCGIFSTATS
, &request
, sizeof(struct ifreq
)) < 0) {
132 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "pcap_stats: %s",
139 handlep
->stat
.ps_recv
+= request
.ifr_stats
.receive
.packets
;
140 handlep
->stat
.ps_drop
+= request
.ifr_stats
.receive
.dropped
;
141 *stats
= handlep
->stat
;
147 pcap_activate_haiku(pcap_t
*handle
)
149 struct pcap_haiku
* handlep
= (struct pcap_haiku
*)handle
->priv
;
151 const char* device
= handle
->opt
.device
;
153 handle
->read_op
= pcap_read_haiku
;
154 handle
->setfilter_op
= pcap_install_bpf_program
; /* no kernel filtering */
155 handle
->inject_op
= pcap_inject_haiku
;
156 handle
->stats_op
= pcap_stats_haiku
;
158 // use default hooks where possible
159 handle
->getnonblock_op
= pcap_getnonblock_fd
;
160 handle
->setnonblock_op
= pcap_setnonblock_fd
;
163 * Turn a negative snapshot value (invalid), a snapshot value of
164 * 0 (unspecified), or a value bigger than the normal maximum
165 * value, into the maximum allowed value.
167 * If some application really *needs* a bigger snapshot
168 * length, we should just increase MAXIMUM_SNAPLEN.
170 if (handle
->snapshot
<= 0 || handle
->snapshot
> MAXIMUM_SNAPLEN
)
171 handle
->snapshot
= MAXIMUM_SNAPLEN
;
173 handlep
->device
= strdup(device
);
174 if (handlep
->device
== NULL
) {
175 pcap_fmt_errmsg_for_errno(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
180 handle
->bufsize
= 65536;
181 // TODO: should be determined by interface MTU
183 // allocate buffer for monitoring the device
184 handle
->buffer
= (u_char
*)malloc(handle
->bufsize
);
185 if (handle
->buffer
== NULL
) {
186 pcap_fmt_errmsg_for_errno(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
187 errno
, "buffer malloc");
192 handle
->linktype
= DLT_EN10MB
;
193 // TODO: check interface type!
199 // #pragma mark - pcap API
203 pcap_create_interface(const char *device
, char *errorBuffer
)
205 // TODO: handle promiscuous mode!
207 // we need a socket to talk to the networking stack
208 int pcapSocket
= socket(AF_INET
, SOCK_DGRAM
, 0);
209 if (pcapSocket
< 0) {
210 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
,
211 "The networking stack doesn't seem to be available.\n");
215 struct ifreq request
;
216 if (!prepare_request(&request
, device
)) {
217 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
,
218 "Interface name \"%s\" is too long.", device
);
223 // check if the interface exist
224 if (ioctl(pcapSocket
, SIOCGIFINDEX
, &request
, sizeof(request
)) < 0) {
225 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
,
226 "Interface \"%s\" does not exist.\n", device
);
232 // no longer needed after this point
234 // get link level interface for this interface
236 pcapSocket
= socket(AF_LINK
, SOCK_DGRAM
, 0);
237 if (pcapSocket
< 0) {
238 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
, "No link level: %s\n",
244 if (ioctl(pcapSocket
, SIOCSPACKETCAP
, &request
, sizeof(struct ifreq
)) < 0) {
245 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
, "Cannot start monitoring: %s\n",
251 pcap_t
* handle
= PCAP_CREATE_COMMON(errorBuffer
, struct pcap_haiku
);
252 if (handle
== NULL
) {
253 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
, "malloc: %s", strerror(errno
));
258 handle
->selectable_fd
= pcapSocket
;
259 handle
->fd
= pcapSocket
;
261 handle
->activate_op
= pcap_activate_haiku
;
267 can_be_bound(const char *name _U_
)
273 get_if_flags(const char *name _U_
, bpf_u_int32
*flags
, char *errbuf _U_
)
276 if (*flags
& PCAP_IF_LOOPBACK
) {
278 * Loopback devices aren't wireless, and "connected"/
279 * "disconnected" doesn't apply to them.
281 *flags
|= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE
;
288 pcap_platform_finddevs(pcap_if_list_t
* _allDevices
, char* errorBuffer
)
290 return pcap_findalldevs_interfaces(_allDevices
, errorBuffer
, can_be_bound
,
295 * Libpcap version string.
298 pcap_lib_version(void)
300 return (PCAP_VERSION_STRING
);