diff options
author | murray <murray@FreeBSD.org> | 2002-02-19 11:04:34 +0000 |
---|---|---|
committer | murray <murray@FreeBSD.org> | 2002-02-19 11:04:34 +0000 |
commit | 57b30d23e7c11fa1a8c8c23f27de40971872952f (patch) | |
tree | 229464d9b3244ab78e2784c9a0a1f78de317089a /contrib/isc-dhcp/common/bpf.c | |
parent | 7acb11388cf5d680b16902b8ed6f46c46dc4d47b (diff) | |
download | FreeBSD-src-57b30d23e7c11fa1a8c8c23f27de40971872952f.zip FreeBSD-src-57b30d23e7c11fa1a8c8c23f27de40971872952f.tar.gz |
Import ISC DHCP 3.0.1 RC6 client.
Diffstat (limited to 'contrib/isc-dhcp/common/bpf.c')
-rw-r--r-- | contrib/isc-dhcp/common/bpf.c | 227 |
1 files changed, 168 insertions, 59 deletions
diff --git a/contrib/isc-dhcp/common/bpf.c b/contrib/isc-dhcp/common/bpf.c index e204dfe..49af907 100644 --- a/contrib/isc-dhcp/common/bpf.c +++ b/contrib/isc-dhcp/common/bpf.c @@ -3,8 +3,8 @@ BPF socket interface code, originally contributed by Archie Cobbs. */ /* - * Copyright (c) 1995, 1996, 1998, 1999 - * The Internet Software Consortium. All rights reserved. + * Copyright (c) 1996-2000 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,16 +33,21 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * This software was contributed to the Internet Software Consortium + * by Archie Cobbs, and is now maintained by Ted Lemon in cooperation + * with Nominum, Inc. To learn more about the Internet Software + * Consortium, see ``http://www.isc.org/''. To learn more about Vixie + * Enterprises, see ``http://www.vix.com''. To learn more about + * Nominum, Inc., see ``http://www.nominum.com''. + * + * Patches for FDDI support on Digital Unix were written by Bill + * Stapleton, and maintained for a while by Mike Meredith before he + * managed to get me to integrate them. */ #ifndef lint static char copyright[] = -"$Id: bpf.c,v 1.19.2.10 1999/05/27 17:44:51 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: bpf.c,v 1.48 2001/04/08 21:12:49 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -55,7 +60,6 @@ static char copyright[] = # else # include <sys/ioctl.h> # include <sys/uio.h> - # include <net/bpf.h> # if defined (NEED_OSF_PFILT_HACKS) # include <net/pfilt.h> @@ -110,11 +114,11 @@ int if_register_bpf (info) continue; } else { if (!b) - error ("No bpf devices.%s%s%s", + log_fatal ("No bpf devices.%s%s%s", " Please read the README", " section for your operating", " system."); - error ("Can't find free bpf: %m"); + log_fatal ("Can't find free bpf: %m"); } } else { break; @@ -123,7 +127,7 @@ int if_register_bpf (info) /* Set the BPF device to point at this interface. */ if (ioctl (sock, BIOCSETIF, info -> ifp) < 0) - error ("Can't attach interface %s to bpf device %s: %m", + log_fatal ("Can't attach interface %s to bpf device %s: %m", info -> name, filename); return sock; @@ -142,11 +146,32 @@ void if_register_send (info) info -> wfdesc = info -> rfdesc; #endif if (!quiet_interface_discovery) - note ("Sending on BPF/%s/%s%s%s", + log_info ("Sending on BPF/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_send (info) + struct interface_info *info; +{ + /* If we're using the bpf API for sending and receiving, + we don't need to register this interface twice. */ +#ifndef USE_BPF_RECEIVE + close (info -> wfdesc); +#endif + info -> wfdesc = -1; + + if (!quiet_interface_discovery) + log_info ("Disabling output on BPF/%s/%s%s%s", info -> name, - print_hw_addr (info -> hw_address.htype, - info -> hw_address.hlen, - info -> hw_address.haddr), + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); @@ -185,8 +210,12 @@ struct bpf_insn dhcp_bpf_filter [] = { BPF_STMT(BPF_RET+BPF_K, 0), }; -int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn); +#if defined (DEC_FDDI) +struct bpf_insn *bpf_fddi_filter; +#endif +int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn); +#if defined (HAVE_TR_SUPPORT) struct bpf_insn dhcp_bpf_tr_filter [] = { /* accept all token ring packets due to variable length header */ /* if we want to get clever, insert the program here */ @@ -200,7 +229,8 @@ struct bpf_insn dhcp_bpf_tr_filter [] = { int dhcp_bpf_tr_filter_len = (sizeof dhcp_bpf_tr_filter / sizeof (struct bpf_insn)); -#endif +#endif /* HAVE_TR_SUPPORT */ +#endif /* USE_LPF_RECEIVE || USE_BPF_RECEIVE */ #if defined (USE_BPF_RECEIVE) void if_register_receive (info) @@ -211,50 +241,80 @@ void if_register_receive (info) u_int32_t addr; struct bpf_program p; u_int32_t bits; +#ifdef DEC_FDDI + int link_layer; +#endif /* DEC_FDDI */ /* Open a BPF device and hang it on this interface... */ info -> rfdesc = if_register_bpf (info); /* Make sure the BPF version is in range... */ if (ioctl (info -> rfdesc, BIOCVERSION, &v) < 0) - error ("Can't get BPF version: %m"); + log_fatal ("Can't get BPF version: %m"); if (v.bv_major != BPF_MAJOR_VERSION || v.bv_minor < BPF_MINOR_VERSION) - error ("Kernel BPF version out of range - recompile dhcpd!"); + log_fatal ("BPF version mismatch - recompile DHCP!"); /* Set immediate mode so that reads return as soon as a packet comes in, rather than waiting for the input buffer to fill with packets. */ if (ioctl (info -> rfdesc, BIOCIMMEDIATE, &flag) < 0) - error ("Can't set immediate mode on bpf device: %m"); + log_fatal ("Can't set immediate mode on bpf device: %m"); #ifdef NEED_OSF_PFILT_HACKS /* Allow the copyall flag to be set... */ if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) - error ("Can't set ALLOWCOPYALL: %m"); + log_fatal ("Can't set ALLOWCOPYALL: %m"); /* Clear all the packet filter mode bits first... */ bits = 0; if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) - error ("Can't clear pfilt bits: %m"); + log_fatal ("Can't clear pfilt bits: %m"); /* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */ bits = ENBATCH | ENCOPYALL | ENBPFHDR; if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) - error ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m"); + log_fatal ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m"); #endif /* Get the required BPF buffer length from the kernel. */ if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0) - error ("Can't get bpf buffer length: %m"); - info -> rbuf = malloc (info -> rbuf_max); + log_fatal ("Can't get bpf buffer length: %m"); + info -> rbuf = dmalloc (info -> rbuf_max, MDL); if (!info -> rbuf) - error ("Can't allocate %d bytes for bpf input buffer."); + log_fatal ("Can't allocate %ld bytes for bpf input buffer.", + (long)(info -> rbuf_max)); info -> rbuf_offset = 0; info -> rbuf_len = 0; /* Set up the bpf filter program structure. */ p.bf_len = dhcp_bpf_filter_len; + +#ifdef DEC_FDDI + /* See if this is an FDDI interface, flag it for later. */ + if (ioctl(info -> rfdesc, BIOCGDLT, &link_layer) >= 0 && + link_layer == DLT_FDDI) { + if (!bpf_fddi_filter) { + bpf_fddi_filter = dmalloc (sizeof bpf_fddi_filter, + MDL); + if (!bpf_fddi_filter) + log_fatal ("No memory for FDDI filter."); + memcpy (bpf_fddi_filter, + dhcp_bpf_filter, sizeof dhcp_bpf_filter); + /* Patch the BPF program to account for the difference + in length between ethernet headers (14), FDDI and + 802.2 headers (16 +8=24, +10). + XXX changes to filter program may require changes to + XXX the insn number(s) used below! */ + bpf_fddi_filter[0].k += 10; + bpf_fddi_filter[2].k += 10; + bpf_fddi_filter[4].k += 10; + bpf_fddi_filter[6].k += 10; + bpf_fddi_filter[7].k += 10; + } + p.bf_insns = bpf_fddi_filter; + } else +#endif /* DEC_FDDI */ p.bf_insns = dhcp_bpf_filter; /* Patch the server port into the BPF program... @@ -263,13 +323,30 @@ void if_register_receive (info) dhcp_bpf_filter [8].k = ntohs (local_port); if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0) - error ("Can't install packet filter program: %m"); + log_fatal ("Can't install packet filter program: %m"); if (!quiet_interface_discovery) - note ("Listening on BPF/%s/%s%s%s", + log_info ("Listening on BPF/%s/%s%s%s", info -> name, - print_hw_addr (info -> hw_address.htype, - info -> hw_address.hlen, - info -> hw_address.haddr), + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_receive (info) + struct interface_info *info; +{ + close (info -> rfdesc); + info -> rfdesc = -1; + + if (!quiet_interface_discovery) + log_info ("Disabling input on BPF/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); @@ -286,30 +363,35 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct sockaddr_in *to; struct hardware *hto; { - int bufp = 0; - unsigned char buf [256]; - struct iovec iov [2]; + unsigned hbufp = 0, ibufp = 0; + double hw [4]; + double ip [32]; + struct iovec iov [3]; int result; + int fudge; if (!strcmp (interface -> name, "fallback")) return send_fallback (interface, packet, raw, len, from, to, hto); /* Assemble the headers... */ - assemble_hw_header (interface, buf, &bufp, hto); - assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, + assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto); + assemble_udp_ip_header (interface, + (unsigned char *)ip, &ibufp, from.s_addr, to -> sin_addr.s_addr, to -> sin_port, (unsigned char *)raw, len); /* Fire it off */ - iov [0].iov_base = (char *)buf; - iov [0].iov_len = bufp; - iov [1].iov_base = (char *)raw; - iov [1].iov_len = len; - - result = writev(interface -> wfdesc, iov, 2); + iov [0].iov_base = ((char *)hw); + iov [0].iov_len = hbufp; + iov [1].iov_base = ((char *)ip); + iov [1].iov_len = ibufp; + iov [2].iov_base = (char *)raw; + iov [2].iov_len = len; + + result = writev(interface -> wfdesc, iov, 3); if (result < 0) - warn ("send_packet: %m"); + log_error ("send_packet: %m"); return result; } #endif /* USE_BPF_SEND */ @@ -340,10 +422,16 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) length = read (interface -> rfdesc, interface -> rbuf, interface -> rbuf_max); - if (length <= 0) + if (length <= 0) { + if (errno == EIO) { + dhcp_interface_remove + ((omapi_object_t *)interface, + (omapi_object_t *)0); + } return length; + } interface -> rbuf_offset = 0; - interface -> rbuf_len = length; + interface -> rbuf_len = BPF_WORDALIGN (length); } /* If there isn't room for a whole bpf header, something went @@ -370,8 +458,9 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) the packet won't fit in the input buffer, all we can do is drop it. */ if (hdr.bh_caplen != hdr.bh_datalen) { - interface -> rbuf_offset += - hdr.bh_hdrlen = hdr.bh_caplen; + interface -> rbuf_offset = + BPF_WORDALIGN (interface -> rbuf_offset + + hdr.bh_hdrlen + hdr.bh_caplen); continue; } @@ -388,7 +477,9 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) physical layer that supports this, but WTH), skip this packet. */ if (offset < 0) { - interface -> rbuf_offset += hdr.bh_caplen; + interface -> rbuf_offset = + BPF_WORDALIGN (interface -> rbuf_offset + + hdr.bh_caplen); continue; } interface -> rbuf_offset += offset; @@ -404,30 +495,37 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) /* If the IP or UDP checksum was bad, skip the packet... */ if (offset < 0) { - interface -> rbuf_offset += hdr.bh_caplen; + interface -> rbuf_offset = + BPF_WORDALIGN (interface -> rbuf_offset + + hdr.bh_caplen); continue; } - interface -> rbuf_offset += offset; + interface -> rbuf_offset = interface -> rbuf_offset + offset; hdr.bh_caplen -= offset; /* If there's not enough room to stash the packet data, we have to skip it (this shouldn't happen in real life, though). */ if (hdr.bh_caplen > len) { - interface -> rbuf_offset += hdr.bh_caplen; + interface -> rbuf_offset = + BPF_WORDALIGN (interface -> rbuf_offset + + hdr.bh_caplen); continue; } /* Copy out the data in the packet... */ memcpy (buf, interface -> rbuf + interface -> rbuf_offset, hdr.bh_caplen); - interface -> rbuf_offset += hdr.bh_caplen; + interface -> rbuf_offset = + BPF_WORDALIGN (interface -> rbuf_offset + + hdr.bh_caplen); return hdr.bh_caplen; } while (!length); return 0; } -int can_unicast_without_arp () +int can_unicast_without_arp (ip) + struct interface_info *ip; { return 1; } @@ -438,14 +536,25 @@ int can_receive_unicast_unconfigured (ip) return 1; } +int supports_multiple_interfaces (ip) + struct interface_info *ip; +{ + return 1; +} + void maybe_setup_fallback () { - struct interface_info *fbi; - fbi = setup_fallback (); - if (fbi) { + isc_result_t status; + struct interface_info *fbi = (struct interface_info *)0; + if (setup_fallback (&fbi, MDL)) { if_register_fallback (fbi); - add_protocol ("fallback", fallback_interface -> wfdesc, - fallback_discard, fallback_interface); + status = omapi_register_io_object ((omapi_object_t *)fbi, + if_readsocket, 0, + fallback_discard, 0, 0); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register I/O handle for %s: %s", + fbi -> name, isc_result_totext (status)); + interface_dereference (&fbi, MDL); } } #endif |