1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate * 26*0Sstevel@tonic-gate * BOUND state of the DHCP client state machine. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #include <sys/socket.h> 32*0Sstevel@tonic-gate #include <sys/types.h> 33*0Sstevel@tonic-gate #include <string.h> 34*0Sstevel@tonic-gate #include <netinet/in.h> 35*0Sstevel@tonic-gate #include <sys/sockio.h> 36*0Sstevel@tonic-gate #include <unistd.h> 37*0Sstevel@tonic-gate #include <time.h> 38*0Sstevel@tonic-gate #include <arpa/inet.h> 39*0Sstevel@tonic-gate #include <stdlib.h> 40*0Sstevel@tonic-gate #include <sys/sysmacros.h> 41*0Sstevel@tonic-gate #include <dhcp_hostconf.h> 42*0Sstevel@tonic-gate #include <dhcpmsg.h> 43*0Sstevel@tonic-gate #include <stdio.h> /* snprintf */ 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate #include "defaults.h" 46*0Sstevel@tonic-gate #include "arp_check.h" 47*0Sstevel@tonic-gate #include "states.h" 48*0Sstevel@tonic-gate #include "packet.h" 49*0Sstevel@tonic-gate #include "util.h" 50*0Sstevel@tonic-gate #include "agent.h" 51*0Sstevel@tonic-gate #include "interface.h" 52*0Sstevel@tonic-gate #include "script_handler.h" 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate #define IS_DHCP(plp) ((plp)->opts[CD_DHCP_TYPE] != NULL) 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate static int configure_if(struct ifslist *); 57*0Sstevel@tonic-gate static int configure_timers(struct ifslist *); 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate /* 60*0Sstevel@tonic-gate * bound_event_cb(): callback for script_start on the event EVENT_BOUND 61*0Sstevel@tonic-gate * 62*0Sstevel@tonic-gate * input: struct ifslist *: the interface configured 63*0Sstevel@tonic-gate * const char *: unused 64*0Sstevel@tonic-gate * output: int: always 1 65*0Sstevel@tonic-gate */ 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate /* ARGSUSED */ 68*0Sstevel@tonic-gate static int 69*0Sstevel@tonic-gate bound_event_cb(struct ifslist *ifsp, const char *msg) 70*0Sstevel@tonic-gate { 71*0Sstevel@tonic-gate ipc_action_finish(ifsp, DHCP_IPC_SUCCESS); 72*0Sstevel@tonic-gate async_finish(ifsp); 73*0Sstevel@tonic-gate return (1); 74*0Sstevel@tonic-gate } 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* 77*0Sstevel@tonic-gate * dhcp_bound(): configures an interface and ifs using information contained 78*0Sstevel@tonic-gate * in the ACK packet and sets up lease timers. before starting, 79*0Sstevel@tonic-gate * the requested address is arped to make sure it's not in use. 80*0Sstevel@tonic-gate * 81*0Sstevel@tonic-gate * input: struct ifslist *: the interface to move to bound 82*0Sstevel@tonic-gate * PKT_LIST *: the ACK packet, or NULL if it should use ifsp->if_ack 83*0Sstevel@tonic-gate * output: int: 0 on failure, 1 on success 84*0Sstevel@tonic-gate */ 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate int 87*0Sstevel@tonic-gate dhcp_bound(struct ifslist *ifsp, PKT_LIST *ack) 88*0Sstevel@tonic-gate { 89*0Sstevel@tonic-gate lease_t cur_lease, new_lease; 90*0Sstevel@tonic-gate int msg_level; 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate if (ack != NULL) { 93*0Sstevel@tonic-gate /* If ack we're replacing is not the original, then free it */ 94*0Sstevel@tonic-gate if (ifsp->if_ack != ifsp->if_orig_ack) 95*0Sstevel@tonic-gate free_pkt_list(&ifsp->if_ack); 96*0Sstevel@tonic-gate ifsp->if_ack = ack; 97*0Sstevel@tonic-gate /* Save the first ack as the original */ 98*0Sstevel@tonic-gate if (ifsp->if_orig_ack == NULL) 99*0Sstevel@tonic-gate ifsp->if_orig_ack = ack; 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate switch (ifsp->if_state) { 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate case ADOPTING: 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate /* 107*0Sstevel@tonic-gate * if we're adopting an interface, the lease timers 108*0Sstevel@tonic-gate * only provide an upper bound since we don't know 109*0Sstevel@tonic-gate * from what time they are relative to. assume we 110*0Sstevel@tonic-gate * have a lease time of at most DHCP_ADOPT_LEASE_MAX. 111*0Sstevel@tonic-gate */ 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate if (!IS_DHCP(ifsp->if_ack)) 114*0Sstevel@tonic-gate return (0); 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate (void) memcpy(&new_lease, 117*0Sstevel@tonic-gate ifsp->if_ack->opts[CD_LEASE_TIME]->value, sizeof (lease_t)); 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate new_lease = htonl(MIN(ntohl(new_lease), DHCP_ADOPT_LEASE_MAX)); 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate (void) memcpy(ifsp->if_ack->opts[CD_LEASE_TIME]->value, 122*0Sstevel@tonic-gate &new_lease, sizeof (lease_t)); 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate /* 125*0Sstevel@tonic-gate * we have no idea when the REQUEST that generated 126*0Sstevel@tonic-gate * this ACK was sent, but for diagnostic purposes 127*0Sstevel@tonic-gate * we'll assume its close to the current time. 128*0Sstevel@tonic-gate */ 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate ifsp->if_newstart_monosec = monosec(); 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate /* FALLTHRU into REQUESTING/INIT_REBOOT */ 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate case REQUESTING: 135*0Sstevel@tonic-gate case INIT_REBOOT: 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate if (configure_if(ifsp) == 0) 138*0Sstevel@tonic-gate return (0); 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate if (configure_timers(ifsp) == 0) 141*0Sstevel@tonic-gate return (0); 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate /* 144*0Sstevel@tonic-gate * if the state is ADOPTING, event loop has not been started 145*0Sstevel@tonic-gate * at this time; so don''t run the script. 146*0Sstevel@tonic-gate */ 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate if (ifsp->if_state != ADOPTING) { 149*0Sstevel@tonic-gate (void) script_start(ifsp, EVENT_BOUND, bound_event_cb, 150*0Sstevel@tonic-gate NULL, NULL); 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate break; 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate case RENEWING: 156*0Sstevel@tonic-gate case REBINDING: 157*0Sstevel@tonic-gate case BOUND: 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate cur_lease = ifsp->if_lease; 160*0Sstevel@tonic-gate if (configure_timers(ifsp) == 0) 161*0Sstevel@tonic-gate return (0); 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate /* 164*0Sstevel@tonic-gate * if the current lease is mysteriously close 165*0Sstevel@tonic-gate * to the new lease, warn the user... 166*0Sstevel@tonic-gate */ 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate if (abs((ifsp->if_newstart_monosec + ifsp->if_lease) - 169*0Sstevel@tonic-gate (ifsp->if_curstart_monosec + cur_lease)) < DHCP_LEASE_EPS) { 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate if (ifsp->if_lease < DHCP_LEASE_ERROR_THRESH) 172*0Sstevel@tonic-gate msg_level = MSG_ERROR; 173*0Sstevel@tonic-gate else 174*0Sstevel@tonic-gate msg_level = MSG_VERBOSE; 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate dhcpmsg(msg_level, "lease renewed but lease time not " 177*0Sstevel@tonic-gate "extended (expires in %d seconds)", ifsp->if_lease); 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate (void) script_start(ifsp, EVENT_EXTEND, bound_event_cb, 182*0Sstevel@tonic-gate NULL, NULL); 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate break; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate case INFORM_SENT: 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate (void) bound_event_cb(ifsp, NULL); 189*0Sstevel@tonic-gate ifsp->if_state = INFORMATION; 190*0Sstevel@tonic-gate break; 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate default: 193*0Sstevel@tonic-gate /* something is really bizarre... */ 194*0Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "dhcp_bound: called in unexpected state"); 195*0Sstevel@tonic-gate return (0); 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate if (ifsp->if_state != INFORMATION) { 199*0Sstevel@tonic-gate ifsp->if_state = BOUND; 200*0Sstevel@tonic-gate ifsp->if_curstart_monosec = ifsp->if_newstart_monosec; 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate /* 204*0Sstevel@tonic-gate * remove any stale hostconf file that might be lying around for 205*0Sstevel@tonic-gate * this interface. (in general, it's harmless, since we'll write a 206*0Sstevel@tonic-gate * fresh one when we exit anyway, but just to reduce confusion..) 207*0Sstevel@tonic-gate */ 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate (void) remove_hostconf(ifsp->if_name); 210*0Sstevel@tonic-gate return (1); 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate /* 214*0Sstevel@tonic-gate * configure_timers(): configures the lease timers on an interface 215*0Sstevel@tonic-gate * 216*0Sstevel@tonic-gate * input: struct ifslist *: the interface to configure (with a valid if_ack) 217*0Sstevel@tonic-gate * output: int: 1 on success, 0 on failure 218*0Sstevel@tonic-gate */ 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate int 221*0Sstevel@tonic-gate configure_timers(struct ifslist *ifsp) 222*0Sstevel@tonic-gate { 223*0Sstevel@tonic-gate lease_t lease, t1, t2; 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate if (ifsp->if_ack->opts[CD_DHCP_TYPE] != NULL && 226*0Sstevel@tonic-gate (ifsp->if_ack->opts[CD_LEASE_TIME] == NULL || 227*0Sstevel@tonic-gate ifsp->if_ack->opts[CD_LEASE_TIME]->len != sizeof (lease_t))) { 228*0Sstevel@tonic-gate send_decline(ifsp, "Missing or corrupted lease time", 229*0Sstevel@tonic-gate &ifsp->if_ack->pkt->yiaddr); 230*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "configure_timers: missing or corrupted " 231*0Sstevel@tonic-gate "lease time in ACK on %s", ifsp->if_name); 232*0Sstevel@tonic-gate return (0); 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate cancel_ifs_timers(ifsp); 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate /* 238*0Sstevel@tonic-gate * type has already been verified as ACK. if type is not set, 239*0Sstevel@tonic-gate * then we got a BOOTP packet. we now fetch the t1, t2, and 240*0Sstevel@tonic-gate * lease options out of the packet into variables. they are 241*0Sstevel@tonic-gate * returned as relative host-byte-ordered times. 242*0Sstevel@tonic-gate */ 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate get_pkt_times(ifsp->if_ack, &lease, &t1, &t2); 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate ifsp->if_t1 = t1; 247*0Sstevel@tonic-gate ifsp->if_t2 = t2; 248*0Sstevel@tonic-gate ifsp->if_lease = lease; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate if (ifsp->if_lease == DHCP_PERM) { 251*0Sstevel@tonic-gate dhcpmsg(MSG_INFO, "%s acquired permanent lease", ifsp->if_name); 252*0Sstevel@tonic-gate return (1); 253*0Sstevel@tonic-gate } 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate dhcpmsg(MSG_INFO, "%s acquired lease, expires %s", ifsp->if_name, 256*0Sstevel@tonic-gate monosec_to_string(ifsp->if_newstart_monosec + ifsp->if_lease)); 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate dhcpmsg(MSG_INFO, "%s begins renewal at %s", ifsp->if_name, 259*0Sstevel@tonic-gate monosec_to_string(ifsp->if_newstart_monosec + ifsp->if_t1)); 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate dhcpmsg(MSG_INFO, "%s begins rebinding at %s", ifsp->if_name, 262*0Sstevel@tonic-gate monosec_to_string(ifsp->if_newstart_monosec + ifsp->if_t2)); 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate /* 265*0Sstevel@tonic-gate * according to RFC2131, there is no minimum lease time, but don't 266*0Sstevel@tonic-gate * set up renew/rebind timers if lease is shorter than DHCP_REBIND_MIN. 267*0Sstevel@tonic-gate */ 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate if (schedule_ifs_timer(ifsp, DHCP_LEASE_TIMER, lease, dhcp_expire) == 0) 270*0Sstevel@tonic-gate goto failure; 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate if (lease < DHCP_REBIND_MIN) { 273*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "dhcp_bound: lease on %s is for " 274*0Sstevel@tonic-gate "less than %d seconds!", ifsp->if_name, DHCP_REBIND_MIN); 275*0Sstevel@tonic-gate return (1); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate if (schedule_ifs_timer(ifsp, DHCP_T1_TIMER, t1, dhcp_renew) == 0) 279*0Sstevel@tonic-gate goto failure; 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate if (schedule_ifs_timer(ifsp, DHCP_T2_TIMER, t2, dhcp_rebind) == 0) 282*0Sstevel@tonic-gate goto failure; 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate return (1); 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate failure: 287*0Sstevel@tonic-gate cancel_ifs_timers(ifsp); 288*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "dhcp_bound: cannot schedule lease timers"); 289*0Sstevel@tonic-gate return (0); 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate /* 293*0Sstevel@tonic-gate * configure_if(): configures an interface with DHCP parameters from an ACK 294*0Sstevel@tonic-gate * 295*0Sstevel@tonic-gate * input: struct ifslist *: the interface to configure (with a valid if_ack) 296*0Sstevel@tonic-gate * output: int: 1 on success, 0 on failure 297*0Sstevel@tonic-gate */ 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate static int 300*0Sstevel@tonic-gate configure_if(struct ifslist *ifsp) 301*0Sstevel@tonic-gate { 302*0Sstevel@tonic-gate struct ifreq ifr; 303*0Sstevel@tonic-gate struct sockaddr_in *sin; 304*0Sstevel@tonic-gate PKT_LIST *ack = ifsp->if_ack; 305*0Sstevel@tonic-gate DHCP_OPT *router_list; 306*0Sstevel@tonic-gate uchar_t *target_hwaddr; 307*0Sstevel@tonic-gate int i; 308*0Sstevel@tonic-gate char in_use[256] = "IP address already in use by"; 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate /* 311*0Sstevel@tonic-gate * if we're using DHCP, then we'll have a valid CD_SERVER_ID 312*0Sstevel@tonic-gate * (we checked in dhcp_acknak()); set it now so that 313*0Sstevel@tonic-gate * ifsp->if_server is valid in case we need to send_decline(). 314*0Sstevel@tonic-gate * note that we use comparisons against opts[CD_DHCP_TYPE] 315*0Sstevel@tonic-gate * since we haven't set DHCP_IF_BOOTP yet (we don't do that 316*0Sstevel@tonic-gate * until we're sure we want the offered address.) 317*0Sstevel@tonic-gate */ 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate if (ifsp->if_ack->opts[CD_DHCP_TYPE] != NULL) 320*0Sstevel@tonic-gate (void) memcpy(&ifsp->if_server.s_addr, 321*0Sstevel@tonic-gate ack->opts[CD_SERVER_ID]->value, sizeof (ipaddr_t)); 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate /* no big deal if this fails; we'll just have less diagnostics */ 324*0Sstevel@tonic-gate target_hwaddr = malloc(ifsp->if_hwlen); 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate if (arp_check(ifsp, 0, ack->pkt->yiaddr.s_addr, target_hwaddr, 327*0Sstevel@tonic-gate ifsp->if_hwlen, df_get_int(ifsp->if_name, DF_ARP_WAIT)) == 1) { 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate for (i = 0; i < ifsp->if_hwlen; i++) 330*0Sstevel@tonic-gate (void) snprintf(in_use, sizeof (in_use), "%s %02x", 331*0Sstevel@tonic-gate in_use, target_hwaddr[i]); 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate dhcpmsg(MSG_ERROR, in_use); 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate if (ifsp->if_ack->opts[CD_DHCP_TYPE] != NULL) 336*0Sstevel@tonic-gate send_decline(ifsp, in_use, &ack->pkt->yiaddr); 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate ifsp->if_bad_offers++; 339*0Sstevel@tonic-gate free(target_hwaddr); 340*0Sstevel@tonic-gate return (0); 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate free(target_hwaddr); 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate ifsp->if_addr.s_addr = ack->pkt->yiaddr.s_addr; 345*0Sstevel@tonic-gate if (ifsp->if_addr.s_addr == htonl(INADDR_ANY)) { 346*0Sstevel@tonic-gate dhcpmsg(MSG_ERROR, "configure_if: got invalid IP address"); 347*0Sstevel@tonic-gate return (0); 348*0Sstevel@tonic-gate } 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate (void) memset(&ifr, 0, sizeof (struct ifreq)); 351*0Sstevel@tonic-gate (void) strlcpy(ifr.ifr_name, ifsp->if_name, IFNAMSIZ); 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate /* 354*0Sstevel@tonic-gate * bring the interface online. note that there is no optimal 355*0Sstevel@tonic-gate * order here: it is considered bad taste (and in > solaris 7, 356*0Sstevel@tonic-gate * likely illegal) to bring an interface up before it has an 357*0Sstevel@tonic-gate * ip address. however, due to an apparent bug in sun fddi 358*0Sstevel@tonic-gate * 5.0, fddi will not obtain a network routing entry unless 359*0Sstevel@tonic-gate * the interface is brought up before it has an ip address. 360*0Sstevel@tonic-gate * we take the lesser of the two evils; if fddi customers have 361*0Sstevel@tonic-gate * problems, they can get a newer fddi distribution which 362*0Sstevel@tonic-gate * fixes the problem. 363*0Sstevel@tonic-gate */ 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate /* LINTED [ifr_addr is a sockaddr which will be aligned] */ 366*0Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr.ifr_addr; 367*0Sstevel@tonic-gate sin->sin_family = AF_INET; 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate if (ack->opts[CD_SUBNETMASK] != NULL && 370*0Sstevel@tonic-gate ack->opts[CD_SUBNETMASK]->len == sizeof (ipaddr_t)) { 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate (void) memcpy(&ifsp->if_netmask.s_addr, 373*0Sstevel@tonic-gate ack->opts[CD_SUBNETMASK]->value, sizeof (ipaddr_t)); 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate } else { 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate if (ack->opts[CD_SUBNETMASK] != NULL && 378*0Sstevel@tonic-gate ack->opts[CD_SUBNETMASK]->len != sizeof (ipaddr_t)) 379*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "configure_if: specified subnet " 380*0Sstevel@tonic-gate "mask length is %d instead of %d, ignoring", 381*0Sstevel@tonic-gate ack->opts[CD_SUBNETMASK]->len, sizeof (ipaddr_t)); 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate /* 384*0Sstevel@tonic-gate * no legitimate IP subnet mask specified.. use best 385*0Sstevel@tonic-gate * guess. recall that if_addr is in network order, so 386*0Sstevel@tonic-gate * imagine it's 0x11223344: then when it is read into 387*0Sstevel@tonic-gate * a register on x86, it becomes 0x44332211, so we 388*0Sstevel@tonic-gate * must ntohl() it to convert it to 0x11223344 in 389*0Sstevel@tonic-gate * order to use the macros in <netinet/in.h>. 390*0Sstevel@tonic-gate */ 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate if (IN_CLASSA(ntohl(ifsp->if_addr.s_addr))) 393*0Sstevel@tonic-gate ifsp->if_netmask.s_addr = htonl(IN_CLASSA_NET); 394*0Sstevel@tonic-gate else if (IN_CLASSB(ntohl(ifsp->if_addr.s_addr))) 395*0Sstevel@tonic-gate ifsp->if_netmask.s_addr = htonl(IN_CLASSB_NET); 396*0Sstevel@tonic-gate else if (IN_CLASSC(ntohl(ifsp->if_addr.s_addr))) 397*0Sstevel@tonic-gate ifsp->if_netmask.s_addr = htonl(IN_CLASSC_NET); 398*0Sstevel@tonic-gate else /* must be class d */ 399*0Sstevel@tonic-gate ifsp->if_netmask.s_addr = htonl(IN_CLASSD_NET); 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "configure_if: no IP netmask specified " 402*0Sstevel@tonic-gate "for %s, making best guess", ifsp->if_name); 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate dhcpmsg(MSG_INFO, "setting IP netmask to %s on %s", 406*0Sstevel@tonic-gate inet_ntoa(ifsp->if_netmask), ifsp->if_name); 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate sin->sin_addr = ifsp->if_netmask; 409*0Sstevel@tonic-gate if (ioctl(ifsp->if_sock_fd, SIOCSIFNETMASK, &ifr) == -1) { 410*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "cannot set IP netmask on %s", ifsp->if_name); 411*0Sstevel@tonic-gate return (0); 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate dhcpmsg(MSG_INFO, "setting IP address to %s on %s", 415*0Sstevel@tonic-gate inet_ntoa(ifsp->if_addr), ifsp->if_name); 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate sin->sin_addr = ifsp->if_addr; 418*0Sstevel@tonic-gate if (ioctl(ifsp->if_sock_fd, SIOCSIFADDR, &ifr) == -1) { 419*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot set IP address on %s", 420*0Sstevel@tonic-gate ifsp->if_name); 421*0Sstevel@tonic-gate return (0); 422*0Sstevel@tonic-gate } 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate if (ack->opts[CD_BROADCASTADDR] != NULL && 425*0Sstevel@tonic-gate ack->opts[CD_BROADCASTADDR]->len == sizeof (ipaddr_t)) { 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate (void) memcpy(&ifsp->if_broadcast.s_addr, 428*0Sstevel@tonic-gate ack->opts[CD_BROADCASTADDR]->value, sizeof (ipaddr_t)); 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate } else { 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate if (ack->opts[CD_BROADCASTADDR] != NULL && 433*0Sstevel@tonic-gate ack->opts[CD_BROADCASTADDR]->len != sizeof (ipaddr_t)) 434*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "configure_if: specified " 435*0Sstevel@tonic-gate "broadcast address length is %d instead of %d, " 436*0Sstevel@tonic-gate "ignoring", ack->opts[CD_BROADCASTADDR]->len, 437*0Sstevel@tonic-gate sizeof (ipaddr_t)); 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate /* 440*0Sstevel@tonic-gate * no legitimate IP broadcast specified. compute it 441*0Sstevel@tonic-gate * from the IP address and netmask. 442*0Sstevel@tonic-gate */ 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate ifsp->if_broadcast.s_addr = ifsp->if_addr.s_addr & 445*0Sstevel@tonic-gate ifsp->if_netmask.s_addr | ~ifsp->if_netmask.s_addr; 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "configure_if: no IP broadcast specified " 448*0Sstevel@tonic-gate "for %s, making best guess", ifsp->if_name); 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate if (ioctl(ifsp->if_sock_fd, SIOCGIFFLAGS, &ifr) == -1) { 452*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot get interface flags for " 453*0Sstevel@tonic-gate "%s", ifsp->if_name); 454*0Sstevel@tonic-gate return (0); 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate ifr.ifr_flags |= IFF_UP; 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate if (ioctl(ifsp->if_sock_fd, SIOCSIFFLAGS, &ifr) == -1) { 460*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot set interface flags for " 461*0Sstevel@tonic-gate "%s", ifsp->if_name); 462*0Sstevel@tonic-gate return (0); 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate /* 466*0Sstevel@tonic-gate * the kernel will set the broadcast address for us as part of 467*0Sstevel@tonic-gate * bringing the interface up. since experience has shown that dhcp 468*0Sstevel@tonic-gate * servers sometimes provide a bogus broadcast address, we let the 469*0Sstevel@tonic-gate * kernel set it so that it's guaranteed to be correct. 470*0Sstevel@tonic-gate * 471*0Sstevel@tonic-gate * also, note any inconsistencies and save the broadcast address the 472*0Sstevel@tonic-gate * kernel set so that we can watch for changes to it. 473*0Sstevel@tonic-gate */ 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate if (ioctl(ifsp->if_sock_fd, SIOCGIFBRDADDR, &ifr) == -1) { 476*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot get broadcast address " 477*0Sstevel@tonic-gate "for %s", ifsp->if_name); 478*0Sstevel@tonic-gate return (0); 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate if (ifsp->if_broadcast.s_addr != sin->sin_addr.s_addr) { 482*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "incorrect broadcast address %s specified " 483*0Sstevel@tonic-gate "for %s; ignoring", inet_ntoa(ifsp->if_broadcast), 484*0Sstevel@tonic-gate ifsp->if_name); 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate ifsp->if_broadcast = sin->sin_addr; 488*0Sstevel@tonic-gate dhcpmsg(MSG_INFO, "using broadcast address %s on %s", 489*0Sstevel@tonic-gate inet_ntoa(ifsp->if_broadcast), ifsp->if_name); 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate /* 492*0Sstevel@tonic-gate * add each provided router; we'll clean them up when the 493*0Sstevel@tonic-gate * interface goes away or when our lease expires. 494*0Sstevel@tonic-gate */ 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate router_list = ack->opts[CD_ROUTER]; 497*0Sstevel@tonic-gate if (router_list && (router_list->len % sizeof (ipaddr_t)) == 0) { 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate ifsp->if_nrouters = router_list->len / sizeof (ipaddr_t); 500*0Sstevel@tonic-gate ifsp->if_routers = malloc(router_list->len); 501*0Sstevel@tonic-gate if (ifsp->if_routers == NULL) { 502*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot allocate " 503*0Sstevel@tonic-gate "default router list, ignoring default routers"); 504*0Sstevel@tonic-gate ifsp->if_nrouters = 0; 505*0Sstevel@tonic-gate } 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate for (i = 0; i < ifsp->if_nrouters; i++) { 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate (void) memcpy(&ifsp->if_routers[i].s_addr, 510*0Sstevel@tonic-gate router_list->value + (i * sizeof (ipaddr_t)), 511*0Sstevel@tonic-gate sizeof (ipaddr_t)); 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate if (add_default_route(ifsp->if_name, 514*0Sstevel@tonic-gate &ifsp->if_routers[i]) == 0) { 515*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot add " 516*0Sstevel@tonic-gate "default router %s on %s", inet_ntoa( 517*0Sstevel@tonic-gate ifsp->if_routers[i]), ifsp->if_name); 518*0Sstevel@tonic-gate ifsp->if_routers[i].s_addr = htonl(INADDR_ANY); 519*0Sstevel@tonic-gate continue; 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate dhcpmsg(MSG_INFO, "added default router %s on %s", 523*0Sstevel@tonic-gate inet_ntoa(ifsp->if_routers[i]), ifsp->if_name); 524*0Sstevel@tonic-gate } 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate ifsp->if_sock_ip_fd = socket(AF_INET, SOCK_DGRAM, 0); 528*0Sstevel@tonic-gate if (ifsp->if_sock_ip_fd == -1) { 529*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot create socket on %s", 530*0Sstevel@tonic-gate ifsp->if_name); 531*0Sstevel@tonic-gate return (0); 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate if (bind_sock(ifsp->if_sock_ip_fd, IPPORT_BOOTPC, 535*0Sstevel@tonic-gate ntohl(ifsp->if_addr.s_addr)) == 0) { 536*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot bind socket on %s", 537*0Sstevel@tonic-gate ifsp->if_name); 538*0Sstevel@tonic-gate return (0); 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate /* 542*0Sstevel@tonic-gate * we wait until here to bind if_sock_fd because it turns out 543*0Sstevel@tonic-gate * the kernel has difficulties doing binds before interfaces 544*0Sstevel@tonic-gate * are up (although it may work sometimes, it doesn't work all 545*0Sstevel@tonic-gate * the time.) that's okay, because we don't use if_sock_fd 546*0Sstevel@tonic-gate * for receiving data until we're BOUND anyway. 547*0Sstevel@tonic-gate */ 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate if (bind_sock(ifsp->if_sock_fd, IPPORT_BOOTPC, INADDR_BROADCAST) == 0) { 550*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot bind broadcast socket " 551*0Sstevel@tonic-gate "on %s", ifsp->if_name); 552*0Sstevel@tonic-gate return (0); 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate /* 556*0Sstevel@tonic-gate * we'll be using if_sock_fd for the remainder of the lease; 557*0Sstevel@tonic-gate * blackhole if_dlpi_fd. 558*0Sstevel@tonic-gate */ 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate set_packet_filter(ifsp->if_dlpi_fd, blackhole_filter, 0, "blackhole"); 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate if (ack->opts[CD_DHCP_TYPE] == NULL) 563*0Sstevel@tonic-gate ifsp->if_dflags |= DHCP_IF_BOOTP; 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "configure_if: bound ifsp->if_sock_ip_fd"); 566*0Sstevel@tonic-gate return (1); 567*0Sstevel@tonic-gate } 568