bpf.c 18.9 KB
Newer Older
Ted Lemon's avatar
Ted Lemon committed
1 2 3 4 5
/* bpf.c

   BPF socket interface code, originally contributed by Archie Cobbs. */

/*
6
 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1996-2003 by Internet Software Consortium
Ted Lemon's avatar
Ted Lemon committed
8
 *
9 10 11
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
Ted Lemon's avatar
Ted Lemon committed
12
 *
13 14 15 16 17 18 19
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Ted Lemon's avatar
Ted Lemon committed
20
 *
21 22 23 24
 *   Internet Systems Consortium, Inc.
 *   950 Charter Street
 *   Redwood City, CA 94063
 *   <info@isc.org>
25
 *   https://www.isc.org/
Ted Lemon's avatar
Ted Lemon committed
26
 *
27 28
 * This software was contributed to Internet Systems Consortium
 * by Archie Cobbs.
29 30 31 32
 *
 * 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.
Ted Lemon's avatar
Ted Lemon committed
33 34 35
 */

#include "dhcpd.h"
Ted Lemon's avatar
Ted Lemon committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49
#if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE)	\
				|| defined (USE_LPF_RECEIVE)
# if defined (USE_LPF_RECEIVE)
#  include <asm/types.h>
#  include <linux/filter.h>
#  define bpf_insn sock_filter /* Linux: dare to be gratuitously different. */
# else
#  include <sys/ioctl.h>
#  include <sys/uio.h>
#  include <net/bpf.h>
#  if defined (NEED_OSF_PFILT_HACKS)
#   include <net/pfilt.h>
#  endif
# endif
Ted Lemon's avatar
Ted Lemon committed
50 51

#include <netinet/in_systm.h>
52 53 54
#include "includes/netinet/ip.h"
#include "includes/netinet/udp.h"
#include "includes/netinet/if_ether.h"
Ted Lemon's avatar
Ted Lemon committed
55
#endif
Ted Lemon's avatar
Ted Lemon committed
56

57 58
#if defined(USE_BPF_SEND) || defined(USE_BPF_RECEIVE) || defined(USE_BPF_HWADDR)
#include <net/if_types.h>
59
#include <ifaddrs.h>
60
#endif
61

62 63
#include <errno.h>

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
/* Reinitializes the specified interface after an address change.   This
   is not required for packet-filter APIs. */

#ifdef USE_BPF_SEND
void if_reinitialize_send (info)
	struct interface_info *info;
{
}
#endif

#ifdef USE_BPF_RECEIVE
void if_reinitialize_receive (info)
	struct interface_info *info;
{
}
#endif

Ted Lemon's avatar
Ted Lemon committed
81 82 83 84
/* Called by get_interface_list for each interface that's discovered.
   Opens a packet filter for each interface and adds it to the select
   mask. */

Ted Lemon's avatar
Ted Lemon committed
85
#if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE)
86
int if_register_bpf (info)
87
	struct interface_info *info;
Ted Lemon's avatar
Ted Lemon committed
88
{
89
	int sock;
Ted Lemon's avatar
Ted Lemon committed
90
	char filename[50];
91
	int b;
Ted Lemon's avatar
Ted Lemon committed
92 93 94

	/* Open a BPF device */
	for (b = 0; 1; b++) {
95
		/* %Audit% 31 bytes max. %2004.06.17,Safe% */
96
		sprintf(filename, BPF_FORMAT, b);
97 98
		sock = open (filename, O_RDWR, 0);
		if (sock < 0) {
Ted Lemon's avatar
Ted Lemon committed
99 100 101
			if (errno == EBUSY) {
				continue;
			} else {
Ted Lemon's avatar
Ted Lemon committed
102
				if (!b)
103
					log_fatal ("No bpf devices.%s%s%s",
Ted Lemon's avatar
Ted Lemon committed
104 105 106
					       "   Please read the README",
					       " section for your operating",
					       " system.");
107
				log_fatal ("Can't find free bpf: %m");
Ted Lemon's avatar
Ted Lemon committed
108 109 110 111 112 113 114
			}
		} else {
			break;
		}
	}

	/* 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",
Ted Lemon's avatar
Ted Lemon committed
117
		       info -> name, filename);
118

119 120
	get_hw_addr(info->name, &info->hw_address);

121 122 123 124 125
	return sock;
}
#endif /* USE_BPF_SEND || USE_BPF_RECEIVE */

#ifdef USE_BPF_SEND
126
void if_register_send (info)
127 128 129 130 131 132 133 134 135
	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
	info -> wfdesc = if_register_bpf (info, interface);
#else
	info -> wfdesc = info -> rfdesc;
#endif
136
	if (!quiet_interface_discovery)
137
		log_info ("Sending on   BPF/%s/%s%s%s",
138
		      info -> name,
Ted Lemon's avatar
Ted Lemon committed
139 140 141
		      print_hw_addr (info -> hw_address.hbuf [0],
				     info -> hw_address.hlen - 1,
				     &info -> hw_address.hbuf [1]),
142
		      (info -> shared_network ? "/" : ""),
143
		      (info -> shared_network ?
144
		       info -> shared_network -> name : ""));
Ted Lemon's avatar
Ted Lemon committed
145
}
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

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.hbuf [0],
				     info -> hw_address.hlen - 1,
				     &info -> hw_address.hbuf [1]),
		      (info -> shared_network ? "/" : ""),
		      (info -> shared_network ?
		       info -> shared_network -> name : ""));
}
167 168
#endif /* USE_BPF_SEND */

