]> The Tcpdump Group git mirrors - libpcap/blob - pcap-hurd.c
Remove some apparently-unneeded includes.
[libpcap] / pcap-hurd.c
1 #define _GNU_SOURCE
2
3 /* XXX Hack not to include the Mach BPF interface */
4 #define _DEVICE_BPF_H_
5
6 #include <config.h>
7
8 #include <fcntl.h>
9 #include <hurd.h>
10 #include <mach.h>
11 #include <time.h>
12 #include <errno.h>
13 #include <stdio.h>
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <device/device.h>
18 #include <device/device_types.h>
19 #include <device/net_status.h>
20 #include <net/if_ether.h>
21
22 #include "pcap-int.h"
23
24 struct pcap_hurd {
25 struct pcap_stat stat;
26 device_t mach_dev;
27 mach_port_t rcv_port;
28 int filtering_in_kernel;
29 };
30
31 /* Accept all packets. */
32 static struct bpf_insn filter[] = {
33 { NETF_IN | NETF_OUT | NETF_BPF, 0, 0, 0 },
34 { BPF_RET | BPF_K, 0, 0, MAXIMUM_SNAPLEN },
35 };
36
37 /* device_set_filter calls net_set_filter which uses CSPF_BYTES which counts in
38 * shorts, not elements, so using extra parenthesis to silence compilers which
39 * believe we are computing wrong here. */
40 #define FILTER_COUNT (sizeof(filter) / (sizeof(short)))
41
42 static int
43 PCAP_WARN_UNUSED_RESULT
44 pcap_device_set_filter(pcap_t *p, filter_array_t filter_array,
45 const mach_msg_type_number_t filter_count)
46 {
47 kern_return_t kr;
48 struct pcap_hurd *ph = p->priv;
49 kr = device_set_filter(ph->mach_dev, ph->rcv_port,
50 MACH_MSG_TYPE_MAKE_SEND, 0,
51 filter_array, filter_count);
52 if (! kr)
53 return 0;
54 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno,
55 "device_set_filter");
56 return PCAP_ERROR;
57 }
58
59 static int
60 pcap_setfilter_hurd(pcap_t *p, struct bpf_program *program)
61 {
62 if (! program || pcapint_install_bpf_program(p, program) < 0) {
63 pcapint_strlcpy(p->errbuf, "setfilter: invalid program",
64 sizeof(p->errbuf));
65 return PCAP_ERROR;
66 }
67
68 /*
69 * The bytecode is valid and the copy in p->fcode can be used for
70 * userland filtering if kernel filtering does not work out.
71 *
72 * The kernel BPF implementation supports neither BPF_MOD nor BPF_XOR,
73 * it also fails to reject unsupported bytecode properly, so the check
74 * must be done here.
75 */
76 struct pcap_hurd *ph = p->priv;
77 for (u_int i = 0; i < program->bf_len; i++) {
78 u_short c = program->bf_insns[i].code;
79 if (BPF_CLASS(c) == BPF_ALU &&
80 (BPF_OP(c) == BPF_MOD || BPF_OP(c) == BPF_XOR))
81 goto userland;
82 }
83
84 /*
85 * The kernel takes an array of 16-bit Hurd network filter commands, no
86 * more than NET_MAX_FILTER elements. The first four commands form a
87 * header that says "BPF bytecode follows", the rest is a binary copy
88 * of 64-bit instructions of the required BPF bytecode.
89 */
90 mach_msg_type_number_t cmdcount = 4 + 4 * program->bf_len;
91 if (cmdcount > NET_MAX_FILTER)
92 goto userland;
93
94 filter_t cmdbuffer[NET_MAX_FILTER];
95 memcpy(cmdbuffer, filter, sizeof(struct bpf_insn));
96 memcpy(cmdbuffer + 4, program->bf_insns,
97 program->bf_len * sizeof(struct bpf_insn));
98 if (pcap_device_set_filter(p, cmdbuffer, cmdcount))
99 goto userland;
100 ph->filtering_in_kernel = 1;
101 return 0;
102
103 userland:
104 /*
105 * Could not install a new kernel filter for a reason, so replace any
106 * previous kernel filter with one that accepts all packets and lets
107 * userland filtering do the job. If that fails too, something is
108 * badly broken and even userland filtering would not work correctly,
109 * so expose the failure.
110 */
111 ph->filtering_in_kernel = 0;
112 return pcap_device_set_filter(p, (filter_array_t)filter, FILTER_COUNT);
113 }
114
115 static int
116 pcap_read_hurd(pcap_t *p, int cnt _U_, pcap_handler callback, u_char *user)
117 {
118 struct net_rcv_msg *msg;
119 struct pcap_hurd *ph;
120 struct pcap_pkthdr h;
121 struct timespec ts;
122 int wirelen, caplen;
123 u_char *pkt;
124 kern_return_t kr;
125
126 ph = p->priv;
127 msg = (struct net_rcv_msg *)p->buffer;
128
129 retry:
130 if (p->break_loop) {
131 p->break_loop = 0;
132 return PCAP_ERROR_BREAK;
133 }
134
135 kr = mach_msg(&msg->msg_hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0,
136 p->bufsize, ph->rcv_port, MACH_MSG_TIMEOUT_NONE,
137 MACH_PORT_NULL);
138 clock_gettime(CLOCK_REALTIME, &ts);
139
140 if (kr) {
141 if (kr == MACH_RCV_INTERRUPTED)
142 goto retry;
143
144 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, kr,
145 "mach_msg");
146 return PCAP_ERROR;
147 }
148
149 ph->stat.ps_recv++;
150
151 /* XXX Ethernet support only */
152 /*
153 * wirelen calculation assumes the following:
154 * msg->packet_type.msgt_name == MACH_MSG_TYPE_BYTE
155 * msg->packet_type.msgt_size == 8
156 * msg->packet_type.msgt_number is a size in bytes
157 */
158 wirelen = ETH_HLEN + msg->net_rcv_msg_packet_count
159 - sizeof(struct packet_header);
160 pkt = p->buffer + offsetof(struct net_rcv_msg, packet)
161 + sizeof(struct packet_header) - ETH_HLEN;
162 memmove(pkt, p->buffer + offsetof(struct net_rcv_msg, header),
163 ETH_HLEN);
164
165 /*
166 * It seems, kernel device filters treat the K in BPF_MOD as a Boolean:
167 * so long as it is positive, the Mach message will contain the entire
168 * packet and wirelen will be set accordingly. Thus the caplen value
169 * for the callback needs to be calculated for every packet no matter
170 * which type of filtering is in effect.
171 *
172 * For the userland filtering this calculated value is not an input:
173 * buflen always equals wirelen and a userland program can examine the
174 * entire packet, same way as a kernel program. It is not an output
175 * either: pcapint_filter() returns either zero or MAXIMUM_SNAPLEN.
176 * The same principle applies to kernel filtering.
177 */
178 caplen = (wirelen > p->snapshot) ? p->snapshot : wirelen;
179
180 if (! ph->filtering_in_kernel &&
181 ! pcapint_filter(p->fcode.bf_insns, pkt, wirelen, wirelen)) {
182 ph->stat.ps_drop++;
183 return 0;
184 }
185
186 h.ts.tv_sec = ts.tv_sec;
187 h.ts.tv_usec = ts.tv_nsec / 1000;
188 h.len = wirelen;
189 h.caplen = caplen;
190 callback(user, &h, pkt);
191 return 1;
192 }
193
194 static int
195 pcap_inject_hurd(pcap_t *p, const void *buf, int size)
196 {
197 struct pcap_hurd *ph;
198 kern_return_t kr;
199 int count;
200
201 ph = p->priv;
202 kr = device_write(ph->mach_dev, D_NOWAIT, 0,
203 (io_buf_ptr_t)buf, size, &count);
204
205 if (kr) {
206 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, kr,
207 "device_write");
208 return -1;
209 }
210
211 return count;
212 }
213
214 static int
215 pcap_stats_hurd(pcap_t *p, struct pcap_stat *ps)
216 {
217 struct pcap_hurd *ph;
218
219 ph = p->priv;
220 *ps = ph->stat;
221 return 0;
222 }
223
224 static void
225 pcap_cleanup_hurd(pcap_t *p)
226 {
227 struct pcap_hurd *ph;
228
229 ph = p->priv;
230
231 if (ph->rcv_port != MACH_PORT_NULL) {
232 mach_port_deallocate(mach_task_self(), ph->rcv_port);
233 ph->rcv_port = MACH_PORT_NULL;
234 }
235
236 if (ph->mach_dev != MACH_PORT_NULL) {
237 device_close(ph->mach_dev);
238 ph->mach_dev = MACH_PORT_NULL;
239 }
240
241 pcapint_cleanup_live_common(p);
242 }
243
244 static int
245 pcap_activate_hurd(pcap_t *p)
246 {
247 struct pcap_hurd *ph;
248 mach_port_t master;
249 kern_return_t kr;
250 int ret = PCAP_ERROR;
251
252 ph = p->priv;
253
254 if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
255 p->snapshot = MAXIMUM_SNAPLEN;
256
257 /* Try devnode first */
258 master = file_name_lookup(p->opt.device, O_READ | O_WRITE, 0);
259
260 if (master != MACH_PORT_NULL)
261 kr = device_open(master, D_WRITE | D_READ, "eth", &ph->mach_dev);
262 else {
263 /* If unsuccessful, try Mach device */
264 kr = get_privileged_ports(NULL, &master);
265
266 if (kr) {
267 pcapint_fmt_errmsg_for_errno(p->errbuf,
268 PCAP_ERRBUF_SIZE, kr, "get_privileged_ports");
269 if (kr == EPERM)
270 ret = PCAP_ERROR_PERM_DENIED;
271 goto error;
272 }
273
274 kr = device_open(master, D_READ | D_WRITE, p->opt.device,
275 &ph->mach_dev);
276 }
277
278 mach_port_deallocate(mach_task_self(), master);
279
280 if (kr) {
281 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, kr,
282 "device_open");
283 if (kr == ED_NO_SUCH_DEVICE) /* not ENODEV */
284 ret = PCAP_ERROR_NO_SUCH_DEVICE;
285 goto error;
286 }
287
288 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
289 &ph->rcv_port);
290
291 if (kr) {
292 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, kr,
293 "mach_port_allocate");
294 goto error;
295 }
296
297 p->bufsize = sizeof(struct net_rcv_msg);
298 p->buffer = malloc(p->bufsize);
299
300 if (p->buffer == NULL) {
301 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
302 errno, "malloc");
303 goto error;
304 }
305
306 /*
307 * XXX Ethernet only currently
308 *
309 * XXX - does "Ethernet only currently" mean "the only devices
310 * on which the Hurd supports packet capture are Ethernet
311 * devices", or "it supports other devices but makes them
312 * all provide Ethernet headers"?
313 *
314 * If the latter, is there a way to determine whether the
315 * device is a real Ethernet, so that we could offer DLT_DOCSIS,
316 * in case you're capturing DOCSIS traffic that a Cisco Cable
317 * Modem Termination System is putting out onto an Ethernet
318 * (it doesn't put an Ethernet header onto the wire, it puts
319 * raw DOCSIS frames out on the wire inside the low-level
320 * Ethernet framing)?
321 */
322 p->linktype = DLT_EN10MB;
323
324 p->read_op = pcap_read_hurd;
325 p->inject_op = pcap_inject_hurd;
326 p->setfilter_op = pcap_setfilter_hurd;
327 p->stats_op = pcap_stats_hurd;
328
329 return 0;
330
331 error:
332 pcap_cleanup_hurd(p);
333 return ret;
334 }
335
336 pcap_t *
337 pcapint_create_interface(const char *device _U_, char *ebuf)
338 {
339 struct pcap_hurd *ph;
340 pcap_t *p;
341
342 p = PCAP_CREATE_COMMON(ebuf, struct pcap_hurd);
343 if (p == NULL)
344 return NULL;
345
346 ph = p->priv;
347 ph->mach_dev = MACH_PORT_NULL;
348 ph->rcv_port = MACH_PORT_NULL;
349 p->activate_op = pcap_activate_hurd;
350 return p;
351 }
352
353 static int
354 can_be_bound(const char *name)
355 {
356 /*
357 * On Hurd lo appears in the list of interfaces, but the call to
358 * device_open() fails with: "(os/device) no such device".
359 */
360 if (! strcmp(name, "lo"))
361 return 0;
362 return 1;
363 }
364
365 static int
366 get_if_flags(const char *name _U_, bpf_u_int32 *flags, char *errbuf _U_)
367 {
368 /*
369 * This would apply to the loopback interface if it worked. Ethernet
370 * interfaces appear up and running regardless of the link status.
371 */
372 *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
373 return 0;
374 }
375
376 int
377 pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
378 {
379 return pcapint_findalldevs_interfaces(devlistp, errbuf, can_be_bound,
380 get_if_flags);
381 }
382
383 /*
384 * Libpcap version string.
385 */
386 const char *
387 pcap_lib_version(void)
388 {
389 return PCAP_VERSION_STRING;
390 }