dhcpv4.c revision 4a634bb80136cc001d14ab96addd9915105e5223
6331N/A * The contents of this file are subject to the terms of the 6331N/A * Common Development and Distribution License (the "License"). 6331N/A * You may not use this file except in compliance with the License. 6331N/A * See the License for the specific language governing permissions 6331N/A * and limitations under the License. 6331N/A * When distributing Covered Code, include this CDDL HEADER in each 6331N/A * If applicable, add the following below this CDDL HEADER, with the 6331N/A * fields enclosed by brackets "[]" replaced with your own identifying 6331N/A * information: Portions Copyright [yyyy] [name of copyright owner] 6331N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 6331N/A * Use is subject to license terms. 6331N/A#
pragma ident "%Z%%M% %I% %E% SMI" static char *
s_n =
"INIT";
* Returns: the updated options ptr. * Parameter request list. * This parameter request list is used in the normal 4-packet * CD_REQUESTED_IP_ADDR or CD_LEASE_TIME. 4,
/* number of options requested */ * Set hardware specific fields * The mac address does not fit in the chaddr * field, thus it can not be sent to the server, * thus server can not unicast the reply. Per * RFC 2131 4.4.1, client can set this bit in * Classids based on mfg name: Commas (,) are * converted to periods (.), and spaces ( ) are removed. for (i = 0; i <
len; i++,
tp++) {
* Collects BOOTP responses. Length has to be right, it has to be * a BOOTP reply pkt, with the same XID and HW address as ours. Adds * Returns 0 if no error processing packet, 1 if an error occurred and/or * collection of replies should stop. Used in inet() calls. /* Add a packet to the pkt list */ return (
1);
/* got enough packets already */ * Checks if BOOTP exchange(s) were successful. Returns 1 if they * were, 0 otherwise. Used in inet() calls. /* remember the secs - we may need them later */ * This function accesses the network. Opens a connection, and binds to * it if a client binding doesn't already exist. If 'tries' is 0, then * attempts are made to get a valid response. If 'tol' is not zero, * then this function will wait for 'tol' milliseconds for more than one * response to a transmit. * Returns 0 for success, errno otherwise. dprintf(
"%s: Cannot bind to port %d, errno: %d\n",
dprintf(
"%s: sendto failed with errno: %d\n",
break;
/* don't bother to check for reply */ continue;
/* DONT WAIT */ break;
/* Stop collecting */ break;
/* collection timeout */ break;
/* got the goods */ * Print the message from the server. * This function scans the list of OFFERS, and returns the "best" offer. * The criteria used for determining this is: * DHCP OFFER (not BOOTP), same client_id as ours, same class_id, * Longest lease, all the options we need. * DHCP OFFER, no class_id, short lease, only some of the options we need. * DON'T select an offer from a server that gave us a configuration we * couldn't use. Take this server off the "bad" list when this is done. * Next time, we could potentially retry this server's configuration. * NOTE: perhaps this bad server should have a counter associated with it. /* Pass one. Scan for options, set appropriate opt field. */ /* Garbled Options. Nuke this pkt. */ printf(
"%s: Unexpected DHCP message.\n",
"%s: Garbled DHCP message type.\n",
printf(
"%s: Bad option overload.\n",
* Pass two. Pick out the best offer. Point system. * 2) Encapsulated vendor option * 3) Non-null sname and siaddr fields dprintf(
"%s: Unexpected DHCP message." " Expected OFFER message.\n",
s_n);
dprintf(
"%s: DHCP OFFER message without lease " "time parameter.\n",
s_n);
dprintf(
"%s: Lease expiration time is " dprintf(
"%s: DHCP OFFER message without server " "parameter is garbled.\n",
s_n);
/* Valid DHCP OFFER. See if we got our parameters. */ dprintf(
"%s: Found valid DHCP OFFER message.\n",
s_n);
* Also could be faked, though more difficult * because the encapsulation is hard to encode * on a BOOTP server; plus there's not as much * real estate in the packet for options, so * it's likely this option would get dropped. * Prefer options that have diskless boot significance printf(
"%s: This server configuration has '%d' points.\n",
s_n,
dprintf(
"%s: No valid BOOTP reply or DHCP OFFER was found.\n",
* Send a decline message to the generator of the DHCPACK. * Use the given yiaddr in our ciaddr field so server can identify us. * Implementings SELECTING state of DHCP client state machine. * If a clientid was set using dhcp_set_client_id(), add this * implements the REQUESTING state of the DHCP client state machine. /* here we scan the list of OFFERS, select the best one. */ dprintf(
"%s: No valid BOOTP reply or DHCP OFFER was found.\n",
* Check to see if we got an OFFER pkt(s). If not, then We only got * a response from a BOOTP server. We'll go to the bound state and * try to use that configuration. /* Someone responded! go back to SELECTING state. */ printf(
"%s: Some host already using BOOTP %s.\n",
s_n,
* if we got a message from the server, display it. * Assemble a DHCPREQUEST, with the ciaddr field set to 0, since we * got here from DISCOVER state. Keep secs field the same for relay * agents. We start with the DHCPOFFER packet we got, and the * options contained in it to make a requested option list. /* Time from Successful DISCOVER message. */ /* our offered lease minus boot time */ /* our offered IP address, as required. */ * If a clientid was set using dhcp_set_client_id(), add this /* Done with the OFFER pkt. */ * We make 4 attempts here. We wait for 2 seconds to accumulate * requests, just in case a BOOTP server is too fast! continue;
/* garbled options */ printf(
"%s: rejected by DHCP server: %s\n",
dprintf(
"%s: Unexpected DHCP message type.\n",
s_n);
/* arp our new address, just to make sure */ * No response. Check if lease is ok. return (0);
/* passes the tests! */ dprintf(
"%s: No valid DHCP acknowledge messages received.\n",
s_n);
* Implements BOUND state of DHCP client state machine. /* First, set the bare essentials. (IP layer parameters) */ * Ensure that the Boot NFS READ size, if given, is an int16_t. * Set subnetmask. Nice, but not required. * Set default IP TTL. Nice, but not required. * Set default router. Not required, although we'll know soon for (k = 0,
fnd = 0; k <
2 &&
fnd == 0; k++) {
"%s: Warning: Router %s is unreachable.\n",
* If fnd is 0, we didn't find a working router. We'll * still try to use first default router. If we got * a bad router address (like not on the same net), "%s: Warning: Using default router: %s\n",
/* ipv4_route expects network order IP addresses */ * Set hostname. Not required. * We don't care about the lease time.... We can't enforce it anyway. * Convert the DHCPACK into a pure ASCII boot property for use by the kernel * later in the boot process. buflen = (
pl->
len *
2) +
1;
/* extra space for null (1) */ * Examines /chosen node for "bootp-response" property. If it exists, this * property is the DHCPACK cached there by the PROM's DHCP implementation. * If cache_present is B_TRUE, we simply return B_TRUE if the property exists * w/o decoding it. If cache_present is B_FALSE, we decode the packet and * use it as our state packet for the jump to BOUND mode. Note that it's good * enough that the cache exists w/o validation for determining if that's what * We'll short-circuit the DHCP exchange by accepting this packet. We build a * PKT_LIST structure, and copy the bootp-response property value into a * PKT buffer we allocated. We then scan the PKT for options, and then * set state_pl to point to it. * Returns B_TRUE if a packet was cached (and was processed correctly), false * otherwise. The caller needs to make the state change from SELECTING to * BOUND upon a B_TRUE return from this function. * Returns 0 for success, nonzero otherwise. * DHCP client state machine. dprintf(
"%s: Using PROM cached BOOT reply...\n",
"%s: No DHCP response after %d tries.\n",
/* major network problems */ dprintf(
"%s: Network transaction failed: %d\n",
/* major network problems */ dprintf(
"%s: Network transaction failed: %d\n",
* We just "give up" if bound state fails. * Returns a copy of the DHCP-supplied value of the parameter requested * Sets the clientid option.