Ted Lemon's avatar
Ted Lemon committed
169
#if defined (USE_BPF_RECEIVE) || defined (USE_LPF_RECEIVE)
170 171 172 173
/* Packet filter program...
   XXX Changes to the filter program may require changes to the constant
   offsets used in if_register_send to patch the BPF program! XXX */

Ted Lemon's avatar
Ted Lemon committed
174
struct bpf_insn dhcp_bpf_filter [] = {
175 176
	/* Make sure this is an IP packet... */
	BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
177
	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
178 179 180

	/* Make sure it's a UDP packet... */
	BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23),
181
	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
182 183 184

	/* Make sure this isn't a fragment... */
	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
185
	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
186 187 188 189 190 191

	/* Get the IP header length... */
	BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),

	/* Make sure it's to the right port... */
	BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
192
	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),             /* patch */
Ted Lemon's avatar
Ted Lemon committed
193

194
	/* If we passed all the tests, ask for the whole packet. */
Francis Dupont's avatar
Francis Dupont committed
195
	BPF_STMT (BPF_RET + BPF_K, (u_int)-1),
196 197

	/* Otherwise, drop it. */
Francis Dupont's avatar
Francis Dupont committed
198
	BPF_STMT (BPF_RET + BPF_K, 0),
199 200
};

Francis Dupont's avatar
Francis Dupont committed
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
#if defined(RELAY_PORT)
/*
 * For relay port extension
 */
struct bpf_insn dhcp_bpf_relay_filter [] = {
	/* Make sure this is an IP packet... */
	BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10),

	/* Make sure it's a UDP packet... */
	BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23),
	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8),

	/* Make sure this isn't a fragment... */
	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0),

	/* Get the IP header length... */
	BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),

	/* Make sure it's to the right port... */
	BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 2, 0),             /* patch */

	/* relay can have an alternative port... */
	BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),             /* patch */

	/* If we passed all the tests, ask for the whole packet. */
	BPF_STMT (BPF_RET + BPF_K, (u_int)-1),

	/* Otherwise, drop it. */
	BPF_STMT (BPF_RET + BPF_K, 0),
};

int dhcp_bpf_relay_filter_len =
	sizeof dhcp_bpf_relay_filter / sizeof (struct bpf_insn);
#endif

240
#if defined (DEC_FDDI)
241
struct bpf_insn *bpf_fddi_filter = NULL;
242
#endif
243

Ted Lemon's avatar
Ted Lemon committed
244
int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn);
245
#if defined (HAVE_TR_SUPPORT)
Ted Lemon's avatar
Ted Lemon committed
246 247 248 249 250 251 252 253 254 255 256 257 258
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 */

	/* If we passed all the tests, ask for the whole packet. */
	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),

	/* Otherwise, drop it. */
	BPF_STMT(BPF_RET+BPF_K, 0),
};

int dhcp_bpf_tr_filter_len = (sizeof dhcp_bpf_tr_filter /
			      sizeof (struct bpf_insn));
259 260
#endif /* HAVE_TR_SUPPORT */
#endif /* USE_LPF_RECEIVE || USE_BPF_RECEIVE */
Ted Lemon's avatar
Ted Lemon committed
261 262

#if defined (USE_BPF_RECEIVE)
263
void if_register_receive (info)
264 265 266 267 268
	struct interface_info *info;
{
	int flag = 1;
	struct bpf_version v;
	struct bpf_program p;
269
#ifdef NEED_OSF_PFILT_HACKS
270
	u_int32_t bits;
271
#endif
272 273 274
#ifdef DEC_FDDI
	int link_layer;
#endif /* DEC_FDDI */
275 276

	/* Open a BPF device and hang it on this interface... */
277
	info -> rfdesc = if_register_bpf (info);
278 279 280

