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
, pcap_handler callback
,
53 // Receive a single packet
55 struct pcap_haiku
* handlep
= (struct pcap_haiku
*)handle
->priv
;
56 u_char
* buffer
= (u_char
*)handle
->buffer
+ handle
->offset
;
57 struct sockaddr_dl from
;
58 ssize_t bytesReceived
;
60 if (handle
->break_loop
) {
61 // Clear the break loop flag, and return -2 to indicate our
63 handle
->break_loop
= 0;
67 socklen_t fromLength
= sizeof(from
);
68 bytesReceived
= recvfrom(handle
->fd
, buffer
, handle
->bufsize
, MSG_TRUNC
,
69 (struct sockaddr
*)&from
, &fromLength
);
70 } while (bytesReceived
< 0 && errno
== B_INTERRUPTED
);
72 if (bytesReceived
< 0) {
73 if (errno
== B_WOULD_BLOCK
) {
74 // there is no packet for us
78 snprintf(handle
->errbuf
, sizeof(handle
->errbuf
),
79 "recvfrom: %s", strerror(errno
));
83 int32 captureLength
= bytesReceived
;
84 if (captureLength
> handle
->snapshot
)
85 captureLength
= handle
->snapshot
;
87 // run the packet filter
88 if (handle
->fcode
.bf_insns
) {
89 if (pcap_filter(handle
->fcode
.bf_insns
, buffer
, bytesReceived
,
90 captureLength
) == 0) {
91 // packet got rejected
96 // fill in pcap_header
98 header
.caplen
= captureLength
;
99 header
.len
= bytesReceived
;
100 header
.ts
.tv_usec
= system_time() % 1000000;
101 header
.ts
.tv_sec
= system_time() / 1000000;
102 // TODO: get timing from packet!!!
104 /* Call the user supplied callback function */
105 callback(userdata
, &header
, buffer
);
111 pcap_inject_haiku(pcap_t
*handle
, const void *buffer
, int size
)
113 // we don't support injecting packets yet
114 // TODO: use the AF_LINK protocol (we need another socket for this) to
115 // inject the packets
116 strlcpy(handle
->errbuf
, "Sending packets isn't supported yet",
123 pcap_stats_haiku(pcap_t
*handle
, struct pcap_stat
*stats
)
125 struct pcap_haiku
* handlep
= (struct pcap_haiku
*)handle
->priv
;
127 int socket
= ::socket(AF_INET
, SOCK_DGRAM
, 0);
131 prepare_request(request
, handlep
->device
);
132 if (ioctl(socket
, SIOCGIFSTATS
, &request
, sizeof(struct ifreq
)) < 0) {
133 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "pcap_stats: %s",
140 handlep
->stat
.ps_recv
+= request
.ifr_stats
.receive
.packets
;
141 handlep
->stat
.ps_drop
+= request
.ifr_stats
.receive
.dropped
;
142 *stats
= handlep
->stat
;
148 pcap_activate_haiku(pcap_t
*handle
)
150 struct pcap_haiku
* handlep
= (struct pcap_haiku
*)handle
->priv
;
152 const char* device
= handle
->opt
.device
;
154 handle
->read_op
= pcap_read_haiku
;
155 handle
->setfilter_op
= install_bpf_program
; /* no kernel filtering */
156 handle
->inject_op
= pcap_inject_haiku
;
157 handle
->stats_op
= pcap_stats_haiku
;
159 // use default hooks where possible
160 handle
->getnonblock_op
= pcap_getnonblock_fd
;
161 handle
->setnonblock_op
= pcap_setnonblock_fd
;
164 * Turn a negative snapshot value (invalid), a snapshot value of
165 * 0 (unspecified), or a value bigger than the normal maximum
166 * value, into the maximum allowed value.
168 * If some application really *needs* a bigger snapshot
169 * length, we should just increase MAXIMUM_SNAPLEN.
171 if (handle
->snapshot
<= 0 || handle
->snapshot
> MAXIMUM_SNAPLEN
)
172 handle
->snapshot
= MAXIMUM_SNAPLEN
;
174 handlep
->device
= strdup(device
);
175 if (handlep
->device
== NULL
) {
176 pcap_fmt_errmsg_for_errno(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
181 handle
->bufsize
= 65536;
182 // TODO: should be determined by interface MTU
184 // allocate buffer for monitoring the device
185 handle
->buffer
= (u_char
*)malloc(handle
->bufsize
);
186 if (handle
->buffer
== NULL
) {
187 pcap_fmt_errmsg_for_errno(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
188 errno
, "buffer malloc");
193 handle
->linktype
= DLT_EN10MB
;
194 // TODO: check interface type!
200 // #pragma mark - pcap API
204 pcap_create_interface(const char *device
, char *errorBuffer
)
206 // TODO: handle promiscuous mode!
208 // we need a socket to talk to the networking stack
209 int socket
= ::socket(AF_INET
, SOCK_DGRAM
, 0);
211 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
,
212 "The networking stack doesn't seem to be available.\n");
216 struct ifreq request
;
217 if (!prepare_request(request
, device
)) {
218 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
,
219 "Interface name \"%s\" is too long.", device
);
224 // check if the interface exist
225 if (ioctl(socket
, SIOCGIFINDEX
, &request
, sizeof(request
)) < 0) {
226 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
,
227 "Interface \"%s\" does not exist.\n", device
);
233 // no longer needed after this point
235 // get link level interface for this interface
237 socket
= ::socket(AF_LINK
, SOCK_DGRAM
, 0);
239 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
, "No link level: %s\n",
245 if (ioctl(socket
, SIOCSPACKETCAP
, &request
, sizeof(struct ifreq
)) < 0) {
246 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
, "Cannot start monitoring: %s\n",
252 struct wrapper_struct
{ pcap_t __common
; struct pcap_haiku __private
; };
253 pcap_t
* handle
= pcap_create_common(errorBuffer
,
254 sizeof (struct wrapper_struct
),
255 offsetof (struct wrapper_struct
, __private
));
257 if (handle
== NULL
) {
258 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
, "malloc: %s", strerror(errno
));
263 handle
->selectable_fd
= socket
;
266 handle
->activate_op
= pcap_activate_haiku
;
272 can_be_bound(const char *name
)
278 get_if_flags(const char *name
, bpf_u_int32
*flags
, char *errbuf
)
281 if (*flags
& PCAP_IF_LOOPBACK
) {
283 * Loopback devices aren't wireless, and "connected"/
284 * "disconnected" doesn't apply to them.
286 *flags
|= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE
;
293 pcap_platform_finddevs(pcap_if_list_t
* _allDevices
, char* errorBuffer
)
295 return pcap_findalldevs_interfaces(_allDevices
, errorBuffer
, can_be_bound
,
300 * Libpcap version string.
302 extern "C" const char *
303 pcap_lib_version(void)
305 return (PCAP_VERSION_STRING
);