Annotation of embedaddon/dhcp/common/bpf.c, revision 1.1.1.1.2.1
1.1 misho 1: /* bpf.c
2:
3: BPF socket interface code, originally contributed by Archie Cobbs. */
4:
5: /*
6: * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
7: * Copyright (c) 1996-2003 by Internet Software Consortium
8: *
9: * Permission to use, copy, modify, and distribute this software for any
10: * purpose with or without fee is hereby granted, provided that the above
11: * copyright notice and this permission notice appear in all copies.
12: *
13: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20: *
21: * Internet Systems Consortium, Inc.
22: * 950 Charter Street
23: * Redwood City, CA 94063
24: * <info@isc.org>
25: * https://www.isc.org/
26: *
27: * This software was contributed to Internet Systems Consortium
28: * by Archie Cobbs.
29: *
30: * Patches for FDDI support on Digital Unix were written by Bill
31: * Stapleton, and maintained for a while by Mike Meredith before he
32: * managed to get me to integrate them.
33: */
34:
35: #include "dhcpd.h"
36: #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) \
37: || defined (USE_LPF_RECEIVE)
38: # if defined (USE_LPF_RECEIVE)
39: # include <asm/types.h>
40: # include <linux/filter.h>
41: # define bpf_insn sock_filter /* Linux: dare to be gratuitously different. */
42: # else
43: # include <sys/ioctl.h>
44: # include <sys/uio.h>
45: # include <net/bpf.h>
46: # include <net/if_types.h>
47: # if defined (NEED_OSF_PFILT_HACKS)
48: # include <net/pfilt.h>
49: # endif
50: # endif
51:
52: #include <netinet/in_systm.h>
53: #include "includes/netinet/ip.h"
54: #include "includes/netinet/udp.h"
55: #include "includes/netinet/if_ether.h"
56: #endif
57:
58: #ifdef USE_BPF_RECEIVE
59: #include <ifaddrs.h>
60: #endif
61:
62: #include <errno.h>
63:
64: /* Reinitializes the specified interface after an address change. This
65: is not required for packet-filter APIs. */
66:
67: #ifdef USE_BPF_SEND
68: void if_reinitialize_send (info)
69: struct interface_info *info;
70: {
71: }
72: #endif
73:
74: #ifdef USE_BPF_RECEIVE
75: void if_reinitialize_receive (info)
76: struct interface_info *info;
77: {
78: }
79: #endif
80:
81: /* Called by get_interface_list for each interface that's discovered.
82: Opens a packet filter for each interface and adds it to the select
83: mask. */
84:
85: #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE)
86: int if_register_bpf (info)
87: struct interface_info *info;
88: {
89: int sock;
90: char filename[50];
91: int b;
92:
93: /* Open a BPF device */
94: for (b = 0; 1; b++) {
95: /* %Audit% 31 bytes max. %2004.06.17,Safe% */
96: sprintf(filename, BPF_FORMAT, b);
97: sock = open (filename, O_RDWR, 0);
98: if (sock < 0) {
99: if (errno == EBUSY) {
100: continue;
101: } else {
102: if (!b)
103: log_fatal ("No bpf devices.%s%s%s",
104: " Please read the README",
105: " section for your operating",
106: " system.");
107: log_fatal ("Can't find free bpf: %m");
108: }
109: } else {
110: break;
111: }
112: }
113:
114: /* Set the BPF device to point at this interface. */
115: if (ioctl (sock, BIOCSETIF, info -> ifp) < 0)
116: log_fatal ("Can't attach interface %s to bpf device %s: %m",
117: info -> name, filename);
118:
119: get_hw_addr(info->name, &info->hw_address);
120:
121: return sock;
122: }
123: #endif /* USE_BPF_SEND || USE_BPF_RECEIVE */
124:
125: #ifdef USE_BPF_SEND
126: void if_register_send (info)
127: struct interface_info *info;
128: {
129: /* If we're using the bpf API for sending and receiving,
130: we don't need to register this interface twice. */
131: #ifndef USE_BPF_RECEIVE
132: info -> wfdesc = if_register_bpf (info, interface);
133: #else
134: info -> wfdesc = info -> rfdesc;
135: #endif
136: if (!quiet_interface_discovery)
137: log_info ("Sending on BPF/%s/%s%s%s",
138: info -> name,
139: print_hw_addr (info -> hw_address.hbuf [0],
140: info -> hw_address.hlen - 1,
141: &info -> hw_address.hbuf [1]),
142: (info -> shared_network ? "/" : ""),
143: (info -> shared_network ?
144: info -> shared_network -> name : ""));
145: }
146:
147: void if_deregister_send (info)
148: struct interface_info *info;
149: {
150: /* If we're using the bpf API for sending and receiving,
151: we don't need to register this interface twice. */
152: #ifndef USE_BPF_RECEIVE
153: close (info -> wfdesc);
154: #endif
155: info -> wfdesc = -1;
156:
157: if (!quiet_interface_discovery)
158: log_info ("Disabling output on BPF/%s/%s%s%s",
159: info -> name,
160: print_hw_addr (info -> hw_address.hbuf [0],
161: info -> hw_address.hlen - 1,
162: &info -> hw_address.hbuf [1]),
163: (info -> shared_network ? "/" : ""),
164: (info -> shared_network ?
165: info -> shared_network -> name : ""));
166: }
167: #endif /* USE_BPF_SEND */
168:
169: #if defined (USE_BPF_RECEIVE) || defined (USE_LPF_RECEIVE)
170: /* Packet filter program...
171: XXX Changes to the filter program may require changes to the constant
172: offsets used in if_register_send to patch the BPF program! XXX */
173:
174: struct bpf_insn dhcp_bpf_filter [] = {
175: /* Make sure this is an IP packet... */
176: BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
177: BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
178:
179: /* Make sure it's a UDP packet... */
180: BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23),
181: BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
182:
183: /* Make sure this isn't a fragment... */
184: BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
185: BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
186:
187: /* Get the IP header length... */
188: BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),
189:
190: /* Make sure it's to the right port... */
191: BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
192: BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */
193:
194: /* If we passed all the tests, ask for the whole packet. */
195: BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
196:
197: /* Otherwise, drop it. */
198: BPF_STMT(BPF_RET+BPF_K, 0),
199: };
200:
201: #if defined (DEC_FDDI)
202: struct bpf_insn *bpf_fddi_filter;
203: #endif
204:
205: int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn);
206: #if defined (HAVE_TR_SUPPORT)
207: struct bpf_insn dhcp_bpf_tr_filter [] = {
208: /* accept all token ring packets due to variable length header */
209: /* if we want to get clever, insert the program here */
210:
211: /* If we passed all the tests, ask for the whole packet. */
212: BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
213:
214: /* Otherwise, drop it. */
215: BPF_STMT(BPF_RET+BPF_K, 0),
216: };
217:
218: int dhcp_bpf_tr_filter_len = (sizeof dhcp_bpf_tr_filter /
219: sizeof (struct bpf_insn));
220: #endif /* HAVE_TR_SUPPORT */
221: #endif /* USE_LPF_RECEIVE || USE_BPF_RECEIVE */
222:
223: #if defined (USE_BPF_RECEIVE)
224: void if_register_receive (info)
225: struct interface_info *info;
226: {
227: int flag = 1;
228: struct bpf_version v;
229: struct bpf_program p;
230: #ifdef NEED_OSF_PFILT_HACKS
231: u_int32_t bits;
232: #endif
233: #ifdef DEC_FDDI
234: int link_layer;
235: #endif /* DEC_FDDI */
236:
237: /* Open a BPF device and hang it on this interface... */
238: info -> rfdesc = if_register_bpf (info);
239:
240: /* Make sure the BPF version is in range... */
241: if (ioctl (info -> rfdesc, BIOCVERSION, &v) < 0)
242: log_fatal ("Can't get BPF version: %m");
243:
244: if (v.bv_major != BPF_MAJOR_VERSION ||
245: v.bv_minor < BPF_MINOR_VERSION)
246: log_fatal ("BPF version mismatch - recompile DHCP!");
247:
248: /* Set immediate mode so that reads return as soon as a packet
249: comes in, rather than waiting for the input buffer to fill with
250: packets. */
251: if (ioctl (info -> rfdesc, BIOCIMMEDIATE, &flag) < 0)
252: log_fatal ("Can't set immediate mode on bpf device: %m");
253:
254: #ifdef NEED_OSF_PFILT_HACKS
255: /* Allow the copyall flag to be set... */
256: if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
257: log_fatal ("Can't set ALLOWCOPYALL: %m");
258:
259: /* Clear all the packet filter mode bits first... */
260: bits = 0;
261: if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
262: log_fatal ("Can't clear pfilt bits: %m");
263:
264: /* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */
265: bits = ENBATCH | ENCOPYALL | ENBPFHDR;
266: if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
267: log_fatal ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m");
268: #endif
269: /* Get the required BPF buffer length from the kernel. */
270: if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0)
271: log_fatal ("Can't get bpf buffer length: %m");
272: info -> rbuf = dmalloc (info -> rbuf_max, MDL);
273: if (!info -> rbuf)
274: log_fatal ("Can't allocate %ld bytes for bpf input buffer.",
275: (long)(info -> rbuf_max));
276: info -> rbuf_offset = 0;
277: info -> rbuf_len = 0;
278:
279: /* Set up the bpf filter program structure. */
280: p.bf_len = dhcp_bpf_filter_len;
281:
282: #ifdef DEC_FDDI
283: /* See if this is an FDDI interface, flag it for later. */
284: if (ioctl(info -> rfdesc, BIOCGDLT, &link_layer) >= 0 &&
285: link_layer == DLT_FDDI) {
286: if (!bpf_fddi_filter) {
287: bpf_fddi_filter = dmalloc (sizeof bpf_fddi_filter,
288: MDL);
289: if (!bpf_fddi_filter)
290: log_fatal ("No memory for FDDI filter.");
291: memcpy (bpf_fddi_filter,
292: dhcp_bpf_filter, sizeof dhcp_bpf_filter);
293: /* Patch the BPF program to account for the difference
294: in length between ethernet headers (14), FDDI and
295: 802.2 headers (16 +8=24, +10).
296: XXX changes to filter program may require changes to
297: XXX the insn number(s) used below! */
298: bpf_fddi_filter[0].k += 10;
299: bpf_fddi_filter[2].k += 10;
300: bpf_fddi_filter[4].k += 10;
301: bpf_fddi_filter[6].k += 10;
302: bpf_fddi_filter[7].k += 10;
303: }
304: p.bf_insns = bpf_fddi_filter;
305: } else
306: #endif /* DEC_FDDI */
307: p.bf_insns = dhcp_bpf_filter;
308:
309: /* Patch the server port into the BPF program...
310: XXX changes to filter program may require changes
311: to the insn number(s) used below! XXX */
312: dhcp_bpf_filter [8].k = ntohs (local_port);
313:
314: if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0)
315: log_fatal ("Can't install packet filter program: %m");
316: if (!quiet_interface_discovery)
317: log_info ("Listening on BPF/%s/%s%s%s",
318: info -> name,
319: print_hw_addr (info -> hw_address.hbuf [0],
320: info -> hw_address.hlen - 1,
321: &info -> hw_address.hbuf [1]),
322: (info -> shared_network ? "/" : ""),
323: (info -> shared_network ?
324: info -> shared_network -> name : ""));
325: }
326:
327: void if_deregister_receive (info)
328: struct interface_info *info;
329: {
330: close (info -> rfdesc);
331: info -> rfdesc = -1;
332:
333: if (!quiet_interface_discovery)
334: log_info ("Disabling input on BPF/%s/%s%s%s",
335: info -> name,
336: print_hw_addr (info -> hw_address.hbuf [0],
337: info -> hw_address.hlen - 1,
338: &info -> hw_address.hbuf [1]),
339: (info -> shared_network ? "/" : ""),
340: (info -> shared_network ?
341: info -> shared_network -> name : ""));
342: }
343: #endif /* USE_BPF_RECEIVE */
344:
345: #ifdef USE_BPF_SEND
346: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
347: struct interface_info *interface;
348: struct packet *packet;
349: struct dhcp_packet *raw;
350: size_t len;
351: struct in_addr from;
352: struct sockaddr_in *to;
353: struct hardware *hto;
354: {
355: unsigned hbufp = 0, ibufp = 0;
356: double hw [4];
357: double ip [32];
358: struct iovec iov [3];
359: int result;
360:
361: if (!strcmp (interface -> name, "fallback"))
362: return send_fallback (interface, packet, raw,
363: len, from, to, hto);
364:
365: /* Assemble the headers... */
366: assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto);
367: assemble_udp_ip_header (interface,
368: (unsigned char *)ip, &ibufp, from.s_addr,
369: to -> sin_addr.s_addr, to -> sin_port,
370: (unsigned char *)raw, len);
371:
372: /* Fire it off */
373: iov [0].iov_base = ((char *)hw);
374: iov [0].iov_len = hbufp;
375: iov [1].iov_base = ((char *)ip);
376: iov [1].iov_len = ibufp;
377: iov [2].iov_base = (char *)raw;
378: iov [2].iov_len = len;
379:
380: result = writev(interface -> wfdesc, iov, 3);
381: if (result < 0)
382: log_error ("send_packet: %m");
383: return result;
384: }
385: #endif /* USE_BPF_SEND */
386:
387: #ifdef USE_BPF_RECEIVE
388: ssize_t receive_packet (interface, buf, len, from, hfrom)
389: struct interface_info *interface;
390: unsigned char *buf;
391: size_t len;
392: struct sockaddr_in *from;
393: struct hardware *hfrom;
394: {
395: int length = 0;
396: int offset = 0;
397: struct bpf_hdr hdr;
398: unsigned paylen;
399:
400: /* All this complexity is because BPF doesn't guarantee
401: that only one packet will be returned at a time. We're
402: getting what we deserve, though - this is a terrible abuse
403: of the BPF interface. Sigh. */
404:
405: /* Process packets until we get one we can return or until we've
406: done a read and gotten nothing we can return... */
407:
408: do {
409: /* If the buffer is empty, fill it. */
410: if (interface -> rbuf_offset == interface -> rbuf_len) {
411: length = read (interface -> rfdesc,
412: interface -> rbuf,
413: (size_t)interface -> rbuf_max);
414: if (length <= 0) {
415: #ifdef __FreeBSD__
416: if (errno == ENXIO) {
417: #else
418: if (errno == EIO) {
419: #endif
420: dhcp_interface_remove
421: ((omapi_object_t *)interface,
422: (omapi_object_t *)0);
423: }
424: return length;
425: }
426: interface -> rbuf_offset = 0;
427: interface -> rbuf_len = BPF_WORDALIGN (length);
428: }
429:
430: /* If there isn't room for a whole bpf header, something went
431: wrong, but we'll ignore it and hope it goes away... XXX */
432: if (interface -> rbuf_len -
433: interface -> rbuf_offset < sizeof hdr) {
434: interface -> rbuf_offset = interface -> rbuf_len;
435: continue;
436: }
437:
438: /* Copy out a bpf header... */
439: memcpy (&hdr, &interface -> rbuf [interface -> rbuf_offset],
440: sizeof hdr);
441:
442: /* If the bpf header plus data doesn't fit in what's left
443: of the buffer, stick head in sand yet again... */
444: if (interface -> rbuf_offset +
445: hdr.bh_hdrlen + hdr.bh_caplen > interface -> rbuf_len) {
446: interface -> rbuf_offset = interface -> rbuf_len;
447: continue;
448: }
449:
450: /* If the captured data wasn't the whole packet, or if
451: the packet won't fit in the input buffer, all we
452: can do is drop it. */
453: if (hdr.bh_caplen != hdr.bh_datalen) {
454: interface -> rbuf_offset =
455: BPF_WORDALIGN (interface -> rbuf_offset +
456: hdr.bh_hdrlen + hdr.bh_caplen);
457: continue;
458: }
459:
460: /* Skip over the BPF header... */
461: interface -> rbuf_offset += hdr.bh_hdrlen;
462:
463: /* Decode the physical header... */
464: offset = decode_hw_header (interface,
465: interface -> rbuf,
466: interface -> rbuf_offset,
467: hfrom);
468:
469: /* If a physical layer checksum failed (dunno of any
470: physical layer that supports this, but WTH), skip this
471: packet. */
472: if (offset < 0) {
473: interface -> rbuf_offset =
474: BPF_WORDALIGN (interface -> rbuf_offset +
475: hdr.bh_caplen);
476: continue;
477: }
478: interface -> rbuf_offset += offset;
479: hdr.bh_caplen -= offset;
480:
481: /* Decode the IP and UDP headers... */
482: offset = decode_udp_ip_header (interface,
483: interface -> rbuf,
484: interface -> rbuf_offset,
485: from, hdr.bh_caplen, &paylen);
486:
487: /* If the IP or UDP checksum was bad, skip the packet... */
488: if (offset < 0) {
489: interface -> rbuf_offset =
490: BPF_WORDALIGN (interface -> rbuf_offset +
491: hdr.bh_caplen);
492: continue;
493: }
494: interface -> rbuf_offset = interface -> rbuf_offset + offset;
495: hdr.bh_caplen -= offset;
496:
497: /* If there's not enough room to stash the packet data,
498: we have to skip it (this shouldn't happen in real
499: life, though). */
500: if (hdr.bh_caplen > len) {
501: interface -> rbuf_offset =
502: BPF_WORDALIGN (interface -> rbuf_offset +
503: hdr.bh_caplen);
504: continue;
505: }
506:
507: /* Copy out the data in the packet... */
508: memcpy(buf, interface->rbuf + interface->rbuf_offset, paylen);
509: interface -> rbuf_offset =
510: BPF_WORDALIGN (interface -> rbuf_offset +
511: hdr.bh_caplen);
512: return paylen;
513: } while (!length);
514: return 0;
515: }
516:
517: int can_unicast_without_arp (ip)
518: struct interface_info *ip;
519: {
520: return 1;
521: }
522:
523: int can_receive_unicast_unconfigured (ip)
524: struct interface_info *ip;
525: {
526: return 1;
527: }
528:
529: int supports_multiple_interfaces (ip)
530: struct interface_info *ip;
531: {
532: return 1;
533: }
534:
535: void maybe_setup_fallback ()
536: {
537: isc_result_t status;
538: struct interface_info *fbi = (struct interface_info *)0;
539: if (setup_fallback (&fbi, MDL)) {
540: if_register_fallback (fbi);
541: status = omapi_register_io_object ((omapi_object_t *)fbi,
542: if_readsocket, 0,
543: fallback_discard, 0, 0);
544: if (status != ISC_R_SUCCESS)
545: log_fatal ("Can't register I/O handle for %s: %s",
546: fbi -> name, isc_result_totext (status));
547: interface_dereference (&fbi, MDL);
548: }
549: }
550:
551: void
552: get_hw_addr(const char *name, struct hardware *hw) {
553: struct ifaddrs *ifa;
554: struct ifaddrs *p;
555: struct sockaddr_dl *sa;
556:
557: if (getifaddrs(&ifa) != 0) {
558: log_fatal("Error getting interface information; %m");
559: }
560:
561: /*
562: * Loop through our interfaces finding a match.
563: */
564: sa = NULL;
565: for (p=ifa; (p != NULL) && (sa == NULL); p = p->ifa_next) {
566: if ((p->ifa_addr->sa_family == AF_LINK) &&
567: !strcmp(p->ifa_name, name)) {
568: sa = (struct sockaddr_dl *)p->ifa_addr;
569: }
570: }
571: if (sa == NULL) {
572: log_fatal("No interface called '%s'", name);
573: }
574:
575: /*
576: * Pull out the appropriate information.
577: */
578: switch (sa->sdl_type) {
579: case IFT_ETHER:
1.1.1.1.2.1! misho 580: case IFT_L2VLAN:
1.1 misho 581: hw->hlen = sa->sdl_alen + 1;
582: hw->hbuf[0] = HTYPE_ETHER;
583: memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
584: break;
585: case IFT_ISO88023:
586: case IFT_ISO88024: /* "token ring" */
587: case IFT_ISO88025:
588: case IFT_ISO88026:
589: hw->hlen = sa->sdl_alen + 1;
590: hw->hbuf[0] = HTYPE_IEEE802;
591: memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
592: break;
593: #ifdef IFT_FDDI
594: case IFT_FDDI:
595: hw->hlen = sa->sdl_alen + 1;
596: hw->hbuf[0] = HTYPE_FDDI;
597: memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
598: break;
599: #endif /* IFT_FDDI */
600: default:
601: log_fatal("Unsupported device type %d for \"%s\"",
602: sa->sdl_type, name);
603: }
604:
605: freeifaddrs(ifa);
606: }
607: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>