	/* Make sure the BPF version is in range... */
	if (ioctl (info -> rfdesc, BIOCVERSION, &v) < 0)
281
		log_fatal ("Can't get BPF version: %m");
282 283 284

	if (v.bv_major != BPF_MAJOR_VERSION ||
	    v.bv_minor < BPF_MINOR_VERSION)
285
		log_fatal ("BPF version mismatch - recompile DHCP!");
286 287 288 289 290

	/* 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)
291
		log_fatal ("Can't set immediate mode on bpf device: %m");
292

293 294 295
#ifdef NEED_OSF_PFILT_HACKS
	/* Allow the copyall flag to be set... */
	if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
296
		log_fatal ("Can't set ALLOWCOPYALL: %m");
297 298 299 300

	/* Clear all the packet filter mode bits first... */
	bits = 0;
	if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
301
		log_fatal ("Can't clear pfilt bits: %m");
302 303 304 305

	/* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */
	bits = ENBATCH | ENCOPYALL | ENBPFHDR;
	if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
306
		log_fatal ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m");
307
#endif
308 309
	/* Get the required BPF buffer length from the kernel. */
	if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0)
310
		log_fatal ("Can't get bpf buffer length: %m");
311
	info -> rbuf = dmalloc (info -> rbuf_max, MDL);
312
	if (!info -> rbuf)
Ted Lemon's avatar
Ted Lemon committed
313 314
		log_fatal ("Can't allocate %ld bytes for bpf input buffer.",
			   (long)(info -> rbuf_max));
315 316 317 318
	info -> rbuf_offset = 0;
	info -> rbuf_len = 0;

	/* Set up the bpf filter program structure. */
Ted Lemon's avatar
Ted Lemon committed
319
	p.bf_len = dhcp_bpf_filter_len;
320 321 322 323 324

#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) {
325
		if (!bpf_fddi_filter) {
326
			bpf_fddi_filter = dmalloc (sizeof dhcp_bpf_filter,
327
						    MDL);
328
			if (!bpf_fddi_filter)
329
				log_fatal ("No memory for FDDI filter.");
330
			memcpy (bpf_fddi_filter,
331 332 333 334 335 336
				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! */
337 338 339 340 341
			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;
342
		}
343
		p.bf_insns = bpf_fddi_filter;
344 345
	} else
#endif /* DEC_FDDI */
Ted Lemon's avatar
Ted Lemon committed
346
	p.bf_insns = dhcp_bpf_filter;
347

Ted Lemon's avatar
Ted Lemon committed
348 349 350
        /* Patch the server port into the BPF  program...
	   XXX changes to filter program may require changes
	   to the insn number(s) used below! XXX */
Francis Dupont's avatar
Francis Dupont committed
351 352 353 354 355 356 357 358 359 360 361 362 363
#if defined(RELAY_PORT)
	if (relay_port) {
		/*
		 * If user defined relay UDP port, we need to filter
		 * also on the user UDP port.
		 */
		p.bf_len = dhcp_bpf_relay_filter_len;
		p.bf_insns = dhcp_bpf_relay_filter;

		dhcp_bpf_relay_filter [10].k = ntohs (relay_port);
	}
#endif
	p.bf_insns [8].k = ntohs (local_port);
Ted Lemon's avatar
Ted Lemon committed
364

365
	if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0)
366
		log_fatal ("Can't install packet filter program: %m");
367
	if (!quiet_interface_discovery)
368
		log_info ("Listening on BPF/%s/%s%s%s",
369
		      info -> name,
Ted Lemon's avatar
Ted Lemon committed
370
		      print_hw_addr (info -> hw_address.hbuf [0],
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
				     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],
Ted Lemon's avatar
Ted Lemon committed
388 389
				     info -> hw_address.hlen - 1,
				     &info -> hw_address.hbuf [1]),
390
		      (info -> shared_network ? "/" : ""),
391
		      (info -> shared_network ?
392
		       info -> shared_network -> name : ""));
393 394 395 396
}
#endif /* USE_BPF_RECEIVE */

#ifdef USE_BPF_SEND
397
ssize_t send_packet (interface, packet, raw, len, from, to, hto)
398 399 400 401
	struct interface_info *interface;
	struct packet *packet;
	struct dhcp_packet *raw;
	size_t len;
402
	struct in_addr from;
