Home | History | Annotate | Line # | Download | only in common
      1  1.2  christos /*	$NetBSD: nit.c,v 1.3 2022/04/03 01:10:58 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* nit.c
      4  1.1  christos 
      5  1.1  christos    Network Interface Tap (NIT) network interface code, by Ted Lemon
      6  1.1  christos    with one crucial tidbit of help from Stu Grossmen. */
      7  1.1  christos 
      8  1.1  christos /*
      9  1.3  christos  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
     10  1.1  christos  * Copyright (c) 1996-2003 by Internet Software Consortium
     11  1.1  christos  *
     12  1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
     13  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     14  1.1  christos  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     15  1.1  christos  *
     16  1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     17  1.1  christos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     18  1.1  christos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     19  1.1  christos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     20  1.1  christos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     21  1.1  christos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     22  1.1  christos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     23  1.1  christos  *
     24  1.1  christos  *   Internet Systems Consortium, Inc.
     25  1.3  christos  *   PO Box 360
     26  1.3  christos  *   Newmarket, NH 03857 USA
     27  1.1  christos  *   <info (at) isc.org>
     28  1.1  christos  *   https://www.isc.org/
     29  1.1  christos  *
     30  1.1  christos  */
     31  1.1  christos 
     32  1.1  christos #include <sys/cdefs.h>
     33  1.2  christos __RCSID("$NetBSD: nit.c,v 1.3 2022/04/03 01:10:58 christos Exp $");
     34  1.1  christos 
     35  1.1  christos #include "dhcpd.h"
     36  1.1  christos #if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE)
     37  1.1  christos #include <sys/ioctl.h>
     38  1.1  christos #include <sys/uio.h>
     39  1.1  christos 
     40  1.1  christos #include <sys/time.h>
     41  1.1  christos #include <net/nit.h>
     42  1.1  christos #include <net/nit_if.h>
     43  1.1  christos #include <net/nit_pf.h>
     44  1.1  christos #include <net/nit_buf.h>
     45  1.1  christos #include <sys/stropts.h>
     46  1.1  christos #include <net/packetfilt.h>
     47  1.1  christos 
     48  1.1  christos #include <netinet/in_systm.h>
     49  1.1  christos #include "includes/netinet/ip.h"
     50  1.1  christos #include "includes/netinet/udp.h"
     51  1.1  christos #include "includes/netinet/if_ether.h"
     52  1.1  christos 
     53  1.1  christos /* Reinitializes the specified interface after an address change.   This
     54  1.1  christos    is not required for packet-filter APIs. */
     55  1.1  christos 
     56  1.1  christos #ifdef USE_NIT_SEND
     57  1.1  christos void if_reinitialize_send (info)
     58  1.1  christos 	struct interface_info *info;
     59  1.1  christos {
     60  1.1  christos }
     61  1.1  christos #endif
     62  1.1  christos 
     63  1.1  christos #ifdef USE_NIT_RECEIVE
     64  1.1  christos void if_reinitialize_receive (info)
     65  1.1  christos 	struct interface_info *info;
     66  1.1  christos {
     67  1.1  christos }
     68  1.1  christos #endif
     69  1.1  christos 
     70  1.1  christos /* Called by get_interface_list for each interface that's discovered.
     71  1.1  christos    Opens a packet filter for each interface and adds it to the select
     72  1.1  christos    mask. */
     73  1.1  christos 
     74  1.1  christos int if_register_nit (info)
     75  1.1  christos 	struct interface_info *info;
     76  1.1  christos {
     77  1.1  christos 	int sock;
     78  1.1  christos 	char filename[50];
     79  1.1  christos 	struct ifreq ifr;
     80  1.1  christos 	struct strioctl sio;
     81  1.1  christos 
     82  1.1  christos 	/* Open a NIT device */
     83  1.1  christos 	sock = open ("/dev/nit", O_RDWR);
     84  1.1  christos 	if (sock < 0)
     85  1.1  christos 		log_fatal ("Can't open NIT device for %s: %m", info -> name);
     86  1.1  christos 
     87  1.1  christos 	/* Set the NIT device to point at this interface. */
     88  1.1  christos 	sio.ic_cmd = NIOCBIND;
     89  1.1  christos 	sio.ic_len = sizeof *(info -> ifp);
     90  1.1  christos 	sio.ic_dp = (char *)(info -> ifp);
     91  1.1  christos 	sio.ic_timout = INFTIM;
     92  1.1  christos 	if (ioctl (sock, I_STR, &sio) < 0)
     93  1.1  christos 		log_fatal ("Can't attach interface %s to nit device: %m",
     94  1.1  christos 		       info -> name);
     95  1.1  christos 
     96  1.1  christos 	/* Get the low-level address... */
     97  1.1  christos 	sio.ic_cmd = SIOCGIFADDR;
     98  1.1  christos 	sio.ic_len = sizeof ifr;
     99  1.1  christos 	sio.ic_dp = (char *)&ifr;
    100  1.1  christos 	sio.ic_timout = INFTIM;
    101  1.1  christos 	if (ioctl (sock, I_STR, &sio) < 0)
    102  1.1  christos 		log_fatal ("Can't get physical layer address for %s: %m",
    103  1.1  christos 		       info -> name);
    104  1.1  christos 
    105  1.1  christos 	/* XXX code below assumes ethernet interface! */
    106  1.1  christos 	info -> hw_address.hlen = 7;
    107  1.1  christos 	info -> hw_address.hbuf [0] = ARPHRD_ETHER;
    108  1.1  christos 	memcpy (&info -> hw_address.hbuf [1],
    109  1.1  christos 		ifr.ifr_ifru.ifru_addr.sa_data, 6);
    110  1.1  christos 
    111  1.1  christos 	if (ioctl (sock, I_PUSH, "pf") < 0)
    112  1.1  christos 		log_fatal ("Can't push packet filter onto NIT for %s: %m",
    113  1.1  christos 		       info -> name);
    114  1.1  christos 
    115  1.1  christos 	return sock;
    116  1.1  christos }
    117  1.1  christos #endif /* USE_NIT_SEND || USE_NIT_RECEIVE */
    118  1.1  christos 
    119  1.1  christos #ifdef USE_NIT_SEND
    120  1.1  christos void if_register_send (info)
    121  1.1  christos 	struct interface_info *info;
    122  1.1  christos {
    123  1.1  christos 	/* If we're using the nit API for sending and receiving,
    124  1.1  christos 	   we don't need to register this interface twice. */
    125  1.1  christos #ifndef USE_NIT_RECEIVE
    126  1.1  christos 	struct packetfilt pf;
    127  1.1  christos 	struct strioctl sio;
    128  1.1  christos 
    129  1.1  christos 	info -> wfdesc = if_register_nit (info);
    130  1.1  christos 
    131  1.1  christos 	pf.Pf_Priority = 0;
    132  1.1  christos 	pf.Pf_FilterLen = 1;
    133  1.1  christos 	pf.Pf_Filter [0] = ENF_PUSHZERO;
    134  1.1  christos 
    135  1.1  christos 	/* Set up an NIT filter that rejects everything... */
    136  1.1  christos 	sio.ic_cmd = NIOCSETF;
    137  1.1  christos 	sio.ic_len = sizeof pf;
    138  1.1  christos 	sio.ic_dp = (char *)&pf;
    139  1.1  christos 	sio.ic_timout = INFTIM;
    140  1.1  christos 	if (ioctl (info -> wfdesc, I_STR, &sio) < 0)
    141  1.1  christos 		log_fatal ("Can't set NIT filter: %m");
    142  1.1  christos #else
    143  1.1  christos 	info -> wfdesc = info -> rfdesc;
    144  1.1  christos #endif
    145  1.1  christos         if (!quiet_interface_discovery)
    146  1.1  christos 		log_info ("Sending on   NIT/%s%s%s",
    147  1.1  christos 		      print_hw_addr (info -> hw_address.hbuf [0],
    148  1.1  christos 				     info -> hw_address.hlen - 1,
    149  1.1  christos 				     &info -> hw_address.hbuf [1]),
    150  1.1  christos 		      (info -> shared_network ? "/" : ""),
    151  1.1  christos 		      (info -> shared_network ?
    152  1.1  christos 		       info -> shared_network -> name : ""));
    153  1.1  christos }
    154  1.1  christos 
    155  1.1  christos void if_deregister_send (info)
    156  1.1  christos 	struct interface_info *info;
    157  1.1  christos {
    158  1.1  christos 	/* If we're using the nit API for sending and receiving,
    159  1.1  christos 	   we don't need to register this interface twice. */
    160  1.1  christos #ifndef USE_NIT_RECEIVE
    161  1.1  christos 	close (info -> wfdesc);
    162  1.1  christos #endif
    163  1.1  christos 	info -> wfdesc = -1;
    164  1.1  christos         if (!quiet_interface_discovery)
    165  1.1  christos 		log_info ("Disabling output on NIT/%s%s%s",
    166  1.1  christos 		      print_hw_addr (info -> hw_address.hbuf [0],
    167  1.1  christos 				     info -> hw_address.hlen - 1,
    168  1.1  christos 				     &info -> hw_address.hbuf [1]),
    169  1.1  christos 		      (info -> shared_network ? "/" : ""),
    170  1.1  christos 		      (info -> shared_network ?
    171  1.1  christos 		       info -> shared_network -> name : ""));
    172  1.1  christos }
    173  1.1  christos #endif /* USE_NIT_SEND */
    174  1.1  christos 
    175  1.1  christos #ifdef USE_NIT_RECEIVE
    176  1.1  christos /* Packet filter program...
    177  1.1  christos    XXX Changes to the filter program may require changes to the constant
    178  1.1  christos    offsets used in if_register_send to patch the NIT program! XXX */
    179  1.1  christos 
    180  1.1  christos #if defined(RELAY_PORT)
    181  1.1  christos #error "Relay port is not yet supported for NIT"
    182  1.1  christos #endif
    183  1.1  christos 
    184  1.1  christos void if_register_receive (info)
    185  1.1  christos 	struct interface_info *info;
    186  1.1  christos {
    187  1.1  christos 	int flag = 1;
    188  1.1  christos 	u_int32_t x;
    189  1.1  christos 	struct packetfilt pf;
    190  1.1  christos 	struct strioctl sio;
    191  1.1  christos 	u_int16_t addr [2];
    192  1.1  christos 	struct timeval t;
    193  1.1  christos 
    194  1.1  christos 	/* Open a NIT device and hang it on this interface... */
    195  1.1  christos 	info -> rfdesc = if_register_nit (info);
    196  1.1  christos 
    197  1.1  christos 	/* Set the snap length to 0, which means always take the whole
    198  1.1  christos 	   packet. */
    199  1.1  christos 	x = 0;
    200  1.1  christos 	if (ioctl (info -> rfdesc, NIOCSSNAP, &x) < 0)
    201  1.1  christos 		log_fatal ("Can't set NIT snap length on %s: %m", info -> name);
    202  1.1  christos 
    203  1.1  christos 	/* Set the stream to byte stream mode */
    204  1.1  christos 	if (ioctl (info -> rfdesc, I_SRDOPT, RMSGN) != 0)
    205  1.1  christos 		log_info ("I_SRDOPT failed on %s: %m", info -> name);
    206  1.1  christos 
    207  1.1  christos #if 0
    208  1.1  christos 	/* Push on the chunker... */
    209  1.1  christos 	if (ioctl (info -> rfdesc, I_PUSH, "nbuf") < 0)
    210  1.1  christos 		log_fatal ("Can't push chunker onto NIT STREAM: %m");
    211  1.1  christos 
    212  1.1  christos 	/* Set the timeout to zero. */
    213  1.1  christos 	t.tv_sec = 0;
    214  1.1  christos 	t.tv_usec = 0;
    215  1.1  christos 	if (ioctl (info -> rfdesc, NIOCSTIME, &t) < 0)
    216  1.1  christos 		log_fatal ("Can't set chunk timeout: %m");
    217  1.1  christos #endif
    218  1.1  christos 
    219  1.1  christos 	/* Ask for no header... */
    220  1.1  christos 	x = 0;
    221  1.1  christos 	if (ioctl (info -> rfdesc, NIOCSFLAGS, &x) < 0)
    222  1.1  christos 		log_fatal ("Can't set NIT flags on %s: %m", info -> name);
    223  1.1  christos 
    224  1.1  christos 	/* Set up the NIT filter program. */
    225  1.1  christos 	/* XXX Unlike the BPF filter program, this one won't work if the
    226  1.1  christos 	   XXX IP packet is fragmented or if there are options on the IP
    227  1.1  christos 	   XXX header. */
    228  1.1  christos 	pf.Pf_Priority = 0;
    229  1.1  christos 	pf.Pf_FilterLen = 0;
    230  1.1  christos 
    231  1.1  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 6;
    232  1.1  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
    233  1.1  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
    234  1.1  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT;
    235  1.1  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
    236  1.1  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 11;
    237  1.1  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
    238  1.1  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0xFF);
    239  1.1  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_CAND;
    240  1.1  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 18;
    241  1.1  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
    242  1.2  christos 	pf.Pf_Filter [pf.Pf_FilterLen++] = *libdhcp_callbacks.local_port;
    243  1.1  christos 
    244  1.1  christos 	/* Install the filter... */
    245  1.1  christos 	sio.ic_cmd = NIOCSETF;
    246  1.1  christos 	sio.ic_len = sizeof pf;
    247  1.1  christos 	sio.ic_dp = (char *)&pf;
    248  1.1  christos 	sio.ic_timout = INFTIM;
    249  1.1  christos 	if (ioctl (info -> rfdesc, I_STR, &sio) < 0)
    250  1.1  christos 		log_fatal ("Can't set NIT filter on %s: %m", info -> name);
    251  1.1  christos 
    252  1.1  christos         if (!quiet_interface_discovery)
    253  1.1  christos 		log_info ("Listening on NIT/%s%s%s",
    254  1.1  christos 		      print_hw_addr (info -> hw_address.hbuf [0],
    255  1.1  christos 				     info -> hw_address.hlen - 1,
    256  1.1  christos 				     &info -> hw_address.hbuf [1]),
    257  1.1  christos 		      (info -> shared_network ? "/" : ""),
    258  1.1  christos 		      (info -> shared_network ?
    259  1.1  christos 		       info -> shared_network -> name : ""));
    260  1.1  christos }
    261  1.1  christos 
    262  1.1  christos void if_deregister_receive (info)
    263  1.1  christos 	struct interface_info *info;
    264  1.1  christos {
    265  1.1  christos 	/* If we're using the nit API for sending and receiving,
    266  1.1  christos 	   we don't need to register this interface twice. */
    267  1.1  christos 	close (info -> rfdesc);
    268  1.1  christos 	info -> rfdesc = -1;
    269  1.1  christos 
    270  1.1  christos         if (!quiet_interface_discovery)
    271  1.1  christos 		log_info ("Disabling input on NIT/%s%s%s",
    272  1.1  christos 		      print_hw_addr (info -> hw_address.hbuf [0],
    273  1.1  christos 				     info -> hw_address.hlen - 1,
    274  1.1  christos 				     &info -> hw_address.hbuf [1]),
    275  1.1  christos 		      (info -> shared_network ? "/" : ""),
    276  1.1  christos 		      (info -> shared_network ?
    277  1.1  christos 		       info -> shared_network -> name : ""));
    278  1.1  christos }
    279  1.1  christos #endif /* USE_NIT_RECEIVE */
    280  1.1  christos 
    281  1.1  christos #ifdef USE_NIT_SEND
    282  1.1  christos ssize_t send_packet (interface, packet, raw, len, from, to, hto)
    283  1.1  christos 	struct interface_info *interface;
    284  1.1  christos 	struct packet *packet;
    285  1.1  christos 	struct dhcp_packet *raw;
    286  1.1  christos 	size_t len;
    287  1.1  christos 	struct in_addr from;
    288  1.1  christos 	struct sockaddr_in *to;
    289  1.1  christos 	struct hardware *hto;
    290  1.1  christos {
    291  1.1  christos 	unsigned hbufp, ibufp;
    292  1.1  christos 	double hh [16];
    293  1.1  christos 	double ih [1536 / sizeof (double)];
    294  1.1  christos 	unsigned char *buf = (unsigned char *)ih;
    295  1.1  christos 	struct sockaddr *junk;
    296  1.1  christos 	struct strbuf ctl, data;
    297  1.1  christos 	struct sockaddr_in foo;
    298  1.1  christos 	int result;
    299  1.1  christos 
    300  1.1  christos 	if (!strcmp (interface -> name, "fallback"))
    301  1.1  christos 		return send_fallback (interface, packet, raw,
    302  1.1  christos 				      len, from, to, hto);
    303  1.1  christos 
    304  1.1  christos 	if (hto == NULL && interface->anycast_mac_addr.hlen)
    305  1.1  christos 		hto = &interface->anycast_mac_addr;
    306  1.1  christos 
    307  1.1  christos 	/* Start with the sockaddr struct... */
    308  1.1  christos 	junk = (struct sockaddr *)&hh [0];
    309  1.1  christos 	hbufp = (((unsigned char *)&junk -> sa_data [0]) -
    310  1.1  christos 		 (unsigned char *)&hh[0]);
    311  1.1  christos 	ibufp = 0;
    312  1.1  christos 
    313  1.1  christos 	/* Assemble the headers... */
    314  1.1  christos 	assemble_hw_header (interface, (unsigned char *)junk, &hbufp, hto);
    315  1.1  christos 	assemble_udp_ip_header (interface, buf, &ibufp,
    316  1.1  christos 				from.s_addr, to -> sin_addr.s_addr,
    317  1.1  christos 				to -> sin_port, (unsigned char *)raw, len);
    318  1.1  christos 
    319  1.1  christos 	/* Copy the data into the buffer (yuk). */
    320  1.1  christos 	memcpy (buf + ibufp, raw, len);
    321  1.1  christos 
    322  1.1  christos 	/* Set up the sockaddr structure... */
    323  1.1  christos #if USE_SIN_LEN
    324  1.1  christos 	junk -> sa_len = hbufp - 2; /* XXX */
    325  1.1  christos #endif
    326  1.1  christos 	junk -> sa_family = AF_UNSPEC;
    327  1.1  christos 
    328  1.1  christos 	/* Set up the msg_buf structure... */
    329  1.1  christos 	ctl.buf = (char *)&hh [0];
    330  1.1  christos 	ctl.maxlen = ctl.len = hbufp;
    331  1.1  christos 	data.buf = (char *)&ih [0];
    332  1.1  christos 	data.maxlen = data.len = ibufp + len;
    333  1.1  christos 
    334  1.1  christos 	result = putmsg (interface -> wfdesc, &ctl, &data, 0);
    335  1.1  christos 	if (result < 0)
    336  1.1  christos 		log_error ("send_packet: %m");
    337  1.1  christos 	return result;
    338  1.1  christos }
    339  1.1  christos #endif /* USE_NIT_SEND */
    340  1.1  christos 
    341  1.1  christos #ifdef USE_NIT_RECEIVE
    342  1.1  christos ssize_t receive_packet (interface, buf, len, from, hfrom)
    343  1.1  christos 	struct interface_info *interface;
    344  1.1  christos 	unsigned char *buf;
    345  1.1  christos 	size_t len;
    346  1.1  christos 	struct sockaddr_in *from;
    347  1.1  christos 	struct hardware *hfrom;
    348  1.1  christos {
    349  1.1  christos 	int nread;
    350  1.1  christos 	int length = 0;
    351  1.1  christos 	int offset = 0;
    352  1.1  christos 	unsigned char ibuf [1536];
    353  1.1  christos 	int bufix = 0;
    354  1.1  christos 	unsigned paylen;
    355  1.1  christos 
    356  1.1  christos 	length = read (interface -> rfdesc, ibuf, sizeof ibuf);
    357  1.1  christos 	if (length <= 0)
    358  1.1  christos 		return length;
    359  1.1  christos 
    360  1.1  christos 	/* Decode the physical header... */
    361  1.1  christos 	offset = decode_hw_header (interface, ibuf, bufix, hfrom);
    362  1.1  christos 
    363  1.1  christos 	/* If a physical layer checksum failed (dunno of any
    364  1.1  christos 	   physical layer that supports this, but WTH), skip this
    365  1.1  christos 	   packet. */
    366  1.1  christos 	if (offset < 0) {
    367  1.1  christos 		return 0;
    368  1.1  christos 	}
    369  1.1  christos 
    370  1.1  christos 	bufix += offset;
    371  1.1  christos 	length -= offset;
    372  1.1  christos 
    373  1.1  christos 	/* Decode the IP and UDP headers... */
    374  1.1  christos 	offset = decode_udp_ip_header (interface, ibuf, bufix,
    375  1.1  christos 				       from, length, &paylen, 1);
    376  1.1  christos 
    377  1.1  christos 	/* If the IP or UDP checksum was bad, skip the packet... */
    378  1.1  christos 	if (offset < 0)
    379  1.1  christos 		return 0;
    380  1.1  christos 
    381  1.1  christos 	bufix += offset;
    382  1.1  christos 	length -= offset;
    383  1.1  christos 
    384  1.1  christos 	if (length < paylen)
    385  1.1  christos 		log_fatal("Internal inconsistency at %s:%d.", MDL);
    386  1.1  christos 
    387  1.1  christos 	/* Copy out the data in the packet... */
    388  1.1  christos 	memcpy(buf, &ibuf[bufix], paylen);
    389  1.1  christos 	return paylen;
    390  1.1  christos }
    391  1.1  christos 
    392  1.1  christos int can_unicast_without_arp (ip)
    393  1.1  christos 	struct interface_info *ip;
    394  1.1  christos {
    395  1.1  christos 	return 1;
    396  1.1  christos }
    397  1.1  christos 
    398  1.1  christos int can_receive_unicast_unconfigured (ip)
    399  1.1  christos 	struct interface_info *ip;
    400  1.1  christos {
    401  1.1  christos 	return 1;
    402  1.1  christos }
    403  1.1  christos 
    404  1.1  christos int supports_multiple_interfaces (ip)
    405  1.1  christos 	struct interface_info *ip;
    406  1.1  christos {
    407  1.1  christos 	return 1;
    408  1.1  christos }
    409  1.1  christos 
    410  1.1  christos void maybe_setup_fallback ()
    411  1.1  christos {
    412  1.1  christos 	isc_result_t status;
    413  1.1  christos 	struct interface_info *fbi = (struct interface_info *)0;
    414  1.1  christos 	if (setup_fallback (&fbi, MDL)) {
    415  1.1  christos 		if_register_fallback (fbi);
    416  1.1  christos 		status = omapi_register_io_object ((omapi_object_t *)fbi,
    417  1.1  christos 						   if_readsocket, 0,
    418  1.1  christos 						   fallback_discard, 0, 0);
    419  1.1  christos 		if (status != ISC_R_SUCCESS)
    420  1.1  christos 			log_fatal ("Can't register I/O handle for %s: %s",
    421  1.1  christos 				   fbi -> name, isc_result_totext (status));
    422  1.1  christos 		interface_dereference (&fbi, MDL);
    423  1.1  christos 	}
    424  1.1  christos }
    425  1.1  christos #endif
    426