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