403 404 405
	struct sockaddr_in *to;
	struct hardware *hto;
{
406 407 408 409
	unsigned hbufp = 0, ibufp = 0;
	double hw [4];
	double ip [32];
	struct iovec iov [3];
410
	int result;
411

Ted Lemon's avatar
Ted Lemon committed
412 413 414 415
	if (!strcmp (interface -> name, "fallback"))
		return send_fallback (interface, packet, raw,
				      len, from, to, hto);

416 417 418
	if (hto == NULL && interface->anycast_mac_addr.hlen)
		hto = &interface->anycast_mac_addr;

419
	/* Assemble the headers... */
420 421 422
	assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto);
	assemble_udp_ip_header (interface,
				(unsigned char *)ip, &ibufp, from.s_addr,
423 424 425 426
				to -> sin_addr.s_addr, to -> sin_port,
				(unsigned char *)raw, len);

	/* Fire it off */
427 428 429 430 431 432 433 434
	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);
435
	if (result < 0)
Ted Lemon's avatar
Ted Lemon committed
436
		log_error ("send_packet: %m");
437
	return result;
438 439 440 441
}
#endif /* USE_BPF_SEND */

#ifdef USE_BPF_RECEIVE
442
ssize_t receive_packet (interface, buf, len, from, hfrom)
443 444 445 446 447 448 449 450 451
	struct interface_info *interface;
	unsigned char *buf;
	size_t len;
	struct sockaddr_in *from;
	struct hardware *hfrom;
{
	int length = 0;
	int offset = 0;
	struct bpf_hdr hdr;
452
	unsigned paylen;
453 454 455 456 457 458 459 460 461

	/* All this complexity is because BPF doesn't guarantee
	   that only one packet will be returned at a time.   We're
	   getting what we deserve, though - this is a terrible abuse
	   of the BPF interface.   Sigh. */

	/* Process packets until we get one we can return or until we've
	   done a read and gotten nothing we can return... */

462 463 464 465 466
	/* If the buffer is empty, fill it. */
	if (interface->rbuf_offset >= interface->rbuf_len) {
		length = read(interface->rfdesc, interface->rbuf,
			      (size_t)interface->rbuf_max);
		if (length <= 0) {
467
#ifdef __FreeBSD__
468
			if (errno == ENXIO) {
469
#else
470
			if (errno == EIO) {
471
#endif
472 473
				dhcp_interface_remove
					((omapi_object_t *)interface, NULL);
474
			}
475
			return (length);
476
		}
477 478 479
		interface->rbuf_offset = 0;
		interface->rbuf_len = BPF_WORDALIGN(length);
	}
480

481
	do {
482 483
		/* If there isn't room for a whole bpf header, something went
		   wrong, but we'll ignore it and hope it goes away... XXX */
484 485 486
		if (interface->rbuf_len -
		    interface->rbuf_offset < sizeof hdr) {
			interface->rbuf_offset = interface->rbuf_len;
487 488 489 490
			continue;
		}

		/* Copy out a bpf header... */
491 492
		memcpy(&hdr, &interface->rbuf[interface->rbuf_offset],
		       sizeof hdr);
493 494 495

		/* If the bpf header plus data doesn't fit in what's left
		   of the buffer, stick head in sand yet again... */
496 497 498
		if (interface->rbuf_offset +
		    hdr.bh_hdrlen + hdr.bh_caplen > interface->rbuf_len) {
			interface->rbuf_offset = interface->rbuf_len;
499 500 501 502 503 504 505
			continue;
		}

		/* If the captured data wasn't the whole packet, or if
		   the packet won't fit in the input buffer, all we
		   can do is drop it. */
		if (hdr.bh_caplen != hdr.bh_datalen) {
506 507 508
			interface->rbuf_offset =
				BPF_WORDALIGN(interface->rbuf_offset +
					      hdr.bh_hdrlen + hdr.bh_caplen);
509 510 511 512
			continue;
		}

		/* Skip over the BPF header... */
513
		interface->rbuf_offset += hdr.bh_hdrlen;
514 515

		/* Decode the physical header... */
516 517
		offset = decode_hw_header(interface, interface->rbuf,
					  interface->rbuf_offset, hfrom);
518 519 520 521 522

		/* If a physical layer checksum failed (dunno of any
		   physical layer that supports this, but WTH), skip this
		   packet. */
		if (offset < 0) {
523 524 525
			interface->rbuf_offset = 
				BPF_WORDALIGN(interface->rbuf_offset +
					      hdr.bh_caplen);
526 527
			continue;
		}
528
		interface->rbuf_offset += offset;
529 530 531
		hdr.bh_caplen -= offset;

		/* Decode the IP and UDP headers... */
532
		offset = decode_udp_ip_header(interface, interface->rbuf,
533 534
					      interface->rbuf_offset,
                                              from, hdr.bh_caplen, &paylen, 1);
535 536 537

		/* If the IP or UDP checksum was bad, skip the packet... */
		if (offset < 0) {
538 539 540
			interface->rbuf_offset = 
				BPF_WORDALIGN(interface->rbuf_offset +
					      hdr.bh_caplen);
541 542
			continue;
		}
543
		interface->rbuf_offset = interface->rbuf_offset + offset;
544 545 546 547 548 549
		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) {
550 551
			interface->rbuf_offset =
				BPF_WORDALIGN(interface->rbuf_offset +
Ted Lemon's avatar
Ted Lemon committed
552
					       hdr.bh_caplen);
553 554 555 556
			continue;
		}

		/* Copy out the data in the packet... */
557
		memcpy(buf, interface->rbuf + interface->rbuf_offset, paylen);
558 559
		interface->rbuf_offset =
			BPF_WORDALIGN(interface->rbuf_offset + hdr.bh_caplen);
560
		return paylen;
561 562 563
	} while (interface->rbuf_offset < interface->rbuf_len);

