]> The Tcpdump Group git mirrors - libpcap/blob - pcap-haiku.cpp
Update config.{guess,sub}, timestamps 2023-01-01,2023-01-21
[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 }