1*6f9cba8fSJoseph Mingrone /*
2*6f9cba8fSJoseph Mingrone * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3*6f9cba8fSJoseph Mingrone * Distributed under the terms of the MIT License.
4*6f9cba8fSJoseph Mingrone *
5*6f9cba8fSJoseph Mingrone * Authors:
6*6f9cba8fSJoseph Mingrone * Axel Dörfler, axeld@pinc-software.de
7*6f9cba8fSJoseph Mingrone * James Woodcock
8*6f9cba8fSJoseph Mingrone */
9*6f9cba8fSJoseph Mingrone
10*6f9cba8fSJoseph Mingrone
11*6f9cba8fSJoseph Mingrone #include "config.h"
12*6f9cba8fSJoseph Mingrone #include "pcap-int.h"
13*6f9cba8fSJoseph Mingrone
14*6f9cba8fSJoseph Mingrone #include <OS.h>
15*6f9cba8fSJoseph Mingrone
16*6f9cba8fSJoseph Mingrone #include <sys/socket.h>
17*6f9cba8fSJoseph Mingrone #include <sys/sockio.h>
18*6f9cba8fSJoseph Mingrone
19*6f9cba8fSJoseph Mingrone #include <net/if.h>
20*6f9cba8fSJoseph Mingrone #include <net/if_dl.h>
21*6f9cba8fSJoseph Mingrone #include <net/if_types.h>
22*6f9cba8fSJoseph Mingrone
23*6f9cba8fSJoseph Mingrone #include <errno.h>
24*6f9cba8fSJoseph Mingrone #include <stdio.h>
25*6f9cba8fSJoseph Mingrone #include <stdlib.h>
26*6f9cba8fSJoseph Mingrone #include <string.h>
27*6f9cba8fSJoseph Mingrone
28*6f9cba8fSJoseph Mingrone
29*6f9cba8fSJoseph Mingrone /*
30*6f9cba8fSJoseph Mingrone * Private data for capturing on Haiku sockets.
31*6f9cba8fSJoseph Mingrone */
32*6f9cba8fSJoseph Mingrone struct pcap_haiku {
33*6f9cba8fSJoseph Mingrone struct pcap_stat stat;
34*6f9cba8fSJoseph Mingrone char *device; /* device name */
35*6f9cba8fSJoseph Mingrone };
36*6f9cba8fSJoseph Mingrone
37*6f9cba8fSJoseph Mingrone
38*6f9cba8fSJoseph Mingrone bool
prepare_request(struct ifreq & request,const char * name)39*6f9cba8fSJoseph Mingrone prepare_request(struct ifreq& request, const char* name)
40*6f9cba8fSJoseph Mingrone {
41*6f9cba8fSJoseph Mingrone if (strlen(name) >= IF_NAMESIZE)
42*6f9cba8fSJoseph Mingrone return false;
43*6f9cba8fSJoseph Mingrone
44*6f9cba8fSJoseph Mingrone strcpy(request.ifr_name, name);
45*6f9cba8fSJoseph Mingrone return true;
46*6f9cba8fSJoseph Mingrone }
47*6f9cba8fSJoseph Mingrone
48*6f9cba8fSJoseph Mingrone
49*6f9cba8fSJoseph Mingrone static int
pcap_read_haiku(pcap_t * handle,int maxPackets _U_,pcap_handler callback,u_char * userdata)50*6f9cba8fSJoseph Mingrone pcap_read_haiku(pcap_t* handle, int maxPackets _U_, pcap_handler callback,
51*6f9cba8fSJoseph Mingrone u_char* userdata)
52*6f9cba8fSJoseph Mingrone {
53*6f9cba8fSJoseph Mingrone // Receive a single packet
54*6f9cba8fSJoseph Mingrone
55*6f9cba8fSJoseph Mingrone u_char* buffer = (u_char*)handle->buffer + handle->offset;
56*6f9cba8fSJoseph Mingrone struct sockaddr_dl from;
57*6f9cba8fSJoseph Mingrone ssize_t bytesReceived;
58*6f9cba8fSJoseph Mingrone do {
59*6f9cba8fSJoseph Mingrone if (handle->break_loop) {
60*6f9cba8fSJoseph Mingrone // Clear the break loop flag, and return -2 to indicate our
61*6f9cba8fSJoseph Mingrone // reasoning
62*6f9cba8fSJoseph Mingrone handle->break_loop = 0;
63*6f9cba8fSJoseph Mingrone return -2;
64*6f9cba8fSJoseph Mingrone }
65*6f9cba8fSJoseph Mingrone
66*6f9cba8fSJoseph Mingrone socklen_t fromLength = sizeof(from);
67*6f9cba8fSJoseph Mingrone bytesReceived = recvfrom(handle->fd, buffer, handle->bufsize, MSG_TRUNC,
68*6f9cba8fSJoseph Mingrone (struct sockaddr*)&from, &fromLength);
69*6f9cba8fSJoseph Mingrone } while (bytesReceived < 0 && errno == B_INTERRUPTED);
70*6f9cba8fSJoseph Mingrone
71*6f9cba8fSJoseph Mingrone if (bytesReceived < 0) {
72*6f9cba8fSJoseph Mingrone if (errno == B_WOULD_BLOCK) {
73*6f9cba8fSJoseph Mingrone // there is no packet for us
74*6f9cba8fSJoseph Mingrone return 0;
75*6f9cba8fSJoseph Mingrone }
76*6f9cba8fSJoseph Mingrone
77*6f9cba8fSJoseph Mingrone snprintf(handle->errbuf, sizeof(handle->errbuf),
78*6f9cba8fSJoseph Mingrone "recvfrom: %s", strerror(errno));
79*6f9cba8fSJoseph Mingrone return -1;
80*6f9cba8fSJoseph Mingrone }
81*6f9cba8fSJoseph Mingrone
82*6f9cba8fSJoseph Mingrone int32 captureLength = bytesReceived;
83*6f9cba8fSJoseph Mingrone if (captureLength > handle->snapshot)
84*6f9cba8fSJoseph Mingrone captureLength = handle->snapshot;
85*6f9cba8fSJoseph Mingrone
86*6f9cba8fSJoseph Mingrone // run the packet filter
87*6f9cba8fSJoseph Mingrone if (handle->fcode.bf_insns) {
88*6f9cba8fSJoseph Mingrone if (pcap_filter(handle->fcode.bf_insns, buffer, bytesReceived,
89*6f9cba8fSJoseph Mingrone captureLength) == 0) {
90*6f9cba8fSJoseph Mingrone // packet got rejected
91*6f9cba8fSJoseph Mingrone return 0;
92*6f9cba8fSJoseph Mingrone }
93*6f9cba8fSJoseph Mingrone }
94*6f9cba8fSJoseph Mingrone
95*6f9cba8fSJoseph Mingrone // fill in pcap_header
96*6f9cba8fSJoseph Mingrone pcap_pkthdr header;
97*6f9cba8fSJoseph Mingrone header.caplen = captureLength;
98*6f9cba8fSJoseph Mingrone header.len = bytesReceived;
99*6f9cba8fSJoseph Mingrone header.ts.tv_usec = system_time() % 1000000;
100*6f9cba8fSJoseph Mingrone header.ts.tv_sec = system_time() / 1000000;
101*6f9cba8fSJoseph Mingrone // TODO: get timing from packet!!!
102*6f9cba8fSJoseph Mingrone
103*6f9cba8fSJoseph Mingrone /* Call the user supplied callback function */
104*6f9cba8fSJoseph Mingrone callback(userdata, &header, buffer);
105*6f9cba8fSJoseph Mingrone return 1;
106*6f9cba8fSJoseph Mingrone }
107*6f9cba8fSJoseph Mingrone
108*6f9cba8fSJoseph Mingrone
109*6f9cba8fSJoseph Mingrone static int
pcap_inject_haiku(pcap_t * handle,const void * buffer,int size)110*6f9cba8fSJoseph Mingrone pcap_inject_haiku(pcap_t *handle, const void *buffer, int size)
111*6f9cba8fSJoseph Mingrone {
112*6f9cba8fSJoseph Mingrone // we don't support injecting packets yet
113*6f9cba8fSJoseph Mingrone // TODO: use the AF_LINK protocol (we need another socket for this) to
114*6f9cba8fSJoseph Mingrone // inject the packets
115*6f9cba8fSJoseph Mingrone strlcpy(handle->errbuf, "Sending packets isn't supported yet",
116*6f9cba8fSJoseph Mingrone PCAP_ERRBUF_SIZE);
117*6f9cba8fSJoseph Mingrone return -1;
118*6f9cba8fSJoseph Mingrone }
119*6f9cba8fSJoseph Mingrone
120*6f9cba8fSJoseph Mingrone
121*6f9cba8fSJoseph Mingrone static int
pcap_stats_haiku(pcap_t * handle,struct pcap_stat * stats)122*6f9cba8fSJoseph Mingrone pcap_stats_haiku(pcap_t *handle, struct pcap_stat *stats)
123*6f9cba8fSJoseph Mingrone {
124*6f9cba8fSJoseph Mingrone struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
125*6f9cba8fSJoseph Mingrone ifreq request;
126*6f9cba8fSJoseph Mingrone int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
127*6f9cba8fSJoseph Mingrone if (socket < 0) {
128*6f9cba8fSJoseph Mingrone return -1;
129*6f9cba8fSJoseph Mingrone }
130*6f9cba8fSJoseph Mingrone prepare_request(request, handlep->device);
131*6f9cba8fSJoseph Mingrone if (ioctl(socket, SIOCGIFSTATS, &request, sizeof(struct ifreq)) < 0) {
132*6f9cba8fSJoseph Mingrone snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "pcap_stats: %s",
133*6f9cba8fSJoseph Mingrone strerror(errno));
134*6f9cba8fSJoseph Mingrone close(socket);
135*6f9cba8fSJoseph Mingrone return -1;
136*6f9cba8fSJoseph Mingrone }
137*6f9cba8fSJoseph Mingrone
138*6f9cba8fSJoseph Mingrone close(socket);
139*6f9cba8fSJoseph Mingrone handlep->stat.ps_recv += request.ifr_stats.receive.packets;
140*6f9cba8fSJoseph Mingrone handlep->stat.ps_drop += request.ifr_stats.receive.dropped;
141*6f9cba8fSJoseph Mingrone *stats = handlep->stat;
142*6f9cba8fSJoseph Mingrone return 0;
143*6f9cba8fSJoseph Mingrone }
144*6f9cba8fSJoseph Mingrone
145*6f9cba8fSJoseph Mingrone
146*6f9cba8fSJoseph Mingrone static int
pcap_activate_haiku(pcap_t * handle)147*6f9cba8fSJoseph Mingrone pcap_activate_haiku(pcap_t *handle)
148*6f9cba8fSJoseph Mingrone {
149*6f9cba8fSJoseph Mingrone struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
150*6f9cba8fSJoseph Mingrone
151*6f9cba8fSJoseph Mingrone const char* device = handle->opt.device;
152*6f9cba8fSJoseph Mingrone
153*6f9cba8fSJoseph Mingrone handle->read_op = pcap_read_haiku;
154*6f9cba8fSJoseph Mingrone handle->setfilter_op = install_bpf_program; /* no kernel filtering */
155*6f9cba8fSJoseph Mingrone handle->inject_op = pcap_inject_haiku;
156*6f9cba8fSJoseph Mingrone handle->stats_op = pcap_stats_haiku;
157*6f9cba8fSJoseph Mingrone
158*6f9cba8fSJoseph Mingrone // use default hooks where possible
159*6f9cba8fSJoseph Mingrone handle->getnonblock_op = pcap_getnonblock_fd;
160*6f9cba8fSJoseph Mingrone handle->setnonblock_op = pcap_setnonblock_fd;
161*6f9cba8fSJoseph Mingrone
162*6f9cba8fSJoseph Mingrone /*
163*6f9cba8fSJoseph Mingrone * Turn a negative snapshot value (invalid), a snapshot value of
164*6f9cba8fSJoseph Mingrone * 0 (unspecified), or a value bigger than the normal maximum
165*6f9cba8fSJoseph Mingrone * value, into the maximum allowed value.
166*6f9cba8fSJoseph Mingrone *
167*6f9cba8fSJoseph Mingrone * If some application really *needs* a bigger snapshot
168*6f9cba8fSJoseph Mingrone * length, we should just increase MAXIMUM_SNAPLEN.
169*6f9cba8fSJoseph Mingrone */
170*6f9cba8fSJoseph Mingrone if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
171*6f9cba8fSJoseph Mingrone handle->snapshot = MAXIMUM_SNAPLEN;
172*6f9cba8fSJoseph Mingrone
173*6f9cba8fSJoseph Mingrone handlep->device = strdup(device);
174*6f9cba8fSJoseph Mingrone if (handlep->device == NULL) {
175*6f9cba8fSJoseph Mingrone pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
176*6f9cba8fSJoseph Mingrone errno, "strdup");
177*6f9cba8fSJoseph Mingrone return PCAP_ERROR;
178*6f9cba8fSJoseph Mingrone }
179*6f9cba8fSJoseph Mingrone
180*6f9cba8fSJoseph Mingrone handle->bufsize = 65536;
181*6f9cba8fSJoseph Mingrone // TODO: should be determined by interface MTU
182*6f9cba8fSJoseph Mingrone
183*6f9cba8fSJoseph Mingrone // allocate buffer for monitoring the device
184*6f9cba8fSJoseph Mingrone handle->buffer = (u_char*)malloc(handle->bufsize);
185*6f9cba8fSJoseph Mingrone if (handle->buffer == NULL) {
186*6f9cba8fSJoseph Mingrone pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
187*6f9cba8fSJoseph Mingrone errno, "buffer malloc");
188*6f9cba8fSJoseph Mingrone return PCAP_ERROR;
189*6f9cba8fSJoseph Mingrone }
190*6f9cba8fSJoseph Mingrone
191*6f9cba8fSJoseph Mingrone handle->offset = 0;
192*6f9cba8fSJoseph Mingrone handle->linktype = DLT_EN10MB;
193*6f9cba8fSJoseph Mingrone // TODO: check interface type!
194*6f9cba8fSJoseph Mingrone
195*6f9cba8fSJoseph Mingrone return 0;
196*6f9cba8fSJoseph Mingrone }
197*6f9cba8fSJoseph Mingrone
198*6f9cba8fSJoseph Mingrone
199*6f9cba8fSJoseph Mingrone // #pragma mark - pcap API
200*6f9cba8fSJoseph Mingrone
201*6f9cba8fSJoseph Mingrone
202*6f9cba8fSJoseph Mingrone extern "C" pcap_t *
pcap_create_interface(const char * device,char * errorBuffer)203*6f9cba8fSJoseph Mingrone pcap_create_interface(const char *device, char *errorBuffer)
204*6f9cba8fSJoseph Mingrone {
205*6f9cba8fSJoseph Mingrone // TODO: handle promiscuous mode!
206*6f9cba8fSJoseph Mingrone
207*6f9cba8fSJoseph Mingrone // we need a socket to talk to the networking stack
208*6f9cba8fSJoseph Mingrone int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
209*6f9cba8fSJoseph Mingrone if (socket < 0) {
210*6f9cba8fSJoseph Mingrone snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
211*6f9cba8fSJoseph Mingrone "The networking stack doesn't seem to be available.\n");
212*6f9cba8fSJoseph Mingrone return NULL;
213*6f9cba8fSJoseph Mingrone }
214*6f9cba8fSJoseph Mingrone
215*6f9cba8fSJoseph Mingrone struct ifreq request;
216*6f9cba8fSJoseph Mingrone if (!prepare_request(request, device)) {
217*6f9cba8fSJoseph Mingrone snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
218*6f9cba8fSJoseph Mingrone "Interface name \"%s\" is too long.", device);
219*6f9cba8fSJoseph Mingrone close(socket);
220*6f9cba8fSJoseph Mingrone return NULL;
221*6f9cba8fSJoseph Mingrone }
222*6f9cba8fSJoseph Mingrone
223*6f9cba8fSJoseph Mingrone // check if the interface exist
224*6f9cba8fSJoseph Mingrone if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) < 0) {
225*6f9cba8fSJoseph Mingrone snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
226*6f9cba8fSJoseph Mingrone "Interface \"%s\" does not exist.\n", device);
227*6f9cba8fSJoseph Mingrone close(socket);
228*6f9cba8fSJoseph Mingrone return NULL;
229*6f9cba8fSJoseph Mingrone }
230*6f9cba8fSJoseph Mingrone
231*6f9cba8fSJoseph Mingrone close(socket);
232*6f9cba8fSJoseph Mingrone // no longer needed after this point
233*6f9cba8fSJoseph Mingrone
234*6f9cba8fSJoseph Mingrone // get link level interface for this interface
235*6f9cba8fSJoseph Mingrone
236*6f9cba8fSJoseph Mingrone socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
237*6f9cba8fSJoseph Mingrone if (socket < 0) {
238*6f9cba8fSJoseph Mingrone snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "No link level: %s\n",
239*6f9cba8fSJoseph Mingrone strerror(errno));
240*6f9cba8fSJoseph Mingrone return NULL;
241*6f9cba8fSJoseph Mingrone }
242*6f9cba8fSJoseph Mingrone
243*6f9cba8fSJoseph Mingrone // start monitoring
244*6f9cba8fSJoseph Mingrone if (ioctl(socket, SIOCSPACKETCAP, &request, sizeof(struct ifreq)) < 0) {
245*6f9cba8fSJoseph Mingrone snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "Cannot start monitoring: %s\n",
246*6f9cba8fSJoseph Mingrone strerror(errno));
247*6f9cba8fSJoseph Mingrone close(socket);
248*6f9cba8fSJoseph Mingrone return NULL;
249*6f9cba8fSJoseph Mingrone }
250*6f9cba8fSJoseph Mingrone
251*6f9cba8fSJoseph Mingrone struct wrapper_struct { pcap_t __common; struct pcap_haiku __private; };
252*6f9cba8fSJoseph Mingrone pcap_t* handle = pcap_create_common(errorBuffer,
253*6f9cba8fSJoseph Mingrone sizeof (struct wrapper_struct),
254*6f9cba8fSJoseph Mingrone offsetof (struct wrapper_struct, __private));
255*6f9cba8fSJoseph Mingrone
256*6f9cba8fSJoseph Mingrone if (handle == NULL) {
257*6f9cba8fSJoseph Mingrone snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "malloc: %s", strerror(errno));
258*6f9cba8fSJoseph Mingrone close(socket);
259*6f9cba8fSJoseph Mingrone return NULL;
260*6f9cba8fSJoseph Mingrone }
261*6f9cba8fSJoseph Mingrone
262*6f9cba8fSJoseph Mingrone handle->selectable_fd = socket;
263*6f9cba8fSJoseph Mingrone handle->fd = socket;
264*6f9cba8fSJoseph Mingrone
265*6f9cba8fSJoseph Mingrone handle->activate_op = pcap_activate_haiku;
266*6f9cba8fSJoseph Mingrone
267*6f9cba8fSJoseph Mingrone return handle;
268*6f9cba8fSJoseph Mingrone }
269*6f9cba8fSJoseph Mingrone
270*6f9cba8fSJoseph Mingrone static int
can_be_bound(const char * name _U_)271*6f9cba8fSJoseph Mingrone can_be_bound(const char *name _U_)
272*6f9cba8fSJoseph Mingrone {
273*6f9cba8fSJoseph Mingrone return 1;
274*6f9cba8fSJoseph Mingrone }
275*6f9cba8fSJoseph Mingrone
276*6f9cba8fSJoseph Mingrone static int
get_if_flags(const char * name,bpf_u_int32 * flags,char * errbuf)277*6f9cba8fSJoseph Mingrone get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
278*6f9cba8fSJoseph Mingrone {
279*6f9cba8fSJoseph Mingrone /* TODO */
280*6f9cba8fSJoseph Mingrone if (*flags & PCAP_IF_LOOPBACK) {
281*6f9cba8fSJoseph Mingrone /*
282*6f9cba8fSJoseph Mingrone * Loopback devices aren't wireless, and "connected"/
283*6f9cba8fSJoseph Mingrone * "disconnected" doesn't apply to them.
284*6f9cba8fSJoseph Mingrone */
285*6f9cba8fSJoseph Mingrone *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
286*6f9cba8fSJoseph Mingrone return (0);
287*6f9cba8fSJoseph Mingrone }
288*6f9cba8fSJoseph Mingrone return (0);
289*6f9cba8fSJoseph Mingrone }
290*6f9cba8fSJoseph Mingrone
291*6f9cba8fSJoseph Mingrone extern "C" int
pcap_platform_finddevs(pcap_if_list_t * _allDevices,char * errorBuffer)292*6f9cba8fSJoseph Mingrone pcap_platform_finddevs(pcap_if_list_t* _allDevices, char* errorBuffer)
293*6f9cba8fSJoseph Mingrone {
294*6f9cba8fSJoseph Mingrone return pcap_findalldevs_interfaces(_allDevices, errorBuffer, can_be_bound,
295*6f9cba8fSJoseph Mingrone get_if_flags);
296*6f9cba8fSJoseph Mingrone }
297*6f9cba8fSJoseph Mingrone
298*6f9cba8fSJoseph Mingrone /*
299*6f9cba8fSJoseph Mingrone * Libpcap version string.
300*6f9cba8fSJoseph Mingrone */
301*6f9cba8fSJoseph Mingrone extern "C" const char *
pcap_lib_version(void)302*6f9cba8fSJoseph Mingrone pcap_lib_version(void)
303*6f9cba8fSJoseph Mingrone {
304*6f9cba8fSJoseph Mingrone return (PCAP_VERSION_STRING);
305*6f9cba8fSJoseph Mingrone }
306