]> The Tcpdump Group git mirrors - libpcap/blob - pcap-haiku.cpp
4606ca0e252e5038b7956e1b193c17f0886c98f5
[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, pcap_handler callback,
51 u_char* userdata)
52 {
53 // Receive a single packet
54
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;
59 do {
60 if (handle->break_loop) {
61 // Clear the break loop flag, and return -2 to indicate our
62 // reasoning
63 handle->break_loop = 0;
64 return -2;
65 }
66
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);
71
72 if (bytesReceived < 0) {
73 if (errno == B_WOULD_BLOCK) {
74 // there is no packet for us
75 return 0;
76 }
77
78 snprintf(handle->errbuf, sizeof(handle->errbuf),
79 "recvfrom: %s", strerror(errno));
80 return -1;
81 }
82
83 int32 captureLength = bytesReceived;
84 if (captureLength > handle->snapshot)
85 captureLength = handle->snapshot;
86
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
92 return 0;
93 }
94 }
95
96 // fill in pcap_header
97 pcap_pkthdr 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!!!
103
104 /* Call the user supplied callback function */
105 callback(userdata, &header, buffer);
106 return 1;
107 }
108
109
110 static int
111 pcap_inject_haiku(pcap_t *handle, const void *buffer, int size)
112 {
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",
117 PCAP_ERRBUF_SIZE);
118 return -1;
119 }
120
121
122 static int
123 pcap_stats_haiku(pcap_t *handle, struct pcap_stat *stats)
124 {
125 struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
126 ifreq request;
127 int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
128 if (socket < 0) {
129 return -1;
130 }
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",
134 strerror(errno));
135 close(socket);
136 return -1;
137 }
138
139 close(socket);
140 handlep->stat.ps_recv += request.ifr_stats.receive.packets;
141 handlep->stat.ps_drop += request.ifr_stats.receive.dropped;
142 *stats = handlep->stat;
143 return 0;
144 }
145
146
147 static int
148 pcap_activate_haiku(pcap_t *handle)
149 {
150 struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
151
152 const char* device = handle->opt.device;
153
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;
158
159 // use default hooks where possible
160 handle->getnonblock_op = pcap_getnonblock_fd;
161 handle->setnonblock_op = pcap_setnonblock_fd;
162
163 /*
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.
167 *
168 * If some application really *needs* a bigger snapshot
169 * length, we should just increase MAXIMUM_SNAPLEN.
170 */
171 if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
172 handle->snapshot = MAXIMUM_SNAPLEN;
173
174 handlep->device = strdup(device);
175 if (handlep->device == NULL) {
176 pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
177 errno, "strdup");
178 return PCAP_ERROR;
179 }
180
181 handle->bufsize = 65536;
182 // TODO: should be determined by interface MTU
183
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");
189 return PCAP_ERROR;
190 }
191
192 handle->offset = 0;
193 handle->linktype = DLT_EN10MB;
194 // TODO: check interface type!
195
196 return 0;
197 }
198
199
200 // #pragma mark - pcap API
201
202
203 extern "C" pcap_t *
204 pcap_create_interface(const char *device, char *errorBuffer)
205 {
206 // TODO: handle promiscuous mode!
207
208 // we need a socket to talk to the networking stack
209 int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
210 if (socket < 0) {
211 snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
212 "The networking stack doesn't seem to be available.\n");
213 return NULL;
214 }
215
216 struct ifreq request;
217 if (!prepare_request(request, device)) {
218 snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
219 "Interface name \"%s\" is too long.", device);
220 close(socket);
221 return NULL;
222 }
223
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);
228 close(socket);
229 return NULL;
230 }
231
232 close(socket);
233 // no longer needed after this point
234
235 // get link level interface for this interface
236
237 socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
238 if (socket < 0) {
239 snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "No link level: %s\n",
240 strerror(errno));
241 return NULL;
242 }
243
244 // start monitoring
245 if (ioctl(socket, SIOCSPACKETCAP, &request, sizeof(struct ifreq)) < 0) {
246 snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "Cannot start monitoring: %s\n",
247 strerror(errno));
248 close(socket);
249 return NULL;
250 }
251
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));
256
257 if (handle == NULL) {
258 snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "malloc: %s", strerror(errno));
259 close(socket);
260 return NULL;
261 }
262
263 handle->selectable_fd = socket;
264 handle->fd = socket;
265
266 handle->activate_op = pcap_activate_haiku;
267
268 return handle;
269 }
270
271 static int
272 can_be_bound(const char *name)
273 {
274 return 1;
275 }
276
277 static int
278 get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
279 {
280 /* TODO */
281 if (*flags & PCAP_IF_LOOPBACK) {
282 /*
283 * Loopback devices aren't wireless, and "connected"/
284 * "disconnected" doesn't apply to them.
285 */
286 *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
287 return (0);
288 }
289 return (0);
290 }
291
292 extern "C" int
293 pcap_platform_finddevs(pcap_if_list_t* _allDevices, char* errorBuffer)
294 {
295 return pcap_findalldevs_interfaces(_allDevices, errorBuffer, can_be_bound,
296 get_if_flags);
297 }
298
299 /*
300 * Libpcap version string.
301 */
302 extern "C" const char *
303 pcap_lib_version(void)
304 {
305 return (PCAP_VERSION_STRING);
306 }