summaryrefslogtreecommitdiffstats
path: root/contrib/isc-dhcp/common/bpf.c
diff options
context:
space:
mode:
authormurray <murray@FreeBSD.org>2002-02-19 11:04:34 +0000
committermurray <murray@FreeBSD.org>2002-02-19 11:04:34 +0000
commit57b30d23e7c11fa1a8c8c23f27de40971872952f (patch)
tree229464d9b3244ab78e2784c9a0a1f78de317089a /contrib/isc-dhcp/common/bpf.c
parent7acb11388cf5d680b16902b8ed6f46c46dc4d47b (diff)
downloadFreeBSD-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.c227
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
OpenPOWER on IntegriCloud