1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * Standalone dhcp client. 27*7c478bd9Sstevel@tonic-gate */ 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/salib.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/bootcmn.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 37*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 38*7c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 39*7c478bd9Sstevel@tonic-gate #include <netinet/inetutil.h> 40*7c478bd9Sstevel@tonic-gate #include <netinet/dhcp.h> 41*7c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 42*7c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 43*7c478bd9Sstevel@tonic-gate #include <dhcp_impl.h> 44*7c478bd9Sstevel@tonic-gate #include <net/if_types.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/platnames.h> 47*7c478bd9Sstevel@tonic-gate #include <socket_inet.h> 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate #include "ipv4.h" 50*7c478bd9Sstevel@tonic-gate #include "mac.h" 51*7c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h> 52*7c478bd9Sstevel@tonic-gate #include "dhcpv4.h" 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate static char *s_n = "INIT"; 55*7c478bd9Sstevel@tonic-gate static enum DHCPSTATE dhcp_state = INIT; 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate static PKT *dhcp_snd_bufp, *dhcp_rcv_bufp; 58*7c478bd9Sstevel@tonic-gate static int dhcp_buf_size; 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate static const uint8_t magic[] = BOOTMAGIC; /* RFC1048 */ 61*7c478bd9Sstevel@tonic-gate static uint8_t opt_discover[] = { CD_DHCP_TYPE, 1, DISCOVER }; 62*7c478bd9Sstevel@tonic-gate static uint8_t opt_request[] = { CD_DHCP_TYPE, 1, REQUEST }; 63*7c478bd9Sstevel@tonic-gate static uint8_t opt_decline[] = { CD_DHCP_TYPE, 1, DECLINE }; 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate static uint8_t dhcp_classid[DHCP_MAX_OPT_SIZE + 3]; 66*7c478bd9Sstevel@tonic-gate static uint8_t dhcp_clientid[DHCP_MAX_CID_LEN]; 67*7c478bd9Sstevel@tonic-gate static uint8_t dhcp_clientid_len = 0; 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate static uint32_t dhcp_start_time; /* start time (msecs */ 70*7c478bd9Sstevel@tonic-gate static time_t dhcp_secs; 71*7c478bd9Sstevel@tonic-gate static uint32_t timeout; /* timeout in milliseconds */ 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate static int pkt_counter; 74*7c478bd9Sstevel@tonic-gate PKT_LIST *list_tl, *list_hd; 75*7c478bd9Sstevel@tonic-gate PKT_LIST *state_pl = NULL; 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate #define PROM_BOOT_CACHED "bootp-response" 78*7c478bd9Sstevel@tonic-gate #ifndef __i386 79*7c478bd9Sstevel@tonic-gate extern char *bootp_response; /* bootprop.c */ 80*7c478bd9Sstevel@tonic-gate #else 81*7c478bd9Sstevel@tonic-gate char *bootp_response; /* i386 has *real* bsetprop */ 82*7c478bd9Sstevel@tonic-gate #endif /* __i386 */ 83*7c478bd9Sstevel@tonic-gate extern int pagesize; 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate /* 86*7c478bd9Sstevel@tonic-gate * Do whatever reset actions/initialization actions are generic for every 87*7c478bd9Sstevel@tonic-gate * DHCP/bootp message. Set the message type. 88*7c478bd9Sstevel@tonic-gate * 89*7c478bd9Sstevel@tonic-gate * Returns: the updated options ptr. 90*7c478bd9Sstevel@tonic-gate */ 91*7c478bd9Sstevel@tonic-gate static uint8_t * 92*7c478bd9Sstevel@tonic-gate init_msg(PKT *pkt, uint8_t *pkttype) 93*7c478bd9Sstevel@tonic-gate { 94*7c478bd9Sstevel@tonic-gate static uint32_t xid; 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate bzero(pkt, dhcp_buf_size); 97*7c478bd9Sstevel@tonic-gate bcopy(magic, pkt->cookie, sizeof (pkt->cookie)); 98*7c478bd9Sstevel@tonic-gate pkt->op = BOOTREQUEST; 99*7c478bd9Sstevel@tonic-gate if (xid == 0) 100*7c478bd9Sstevel@tonic-gate bcopy(mac_get_addr_buf()+2, &xid, 4); 101*7c478bd9Sstevel@tonic-gate else 102*7c478bd9Sstevel@tonic-gate xid++; 103*7c478bd9Sstevel@tonic-gate pkt->xid = xid; 104*7c478bd9Sstevel@tonic-gate bcopy(pkttype, pkt->options, 3); 105*7c478bd9Sstevel@tonic-gate return ((uint8_t *)(pkt->options + 3)); 106*7c478bd9Sstevel@tonic-gate } 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate /* 109*7c478bd9Sstevel@tonic-gate * Parameter request list. 110*7c478bd9Sstevel@tonic-gate */ 111*7c478bd9Sstevel@tonic-gate static void 112*7c478bd9Sstevel@tonic-gate parameter_request_list(uint8_t **opt) 113*7c478bd9Sstevel@tonic-gate { 114*7c478bd9Sstevel@tonic-gate /* 115*7c478bd9Sstevel@tonic-gate * This parameter request list is used in the normal 4-packet 116*7c478bd9Sstevel@tonic-gate * DHCPDISCOVER/OFFER/REQUEST/ACK exchange; it must not contain 117*7c478bd9Sstevel@tonic-gate * CD_REQUESTED_IP_ADDR or CD_LEASE_TIME. 118*7c478bd9Sstevel@tonic-gate */ 119*7c478bd9Sstevel@tonic-gate static uint8_t prlist[] = { 120*7c478bd9Sstevel@tonic-gate CD_REQUEST_LIST, /* parameter request list option number */ 121*7c478bd9Sstevel@tonic-gate 4, /* number of options requested */ 122*7c478bd9Sstevel@tonic-gate CD_SUBNETMASK, 123*7c478bd9Sstevel@tonic-gate CD_ROUTER, 124*7c478bd9Sstevel@tonic-gate CD_HOSTNAME, 125*7c478bd9Sstevel@tonic-gate CD_VENDOR_SPEC 126*7c478bd9Sstevel@tonic-gate }; 127*7c478bd9Sstevel@tonic-gate if (opt && *opt) { 128*7c478bd9Sstevel@tonic-gate bcopy(prlist, *opt, sizeof (prlist)); 129*7c478bd9Sstevel@tonic-gate *opt += sizeof (prlist); 130*7c478bd9Sstevel@tonic-gate } 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate /* 134*7c478bd9Sstevel@tonic-gate * Set hardware specific fields 135*7c478bd9Sstevel@tonic-gate */ 136*7c478bd9Sstevel@tonic-gate static void 137*7c478bd9Sstevel@tonic-gate set_hw_spec_data(PKT *p, uint8_t **opt, uint8_t *pkttype) 138*7c478bd9Sstevel@tonic-gate { 139*7c478bd9Sstevel@tonic-gate char mfg[DHCP_MAX_OPT_SIZE + 1], cbuf[DHCP_MAX_OPT_SIZE + 1]; 140*7c478bd9Sstevel@tonic-gate uint8_t *tp, *dp; 141*7c478bd9Sstevel@tonic-gate int adjust_len, len, i; 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate p->htype = mac_arp_type(mac_get_type()); 144*7c478bd9Sstevel@tonic-gate len = (uchar_t)mac_get_addr_len(); 145*7c478bd9Sstevel@tonic-gate if (len <= sizeof (p->chaddr)) { 146*7c478bd9Sstevel@tonic-gate p->hlen = len; 147*7c478bd9Sstevel@tonic-gate bcopy(mac_get_addr_buf(), p->chaddr, len); 148*7c478bd9Sstevel@tonic-gate } else { 149*7c478bd9Sstevel@tonic-gate uint8_t type = *(pkttype + 2); 150*7c478bd9Sstevel@tonic-gate /* 151*7c478bd9Sstevel@tonic-gate * The mac address does not fit in the chaddr 152*7c478bd9Sstevel@tonic-gate * field, thus it can not be sent to the server, 153*7c478bd9Sstevel@tonic-gate * thus server can not unicast the reply. Per 154*7c478bd9Sstevel@tonic-gate * RFC 2131 4.4.1, client can set this bit in 155*7c478bd9Sstevel@tonic-gate * DISCOVER/REQUEST. 156*7c478bd9Sstevel@tonic-gate */ 157*7c478bd9Sstevel@tonic-gate if ((type == DISCOVER) || (type == REQUEST)) 158*7c478bd9Sstevel@tonic-gate p->flags = htons(BCAST_MASK); 159*7c478bd9Sstevel@tonic-gate } 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate if (opt && *opt) { 162*7c478bd9Sstevel@tonic-gate if (dhcp_classid[0] == '\0') { 163*7c478bd9Sstevel@tonic-gate /* 164*7c478bd9Sstevel@tonic-gate * Classids based on mfg name: Commas (,) are 165*7c478bd9Sstevel@tonic-gate * converted to periods (.), and spaces ( ) are removed. 166*7c478bd9Sstevel@tonic-gate */ 167*7c478bd9Sstevel@tonic-gate dhcp_classid[0] = CD_CLASS_ID; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate (void) strncpy(mfg, get_mfg_name(), sizeof (mfg)); 170*7c478bd9Sstevel@tonic-gate if (strncmp(mfg, "SUNW", strlen("SUNW")) != 0) { 171*7c478bd9Sstevel@tonic-gate len = strlen("SUNW."); 172*7c478bd9Sstevel@tonic-gate (void) strcpy(cbuf, "SUNW."); 173*7c478bd9Sstevel@tonic-gate } else { 174*7c478bd9Sstevel@tonic-gate len = 0; 175*7c478bd9Sstevel@tonic-gate cbuf[0] = '\0'; 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate len += strlen(mfg); 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate if ((len + 2) < DHCP_MAX_OPT_SIZE) { 180*7c478bd9Sstevel@tonic-gate tp = (uint8_t *)strcat(cbuf, mfg); 181*7c478bd9Sstevel@tonic-gate dp = &dhcp_classid[2]; 182*7c478bd9Sstevel@tonic-gate adjust_len = 0; 183*7c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++, tp++) { 184*7c478bd9Sstevel@tonic-gate if (*tp == ',') { 185*7c478bd9Sstevel@tonic-gate *dp++ = '.'; 186*7c478bd9Sstevel@tonic-gate } else if (*tp == ' ') { 187*7c478bd9Sstevel@tonic-gate adjust_len++; 188*7c478bd9Sstevel@tonic-gate } else { 189*7c478bd9Sstevel@tonic-gate *dp++ = *tp; 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate len -= adjust_len; 193*7c478bd9Sstevel@tonic-gate dhcp_classid[1] = (uint8_t)len; 194*7c478bd9Sstevel@tonic-gate } else 195*7c478bd9Sstevel@tonic-gate prom_panic("Not enough space for class id"); 196*7c478bd9Sstevel@tonic-gate #ifdef DHCP_DEBUG 197*7c478bd9Sstevel@tonic-gate printf("%s: Classid: %s\n", s_n, &dhcp_classid[2]); 198*7c478bd9Sstevel@tonic-gate #endif /* DHCP_DEBUG */ 199*7c478bd9Sstevel@tonic-gate } 200*7c478bd9Sstevel@tonic-gate bcopy(dhcp_classid, *opt, dhcp_classid[1] + 2); 201*7c478bd9Sstevel@tonic-gate *opt += dhcp_classid[1] + 2; 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate } 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate static void 206*7c478bd9Sstevel@tonic-gate flush_list(void) 207*7c478bd9Sstevel@tonic-gate { 208*7c478bd9Sstevel@tonic-gate PKT_LIST *wk, *tmp; 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate wk = list_hd; 211*7c478bd9Sstevel@tonic-gate while (wk != NULL) { 212*7c478bd9Sstevel@tonic-gate tmp = wk; 213*7c478bd9Sstevel@tonic-gate wk = wk->next; 214*7c478bd9Sstevel@tonic-gate bkmem_free((char *)tmp->pkt, tmp->len); 215*7c478bd9Sstevel@tonic-gate bkmem_free((char *)tmp, sizeof (PKT_LIST)); 216*7c478bd9Sstevel@tonic-gate } 217*7c478bd9Sstevel@tonic-gate list_hd = list_tl = NULL; 218*7c478bd9Sstevel@tonic-gate pkt_counter = 0; 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate static void 222*7c478bd9Sstevel@tonic-gate remove_list(PKT_LIST *pl, int flag) 223*7c478bd9Sstevel@tonic-gate { 224*7c478bd9Sstevel@tonic-gate if (list_hd == NULL) 225*7c478bd9Sstevel@tonic-gate return; 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate if (list_hd == list_tl) { 228*7c478bd9Sstevel@tonic-gate list_hd = list_tl = NULL; 229*7c478bd9Sstevel@tonic-gate } else if (list_hd == pl) { 230*7c478bd9Sstevel@tonic-gate list_hd = pl->next; 231*7c478bd9Sstevel@tonic-gate list_hd->prev = NULL; 232*7c478bd9Sstevel@tonic-gate } else if (list_tl == pl) { 233*7c478bd9Sstevel@tonic-gate list_tl = list_tl->prev; 234*7c478bd9Sstevel@tonic-gate list_tl->next = NULL; 235*7c478bd9Sstevel@tonic-gate } else { 236*7c478bd9Sstevel@tonic-gate pl->prev->next = pl->next; 237*7c478bd9Sstevel@tonic-gate pl->next->prev = pl->prev; 238*7c478bd9Sstevel@tonic-gate } 239*7c478bd9Sstevel@tonic-gate pkt_counter--; 240*7c478bd9Sstevel@tonic-gate if (flag) { 241*7c478bd9Sstevel@tonic-gate bkmem_free((char *)pl->pkt, pl->len); 242*7c478bd9Sstevel@tonic-gate bkmem_free((char *)pl, sizeof (PKT_LIST)); 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate } 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate /* 247*7c478bd9Sstevel@tonic-gate * Collects BOOTP responses. Length has to be right, it has to be 248*7c478bd9Sstevel@tonic-gate * a BOOTP reply pkt, with the same XID and HW address as ours. Adds 249*7c478bd9Sstevel@tonic-gate * them to the pkt list. 250*7c478bd9Sstevel@tonic-gate * 251*7c478bd9Sstevel@tonic-gate * Returns 0 if no error processing packet, 1 if an error occurred and/or 252*7c478bd9Sstevel@tonic-gate * collection of replies should stop. Used in inet() calls. 253*7c478bd9Sstevel@tonic-gate */ 254*7c478bd9Sstevel@tonic-gate static int 255*7c478bd9Sstevel@tonic-gate bootp_collect(int len) 256*7c478bd9Sstevel@tonic-gate { 257*7c478bd9Sstevel@tonic-gate PKT *s = (PKT *)dhcp_snd_bufp; 258*7c478bd9Sstevel@tonic-gate PKT *r = (PKT *)dhcp_rcv_bufp; 259*7c478bd9Sstevel@tonic-gate PKT_LIST *pl; 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate if (len < sizeof (PKT)) { 262*7c478bd9Sstevel@tonic-gate dprintf("%s: BOOTP reply too small: %d\n", s_n, len); 263*7c478bd9Sstevel@tonic-gate return (1); 264*7c478bd9Sstevel@tonic-gate } 265*7c478bd9Sstevel@tonic-gate if (r->op == BOOTREPLY && r->xid == s->xid && 266*7c478bd9Sstevel@tonic-gate bcmp((caddr_t)s->chaddr, (caddr_t)r->chaddr, s->hlen) == 0) { 267*7c478bd9Sstevel@tonic-gate /* Add a packet to the pkt list */ 268*7c478bd9Sstevel@tonic-gate if (pkt_counter > (MAX_PKT_LIST - 1)) 269*7c478bd9Sstevel@tonic-gate return (1); /* got enough packets already */ 270*7c478bd9Sstevel@tonic-gate if (((pl = (PKT_LIST *)bkmem_zalloc(sizeof (PKT_LIST))) == 271*7c478bd9Sstevel@tonic-gate NULL) || ((pl->pkt = (PKT *)bkmem_zalloc(len)) == NULL)) { 272*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 273*7c478bd9Sstevel@tonic-gate if (pl != NULL) 274*7c478bd9Sstevel@tonic-gate bkmem_free((char *)pl, sizeof (PKT_LIST)); 275*7c478bd9Sstevel@tonic-gate return (1); 276*7c478bd9Sstevel@tonic-gate } 277*7c478bd9Sstevel@tonic-gate bcopy(dhcp_rcv_bufp, pl->pkt, len); 278*7c478bd9Sstevel@tonic-gate pl->len = len; 279*7c478bd9Sstevel@tonic-gate if (list_hd == NULL) { 280*7c478bd9Sstevel@tonic-gate list_hd = list_tl = pl; 281*7c478bd9Sstevel@tonic-gate pl->prev = NULL; 282*7c478bd9Sstevel@tonic-gate } else { 283*7c478bd9Sstevel@tonic-gate list_tl->next = pl; 284*7c478bd9Sstevel@tonic-gate pl->prev = list_tl; 285*7c478bd9Sstevel@tonic-gate list_tl = pl; 286*7c478bd9Sstevel@tonic-gate } 287*7c478bd9Sstevel@tonic-gate pkt_counter++; 288*7c478bd9Sstevel@tonic-gate pl->next = NULL; 289*7c478bd9Sstevel@tonic-gate } 290*7c478bd9Sstevel@tonic-gate return (0); 291*7c478bd9Sstevel@tonic-gate } 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate /* 294*7c478bd9Sstevel@tonic-gate * Checks if BOOTP exchange(s) were successful. Returns 1 if they 295*7c478bd9Sstevel@tonic-gate * were, 0 otherwise. Used in inet() calls. 296*7c478bd9Sstevel@tonic-gate */ 297*7c478bd9Sstevel@tonic-gate static int 298*7c478bd9Sstevel@tonic-gate bootp_success(void) 299*7c478bd9Sstevel@tonic-gate { 300*7c478bd9Sstevel@tonic-gate PKT *s = (PKT *)dhcp_snd_bufp; 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate if (list_hd != NULL) { 303*7c478bd9Sstevel@tonic-gate /* remember the secs - we may need them later */ 304*7c478bd9Sstevel@tonic-gate dhcp_secs = ntohs(s->secs); 305*7c478bd9Sstevel@tonic-gate return (1); 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate s->secs = htons((uint16_t)((prom_gettime() - dhcp_start_time)/1000)); 308*7c478bd9Sstevel@tonic-gate return (0); 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate /* 312*7c478bd9Sstevel@tonic-gate * This function accesses the network. Opens a connection, and binds to 313*7c478bd9Sstevel@tonic-gate * it if a client binding doesn't already exist. If 'tries' is 0, then 314*7c478bd9Sstevel@tonic-gate * no reply is expected/returned. If 'tries' is non-zero, then 'tries' 315*7c478bd9Sstevel@tonic-gate * attempts are made to get a valid response. If 'tol' is not zero, 316*7c478bd9Sstevel@tonic-gate * then this function will wait for 'tol' milliseconds for more than one 317*7c478bd9Sstevel@tonic-gate * response to a transmit. 318*7c478bd9Sstevel@tonic-gate * 319*7c478bd9Sstevel@tonic-gate * Returns 0 for success, errno otherwise. 320*7c478bd9Sstevel@tonic-gate */ 321*7c478bd9Sstevel@tonic-gate static int 322*7c478bd9Sstevel@tonic-gate inet(uint32_t size, struct in_addr *src, struct in_addr *dest, uint32_t tries, 323*7c478bd9Sstevel@tonic-gate uint32_t tol) 324*7c478bd9Sstevel@tonic-gate { 325*7c478bd9Sstevel@tonic-gate int done = B_FALSE, flags, len; 326*7c478bd9Sstevel@tonic-gate uint32_t attempts = 0; 327*7c478bd9Sstevel@tonic-gate int sd; 328*7c478bd9Sstevel@tonic-gate uint32_t wait_time; /* Max time collect replies */ 329*7c478bd9Sstevel@tonic-gate uint32_t init_timeout; /* Max time wait ANY reply */ 330*7c478bd9Sstevel@tonic-gate uint32_t now; 331*7c478bd9Sstevel@tonic-gate struct sockaddr_in saddr, daddr; 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 334*7c478bd9Sstevel@tonic-gate dprintf("%s: Can't open a socket.\n", s_n); 335*7c478bd9Sstevel@tonic-gate return (errno); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate flags = 0; 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate bzero(&saddr, sizeof (struct sockaddr_in)); 341*7c478bd9Sstevel@tonic-gate saddr.sin_family = AF_INET; 342*7c478bd9Sstevel@tonic-gate saddr.sin_port = htons(IPPORT_BOOTPC); 343*7c478bd9Sstevel@tonic-gate saddr.sin_addr.s_addr = htonl(src->s_addr); 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate if (bind(sd, (struct sockaddr *)&saddr, sizeof (saddr)) < 0) { 346*7c478bd9Sstevel@tonic-gate dprintf("%s: Cannot bind to port %d, errno: %d\n", 347*7c478bd9Sstevel@tonic-gate s_n, IPPORT_BOOTPC, errno); 348*7c478bd9Sstevel@tonic-gate (void) socket_close(sd); 349*7c478bd9Sstevel@tonic-gate return (errno); 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate if (ntohl(dest->s_addr) == INADDR_BROADCAST) { 353*7c478bd9Sstevel@tonic-gate int dontroute = B_TRUE; 354*7c478bd9Sstevel@tonic-gate (void) setsockopt(sd, SOL_SOCKET, SO_DONTROUTE, 355*7c478bd9Sstevel@tonic-gate (const void *)&dontroute, sizeof (dontroute)); 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate bzero(&daddr, sizeof (struct sockaddr_in)); 359*7c478bd9Sstevel@tonic-gate daddr.sin_family = AF_INET; 360*7c478bd9Sstevel@tonic-gate daddr.sin_port = htons(IPPORT_BOOTPS); 361*7c478bd9Sstevel@tonic-gate daddr.sin_addr.s_addr = htonl(dest->s_addr); 362*7c478bd9Sstevel@tonic-gate wait_time = prom_gettime() + tol; 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate do { 365*7c478bd9Sstevel@tonic-gate if (sendto(sd, (char *)dhcp_snd_bufp, size, flags, 366*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&daddr, sizeof (daddr)) < 0) { 367*7c478bd9Sstevel@tonic-gate dprintf("%s: sendto failed with errno: %d\n", 368*7c478bd9Sstevel@tonic-gate s_n, errno); 369*7c478bd9Sstevel@tonic-gate (void) socket_close(sd); 370*7c478bd9Sstevel@tonic-gate return (errno); 371*7c478bd9Sstevel@tonic-gate } 372*7c478bd9Sstevel@tonic-gate if (!tries) 373*7c478bd9Sstevel@tonic-gate break; /* don't bother to check for reply */ 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate now = prom_gettime(); 376*7c478bd9Sstevel@tonic-gate if (timeout == 0) 377*7c478bd9Sstevel@tonic-gate timeout = 4000; 378*7c478bd9Sstevel@tonic-gate else { 379*7c478bd9Sstevel@tonic-gate timeout <<= 1; 380*7c478bd9Sstevel@tonic-gate if (timeout > 64000) 381*7c478bd9Sstevel@tonic-gate timeout = 64000; 382*7c478bd9Sstevel@tonic-gate } 383*7c478bd9Sstevel@tonic-gate init_timeout = now + timeout; 384*7c478bd9Sstevel@tonic-gate wait_time = now + tol; 385*7c478bd9Sstevel@tonic-gate do { 386*7c478bd9Sstevel@tonic-gate if ((len = recvfrom(sd, (char *)dhcp_rcv_bufp, 387*7c478bd9Sstevel@tonic-gate (int)dhcp_buf_size, MSG_DONTWAIT, NULL, 388*7c478bd9Sstevel@tonic-gate NULL)) < 0) { 389*7c478bd9Sstevel@tonic-gate if (errno == EWOULDBLOCK) 390*7c478bd9Sstevel@tonic-gate continue; /* DONT WAIT */ 391*7c478bd9Sstevel@tonic-gate (void) socket_close(sd); 392*7c478bd9Sstevel@tonic-gate flush_list(); 393*7c478bd9Sstevel@tonic-gate return (errno); 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate if (bootp_collect(len)) 397*7c478bd9Sstevel@tonic-gate break; /* Stop collecting */ 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate if (tol != 0) { 400*7c478bd9Sstevel@tonic-gate if (wait_time < prom_gettime()) 401*7c478bd9Sstevel@tonic-gate break; /* collection timeout */ 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate } while (prom_gettime() < init_timeout); 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate if (bootp_success()) { 406*7c478bd9Sstevel@tonic-gate done = B_TRUE; 407*7c478bd9Sstevel@tonic-gate break; /* got the goods */ 408*7c478bd9Sstevel@tonic-gate } 409*7c478bd9Sstevel@tonic-gate } while (++attempts < tries); 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate (void) socket_close(sd); 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate return (done ? 0 : DHCP_NO_DATA); 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate /* 417*7c478bd9Sstevel@tonic-gate * Print the message from the server. 418*7c478bd9Sstevel@tonic-gate */ 419*7c478bd9Sstevel@tonic-gate static void 420*7c478bd9Sstevel@tonic-gate prt_server_msg(DHCP_OPT *p) 421*7c478bd9Sstevel@tonic-gate { 422*7c478bd9Sstevel@tonic-gate int len = p->len; 423*7c478bd9Sstevel@tonic-gate char scratch[DHCP_MAX_OPT_SIZE + 1]; 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate if (p->len > DHCP_MAX_OPT_SIZE) 426*7c478bd9Sstevel@tonic-gate len = DHCP_MAX_OPT_SIZE; 427*7c478bd9Sstevel@tonic-gate bcopy(p->value, scratch, len); 428*7c478bd9Sstevel@tonic-gate scratch[len] = '\0'; 429*7c478bd9Sstevel@tonic-gate printf("%s: Message from server: '%s'\n", s_n, scratch); 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate /* 433*7c478bd9Sstevel@tonic-gate * This function scans the list of OFFERS, and returns the "best" offer. 434*7c478bd9Sstevel@tonic-gate * The criteria used for determining this is: 435*7c478bd9Sstevel@tonic-gate * 436*7c478bd9Sstevel@tonic-gate * The best: 437*7c478bd9Sstevel@tonic-gate * DHCP OFFER (not BOOTP), same client_id as ours, same class_id, 438*7c478bd9Sstevel@tonic-gate * Longest lease, all the options we need. 439*7c478bd9Sstevel@tonic-gate * 440*7c478bd9Sstevel@tonic-gate * Not quite as good: 441*7c478bd9Sstevel@tonic-gate * DHCP OFFER, no class_id, short lease, only some of the options we need. 442*7c478bd9Sstevel@tonic-gate * 443*7c478bd9Sstevel@tonic-gate * We're really reach'in 444*7c478bd9Sstevel@tonic-gate * BOOTP reply. 445*7c478bd9Sstevel@tonic-gate * 446*7c478bd9Sstevel@tonic-gate * DON'T select an offer from a server that gave us a configuration we 447*7c478bd9Sstevel@tonic-gate * couldn't use. Take this server off the "bad" list when this is done. 448*7c478bd9Sstevel@tonic-gate * Next time, we could potentially retry this server's configuration. 449*7c478bd9Sstevel@tonic-gate * 450*7c478bd9Sstevel@tonic-gate * NOTE: perhaps this bad server should have a counter associated with it. 451*7c478bd9Sstevel@tonic-gate */ 452*7c478bd9Sstevel@tonic-gate static PKT_LIST * 453*7c478bd9Sstevel@tonic-gate select_best(void) 454*7c478bd9Sstevel@tonic-gate { 455*7c478bd9Sstevel@tonic-gate PKT_LIST *wk, *tk, *best; 456*7c478bd9Sstevel@tonic-gate int err = 0; 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate /* Pass one. Scan for options, set appropriate opt field. */ 459*7c478bd9Sstevel@tonic-gate wk = list_hd; 460*7c478bd9Sstevel@tonic-gate while (wk != NULL) { 461*7c478bd9Sstevel@tonic-gate if ((err = dhcp_options_scan(wk, B_TRUE)) != 0) { 462*7c478bd9Sstevel@tonic-gate /* Garbled Options. Nuke this pkt. */ 463*7c478bd9Sstevel@tonic-gate if (boothowto & RB_DEBUG) { 464*7c478bd9Sstevel@tonic-gate switch (err) { 465*7c478bd9Sstevel@tonic-gate case DHCP_WRONG_MSG_TYPE: 466*7c478bd9Sstevel@tonic-gate printf("%s: Unexpected DHCP message.\n", 467*7c478bd9Sstevel@tonic-gate s_n); 468*7c478bd9Sstevel@tonic-gate break; 469*7c478bd9Sstevel@tonic-gate case DHCP_GARBLED_MSG_TYPE: 470*7c478bd9Sstevel@tonic-gate printf( 471*7c478bd9Sstevel@tonic-gate "%s: Garbled DHCP message type.\n", 472*7c478bd9Sstevel@tonic-gate s_n); 473*7c478bd9Sstevel@tonic-gate break; 474*7c478bd9Sstevel@tonic-gate case DHCP_BAD_OPT_OVLD: 475*7c478bd9Sstevel@tonic-gate printf("%s: Bad option overload.\n", 476*7c478bd9Sstevel@tonic-gate s_n); 477*7c478bd9Sstevel@tonic-gate break; 478*7c478bd9Sstevel@tonic-gate } 479*7c478bd9Sstevel@tonic-gate } 480*7c478bd9Sstevel@tonic-gate tk = wk; 481*7c478bd9Sstevel@tonic-gate wk = wk->next; 482*7c478bd9Sstevel@tonic-gate remove_list(tk, B_TRUE); 483*7c478bd9Sstevel@tonic-gate continue; 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate wk = wk->next; 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate /* 489*7c478bd9Sstevel@tonic-gate * Pass two. Pick out the best offer. Point system. 490*7c478bd9Sstevel@tonic-gate * What's important? 491*7c478bd9Sstevel@tonic-gate * 0) DHCP 492*7c478bd9Sstevel@tonic-gate * 1) No option overload 493*7c478bd9Sstevel@tonic-gate * 2) Encapsulated vendor option 494*7c478bd9Sstevel@tonic-gate * 3) Non-null sname and siaddr fields 495*7c478bd9Sstevel@tonic-gate * 4) Non-null file field 496*7c478bd9Sstevel@tonic-gate * 5) Hostname 497*7c478bd9Sstevel@tonic-gate * 6) Subnetmask 498*7c478bd9Sstevel@tonic-gate * 7) Router 499*7c478bd9Sstevel@tonic-gate */ 500*7c478bd9Sstevel@tonic-gate best = NULL; 501*7c478bd9Sstevel@tonic-gate for (wk = list_hd; wk != NULL; wk = wk->next) { 502*7c478bd9Sstevel@tonic-gate wk->offset = 0; 503*7c478bd9Sstevel@tonic-gate if (wk->opts[CD_DHCP_TYPE] && 504*7c478bd9Sstevel@tonic-gate wk->opts[CD_DHCP_TYPE]->len == 1) { 505*7c478bd9Sstevel@tonic-gate if (*wk->opts[CD_DHCP_TYPE]->value != OFFER) { 506*7c478bd9Sstevel@tonic-gate dprintf("%s: Unexpected DHCP message." 507*7c478bd9Sstevel@tonic-gate " Expected OFFER message.\n", s_n); 508*7c478bd9Sstevel@tonic-gate continue; 509*7c478bd9Sstevel@tonic-gate } 510*7c478bd9Sstevel@tonic-gate if (!wk->opts[CD_LEASE_TIME]) { 511*7c478bd9Sstevel@tonic-gate dprintf("%s: DHCP OFFER message without lease " 512*7c478bd9Sstevel@tonic-gate "time parameter.\n", s_n); 513*7c478bd9Sstevel@tonic-gate continue; 514*7c478bd9Sstevel@tonic-gate } else { 515*7c478bd9Sstevel@tonic-gate if (wk->opts[CD_LEASE_TIME]->len != 4) { 516*7c478bd9Sstevel@tonic-gate dprintf("%s: Lease expiration time is " 517*7c478bd9Sstevel@tonic-gate "garbled.\n", s_n); 518*7c478bd9Sstevel@tonic-gate continue; 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate } 521*7c478bd9Sstevel@tonic-gate if (!wk->opts[CD_SERVER_ID]) { 522*7c478bd9Sstevel@tonic-gate dprintf("%s: DHCP OFFER message without server " 523*7c478bd9Sstevel@tonic-gate "id parameter.\n", s_n); 524*7c478bd9Sstevel@tonic-gate continue; 525*7c478bd9Sstevel@tonic-gate } else { 526*7c478bd9Sstevel@tonic-gate if (wk->opts[CD_SERVER_ID]->len != 4) { 527*7c478bd9Sstevel@tonic-gate dprintf("%s: Server identifier " 528*7c478bd9Sstevel@tonic-gate "parameter is garbled.\n", s_n); 529*7c478bd9Sstevel@tonic-gate continue; 530*7c478bd9Sstevel@tonic-gate } 531*7c478bd9Sstevel@tonic-gate } 532*7c478bd9Sstevel@tonic-gate /* Valid DHCP OFFER. See if we got our parameters. */ 533*7c478bd9Sstevel@tonic-gate dprintf("%s: Found valid DHCP OFFER message.\n", s_n); 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate wk->offset += 30; 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate /* 538*7c478bd9Sstevel@tonic-gate * Also could be faked, though more difficult 539*7c478bd9Sstevel@tonic-gate * because the encapsulation is hard to encode 540*7c478bd9Sstevel@tonic-gate * on a BOOTP server; plus there's not as much 541*7c478bd9Sstevel@tonic-gate * real estate in the packet for options, so 542*7c478bd9Sstevel@tonic-gate * it's likely this option would get dropped. 543*7c478bd9Sstevel@tonic-gate */ 544*7c478bd9Sstevel@tonic-gate if (wk->opts[CD_VENDOR_SPEC]) 545*7c478bd9Sstevel@tonic-gate wk->offset += 80; 546*7c478bd9Sstevel@tonic-gate } else 547*7c478bd9Sstevel@tonic-gate dprintf("%s: Found valid BOOTP reply.\n", s_n); 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate /* 550*7c478bd9Sstevel@tonic-gate * RFC1048 BOOTP? 551*7c478bd9Sstevel@tonic-gate */ 552*7c478bd9Sstevel@tonic-gate if (bcmp((caddr_t)wk->pkt->cookie, (caddr_t)magic, 553*7c478bd9Sstevel@tonic-gate sizeof (magic)) == 0) { 554*7c478bd9Sstevel@tonic-gate wk->offset += 5; 555*7c478bd9Sstevel@tonic-gate if (wk->opts[CD_SUBNETMASK]) 556*7c478bd9Sstevel@tonic-gate wk->offset++; 557*7c478bd9Sstevel@tonic-gate if (wk->opts[CD_ROUTER]) 558*7c478bd9Sstevel@tonic-gate wk->offset++; 559*7c478bd9Sstevel@tonic-gate if (wk->opts[CD_HOSTNAME]) 560*7c478bd9Sstevel@tonic-gate wk->offset += 5; 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate /* 563*7c478bd9Sstevel@tonic-gate * Prefer options that have diskless boot significance 564*7c478bd9Sstevel@tonic-gate */ 565*7c478bd9Sstevel@tonic-gate if (ntohl(wk->pkt->siaddr.s_addr) != INADDR_ANY) 566*7c478bd9Sstevel@tonic-gate wk->offset += 10; /* server ip */ 567*7c478bd9Sstevel@tonic-gate if (wk->opts[CD_OPTION_OVERLOAD] == NULL) { 568*7c478bd9Sstevel@tonic-gate if (wk->pkt->sname[0] != '\0') 569*7c478bd9Sstevel@tonic-gate wk->offset += 10; /* server name */ 570*7c478bd9Sstevel@tonic-gate if (wk->pkt->file[0] != '\0') 571*7c478bd9Sstevel@tonic-gate wk->offset += 5; /* File to load */ 572*7c478bd9Sstevel@tonic-gate } 573*7c478bd9Sstevel@tonic-gate } 574*7c478bd9Sstevel@tonic-gate #ifdef DHCP_DEBUG 575*7c478bd9Sstevel@tonic-gate printf("%s: This server configuration has '%d' points.\n", s_n, 576*7c478bd9Sstevel@tonic-gate wk->offset); 577*7c478bd9Sstevel@tonic-gate #endif /* DHCP_DEBUG */ 578*7c478bd9Sstevel@tonic-gate if (!best) 579*7c478bd9Sstevel@tonic-gate best = wk; 580*7c478bd9Sstevel@tonic-gate else { 581*7c478bd9Sstevel@tonic-gate if (best->offset < wk->offset) 582*7c478bd9Sstevel@tonic-gate best = wk; 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate if (best) { 586*7c478bd9Sstevel@tonic-gate #ifdef DHCP_DEBUG 587*7c478bd9Sstevel@tonic-gate printf("%s: Found best: points: %d\n", s_n, best->offset); 588*7c478bd9Sstevel@tonic-gate #endif /* DHCP_DEBUG */ 589*7c478bd9Sstevel@tonic-gate remove_list(best, B_FALSE); 590*7c478bd9Sstevel@tonic-gate } else { 591*7c478bd9Sstevel@tonic-gate dprintf("%s: No valid BOOTP reply or DHCP OFFER was found.\n", 592*7c478bd9Sstevel@tonic-gate s_n); 593*7c478bd9Sstevel@tonic-gate } 594*7c478bd9Sstevel@tonic-gate flush_list(); /* toss the remaining list */ 595*7c478bd9Sstevel@tonic-gate return (best); 596*7c478bd9Sstevel@tonic-gate } 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate /* 599*7c478bd9Sstevel@tonic-gate * Send a decline message to the generator of the DHCPACK. 600*7c478bd9Sstevel@tonic-gate */ 601*7c478bd9Sstevel@tonic-gate static void 602*7c478bd9Sstevel@tonic-gate dhcp_decline(char *msg, PKT_LIST *pl) 603*7c478bd9Sstevel@tonic-gate { 604*7c478bd9Sstevel@tonic-gate PKT *pkt; 605*7c478bd9Sstevel@tonic-gate uint8_t *opt, ulen; 606*7c478bd9Sstevel@tonic-gate int pkt_size; 607*7c478bd9Sstevel@tonic-gate struct in_addr nets, ours, t_server, t_yiaddr; 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate if (pl != NULL) { 610*7c478bd9Sstevel@tonic-gate if (pl->opts[CD_SERVER_ID] != NULL && 611*7c478bd9Sstevel@tonic-gate pl->opts[CD_SERVER_ID]->len == sizeof (struct in_addr)) { 612*7c478bd9Sstevel@tonic-gate bcopy(pl->opts[CD_SERVER_ID]->value, 613*7c478bd9Sstevel@tonic-gate &t_server, pl->opts[CD_SERVER_ID]->len); 614*7c478bd9Sstevel@tonic-gate } else 615*7c478bd9Sstevel@tonic-gate t_server.s_addr = htonl(INADDR_BROADCAST); 616*7c478bd9Sstevel@tonic-gate t_yiaddr.s_addr = pl->pkt->yiaddr.s_addr; 617*7c478bd9Sstevel@tonic-gate } 618*7c478bd9Sstevel@tonic-gate pkt = (PKT *)dhcp_snd_bufp; 619*7c478bd9Sstevel@tonic-gate opt = init_msg(pkt, opt_decline); 620*7c478bd9Sstevel@tonic-gate set_hw_spec_data(pkt, &opt, opt_decline); 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate *opt++ = CD_SERVER_ID; 623*7c478bd9Sstevel@tonic-gate *opt++ = sizeof (struct in_addr); 624*7c478bd9Sstevel@tonic-gate bcopy(&t_server, opt, sizeof (struct in_addr)); 625*7c478bd9Sstevel@tonic-gate opt += sizeof (struct in_addr); 626*7c478bd9Sstevel@tonic-gate nets.s_addr = htonl(INADDR_BROADCAST); 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate /* 629*7c478bd9Sstevel@tonic-gate * Use the given yiaddr in our ciaddr field so server can identify us. 630*7c478bd9Sstevel@tonic-gate */ 631*7c478bd9Sstevel@tonic-gate pkt->ciaddr.s_addr = t_yiaddr.s_addr; 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate ipv4_getipaddr(&ours); /* Could be 0, could be yiaddr */ 634*7c478bd9Sstevel@tonic-gate ours.s_addr = htonl(ours.s_addr); 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate ulen = (uint8_t)strlen(msg); 637*7c478bd9Sstevel@tonic-gate *opt++ = CD_MESSAGE; 638*7c478bd9Sstevel@tonic-gate *opt++ = ulen; 639*7c478bd9Sstevel@tonic-gate bcopy(msg, opt, ulen); 640*7c478bd9Sstevel@tonic-gate opt += ulen; 641*7c478bd9Sstevel@tonic-gate *opt++ = CD_END; 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate pkt_size = (uint8_t *)opt - (uint8_t *)pkt; 644*7c478bd9Sstevel@tonic-gate if (pkt_size < sizeof (PKT)) 645*7c478bd9Sstevel@tonic-gate pkt_size = sizeof (PKT); 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate timeout = 0; /* reset timeout */ 648*7c478bd9Sstevel@tonic-gate (void) inet(pkt_size, &ours, &nets, 0, 0L); 649*7c478bd9Sstevel@tonic-gate } 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate /* 652*7c478bd9Sstevel@tonic-gate * Implementings SELECTING state of DHCP client state machine. 653*7c478bd9Sstevel@tonic-gate */ 654*7c478bd9Sstevel@tonic-gate static int 655*7c478bd9Sstevel@tonic-gate dhcp_selecting(void) 656*7c478bd9Sstevel@tonic-gate { 657*7c478bd9Sstevel@tonic-gate int pkt_size; 658*7c478bd9Sstevel@tonic-gate PKT *pkt; 659*7c478bd9Sstevel@tonic-gate uint8_t *opt; 660*7c478bd9Sstevel@tonic-gate uint16_t size; 661*7c478bd9Sstevel@tonic-gate uint32_t lease; 662*7c478bd9Sstevel@tonic-gate struct in_addr nets, ours; 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate pkt = (PKT *)dhcp_snd_bufp; 665*7c478bd9Sstevel@tonic-gate opt = init_msg(pkt, opt_discover); 666*7c478bd9Sstevel@tonic-gate pkt->secs = htons((uint16_t)((prom_gettime() - dhcp_start_time)/1000)); 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate *opt++ = CD_MAX_DHCP_SIZE; 669*7c478bd9Sstevel@tonic-gate *opt++ = sizeof (size); 670*7c478bd9Sstevel@tonic-gate size = (uint16_t)(dhcp_buf_size - sizeof (struct ip) - 671*7c478bd9Sstevel@tonic-gate sizeof (struct udphdr)); 672*7c478bd9Sstevel@tonic-gate size = htons(size); 673*7c478bd9Sstevel@tonic-gate bcopy(&size, opt, sizeof (size)); 674*7c478bd9Sstevel@tonic-gate opt += sizeof (size); 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate set_hw_spec_data(pkt, &opt, opt_discover); 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate *opt++ = CD_LEASE_TIME; 679*7c478bd9Sstevel@tonic-gate *opt++ = sizeof (lease); 680*7c478bd9Sstevel@tonic-gate lease = htonl(DHCP_PERM); /* ask for a permanent lease */ 681*7c478bd9Sstevel@tonic-gate bcopy(&lease, opt, sizeof (lease)); 682*7c478bd9Sstevel@tonic-gate opt += sizeof (lease); 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate /* 685*7c478bd9Sstevel@tonic-gate * If a clientid was set using dhcp_set_client_id(), add this 686*7c478bd9Sstevel@tonic-gate * to the options. 687*7c478bd9Sstevel@tonic-gate */ 688*7c478bd9Sstevel@tonic-gate if (dhcp_clientid_len > 0) { 689*7c478bd9Sstevel@tonic-gate *opt++ = CD_CLIENT_ID; 690*7c478bd9Sstevel@tonic-gate *opt++ = dhcp_clientid_len; 691*7c478bd9Sstevel@tonic-gate bcopy(dhcp_clientid, opt, dhcp_clientid_len); 692*7c478bd9Sstevel@tonic-gate opt += dhcp_clientid_len; 693*7c478bd9Sstevel@tonic-gate } 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate parameter_request_list(&opt); 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate *opt++ = CD_END; 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate pkt_size = (uint8_t *)opt - (uint8_t *)pkt; 700*7c478bd9Sstevel@tonic-gate if (pkt_size < sizeof (PKT)) 701*7c478bd9Sstevel@tonic-gate pkt_size = sizeof (PKT); 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate nets.s_addr = INADDR_BROADCAST; 704*7c478bd9Sstevel@tonic-gate ours.s_addr = INADDR_ANY; 705*7c478bd9Sstevel@tonic-gate timeout = 0; /* reset timeout */ 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate return (inet(pkt_size, &ours, &nets, DHCP_RETRIES, DHCP_WAIT)); 708*7c478bd9Sstevel@tonic-gate } 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate /* 711*7c478bd9Sstevel@tonic-gate * implements the REQUESTING state of the DHCP client state machine. 712*7c478bd9Sstevel@tonic-gate */ 713*7c478bd9Sstevel@tonic-gate static int 714*7c478bd9Sstevel@tonic-gate dhcp_requesting(void) 715*7c478bd9Sstevel@tonic-gate { 716*7c478bd9Sstevel@tonic-gate PKT_LIST *pl, *wk; 717*7c478bd9Sstevel@tonic-gate PKT *pkt, *pl_pkt; 718*7c478bd9Sstevel@tonic-gate uint8_t *opt; 719*7c478bd9Sstevel@tonic-gate int pkt_size, err; 720*7c478bd9Sstevel@tonic-gate uint32_t t_time; 721*7c478bd9Sstevel@tonic-gate struct in_addr nets, ours; 722*7c478bd9Sstevel@tonic-gate DHCP_OPT *doptp; 723*7c478bd9Sstevel@tonic-gate uint16_t size; 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate /* here we scan the list of OFFERS, select the best one. */ 726*7c478bd9Sstevel@tonic-gate state_pl = NULL; 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate if ((pl = select_best()) == NULL) { 729*7c478bd9Sstevel@tonic-gate dprintf("%s: No valid BOOTP reply or DHCP OFFER was found.\n", 730*7c478bd9Sstevel@tonic-gate s_n); 731*7c478bd9Sstevel@tonic-gate return (1); 732*7c478bd9Sstevel@tonic-gate } 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate pl_pkt = pl->pkt; 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate /* 737*7c478bd9Sstevel@tonic-gate * Check to see if we got an OFFER pkt(s). If not, then We only got 738*7c478bd9Sstevel@tonic-gate * a response from a BOOTP server. We'll go to the bound state and 739*7c478bd9Sstevel@tonic-gate * try to use that configuration. 740*7c478bd9Sstevel@tonic-gate */ 741*7c478bd9Sstevel@tonic-gate if (pl->opts[CD_DHCP_TYPE] == NULL) { 742*7c478bd9Sstevel@tonic-gate if (mac_call_arp(&pl_pkt->yiaddr, NULL, DHCP_ARP_TIMEOUT)) { 743*7c478bd9Sstevel@tonic-gate /* Someone responded! go back to SELECTING state. */ 744*7c478bd9Sstevel@tonic-gate printf("%s: Some host already using BOOTP %s.\n", s_n, 745*7c478bd9Sstevel@tonic-gate inet_ntoa(pl_pkt->yiaddr)); 746*7c478bd9Sstevel@tonic-gate bkmem_free((char *)pl->pkt, pl->len); 747*7c478bd9Sstevel@tonic-gate bkmem_free((char *)pl, sizeof (PKT_LIST)); 748*7c478bd9Sstevel@tonic-gate return (1); 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate state_pl = pl; 751*7c478bd9Sstevel@tonic-gate return (0); 752*7c478bd9Sstevel@tonic-gate } 753*7c478bd9Sstevel@tonic-gate 754*7c478bd9Sstevel@tonic-gate /* 755*7c478bd9Sstevel@tonic-gate * if we got a message from the server, display it. 756*7c478bd9Sstevel@tonic-gate */ 757*7c478bd9Sstevel@tonic-gate if (pl->opts[CD_MESSAGE]) 758*7c478bd9Sstevel@tonic-gate prt_server_msg(pl->opts[CD_MESSAGE]); 759*7c478bd9Sstevel@tonic-gate /* 760*7c478bd9Sstevel@tonic-gate * Assemble a DHCPREQUEST, with the ciaddr field set to 0, since we 761*7c478bd9Sstevel@tonic-gate * got here from DISCOVER state. Keep secs field the same for relay 762*7c478bd9Sstevel@tonic-gate * agents. We start with the DHCPOFFER packet we got, and the 763*7c478bd9Sstevel@tonic-gate * options contained in it to make a requested option list. 764*7c478bd9Sstevel@tonic-gate */ 765*7c478bd9Sstevel@tonic-gate pkt = (PKT *)dhcp_snd_bufp; 766*7c478bd9Sstevel@tonic-gate opt = init_msg(pkt, opt_request); 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate /* Time from Successful DISCOVER message. */ 769*7c478bd9Sstevel@tonic-gate pkt->secs = htons((uint16_t)dhcp_secs); 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate size = (uint16_t)(dhcp_buf_size - sizeof (struct ip) - 772*7c478bd9Sstevel@tonic-gate sizeof (struct udphdr)); 773*7c478bd9Sstevel@tonic-gate size = htons(size); 774*7c478bd9Sstevel@tonic-gate *opt++ = CD_MAX_DHCP_SIZE; 775*7c478bd9Sstevel@tonic-gate *opt++ = sizeof (size); 776*7c478bd9Sstevel@tonic-gate bcopy(&size, opt, sizeof (size)); 777*7c478bd9Sstevel@tonic-gate opt += sizeof (size); 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate set_hw_spec_data(pkt, &opt, opt_request); 780*7c478bd9Sstevel@tonic-gate *opt++ = CD_SERVER_ID; 781*7c478bd9Sstevel@tonic-gate *opt++ = pl->opts[CD_SERVER_ID]->len; 782*7c478bd9Sstevel@tonic-gate bcopy(pl->opts[CD_SERVER_ID]->value, opt, 783*7c478bd9Sstevel@tonic-gate pl->opts[CD_SERVER_ID]->len); 784*7c478bd9Sstevel@tonic-gate opt += pl->opts[CD_SERVER_ID]->len; 785*7c478bd9Sstevel@tonic-gate 786*7c478bd9Sstevel@tonic-gate /* our offered lease minus boot time */ 787*7c478bd9Sstevel@tonic-gate *opt++ = CD_LEASE_TIME; 788*7c478bd9Sstevel@tonic-gate *opt++ = 4; 789*7c478bd9Sstevel@tonic-gate bcopy(pl->opts[CD_LEASE_TIME]->value, &t_time, 790*7c478bd9Sstevel@tonic-gate sizeof (t_time)); 791*7c478bd9Sstevel@tonic-gate t_time = ntohl(t_time); 792*7c478bd9Sstevel@tonic-gate if ((uint32_t)t_time != DHCP_PERM) 793*7c478bd9Sstevel@tonic-gate t_time -= (uint32_t)dhcp_secs; 794*7c478bd9Sstevel@tonic-gate t_time = htonl(t_time); 795*7c478bd9Sstevel@tonic-gate bcopy(&t_time, opt, sizeof (t_time)); 796*7c478bd9Sstevel@tonic-gate opt += sizeof (t_time); 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate /* our offered IP address, as required. */ 799*7c478bd9Sstevel@tonic-gate *opt++ = CD_REQUESTED_IP_ADDR; 800*7c478bd9Sstevel@tonic-gate *opt++ = sizeof (struct in_addr); 801*7c478bd9Sstevel@tonic-gate bcopy(&pl_pkt->yiaddr, opt, sizeof (struct in_addr)); 802*7c478bd9Sstevel@tonic-gate opt += sizeof (struct in_addr); 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate /* 805*7c478bd9Sstevel@tonic-gate * If a clientid was set using dhcp_set_client_id(), add this 806*7c478bd9Sstevel@tonic-gate * to the options. 807*7c478bd9Sstevel@tonic-gate */ 808*7c478bd9Sstevel@tonic-gate if (dhcp_clientid_len > 0) { 809*7c478bd9Sstevel@tonic-gate *opt++ = CD_CLIENT_ID; 810*7c478bd9Sstevel@tonic-gate *opt++ = dhcp_clientid_len; 811*7c478bd9Sstevel@tonic-gate bcopy(dhcp_clientid, opt, dhcp_clientid_len); 812*7c478bd9Sstevel@tonic-gate opt += dhcp_clientid_len; 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate parameter_request_list(&opt); 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate *opt++ = CD_END; 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate /* Done with the OFFER pkt. */ 820*7c478bd9Sstevel@tonic-gate bkmem_free((char *)pl->pkt, pl->len); 821*7c478bd9Sstevel@tonic-gate bkmem_free((char *)pl, sizeof (PKT_LIST)); 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate /* 824*7c478bd9Sstevel@tonic-gate * We make 4 attempts here. We wait for 2 seconds to accumulate 825*7c478bd9Sstevel@tonic-gate * requests, just in case a BOOTP server is too fast! 826*7c478bd9Sstevel@tonic-gate */ 827*7c478bd9Sstevel@tonic-gate pkt_size = (uint8_t *)opt - (uint8_t *)pkt; 828*7c478bd9Sstevel@tonic-gate if (pkt_size < sizeof (PKT)) 829*7c478bd9Sstevel@tonic-gate pkt_size = sizeof (PKT); 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate nets.s_addr = INADDR_BROADCAST; 832*7c478bd9Sstevel@tonic-gate ours.s_addr = INADDR_ANY; 833*7c478bd9Sstevel@tonic-gate timeout = 0; /* reset timeout */ 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate if ((err = inet(pkt_size, &ours, &nets, 4, (time_t)2L)) != 0) 836*7c478bd9Sstevel@tonic-gate return (err); 837*7c478bd9Sstevel@tonic-gate for (wk = list_hd; wk != NULL && state_pl == NULL; wk = wk->next) { 838*7c478bd9Sstevel@tonic-gate if (dhcp_options_scan(wk, B_TRUE) != 0 || 839*7c478bd9Sstevel@tonic-gate !wk->opts[CD_DHCP_TYPE]) 840*7c478bd9Sstevel@tonic-gate continue; /* garbled options */ 841*7c478bd9Sstevel@tonic-gate switch (*wk->opts[CD_DHCP_TYPE]->value) { 842*7c478bd9Sstevel@tonic-gate case ACK: 843*7c478bd9Sstevel@tonic-gate remove_list(wk, B_FALSE); 844*7c478bd9Sstevel@tonic-gate state_pl = wk; 845*7c478bd9Sstevel@tonic-gate break; 846*7c478bd9Sstevel@tonic-gate case NAK: 847*7c478bd9Sstevel@tonic-gate printf("%s: rejected by DHCP server: %s\n", 848*7c478bd9Sstevel@tonic-gate s_n, inet_ntoa(*((struct in_addr *)wk-> 849*7c478bd9Sstevel@tonic-gate opts[CD_SERVER_ID]->value))); 850*7c478bd9Sstevel@tonic-gate if (wk->opts[CD_MESSAGE]) 851*7c478bd9Sstevel@tonic-gate prt_server_msg(wk->opts[CD_MESSAGE]); 852*7c478bd9Sstevel@tonic-gate break; 853*7c478bd9Sstevel@tonic-gate default: 854*7c478bd9Sstevel@tonic-gate dprintf("%s: Unexpected DHCP message type.\n", s_n); 855*7c478bd9Sstevel@tonic-gate break; 856*7c478bd9Sstevel@tonic-gate } 857*7c478bd9Sstevel@tonic-gate } 858*7c478bd9Sstevel@tonic-gate flush_list(); 859*7c478bd9Sstevel@tonic-gate if (state_pl != NULL) { 860*7c478bd9Sstevel@tonic-gate if (state_pl->opts[CD_MESSAGE]) 861*7c478bd9Sstevel@tonic-gate prt_server_msg(state_pl->opts[CD_MESSAGE]); 862*7c478bd9Sstevel@tonic-gate pl_pkt = state_pl->pkt; 863*7c478bd9Sstevel@tonic-gate /* arp our new address, just to make sure */ 864*7c478bd9Sstevel@tonic-gate if (!mac_call_arp(&pl_pkt->yiaddr, NULL, DHCP_ARP_TIMEOUT)) { 865*7c478bd9Sstevel@tonic-gate /* 866*7c478bd9Sstevel@tonic-gate * No response. Check if lease is ok. 867*7c478bd9Sstevel@tonic-gate */ 868*7c478bd9Sstevel@tonic-gate doptp = state_pl->opts[CD_LEASE_TIME]; 869*7c478bd9Sstevel@tonic-gate if (state_pl->opts[CD_DHCP_TYPE] && (!doptp || 870*7c478bd9Sstevel@tonic-gate (doptp->len % 4) != 0)) { 871*7c478bd9Sstevel@tonic-gate dhcp_decline("Missing or corrupted lease time", 872*7c478bd9Sstevel@tonic-gate state_pl); 873*7c478bd9Sstevel@tonic-gate err++; 874*7c478bd9Sstevel@tonic-gate } 875*7c478bd9Sstevel@tonic-gate } else { 876*7c478bd9Sstevel@tonic-gate dhcp_decline("IP Address already being used!", 877*7c478bd9Sstevel@tonic-gate state_pl); 878*7c478bd9Sstevel@tonic-gate err++; 879*7c478bd9Sstevel@tonic-gate } 880*7c478bd9Sstevel@tonic-gate if (err) { 881*7c478bd9Sstevel@tonic-gate bkmem_free((char *)state_pl->pkt, state_pl->len); 882*7c478bd9Sstevel@tonic-gate bkmem_free((char *)state_pl, sizeof (PKT_LIST)); 883*7c478bd9Sstevel@tonic-gate state_pl = NULL; 884*7c478bd9Sstevel@tonic-gate } else 885*7c478bd9Sstevel@tonic-gate return (0); /* passes the tests! */ 886*7c478bd9Sstevel@tonic-gate } 887*7c478bd9Sstevel@tonic-gate dprintf("%s: No valid DHCP acknowledge messages received.\n", s_n); 888*7c478bd9Sstevel@tonic-gate return (1); 889*7c478bd9Sstevel@tonic-gate } 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate /* 892*7c478bd9Sstevel@tonic-gate * Implements BOUND state of DHCP client state machine. 893*7c478bd9Sstevel@tonic-gate */ 894*7c478bd9Sstevel@tonic-gate static int 895*7c478bd9Sstevel@tonic-gate dhcp_bound(void) 896*7c478bd9Sstevel@tonic-gate { 897*7c478bd9Sstevel@tonic-gate PKT *pl_pkt = state_pl->pkt; 898*7c478bd9Sstevel@tonic-gate DHCP_OPT *doptp; 899*7c478bd9Sstevel@tonic-gate uint8_t *tp, *hp; 900*7c478bd9Sstevel@tonic-gate int items, i, fnd, k; 901*7c478bd9Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN+1]; 902*7c478bd9Sstevel@tonic-gate struct in_addr subnet, defr, savr, *ipp, xip; 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate #ifdef DHCP_DEBUG 905*7c478bd9Sstevel@tonic-gate if (dhcp_classid[0] != 0) { 906*7c478bd9Sstevel@tonic-gate char scratch[DHCP_MAX_OPT_SIZE + 1]; 907*7c478bd9Sstevel@tonic-gate 908*7c478bd9Sstevel@tonic-gate bcopy(&dhcp_classid[2], scratch, dhcp_classid[1]); 909*7c478bd9Sstevel@tonic-gate scratch[dhcp_classid[1]] = '\0'; 910*7c478bd9Sstevel@tonic-gate printf("Your machine is of the class: '%s'.\n", scratch); 911*7c478bd9Sstevel@tonic-gate } 912*7c478bd9Sstevel@tonic-gate #endif /* DHCP_DEBUG */ 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate /* First, set the bare essentials. (IP layer parameters) */ 915*7c478bd9Sstevel@tonic-gate 916*7c478bd9Sstevel@tonic-gate ipv4_getipaddr(&xip); 917*7c478bd9Sstevel@tonic-gate if (xip.s_addr != INADDR_ANY) 918*7c478bd9Sstevel@tonic-gate ipp = &xip; 919*7c478bd9Sstevel@tonic-gate else { 920*7c478bd9Sstevel@tonic-gate ipp = &pl_pkt->yiaddr; 921*7c478bd9Sstevel@tonic-gate ipp->s_addr = ntohl(ipp->s_addr); 922*7c478bd9Sstevel@tonic-gate ipv4_setipaddr(ipp); 923*7c478bd9Sstevel@tonic-gate } 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate ipp->s_addr = htonl(ipp->s_addr); 926*7c478bd9Sstevel@tonic-gate 927*7c478bd9Sstevel@tonic-gate if (boothowto & RB_VERBOSE) 928*7c478bd9Sstevel@tonic-gate printf("%s: IP address is: %s\n", s_n, inet_ntoa(*ipp)); 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate /* 931*7c478bd9Sstevel@tonic-gate * Ensure that the Boot NFS READ size, if given, is an int16_t. 932*7c478bd9Sstevel@tonic-gate */ 933*7c478bd9Sstevel@tonic-gate if (state_pl->vs[VS_BOOT_NFS_READSIZE] != NULL) { 934*7c478bd9Sstevel@tonic-gate doptp = state_pl->vs[VS_BOOT_NFS_READSIZE]; 935*7c478bd9Sstevel@tonic-gate if (doptp->len != sizeof (int16_t)) 936*7c478bd9Sstevel@tonic-gate state_pl->vs[VS_BOOT_NFS_READSIZE] = NULL; 937*7c478bd9Sstevel@tonic-gate } 938*7c478bd9Sstevel@tonic-gate 939*7c478bd9Sstevel@tonic-gate /* 940*7c478bd9Sstevel@tonic-gate * Set subnetmask. Nice, but not required. 941*7c478bd9Sstevel@tonic-gate */ 942*7c478bd9Sstevel@tonic-gate if (state_pl->opts[CD_SUBNETMASK] != NULL) { 943*7c478bd9Sstevel@tonic-gate doptp = state_pl->opts[CD_SUBNETMASK]; 944*7c478bd9Sstevel@tonic-gate if (doptp->len != 4) 945*7c478bd9Sstevel@tonic-gate state_pl->opts[CD_SUBNETMASK] = NULL; 946*7c478bd9Sstevel@tonic-gate else { 947*7c478bd9Sstevel@tonic-gate bcopy(doptp->value, &subnet, 948*7c478bd9Sstevel@tonic-gate sizeof (struct in_addr)); 949*7c478bd9Sstevel@tonic-gate dprintf("%s: Setting netmask to: %s\n", s_n, 950*7c478bd9Sstevel@tonic-gate inet_ntoa(subnet)); 951*7c478bd9Sstevel@tonic-gate subnet.s_addr = ntohl(subnet.s_addr); 952*7c478bd9Sstevel@tonic-gate ipv4_setnetmask(&subnet); 953*7c478bd9Sstevel@tonic-gate } 954*7c478bd9Sstevel@tonic-gate } 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate /* 957*7c478bd9Sstevel@tonic-gate * Set default IP TTL. Nice, but not required. 958*7c478bd9Sstevel@tonic-gate */ 959*7c478bd9Sstevel@tonic-gate if (state_pl->opts[CD_IPTTL] != NULL) { 960*7c478bd9Sstevel@tonic-gate doptp = state_pl->opts[CD_IPTTL]; 961*7c478bd9Sstevel@tonic-gate if (doptp->len > 1) 962*7c478bd9Sstevel@tonic-gate state_pl->opts[CD_IPTTL] = NULL; 963*7c478bd9Sstevel@tonic-gate else { 964*7c478bd9Sstevel@tonic-gate doptp = state_pl->opts[CD_IPTTL]; 965*7c478bd9Sstevel@tonic-gate ipv4_setmaxttl(*(uint8_t *)doptp->value); 966*7c478bd9Sstevel@tonic-gate dprintf("%s: Setting IP TTL to: %d\n", s_n, 967*7c478bd9Sstevel@tonic-gate *(uint8_t *)doptp->value); 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate } 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate /* 972*7c478bd9Sstevel@tonic-gate * Set default router. Not required, although we'll know soon 973*7c478bd9Sstevel@tonic-gate * enough... 974*7c478bd9Sstevel@tonic-gate */ 975*7c478bd9Sstevel@tonic-gate if (state_pl->opts[CD_ROUTER] != NULL) { 976*7c478bd9Sstevel@tonic-gate doptp = state_pl->opts[CD_ROUTER]; 977*7c478bd9Sstevel@tonic-gate if ((doptp->len % 4) != 0) { 978*7c478bd9Sstevel@tonic-gate state_pl->opts[CD_ROUTER] = NULL; 979*7c478bd9Sstevel@tonic-gate } else { 980*7c478bd9Sstevel@tonic-gate if ((hp = (uint8_t *)bkmem_alloc( 981*7c478bd9Sstevel@tonic-gate mac_get_hdr_len())) == NULL) { 982*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 983*7c478bd9Sstevel@tonic-gate return (-1); 984*7c478bd9Sstevel@tonic-gate } 985*7c478bd9Sstevel@tonic-gate items = doptp->len / sizeof (struct in_addr); 986*7c478bd9Sstevel@tonic-gate tp = doptp->value; 987*7c478bd9Sstevel@tonic-gate bcopy(tp, &savr, sizeof (struct in_addr)); 988*7c478bd9Sstevel@tonic-gate for (i = 0, fnd = 0; i < items; i++) { 989*7c478bd9Sstevel@tonic-gate bcopy(tp, &defr, sizeof (struct in_addr)); 990*7c478bd9Sstevel@tonic-gate for (k = 0, fnd = 0; k < 2 && fnd == 0; k++) { 991*7c478bd9Sstevel@tonic-gate fnd = mac_get_arp(&defr, hp, 992*7c478bd9Sstevel@tonic-gate mac_get_hdr_len(), 993*7c478bd9Sstevel@tonic-gate mac_get_arp_timeout()); 994*7c478bd9Sstevel@tonic-gate } 995*7c478bd9Sstevel@tonic-gate if (fnd) 996*7c478bd9Sstevel@tonic-gate break; 997*7c478bd9Sstevel@tonic-gate dprintf( 998*7c478bd9Sstevel@tonic-gate "%s: Warning: Router %s is unreachable.\n", 999*7c478bd9Sstevel@tonic-gate s_n, inet_ntoa(defr)); 1000*7c478bd9Sstevel@tonic-gate tp += sizeof (struct in_addr); 1001*7c478bd9Sstevel@tonic-gate } 1002*7c478bd9Sstevel@tonic-gate bkmem_free((char *)hp, mac_get_hdr_len()); 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate /* 1005*7c478bd9Sstevel@tonic-gate * If fnd is 0, we didn't find a working router. We'll 1006*7c478bd9Sstevel@tonic-gate * still try to use first default router. If we got 1007*7c478bd9Sstevel@tonic-gate * a bad router address (like not on the same net), 1008*7c478bd9Sstevel@tonic-gate * we're hosed anyway. 1009*7c478bd9Sstevel@tonic-gate */ 1010*7c478bd9Sstevel@tonic-gate if (!fnd) { 1011*7c478bd9Sstevel@tonic-gate dprintf( 1012*7c478bd9Sstevel@tonic-gate "%s: Warning: Using default router: %s\n", 1013*7c478bd9Sstevel@tonic-gate s_n, inet_ntoa(savr)); 1014*7c478bd9Sstevel@tonic-gate defr.s_addr = savr.s_addr; 1015*7c478bd9Sstevel@tonic-gate } 1016*7c478bd9Sstevel@tonic-gate /* ipv4_route expects network order IP addresses */ 1017*7c478bd9Sstevel@tonic-gate (void) ipv4_route(IPV4_ADD_ROUTE, RT_DEFAULT, NULL, 1018*7c478bd9Sstevel@tonic-gate &defr); 1019*7c478bd9Sstevel@tonic-gate } 1020*7c478bd9Sstevel@tonic-gate } 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate /* 1023*7c478bd9Sstevel@tonic-gate * Set hostname. Not required. 1024*7c478bd9Sstevel@tonic-gate */ 1025*7c478bd9Sstevel@tonic-gate if (state_pl->opts[CD_HOSTNAME] != NULL) { 1026*7c478bd9Sstevel@tonic-gate doptp = state_pl->opts[CD_HOSTNAME]; 1027*7c478bd9Sstevel@tonic-gate i = doptp->len; 1028*7c478bd9Sstevel@tonic-gate if (i > MAXHOSTNAMELEN) 1029*7c478bd9Sstevel@tonic-gate i = MAXHOSTNAMELEN; 1030*7c478bd9Sstevel@tonic-gate bcopy(doptp->value, hostname, i); 1031*7c478bd9Sstevel@tonic-gate hostname[i] = '\0'; 1032*7c478bd9Sstevel@tonic-gate (void) sethostname(hostname, i); 1033*7c478bd9Sstevel@tonic-gate if (boothowto & RB_VERBOSE) 1034*7c478bd9Sstevel@tonic-gate printf("%s: Hostname is %s\n", s_n, hostname); 1035*7c478bd9Sstevel@tonic-gate } 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate /* 1038*7c478bd9Sstevel@tonic-gate * We don't care about the lease time.... We can't enforce it anyway. 1039*7c478bd9Sstevel@tonic-gate */ 1040*7c478bd9Sstevel@tonic-gate return (0); 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate 1043*7c478bd9Sstevel@tonic-gate /* 1044*7c478bd9Sstevel@tonic-gate * Convert the DHCPACK into a pure ASCII boot property for use by the kernel 1045*7c478bd9Sstevel@tonic-gate * later in the boot process. 1046*7c478bd9Sstevel@tonic-gate */ 1047*7c478bd9Sstevel@tonic-gate static void 1048*7c478bd9Sstevel@tonic-gate create_bootpresponse_bprop(PKT_LIST *pl) 1049*7c478bd9Sstevel@tonic-gate { 1050*7c478bd9Sstevel@tonic-gate uint_t buflen; 1051*7c478bd9Sstevel@tonic-gate #if defined(__i386) 1052*7c478bd9Sstevel@tonic-gate extern struct bootops bootops; 1053*7c478bd9Sstevel@tonic-gate extern int bsetprop(struct bootops *, char *, caddr_t, int, phandle_t); 1054*7c478bd9Sstevel@tonic-gate #endif /* __i386 */ 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate if (pl == NULL || bootp_response != NULL) 1057*7c478bd9Sstevel@tonic-gate return; 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate buflen = (pl->len * 2) + 1; /* extra space for null (1) */ 1060*7c478bd9Sstevel@tonic-gate if ((bootp_response = bkmem_alloc(buflen)) == NULL) 1061*7c478bd9Sstevel@tonic-gate return; 1062*7c478bd9Sstevel@tonic-gate 1063*7c478bd9Sstevel@tonic-gate if (octet_to_hexascii((uint8_t *)pl->pkt, pl->len, bootp_response, 1064*7c478bd9Sstevel@tonic-gate &buflen) != 0) { 1065*7c478bd9Sstevel@tonic-gate bkmem_free(bootp_response, (pl->len * 2) + 1); 1066*7c478bd9Sstevel@tonic-gate bootp_response = NULL; 1067*7c478bd9Sstevel@tonic-gate } 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate #if defined(__i386) 1070*7c478bd9Sstevel@tonic-gate /* Use bsetprop to create the bootp-response property */ 1071*7c478bd9Sstevel@tonic-gate if (bsetprop(&bootops, "bootp-response", bootp_response, 0, 0) != 1072*7c478bd9Sstevel@tonic-gate BOOT_SUCCESS) { 1073*7c478bd9Sstevel@tonic-gate bkmem_free(bootp_response, (pl->len * 2) + 1); 1074*7c478bd9Sstevel@tonic-gate bootp_response = NULL; 1075*7c478bd9Sstevel@tonic-gate } 1076*7c478bd9Sstevel@tonic-gate #elif defined(__sparc) 1077*7c478bd9Sstevel@tonic-gate prom_create_encoded_prop("bootp-response", pl->pkt, pl->len, 1078*7c478bd9Sstevel@tonic-gate ENCODE_BYTES); 1079*7c478bd9Sstevel@tonic-gate #endif /* __i386 */ 1080*7c478bd9Sstevel@tonic-gate } 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate /* 1083*7c478bd9Sstevel@tonic-gate * Examines /chosen node for "bootp-response" property. If it exists, this 1084*7c478bd9Sstevel@tonic-gate * property is the DHCPACK cached there by the PROM's DHCP implementation. 1085*7c478bd9Sstevel@tonic-gate * 1086*7c478bd9Sstevel@tonic-gate * If cache_present is B_TRUE, we simply return B_TRUE if the property exists 1087*7c478bd9Sstevel@tonic-gate * w/o decoding it. If cache_present is B_FALSE, we decode the packet and 1088*7c478bd9Sstevel@tonic-gate * use it as our state packet for the jump to BOUND mode. Note that it's good 1089*7c478bd9Sstevel@tonic-gate * enough that the cache exists w/o validation for determining if that's what 1090*7c478bd9Sstevel@tonic-gate * the user intended. 1091*7c478bd9Sstevel@tonic-gate * 1092*7c478bd9Sstevel@tonic-gate * We'll short-circuit the DHCP exchange by accepting this packet. We build a 1093*7c478bd9Sstevel@tonic-gate * PKT_LIST structure, and copy the bootp-response property value into a 1094*7c478bd9Sstevel@tonic-gate * PKT buffer we allocated. We then scan the PKT for options, and then 1095*7c478bd9Sstevel@tonic-gate * set state_pl to point to it. 1096*7c478bd9Sstevel@tonic-gate * 1097*7c478bd9Sstevel@tonic-gate * Returns B_TRUE if a packet was cached (and was processed correctly), false 1098*7c478bd9Sstevel@tonic-gate * otherwise. The caller needs to make the state change from SELECTING to 1099*7c478bd9Sstevel@tonic-gate * BOUND upon a B_TRUE return from this function. 1100*7c478bd9Sstevel@tonic-gate */ 1101*7c478bd9Sstevel@tonic-gate int 1102*7c478bd9Sstevel@tonic-gate prom_cached_reply(int cache_present) 1103*7c478bd9Sstevel@tonic-gate { 1104*7c478bd9Sstevel@tonic-gate PKT_LIST *pl; 1105*7c478bd9Sstevel@tonic-gate int len; 1106*7c478bd9Sstevel@tonic-gate #if defined(__i386) 1107*7c478bd9Sstevel@tonic-gate char *ack; 1108*7c478bd9Sstevel@tonic-gate int pxe_ack_cache(char **); 1109*7c478bd9Sstevel@tonic-gate 1110*7c478bd9Sstevel@tonic-gate if ((len = pxe_ack_cache(&ack)) <= 0) 1111*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1112*7c478bd9Sstevel@tonic-gate #else 1113*7c478bd9Sstevel@tonic-gate dnode_t chosen; 1114*7c478bd9Sstevel@tonic-gate char *prop = PROM_BOOT_CACHED; 1115*7c478bd9Sstevel@tonic-gate 1116*7c478bd9Sstevel@tonic-gate chosen = prom_finddevice("/chosen"); 1117*7c478bd9Sstevel@tonic-gate if (chosen == OBP_NONODE || chosen == OBP_BADNODE) 1118*7c478bd9Sstevel@tonic-gate chosen = prom_nextnode((dnode_t)0); /* root node */ 1119*7c478bd9Sstevel@tonic-gate 1120*7c478bd9Sstevel@tonic-gate if ((len = prom_getproplen(chosen, prop)) <= 0) 1121*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1122*7c478bd9Sstevel@tonic-gate #endif /* __i386 */ 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate if (cache_present) 1125*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1126*7c478bd9Sstevel@tonic-gate 1127*7c478bd9Sstevel@tonic-gate if (((pl = (PKT_LIST *)bkmem_zalloc(sizeof (PKT_LIST))) == NULL) || 1128*7c478bd9Sstevel@tonic-gate ((pl->pkt = (PKT *)bkmem_zalloc(len)) == NULL)) { 1129*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1130*7c478bd9Sstevel@tonic-gate if (pl != NULL) 1131*7c478bd9Sstevel@tonic-gate bkmem_free((char *)pl, sizeof (PKT_LIST)); 1132*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1133*7c478bd9Sstevel@tonic-gate } 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate #if defined(__i386) 1136*7c478bd9Sstevel@tonic-gate bcopy(ack, pl->pkt, len); 1137*7c478bd9Sstevel@tonic-gate #else 1138*7c478bd9Sstevel@tonic-gate (void) prom_getprop(chosen, prop, (caddr_t)pl->pkt); 1139*7c478bd9Sstevel@tonic-gate #endif /* __i386 */ 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate pl->len = len; 1142*7c478bd9Sstevel@tonic-gate 1143*7c478bd9Sstevel@tonic-gate if (dhcp_options_scan(pl, B_TRUE) != 0) { 1144*7c478bd9Sstevel@tonic-gate /* garbled packet */ 1145*7c478bd9Sstevel@tonic-gate bkmem_free((char *)pl->pkt, pl->len); 1146*7c478bd9Sstevel@tonic-gate bkmem_free((char *)pl, sizeof (PKT_LIST)); 1147*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1148*7c478bd9Sstevel@tonic-gate } 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate state_pl = pl; 1151*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1152*7c478bd9Sstevel@tonic-gate } 1153*7c478bd9Sstevel@tonic-gate 1154*7c478bd9Sstevel@tonic-gate /* 1155*7c478bd9Sstevel@tonic-gate * Perform DHCP to acquire what we used to get using rarp/bootparams. 1156*7c478bd9Sstevel@tonic-gate * Returns 0 for success, nonzero otherwise. 1157*7c478bd9Sstevel@tonic-gate * 1158*7c478bd9Sstevel@tonic-gate * DHCP client state machine. 1159*7c478bd9Sstevel@tonic-gate */ 1160*7c478bd9Sstevel@tonic-gate int 1161*7c478bd9Sstevel@tonic-gate dhcp(void) 1162*7c478bd9Sstevel@tonic-gate { 1163*7c478bd9Sstevel@tonic-gate int err = 0; 1164*7c478bd9Sstevel@tonic-gate int done = B_FALSE; 1165*7c478bd9Sstevel@tonic-gate 1166*7c478bd9Sstevel@tonic-gate dhcp_buf_size = mac_get_mtu(); 1167*7c478bd9Sstevel@tonic-gate dhcp_snd_bufp = (PKT *)bkmem_alloc(dhcp_buf_size); 1168*7c478bd9Sstevel@tonic-gate dhcp_rcv_bufp = (PKT *)bkmem_alloc(dhcp_buf_size); 1169*7c478bd9Sstevel@tonic-gate 1170*7c478bd9Sstevel@tonic-gate if (dhcp_snd_bufp == NULL || dhcp_rcv_bufp == NULL) { 1171*7c478bd9Sstevel@tonic-gate if (dhcp_snd_bufp != NULL) 1172*7c478bd9Sstevel@tonic-gate bkmem_free((char *)dhcp_snd_bufp, dhcp_buf_size); 1173*7c478bd9Sstevel@tonic-gate if (dhcp_rcv_bufp != NULL) 1174*7c478bd9Sstevel@tonic-gate bkmem_free((char *)dhcp_rcv_bufp, dhcp_buf_size); 1175*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1176*7c478bd9Sstevel@tonic-gate return (-1); 1177*7c478bd9Sstevel@tonic-gate } 1178*7c478bd9Sstevel@tonic-gate 1179*7c478bd9Sstevel@tonic-gate while (err == 0 && !done) { 1180*7c478bd9Sstevel@tonic-gate switch (dhcp_state) { 1181*7c478bd9Sstevel@tonic-gate case INIT: 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate s_n = "INIT"; 1184*7c478bd9Sstevel@tonic-gate if (prom_cached_reply(B_FALSE)) { 1185*7c478bd9Sstevel@tonic-gate dprintf("%s: Using PROM cached BOOT reply...\n", 1186*7c478bd9Sstevel@tonic-gate s_n); 1187*7c478bd9Sstevel@tonic-gate dhcp_state = BOUND; 1188*7c478bd9Sstevel@tonic-gate } else { 1189*7c478bd9Sstevel@tonic-gate dhcp_state = SELECTING; 1190*7c478bd9Sstevel@tonic-gate dhcp_start_time = prom_gettime(); 1191*7c478bd9Sstevel@tonic-gate } 1192*7c478bd9Sstevel@tonic-gate break; 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate case SELECTING: 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate s_n = "SELECTING"; 1197*7c478bd9Sstevel@tonic-gate err = dhcp_selecting(); 1198*7c478bd9Sstevel@tonic-gate switch (err) { 1199*7c478bd9Sstevel@tonic-gate case 0: 1200*7c478bd9Sstevel@tonic-gate dhcp_state = REQUESTING; 1201*7c478bd9Sstevel@tonic-gate break; 1202*7c478bd9Sstevel@tonic-gate case DHCP_NO_DATA: 1203*7c478bd9Sstevel@tonic-gate dprintf( 1204*7c478bd9Sstevel@tonic-gate "%s: No DHCP response after %d tries.\n", 1205*7c478bd9Sstevel@tonic-gate s_n, DHCP_RETRIES); 1206*7c478bd9Sstevel@tonic-gate break; 1207*7c478bd9Sstevel@tonic-gate default: 1208*7c478bd9Sstevel@tonic-gate /* major network problems */ 1209*7c478bd9Sstevel@tonic-gate dprintf("%s: Network transaction failed: %d\n", 1210*7c478bd9Sstevel@tonic-gate s_n, err); 1211*7c478bd9Sstevel@tonic-gate break; 1212*7c478bd9Sstevel@tonic-gate } 1213*7c478bd9Sstevel@tonic-gate break; 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate case REQUESTING: 1216*7c478bd9Sstevel@tonic-gate 1217*7c478bd9Sstevel@tonic-gate s_n = "REQUESTING"; 1218*7c478bd9Sstevel@tonic-gate err = dhcp_requesting(); 1219*7c478bd9Sstevel@tonic-gate switch (err) { 1220*7c478bd9Sstevel@tonic-gate case 0: 1221*7c478bd9Sstevel@tonic-gate dhcp_state = BOUND; 1222*7c478bd9Sstevel@tonic-gate break; 1223*7c478bd9Sstevel@tonic-gate case DHCP_NO_DATA: 1224*7c478bd9Sstevel@tonic-gate dprintf("%s: Request timed out.\n", s_n); 1225*7c478bd9Sstevel@tonic-gate dhcp_state = SELECTING; 1226*7c478bd9Sstevel@tonic-gate err = 0; 1227*7c478bd9Sstevel@tonic-gate (void) sleep(10); 1228*7c478bd9Sstevel@tonic-gate break; 1229*7c478bd9Sstevel@tonic-gate default: 1230*7c478bd9Sstevel@tonic-gate /* major network problems */ 1231*7c478bd9Sstevel@tonic-gate dprintf("%s: Network transaction failed: %d\n", 1232*7c478bd9Sstevel@tonic-gate s_n, err); 1233*7c478bd9Sstevel@tonic-gate break; 1234*7c478bd9Sstevel@tonic-gate } 1235*7c478bd9Sstevel@tonic-gate break; 1236*7c478bd9Sstevel@tonic-gate 1237*7c478bd9Sstevel@tonic-gate case BOUND: 1238*7c478bd9Sstevel@tonic-gate 1239*7c478bd9Sstevel@tonic-gate /* 1240*7c478bd9Sstevel@tonic-gate * We just "give up" if bound state fails. 1241*7c478bd9Sstevel@tonic-gate */ 1242*7c478bd9Sstevel@tonic-gate s_n = "BOUND"; 1243*7c478bd9Sstevel@tonic-gate if ((err = dhcp_bound()) == 0) { 1244*7c478bd9Sstevel@tonic-gate dhcp_state = CONFIGURED; 1245*7c478bd9Sstevel@tonic-gate } 1246*7c478bd9Sstevel@tonic-gate break; 1247*7c478bd9Sstevel@tonic-gate 1248*7c478bd9Sstevel@tonic-gate case CONFIGURED: 1249*7c478bd9Sstevel@tonic-gate s_n = "CONFIGURED"; 1250*7c478bd9Sstevel@tonic-gate create_bootpresponse_bprop(state_pl); 1251*7c478bd9Sstevel@tonic-gate done = B_TRUE; 1252*7c478bd9Sstevel@tonic-gate break; 1253*7c478bd9Sstevel@tonic-gate } 1254*7c478bd9Sstevel@tonic-gate } 1255*7c478bd9Sstevel@tonic-gate bkmem_free((char *)dhcp_snd_bufp, dhcp_buf_size); 1256*7c478bd9Sstevel@tonic-gate bkmem_free((char *)dhcp_rcv_bufp, dhcp_buf_size); 1257*7c478bd9Sstevel@tonic-gate 1258*7c478bd9Sstevel@tonic-gate return (err); 1259*7c478bd9Sstevel@tonic-gate } 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate /* 1262*7c478bd9Sstevel@tonic-gate * Returns a copy of the DHCP-supplied value of the parameter requested 1263*7c478bd9Sstevel@tonic-gate * by code. 1264*7c478bd9Sstevel@tonic-gate */ 1265*7c478bd9Sstevel@tonic-gate boolean_t 1266*7c478bd9Sstevel@tonic-gate dhcp_getinfo(uchar_t optcat, uint16_t code, uint16_t optsize, void *value, 1267*7c478bd9Sstevel@tonic-gate size_t *vallenp) 1268*7c478bd9Sstevel@tonic-gate { 1269*7c478bd9Sstevel@tonic-gate size_t len = *vallenp; 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate if (dhcp_getinfo_pl(state_pl, optcat, code, 1272*7c478bd9Sstevel@tonic-gate optsize, value, &len)) { 1273*7c478bd9Sstevel@tonic-gate 1274*7c478bd9Sstevel@tonic-gate if (len <= *vallenp) { 1275*7c478bd9Sstevel@tonic-gate *vallenp = len; 1276*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1277*7c478bd9Sstevel@tonic-gate } 1278*7c478bd9Sstevel@tonic-gate } 1279*7c478bd9Sstevel@tonic-gate 1280*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1281*7c478bd9Sstevel@tonic-gate } 1282*7c478bd9Sstevel@tonic-gate 1283*7c478bd9Sstevel@tonic-gate /* 1284*7c478bd9Sstevel@tonic-gate * Sets the clientid option. 1285*7c478bd9Sstevel@tonic-gate */ 1286*7c478bd9Sstevel@tonic-gate void 1287*7c478bd9Sstevel@tonic-gate dhcp_set_client_id(uint8_t *clientid, uint8_t clientid_len) 1288*7c478bd9Sstevel@tonic-gate { 1289*7c478bd9Sstevel@tonic-gate bcopy(clientid, dhcp_clientid, clientid_len); 1290*7c478bd9Sstevel@tonic-gate dhcp_clientid_len = clientid_len; 1291*7c478bd9Sstevel@tonic-gate } 1292