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
= (u_char
*)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 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
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
, int size
)
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
;
126 int socket
= ::socket(AF_INET
, SOCK_DGRAM
, 0);
130 prepare_request(request
, handlep
->device
);
131 if (ioctl(socket
, 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
= 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 socket
= ::socket(AF_INET
, SOCK_DGRAM
, 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(socket
, 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 socket
= ::socket(AF_LINK
, SOCK_DGRAM
, 0);
238 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
, "No link level: %s\n",
244 if (ioctl(socket
, SIOCSPACKETCAP
, &request
, sizeof(struct ifreq
)) < 0) {
245 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
, "Cannot start monitoring: %s\n",
251 struct wrapper_struct
{ pcap_t __common
; struct pcap_haiku __private
; };
252 pcap_t
* handle
= pcap_create_common(errorBuffer
,
253 sizeof (struct wrapper_struct
),
254 offsetof (struct wrapper_struct
, __private
));
256 if (handle
== NULL
) {
257 snprintf(errorBuffer
, PCAP_ERRBUF_SIZE
, "malloc: %s", strerror(errno
));
262 handle
->selectable_fd
= socket
;
265 handle
->activate_op
= pcap_activate_haiku
;
271 can_be_bound(const char *name _U_
)
277 get_if_flags(const char *name
, bpf_u_int32
*flags
, char *errbuf
)
280 if (*flags
& PCAP_IF_LOOPBACK
) {
282 * Loopback devices aren't wireless, and "connected"/
283 * "disconnected" doesn't apply to them.
285 *flags
|= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE
;
292 pcap_platform_finddevs(pcap_if_list_t
* _allDevices
, char* errorBuffer
)
294 return pcap_findalldevs_interfaces(_allDevices
, errorBuffer
, can_be_bound
,
299 * Libpcap version string.
301 extern "C" const char *
302 pcap_lib_version(void)
304 return (PCAP_VERSION_STRING
);