Home | History | Annotate | Line # | Download | only in server
      1  1.2  christos /*	$NetBSD: bootp.c,v 1.3 2022/04/03 01:10:59 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* bootp.c
      4  1.1  christos 
      5  1.1  christos    BOOTP Protocol support. */
      6  1.1  christos 
      7  1.1  christos /*
      8  1.3  christos  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
      9  1.1  christos  * Copyright (c) 1995-2003 by Internet Software Consortium
     10  1.1  christos  *
     11  1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
     12  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     13  1.1  christos  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     14  1.1  christos  *
     15  1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     16  1.1  christos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     17  1.1  christos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     18  1.1  christos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     19  1.1  christos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     20  1.1  christos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     21  1.1  christos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     22  1.1  christos  *
     23  1.1  christos  *   Internet Systems Consortium, Inc.
     24  1.3  christos  *   PO Box 360
     25  1.3  christos  *   Newmarket, NH 03857 USA
     26  1.1  christos  *   <info (at) isc.org>
     27  1.1  christos  *   https://www.isc.org/
     28  1.1  christos  *
     29  1.1  christos  */
     30  1.1  christos 
     31  1.1  christos #include <sys/cdefs.h>
     32  1.2  christos __RCSID("$NetBSD: bootp.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
     33  1.1  christos 
     34  1.1  christos #include "dhcpd.h"
     35  1.1  christos #include <errno.h>
     36  1.1  christos 
     37  1.1  christos #if defined (TRACING)
     38  1.1  christos # define send_packet trace_packet_send
     39  1.1  christos #endif
     40  1.1  christos 
     41  1.1  christos void bootp (packet)
     42  1.1  christos 	struct packet *packet;
     43  1.1  christos {
     44  1.1  christos 	int result;
     45  1.1  christos 	struct host_decl *hp = (struct host_decl *)0;
     46  1.1  christos 	struct host_decl *host = (struct host_decl *)0;
     47  1.1  christos 	struct packet outgoing;
     48  1.1  christos 	struct dhcp_packet raw;
     49  1.1  christos 	struct sockaddr_in to;
     50  1.1  christos 	struct in_addr from;
     51  1.1  christos 	struct hardware hto;
     52  1.1  christos 	struct option_state *options = (struct option_state *)0;
     53  1.1  christos 	struct lease *lease = (struct lease *)0;
     54  1.1  christos 	unsigned i;
     55  1.1  christos 	struct data_string d1;
     56  1.1  christos 	struct option_cache *oc;
     57  1.1  christos 	char msgbuf [1024];
     58  1.1  christos 	int ignorep;
     59  1.1  christos 	int peer_has_leases = 0;
     60  1.1  christos 
     61  1.1  christos 	if (packet -> raw -> op != BOOTREQUEST)
     62  1.1  christos 		return;
     63  1.1  christos 
     64  1.1  christos 	/* %Audit% This is log output. %2004.06.17,Safe%
     65  1.1  christos 	 * If we truncate we hope the user can get a hint from the log.
     66  1.1  christos 	 */
     67  1.1  christos 	snprintf (msgbuf, sizeof msgbuf, "BOOTREQUEST from %s via %s",
     68  1.1  christos 		 print_hw_addr (packet -> raw -> htype,
     69  1.1  christos 				packet -> raw -> hlen,
     70  1.1  christos 				packet -> raw -> chaddr),
     71  1.1  christos 		 packet -> raw -> giaddr.s_addr
     72  1.1  christos 		 ? inet_ntoa (packet -> raw -> giaddr)
     73  1.1  christos 		 : packet -> interface -> name);
     74  1.1  christos 
     75  1.1  christos 	if (!locate_network (packet)) {
     76  1.1  christos 		log_info ("%s: network unknown", msgbuf);
     77  1.1  christos 		return;
     78  1.1  christos 	}
     79  1.1  christos 
     80  1.1  christos 	find_lease (&lease, packet, packet -> shared_network,
     81  1.1  christos 		    0, 0, (struct lease *)0, MDL);
     82  1.1  christos 
     83  1.1  christos 	if (lease && lease->host)
     84  1.1  christos 		host_reference(&hp, lease->host, MDL);
     85  1.1  christos 
     86  1.1  christos 	if (!lease || ((lease->flags & STATIC_LEASE) == 0)) {
     87  1.1  christos 		struct host_decl *h;
     88  1.1  christos 
     89  1.1  christos 		/* We didn't find an applicable fixed-address host
     90  1.1  christos 		   declaration.  Just in case we may be able to dynamically
     91  1.1  christos 		   assign an address, see if there's a host declaration
     92  1.1  christos 		   that doesn't have an ip address associated with it. */
     93  1.1  christos 
     94  1.1  christos 		if (!hp)
     95  1.1  christos 			find_hosts_by_haddr(&hp, packet->raw->htype,
     96  1.1  christos 					    packet->raw->chaddr,
     97  1.1  christos 					    packet->raw->hlen, MDL);
     98  1.1  christos 
     99  1.1  christos 		for (h = hp; h; h = h -> n_ipaddr) {
    100  1.1  christos 			if (!h -> fixed_addr) {
    101  1.1  christos 				host_reference(&host, h, MDL);
    102  1.1  christos 				break;
    103  1.1  christos 			}
    104  1.1  christos 		}
    105  1.1  christos 
    106  1.1  christos 		if (hp)
    107  1.1  christos 			host_dereference(&hp, MDL);
    108  1.1  christos 
    109  1.1  christos 		if (host) {
    110  1.1  christos 			host_reference(&hp, host, MDL);
    111  1.1  christos 			host_dereference(&host, MDL);
    112  1.1  christos 		}
    113  1.1  christos 
    114  1.1  christos 		/* Allocate a lease if we have not yet found one. */
    115  1.1  christos 		if (!lease)
    116  1.1  christos 			allocate_lease (&lease, packet,
    117  1.1  christos 					packet -> shared_network -> pools,
    118  1.1  christos 					&peer_has_leases);
    119  1.1  christos 
    120  1.1  christos 		if (lease == NULL) {
    121  1.1  christos 			log_info("%s: BOOTP from dynamic client and no "
    122  1.1  christos 				 "dynamic leases", msgbuf);
    123  1.1  christos 			goto out;
    124  1.1  christos 		}
    125  1.1  christos 
    126  1.1  christos #if defined(FAILOVER_PROTOCOL)
    127  1.1  christos 		if ((lease->pool != NULL) &&
    128  1.1  christos 		    (lease->pool->failover_peer != NULL)) {
    129  1.1  christos 			dhcp_failover_state_t *peer;
    130  1.1  christos 
    131  1.1  christos 			peer = lease->pool->failover_peer;
    132  1.1  christos 
    133  1.1  christos 			/* If we are in a failover state that bars us from
    134  1.1  christos 			 * answering, do not do so.
    135  1.1  christos 			 * If we are in a cooperative state, load balance
    136  1.1  christos 			 * (all) responses.
    137  1.1  christos 			 */
    138  1.1  christos 			if ((peer->service_state == not_responding) ||
    139  1.1  christos 			    (peer->service_state == service_startup)) {
    140  1.1  christos 				log_info("%s: not responding%s",
    141  1.1  christos 					 msgbuf, peer->nrr);
    142  1.1  christos 				goto out;
    143  1.1  christos 			} else if((peer->service_state == cooperating) &&
    144  1.1  christos 				  !load_balance_mine(packet, peer)) {
    145  1.1  christos 				log_info("%s: load balance to peer %s",
    146  1.1  christos 					 msgbuf, peer->name);
    147  1.1  christos 				goto out;
    148  1.1  christos 			}
    149  1.1  christos 		}
    150  1.1  christos #endif
    151  1.1  christos 
    152  1.1  christos 		ack_lease (packet, lease, 0, 0, msgbuf, 0, hp);
    153  1.1  christos 		goto out;
    154  1.1  christos 	}
    155  1.1  christos 
    156  1.1  christos 	/* Run the executable statements to compute the client and server
    157  1.1  christos 	   options. */
    158  1.1  christos 	option_state_allocate (&options, MDL);
    159  1.1  christos 
    160  1.1  christos 	/* Execute the subnet statements. */
    161  1.1  christos 	execute_statements_in_scope (NULL, packet, lease, NULL,
    162  1.1  christos 				     packet->options, options,
    163  1.1  christos 				     &lease->scope, lease->subnet->group,
    164  1.1  christos 				     NULL, NULL);
    165  1.1  christos 
    166  1.1  christos 	/* Execute statements from class scopes. */
    167  1.1  christos 	for (i = packet -> class_count; i > 0; i--) {
    168  1.1  christos 		execute_statements_in_scope(NULL, packet, lease, NULL,
    169  1.1  christos 					    packet->options, options,
    170  1.1  christos 					    &lease->scope,
    171  1.1  christos 					    packet->classes[i - 1]->group,
    172  1.1  christos 					    lease->subnet->group, NULL);
    173  1.1  christos 	}
    174  1.1  christos 
    175  1.1  christos 	/* Execute the host statements. */
    176  1.1  christos 	if (hp != NULL) {
    177  1.1  christos 		execute_statements_in_scope(NULL, packet, lease, NULL,
    178  1.1  christos 					    packet->options, options,
    179  1.1  christos 					    &lease->scope, hp->group,
    180  1.1  christos 					    lease->subnet->group, NULL);
    181  1.1  christos 	}
    182  1.3  christos 
    183  1.1  christos 	/* Drop the request if it's not allowed for this client. */
    184  1.1  christos 	if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTP)) &&
    185  1.1  christos 	    !evaluate_boolean_option_cache(&ignorep, packet, lease,
    186  1.1  christos 					   NULL,
    187  1.1  christos 					   packet->options, options,
    188  1.1  christos 					   &lease->scope, oc, MDL)) {
    189  1.1  christos 		if (!ignorep)
    190  1.1  christos 			log_info ("%s: bootp disallowed", msgbuf);
    191  1.1  christos 		goto out;
    192  1.3  christos 	}
    193  1.1  christos 
    194  1.1  christos 	if ((oc = lookup_option(&server_universe,
    195  1.1  christos 				 options, SV_ALLOW_BOOTING)) &&
    196  1.1  christos 	    !evaluate_boolean_option_cache(&ignorep, packet, lease,
    197  1.1  christos 					   NULL,
    198  1.1  christos 					   packet->options, options,
    199  1.1  christos 					   &lease->scope, oc, MDL)) {
    200  1.1  christos 		if (!ignorep)
    201  1.1  christos 			log_info ("%s: booting disallowed", msgbuf);
    202  1.1  christos 		goto out;
    203  1.1  christos 	}
    204  1.1  christos 
    205  1.1  christos 	/* Set up the outgoing packet... */
    206  1.1  christos 	memset (&outgoing, 0, sizeof outgoing);
    207  1.1  christos 	memset (&raw, 0, sizeof raw);
    208  1.1  christos 	outgoing.raw = &raw;
    209  1.1  christos 
    210  1.1  christos 	/* If we didn't get a known vendor magic number on the way in,
    211  1.1  christos 	   just copy the input options to the output. */
    212  1.1  christos 	i = SV_ALWAYS_REPLY_RFC1048;
    213  1.1  christos 	if (!packet->options_valid &&
    214  1.1  christos 	    !(evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
    215  1.1  christos 					    packet->options, options,
    216  1.1  christos 					    &lease->scope,
    217  1.1  christos 					    lookup_option (&server_universe,
    218  1.1  christos 							   options, i), MDL))) {
    219  1.1  christos 		if (packet->packet_length > DHCP_FIXED_NON_UDP) {
    220  1.1  christos 			memcpy(outgoing.raw->options, packet->raw->options,
    221  1.1  christos 			packet->packet_length - DHCP_FIXED_NON_UDP);
    222  1.1  christos 		}
    223  1.1  christos 
    224  1.1  christos 		outgoing.packet_length =
    225  1.1  christos 			(packet->packet_length < BOOTP_MIN_LEN)
    226  1.1  christos 					       ? BOOTP_MIN_LEN
    227  1.1  christos 					       : packet->packet_length;
    228  1.1  christos 	} else {
    229  1.1  christos 
    230  1.1  christos 		/* Use the subnet mask from the subnet declaration if no other
    231  1.1  christos 		   mask has been provided. */
    232  1.1  christos 		oc = (struct option_cache *)0;
    233  1.1  christos 		i = DHO_SUBNET_MASK;
    234  1.1  christos 		if (!lookup_option (&dhcp_universe, options, i)) {
    235  1.1  christos 			if (option_cache_allocate (&oc, MDL)) {
    236  1.1  christos 				if (make_const_data
    237  1.1  christos 				    (&oc -> expression,
    238  1.1  christos 				     lease -> subnet -> netmask.iabuf,
    239  1.1  christos 				     lease -> subnet -> netmask.len,
    240  1.1  christos 				     0, 0, MDL)) {
    241  1.1  christos 					option_code_hash_lookup(&oc->option,
    242  1.1  christos 							dhcp_universe.code_hash,
    243  1.1  christos 								&i, 0, MDL);
    244  1.1  christos 					save_option (&dhcp_universe,
    245  1.1  christos 						     options, oc);
    246  1.1  christos 				}
    247  1.1  christos 				option_cache_dereference (&oc, MDL);
    248  1.1  christos 			}
    249  1.1  christos 		}
    250  1.1  christos 
    251  1.1  christos 		/* If use-host-decl-names is enabled and there is a hostname
    252  1.1  christos 		 * defined in the host delcartion, send it back in hostname
    253  1.1  christos 		 * option */
    254  1.1  christos 		use_host_decl_name(packet, lease, options);
    255  1.1  christos 
    256  1.1  christos 		/* Pack the options into the buffer.  Unlike DHCP, we
    257  1.1  christos 		   can't pack options into the filename and server
    258  1.1  christos 		   name buffers. */
    259  1.1  christos 
    260  1.1  christos 		outgoing.packet_length =
    261  1.1  christos 			cons_options (packet, outgoing.raw, lease,
    262  1.1  christos 				      (struct client_state *)0, 0,
    263  1.1  christos 				      packet -> options, options,
    264  1.1  christos 				      &lease -> scope,
    265  1.1  christos 				      0, 0, 1, (struct data_string *)0,
    266  1.1  christos 				      (const char *)0);
    267  1.1  christos 		if (outgoing.packet_length < BOOTP_MIN_LEN)
    268  1.1  christos 			outgoing.packet_length = BOOTP_MIN_LEN;
    269  1.1  christos 	}
    270  1.1  christos 
    271  1.1  christos 	/* Take the fields that we care about... */
    272  1.1  christos 	raw.op = BOOTREPLY;
    273  1.1  christos 	raw.htype = packet -> raw -> htype;
    274  1.1  christos 	raw.hlen = packet -> raw -> hlen;
    275  1.1  christos 	memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
    276  1.1  christos 	raw.hops = packet -> raw -> hops;
    277  1.1  christos 	raw.xid = packet -> raw -> xid;
    278  1.1  christos 	raw.secs = packet -> raw -> secs;
    279  1.1  christos 	raw.flags = packet -> raw -> flags;
    280  1.1  christos 	raw.ciaddr = packet -> raw -> ciaddr;
    281  1.1  christos 
    282  1.1  christos 	/* yiaddr is an ipv4 address, it must be 4 octets. */
    283  1.1  christos 	memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4);
    284  1.1  christos 
    285  1.1  christos 	/* If we're always supposed to broadcast to this client, set
    286  1.1  christos 	   the broadcast bit in the bootp flags field. */
    287  1.1  christos 	if ((oc = lookup_option (&server_universe,
    288  1.1  christos 				options, SV_ALWAYS_BROADCAST)) &&
    289  1.1  christos 	    evaluate_boolean_option_cache (&ignorep, packet, lease,
    290  1.1  christos 					   (struct client_state *)0,
    291  1.1  christos 					   packet -> options, options,
    292  1.1  christos 					   &lease -> scope, oc, MDL))
    293  1.1  christos 		raw.flags |= htons (BOOTP_BROADCAST);
    294  1.1  christos 
    295  1.1  christos 	/* Figure out the address of the next server. */
    296  1.1  christos 	memset (&d1, 0, sizeof d1);
    297  1.1  christos 	oc = lookup_option (&server_universe, options, SV_NEXT_SERVER);
    298  1.1  christos 	if (oc &&
    299  1.1  christos 	    evaluate_option_cache (&d1, packet, lease,
    300  1.1  christos 				   (struct client_state *)0,
    301  1.1  christos 				   packet -> options, options,
    302  1.1  christos 				   &lease -> scope, oc, MDL)) {
    303  1.1  christos 		/* If there was more than one answer, take the first. */
    304  1.1  christos 		if (d1.len >= 4 && d1.data)
    305  1.1  christos 			memcpy (&raw.siaddr, d1.data, 4);
    306  1.1  christos 		data_string_forget (&d1, MDL);
    307  1.1  christos 	} else {
    308  1.1  christos 		if ((lease->subnet->shared_network->interface != NULL) &&
    309  1.1  christos 		    lease->subnet->shared_network->interface->address_count)
    310  1.1  christos 		    raw.siaddr =
    311  1.1  christos 			lease->subnet->shared_network->interface->addresses[0];
    312  1.1  christos 		else if (packet->interface->address_count)
    313  1.1  christos 			raw.siaddr = packet->interface->addresses[0];
    314  1.1  christos 	}
    315  1.1  christos 
    316  1.1  christos 	raw.giaddr = packet -> raw -> giaddr;
    317  1.1  christos 
    318  1.1  christos 	/* Figure out the filename. */
    319  1.1  christos 	oc = lookup_option (&server_universe, options, SV_FILENAME);
    320  1.1  christos 	if (oc &&
    321  1.1  christos 	    evaluate_option_cache (&d1, packet, lease,
    322  1.1  christos 				   (struct client_state *)0,
    323  1.1  christos 				   packet -> options, options,
    324  1.1  christos 				   &lease -> scope, oc, MDL)) {
    325  1.1  christos 		memcpy (raw.file, d1.data,
    326  1.1  christos 			d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
    327  1.1  christos 		if (sizeof raw.file > d1.len)
    328  1.1  christos 			memset (&raw.file [d1.len],
    329  1.1  christos 				0, (sizeof raw.file) - d1.len);
    330  1.1  christos 		data_string_forget (&d1, MDL);
    331  1.1  christos 	} else
    332  1.1  christos 		memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
    333  1.1  christos 
    334  1.1  christos 	/* Choose a server name as above. */
    335  1.1  christos 	oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
    336  1.1  christos 	if (oc &&
    337  1.1  christos 	    evaluate_option_cache (&d1, packet, lease,
    338  1.1  christos 				   (struct client_state *)0,
    339  1.1  christos 				   packet -> options, options,
    340  1.1  christos 				   &lease -> scope, oc, MDL)) {
    341  1.1  christos 		memcpy (raw.sname, d1.data,
    342  1.1  christos 			d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
    343  1.1  christos 		if (sizeof raw.sname > d1.len)
    344  1.1  christos 			memset (&raw.sname [d1.len],
    345  1.1  christos 				0, (sizeof raw.sname) - d1.len);
    346  1.1  christos 		data_string_forget (&d1, MDL);
    347  1.1  christos 	}
    348  1.1  christos 
    349  1.1  christos 	/* Execute the commit statements, if there are any. */
    350  1.1  christos 	execute_statements (NULL, packet, lease, NULL, packet->options,
    351  1.1  christos 			    options, &lease->scope, lease->on_star.on_commit,
    352  1.1  christos 			    NULL);
    353  1.1  christos 
    354  1.1  christos 	/* We're done with the option state. */
    355  1.1  christos 	option_state_dereference (&options, MDL);
    356  1.1  christos 
    357  1.1  christos #if defined(DHCPv6) && defined(DHCP4o6)
    358  1.1  christos 	if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
    359  1.1  christos 		/* Report what we're doing... */
    360  1.1  christos 		log_info("%s", msgbuf);
    361  1.1  christos 		log_info("DHCP4o6 BOOTREPLY for %s to %s (%s) via %s",
    362  1.1  christos 			 piaddr(lease->ip_addr),
    363  1.1  christos 			 ((hp != NULL) && (hp->name != NULL)) ?
    364  1.1  christos 				hp -> name : "unknown",
    365  1.1  christos 			 print_hw_addr (packet->raw->htype,
    366  1.1  christos 					packet->raw->hlen,
    367  1.1  christos 					packet->raw->chaddr),
    368  1.1  christos 			 piaddr(packet->client_addr));
    369  1.1  christos 
    370  1.1  christos 		/* fill dhcp4o6_response */
    371  1.1  christos 		packet->dhcp4o6_response->len = outgoing.packet_length;
    372  1.1  christos 		packet->dhcp4o6_response->buffer = NULL;
    373  1.1  christos 		if (!buffer_allocate(&packet->dhcp4o6_response->buffer,
    374  1.1  christos 				     outgoing.packet_length, MDL)) {
    375  1.1  christos 			log_fatal("No memory to store DHCP4o6 reply.");
    376  1.1  christos 		}
    377  1.1  christos 		packet->dhcp4o6_response->data =
    378  1.1  christos 			packet->dhcp4o6_response->buffer->data;
    379  1.1  christos 		memcpy(packet->dhcp4o6_response->buffer->data,
    380  1.1  christos 		       outgoing.raw, outgoing.packet_length);
    381  1.1  christos 		goto out;
    382  1.1  christos 	}
    383  1.1  christos #endif
    384  1.1  christos 
    385  1.1  christos 	/* Set up the hardware destination address... */
    386  1.1  christos 	hto.hbuf [0] = packet -> raw -> htype;
    387  1.1  christos 	hto.hlen = packet -> raw -> hlen + 1;
    388  1.1  christos 	memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
    389  1.1  christos 
    390  1.1  christos 	if (packet->interface->address_count) {
    391  1.1  christos 		from = packet->interface->addresses[0];
    392  1.1  christos 	} else {
    393  1.1  christos 		log_error("%s: Interface %s appears to have no IPv4 "
    394  1.1  christos 			  "addresses, and so dhcpd cannot select a source "
    395  1.1  christos 			  "address.", msgbuf, packet->interface->name);
    396  1.1  christos 		goto out;
    397  1.1  christos 	}
    398  1.1  christos 
    399  1.1  christos 	/* Report what we're doing... */
    400  1.1  christos 	log_info("%s", msgbuf);
    401  1.1  christos 	log_info("BOOTREPLY for %s to %s (%s) via %s",
    402  1.1  christos 		 piaddr(lease->ip_addr),
    403  1.1  christos 		 ((hp != NULL) && (hp->name != NULL)) ? hp -> name : "unknown",
    404  1.1  christos 		 print_hw_addr (packet->raw->htype,
    405  1.1  christos 				packet->raw->hlen,
    406  1.1  christos 				packet->raw->chaddr),
    407  1.1  christos 		 packet->raw->giaddr.s_addr
    408  1.1  christos 		 ? inet_ntoa (packet->raw->giaddr)
    409  1.1  christos 		 : packet->interface->name);
    410  1.1  christos 
    411  1.1  christos 	/* Set up the parts of the address that are in common. */
    412  1.1  christos 	to.sin_family = AF_INET;
    413  1.1  christos #ifdef HAVE_SA_LEN
    414  1.1  christos 	to.sin_len = sizeof to;
    415  1.1  christos #endif
    416  1.1  christos 	memset (to.sin_zero, 0, sizeof to.sin_zero);
    417  1.1  christos 
    418  1.1  christos 	/* If this was gatewayed, send it back to the gateway... */
    419  1.1  christos 	if (raw.giaddr.s_addr) {
    420  1.1  christos 		to.sin_addr = raw.giaddr;
    421  1.1  christos 		to.sin_port = local_port;
    422  1.1  christos 
    423  1.1  christos 		if (fallback_interface) {
    424  1.1  christos 			result = send_packet (fallback_interface, NULL, &raw,
    425  1.1  christos 					      outgoing.packet_length, from,
    426  1.1  christos 					      &to, &hto);
    427  1.1  christos 			if (result < 0) {
    428  1.1  christos 				log_error ("%s:%d: Failed to send %d byte long "
    429  1.1  christos 					   "packet over %s interface.", MDL,
    430  1.1  christos 					   outgoing.packet_length,
    431  1.1  christos 					   fallback_interface->name);
    432  1.1  christos 			}
    433  1.1  christos 
    434  1.1  christos 			goto out;
    435  1.1  christos 		}
    436  1.1  christos 
    437  1.1  christos 	/* If it comes from a client that already knows its address
    438  1.1  christos 	   and is not requesting a broadcast response, and we can
    439  1.1  christos 	   unicast to a client without using the ARP protocol, sent it
    440  1.1  christos 	   directly to that client. */
    441  1.1  christos 	} else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
    442  1.1  christos 		   can_unicast_without_arp (packet -> interface)) {
    443  1.1  christos 		to.sin_addr = raw.yiaddr;
    444  1.1  christos 		to.sin_port = remote_port;
    445  1.1  christos 
    446  1.1  christos 	/* Otherwise, broadcast it on the local network. */
    447  1.1  christos 	} else {
    448  1.1  christos 		to.sin_addr = limited_broadcast;
    449  1.1  christos 		to.sin_port = remote_port; /* XXX */
    450  1.1  christos 	}
    451  1.1  christos 
    452  1.1  christos 	errno = 0;
    453  1.1  christos 	result = send_packet(packet->interface, packet, &raw,
    454  1.1  christos 			     outgoing.packet_length, from, &to, &hto);
    455  1.1  christos 	if (result < 0) {
    456  1.1  christos 		log_error ("%s:%d: Failed to send %d byte long packet over %s"
    457  1.1  christos 			   " interface.", MDL, outgoing.packet_length,
    458  1.1  christos 			   packet->interface->name);
    459  1.1  christos 	}
    460  1.1  christos 
    461  1.1  christos       out:
    462  1.1  christos 
    463  1.1  christos 	if (options)
    464  1.1  christos 		option_state_dereference (&options, MDL);
    465  1.1  christos 	if (lease)
    466  1.1  christos 		lease_dereference (&lease, MDL);
    467  1.1  christos 	if (hp)
    468  1.1  christos 		host_dereference (&hp, MDL);
    469  1.1  christos 	if (host)
    470  1.1  christos 		host_dereference (&host, MDL);
    471  1.1  christos }
    472