	return (0);
564
}
Ted Lemon's avatar
Ted Lemon committed
565

Ted Lemon's avatar
Ted Lemon committed
566 567
int can_unicast_without_arp (ip)
	struct interface_info *ip;
Ted Lemon's avatar
Ted Lemon committed
568 569 570 571
{
	return 1;
}

Ted Lemon's avatar
Ted Lemon committed
572 573
int can_receive_unicast_unconfigured (ip)
	struct interface_info *ip;
574 575 576 577
{
	return 1;
}

578 579 580 581 582 583
int supports_multiple_interfaces (ip)
	struct interface_info *ip;
{
	return 1;
}

Ted Lemon's avatar
Ted Lemon committed
584 585
void maybe_setup_fallback ()
{
Ted Lemon's avatar
Ted Lemon committed
586
	isc_result_t status;
587 588
	struct interface_info *fbi = (struct interface_info *)0;
	if (setup_fallback (&fbi, MDL)) {
Ted Lemon's avatar
Ted Lemon committed
589
		if_register_fallback (fbi);
590
		status = omapi_register_io_object ((omapi_object_t *)fbi,
Ted Lemon's avatar
Ted Lemon committed
591 592 593 594 595
						   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));
596
		interface_dereference (&fbi, MDL);
Ted Lemon's avatar
Ted Lemon committed
597 598
	}
}
599
#endif
600

601
#if defined(USE_BPF_RECEIVE) || defined(USE_BPF_HWADDR)
602 603 604 605
void
get_hw_addr(const char *name, struct hardware *hw) {
	struct ifaddrs *ifa;
	struct ifaddrs *p;
606
	struct sockaddr_dl *sa;
607 608 609 610 611 612 613 614 615 616 617 618

	if (getifaddrs(&ifa) != 0) {
		log_fatal("Error getting interface information; %m");
	}

	/*
	 * Loop through our interfaces finding a match.
	 */
	sa = NULL;
	for (p=ifa; (p != NULL) && (sa == NULL); p = p->ifa_next) {
		if ((p->ifa_addr->sa_family == AF_LINK) && 
		    !strcmp(p->ifa_name, name)) {
619
		    	sa = (struct sockaddr_dl *)p->ifa_addr;
620 621 622 623 624 625 626 627 628
		}
	}
	if (sa == NULL) {
		log_fatal("No interface called '%s'", name);
	}

	/*
	 * Pull out the appropriate information.
	 */
629 630
        switch (sa->sdl_type) {
                case IFT_ETHER:
631 632 633
#if defined (IFT_L2VLAN)
		case IFT_L2VLAN:
#endif
634
                        hw->hlen = sa->sdl_alen + 1;
635
                        hw->hbuf[0] = HTYPE_ETHER;
636
                        memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
637
                        break;
638 639 640 641 642
		case IFT_ISO88023:
		case IFT_ISO88024: /* "token ring" */
		case IFT_ISO88025:
		case IFT_ISO88026:
                        hw->hlen = sa->sdl_alen + 1;
643
                        hw->hbuf[0] = HTYPE_IEEE802;
644
                        memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
645
                        break;
646 647 648
#ifdef IFT_FDDI
                case IFT_FDDI:
                        hw->hlen = sa->sdl_alen + 1;
649
                        hw->hbuf[0] = HTYPE_FDDI;
650
                        memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
651
                        break;
652
#endif /* IFT_FDDI */
653 654
                default:
                        log_fatal("Unsupported device type %d for \"%s\"",
David Hankins's avatar
David Hankins committed
655
                                  sa->sdl_type, name);
656 657 658 659
        }

	freeifaddrs(ifa);
}
660
#endif