10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*2187Smeem * Common Development and Distribution License (the "License"). 6*2187Smeem * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*2187Smeem * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate * 250Sstevel@tonic-gate * BOUND state of the DHCP client state machine. 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/socket.h> 310Sstevel@tonic-gate #include <sys/types.h> 320Sstevel@tonic-gate #include <string.h> 330Sstevel@tonic-gate #include <netinet/in.h> 340Sstevel@tonic-gate #include <sys/sockio.h> 350Sstevel@tonic-gate #include <unistd.h> 360Sstevel@tonic-gate #include <time.h> 370Sstevel@tonic-gate #include <arpa/inet.h> 380Sstevel@tonic-gate #include <stdlib.h> 390Sstevel@tonic-gate #include <sys/sysmacros.h> 400Sstevel@tonic-gate #include <dhcp_hostconf.h> 410Sstevel@tonic-gate #include <dhcpmsg.h> 420Sstevel@tonic-gate #include <stdio.h> /* snprintf */ 430Sstevel@tonic-gate 440Sstevel@tonic-gate #include "defaults.h" 450Sstevel@tonic-gate #include "arp_check.h" 460Sstevel@tonic-gate #include "states.h" 470Sstevel@tonic-gate #include "packet.h" 480Sstevel@tonic-gate #include "util.h" 490Sstevel@tonic-gate #include "agent.h" 500Sstevel@tonic-gate #include "interface.h" 510Sstevel@tonic-gate #include "script_handler.h" 520Sstevel@tonic-gate 530Sstevel@tonic-gate #define IS_DHCP(plp) ((plp)->opts[CD_DHCP_TYPE] != NULL) 540Sstevel@tonic-gate 550Sstevel@tonic-gate static int configure_if(struct ifslist *); 560Sstevel@tonic-gate static int configure_timers(struct ifslist *); 570Sstevel@tonic-gate 580Sstevel@tonic-gate /* 590Sstevel@tonic-gate * bound_event_cb(): callback for script_start on the event EVENT_BOUND 600Sstevel@tonic-gate * 610Sstevel@tonic-gate * input: struct ifslist *: the interface configured 620Sstevel@tonic-gate * const char *: unused 630Sstevel@tonic-gate * output: int: always 1 640Sstevel@tonic-gate */ 650Sstevel@tonic-gate 660Sstevel@tonic-gate /* ARGSUSED */ 670Sstevel@tonic-gate static int 680Sstevel@tonic-gate bound_event_cb(struct ifslist *ifsp, const char *msg) 690Sstevel@tonic-gate { 700Sstevel@tonic-gate ipc_action_finish(ifsp, DHCP_IPC_SUCCESS); 710Sstevel@tonic-gate async_finish(ifsp); 720Sstevel@tonic-gate return (1); 730Sstevel@tonic-gate } 740Sstevel@tonic-gate 750Sstevel@tonic-gate /* 760Sstevel@tonic-gate * dhcp_bound(): configures an interface and ifs using information contained 770Sstevel@tonic-gate * in the ACK packet and sets up lease timers. before starting, 780Sstevel@tonic-gate * the requested address is arped to make sure it's not in use. 790Sstevel@tonic-gate * 800Sstevel@tonic-gate * input: struct ifslist *: the interface to move to bound 810Sstevel@tonic-gate * PKT_LIST *: the ACK packet, or NULL if it should use ifsp->if_ack 820Sstevel@tonic-gate * output: int: 0 on failure, 1 on success 830Sstevel@tonic-gate */ 840Sstevel@tonic-gate 850Sstevel@tonic-gate int 860Sstevel@tonic-gate dhcp_bound(struct ifslist *ifsp, PKT_LIST *ack) 870Sstevel@tonic-gate { 880Sstevel@tonic-gate lease_t cur_lease, new_lease; 890Sstevel@tonic-gate int msg_level; 90*2187Smeem const char *noext = "lease renewed but time not extended"; 91*2187Smeem uint_t minleft; 920Sstevel@tonic-gate 930Sstevel@tonic-gate if (ack != NULL) { 940Sstevel@tonic-gate /* If ack we're replacing is not the original, then free it */ 950Sstevel@tonic-gate if (ifsp->if_ack != ifsp->if_orig_ack) 960Sstevel@tonic-gate free_pkt_list(&ifsp->if_ack); 970Sstevel@tonic-gate ifsp->if_ack = ack; 980Sstevel@tonic-gate /* Save the first ack as the original */ 990Sstevel@tonic-gate if (ifsp->if_orig_ack == NULL) 1000Sstevel@tonic-gate ifsp->if_orig_ack = ack; 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate switch (ifsp->if_state) { 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate case ADOPTING: 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate /* 1080Sstevel@tonic-gate * if we're adopting an interface, the lease timers 1090Sstevel@tonic-gate * only provide an upper bound since we don't know 1100Sstevel@tonic-gate * from what time they are relative to. assume we 1110Sstevel@tonic-gate * have a lease time of at most DHCP_ADOPT_LEASE_MAX. 1120Sstevel@tonic-gate */ 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate if (!IS_DHCP(ifsp->if_ack)) 1150Sstevel@tonic-gate return (0); 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate (void) memcpy(&new_lease, 1180Sstevel@tonic-gate ifsp->if_ack->opts[CD_LEASE_TIME]->value, sizeof (lease_t)); 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate new_lease = htonl(MIN(ntohl(new_lease), DHCP_ADOPT_LEASE_MAX)); 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate (void) memcpy(ifsp->if_ack->opts[CD_LEASE_TIME]->value, 1230Sstevel@tonic-gate &new_lease, sizeof (lease_t)); 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate /* 1260Sstevel@tonic-gate * we have no idea when the REQUEST that generated 1270Sstevel@tonic-gate * this ACK was sent, but for diagnostic purposes 1280Sstevel@tonic-gate * we'll assume its close to the current time. 1290Sstevel@tonic-gate */ 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate ifsp->if_newstart_monosec = monosec(); 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate /* FALLTHRU into REQUESTING/INIT_REBOOT */ 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate case REQUESTING: 1360Sstevel@tonic-gate case INIT_REBOOT: 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate if (configure_if(ifsp) == 0) 1390Sstevel@tonic-gate return (0); 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate if (configure_timers(ifsp) == 0) 1420Sstevel@tonic-gate return (0); 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate /* 1450Sstevel@tonic-gate * if the state is ADOPTING, event loop has not been started 146*2187Smeem * at this time, so don't run the script. 1470Sstevel@tonic-gate */ 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate if (ifsp->if_state != ADOPTING) { 1500Sstevel@tonic-gate (void) script_start(ifsp, EVENT_BOUND, bound_event_cb, 1510Sstevel@tonic-gate NULL, NULL); 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate break; 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate case RENEWING: 1570Sstevel@tonic-gate case REBINDING: 1580Sstevel@tonic-gate case BOUND: 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate cur_lease = ifsp->if_lease; 1610Sstevel@tonic-gate if (configure_timers(ifsp) == 0) 1620Sstevel@tonic-gate return (0); 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate /* 165*2187Smeem * if the current lease is mysteriously close to the new 166*2187Smeem * lease, warn the user. unless there's less than a minute 167*2187Smeem * left, round to the closest minute. 1680Sstevel@tonic-gate */ 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate if (abs((ifsp->if_newstart_monosec + ifsp->if_lease) - 1710Sstevel@tonic-gate (ifsp->if_curstart_monosec + cur_lease)) < DHCP_LEASE_EPS) { 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate if (ifsp->if_lease < DHCP_LEASE_ERROR_THRESH) 1740Sstevel@tonic-gate msg_level = MSG_ERROR; 1750Sstevel@tonic-gate else 1760Sstevel@tonic-gate msg_level = MSG_VERBOSE; 1770Sstevel@tonic-gate 178*2187Smeem minleft = (ifsp->if_lease + 30) / 60; 179*2187Smeem 180*2187Smeem if (ifsp->if_lease < 60) { 181*2187Smeem dhcpmsg(msg_level, "%s; expires in %d seconds", 182*2187Smeem noext, ifsp->if_lease); 183*2187Smeem } else if (minleft == 1) { 184*2187Smeem dhcpmsg(msg_level, "%s; expires in 1 minute", 185*2187Smeem noext); 186*2187Smeem } else { 187*2187Smeem dhcpmsg(msg_level, "%s; expires in %d minutes", 188*2187Smeem noext, minleft); 189*2187Smeem } 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate (void) script_start(ifsp, EVENT_EXTEND, bound_event_cb, 1930Sstevel@tonic-gate NULL, NULL); 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate break; 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate case INFORM_SENT: 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate (void) bound_event_cb(ifsp, NULL); 2000Sstevel@tonic-gate ifsp->if_state = INFORMATION; 2010Sstevel@tonic-gate break; 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate default: 2040Sstevel@tonic-gate /* something is really bizarre... */ 2050Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "dhcp_bound: called in unexpected state"); 2060Sstevel@tonic-gate return (0); 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate if (ifsp->if_state != INFORMATION) { 2100Sstevel@tonic-gate ifsp->if_state = BOUND; 2110Sstevel@tonic-gate ifsp->if_curstart_monosec = ifsp->if_newstart_monosec; 2120Sstevel@tonic-gate } 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate /* 2150Sstevel@tonic-gate * remove any stale hostconf file that might be lying around for 2160Sstevel@tonic-gate * this interface. (in general, it's harmless, since we'll write a 2170Sstevel@tonic-gate * fresh one when we exit anyway, but just to reduce confusion..) 2180Sstevel@tonic-gate */ 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate (void) remove_hostconf(ifsp->if_name); 2210Sstevel@tonic-gate return (1); 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* 2250Sstevel@tonic-gate * configure_timers(): configures the lease timers on an interface 2260Sstevel@tonic-gate * 2270Sstevel@tonic-gate * input: struct ifslist *: the interface to configure (with a valid if_ack) 2280Sstevel@tonic-gate * output: int: 1 on success, 0 on failure 2290Sstevel@tonic-gate */ 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate int 2320Sstevel@tonic-gate configure_timers(struct ifslist *ifsp) 2330Sstevel@tonic-gate { 2340Sstevel@tonic-gate lease_t lease, t1, t2; 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate if (ifsp->if_ack->opts[CD_DHCP_TYPE] != NULL && 2370Sstevel@tonic-gate (ifsp->if_ack->opts[CD_LEASE_TIME] == NULL || 2380Sstevel@tonic-gate ifsp->if_ack->opts[CD_LEASE_TIME]->len != sizeof (lease_t))) { 2390Sstevel@tonic-gate send_decline(ifsp, "Missing or corrupted lease time", 2400Sstevel@tonic-gate &ifsp->if_ack->pkt->yiaddr); 2410Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "configure_timers: missing or corrupted " 2420Sstevel@tonic-gate "lease time in ACK on %s", ifsp->if_name); 2430Sstevel@tonic-gate return (0); 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate cancel_ifs_timers(ifsp); 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate /* 2490Sstevel@tonic-gate * type has already been verified as ACK. if type is not set, 2500Sstevel@tonic-gate * then we got a BOOTP packet. we now fetch the t1, t2, and 2510Sstevel@tonic-gate * lease options out of the packet into variables. they are 2520Sstevel@tonic-gate * returned as relative host-byte-ordered times. 2530Sstevel@tonic-gate */ 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate get_pkt_times(ifsp->if_ack, &lease, &t1, &t2); 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate ifsp->if_t1 = t1; 2580Sstevel@tonic-gate ifsp->if_t2 = t2; 2590Sstevel@tonic-gate ifsp->if_lease = lease; 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate if (ifsp->if_lease == DHCP_PERM) { 2620Sstevel@tonic-gate dhcpmsg(MSG_INFO, "%s acquired permanent lease", ifsp->if_name); 2630Sstevel@tonic-gate return (1); 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate dhcpmsg(MSG_INFO, "%s acquired lease, expires %s", ifsp->if_name, 2670Sstevel@tonic-gate monosec_to_string(ifsp->if_newstart_monosec + ifsp->if_lease)); 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate dhcpmsg(MSG_INFO, "%s begins renewal at %s", ifsp->if_name, 2700Sstevel@tonic-gate monosec_to_string(ifsp->if_newstart_monosec + ifsp->if_t1)); 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate dhcpmsg(MSG_INFO, "%s begins rebinding at %s", ifsp->if_name, 2730Sstevel@tonic-gate monosec_to_string(ifsp->if_newstart_monosec + ifsp->if_t2)); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate /* 2760Sstevel@tonic-gate * according to RFC2131, there is no minimum lease time, but don't 2770Sstevel@tonic-gate * set up renew/rebind timers if lease is shorter than DHCP_REBIND_MIN. 2780Sstevel@tonic-gate */ 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate if (schedule_ifs_timer(ifsp, DHCP_LEASE_TIMER, lease, dhcp_expire) == 0) 2810Sstevel@tonic-gate goto failure; 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate if (lease < DHCP_REBIND_MIN) { 2840Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "dhcp_bound: lease on %s is for " 2850Sstevel@tonic-gate "less than %d seconds!", ifsp->if_name, DHCP_REBIND_MIN); 2860Sstevel@tonic-gate return (1); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate if (schedule_ifs_timer(ifsp, DHCP_T1_TIMER, t1, dhcp_renew) == 0) 2900Sstevel@tonic-gate goto failure; 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate if (schedule_ifs_timer(ifsp, DHCP_T2_TIMER, t2, dhcp_rebind) == 0) 2930Sstevel@tonic-gate goto failure; 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate return (1); 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate failure: 2980Sstevel@tonic-gate cancel_ifs_timers(ifsp); 2990Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "dhcp_bound: cannot schedule lease timers"); 3000Sstevel@tonic-gate return (0); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate /* 3040Sstevel@tonic-gate * configure_if(): configures an interface with DHCP parameters from an ACK 3050Sstevel@tonic-gate * 3060Sstevel@tonic-gate * input: struct ifslist *: the interface to configure (with a valid if_ack) 3070Sstevel@tonic-gate * output: int: 1 on success, 0 on failure 3080Sstevel@tonic-gate */ 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate static int 3110Sstevel@tonic-gate configure_if(struct ifslist *ifsp) 3120Sstevel@tonic-gate { 3130Sstevel@tonic-gate struct ifreq ifr; 3140Sstevel@tonic-gate struct sockaddr_in *sin; 3150Sstevel@tonic-gate PKT_LIST *ack = ifsp->if_ack; 3160Sstevel@tonic-gate DHCP_OPT *router_list; 3170Sstevel@tonic-gate uchar_t *target_hwaddr; 3180Sstevel@tonic-gate int i; 3190Sstevel@tonic-gate char in_use[256] = "IP address already in use by"; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate /* 3220Sstevel@tonic-gate * if we're using DHCP, then we'll have a valid CD_SERVER_ID 3230Sstevel@tonic-gate * (we checked in dhcp_acknak()); set it now so that 3240Sstevel@tonic-gate * ifsp->if_server is valid in case we need to send_decline(). 3250Sstevel@tonic-gate * note that we use comparisons against opts[CD_DHCP_TYPE] 3260Sstevel@tonic-gate * since we haven't set DHCP_IF_BOOTP yet (we don't do that 3270Sstevel@tonic-gate * until we're sure we want the offered address.) 3280Sstevel@tonic-gate */ 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate if (ifsp->if_ack->opts[CD_DHCP_TYPE] != NULL) 3310Sstevel@tonic-gate (void) memcpy(&ifsp->if_server.s_addr, 3320Sstevel@tonic-gate ack->opts[CD_SERVER_ID]->value, sizeof (ipaddr_t)); 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate /* no big deal if this fails; we'll just have less diagnostics */ 3350Sstevel@tonic-gate target_hwaddr = malloc(ifsp->if_hwlen); 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate if (arp_check(ifsp, 0, ack->pkt->yiaddr.s_addr, target_hwaddr, 3380Sstevel@tonic-gate ifsp->if_hwlen, df_get_int(ifsp->if_name, DF_ARP_WAIT)) == 1) { 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate for (i = 0; i < ifsp->if_hwlen; i++) 3410Sstevel@tonic-gate (void) snprintf(in_use, sizeof (in_use), "%s %02x", 3420Sstevel@tonic-gate in_use, target_hwaddr[i]); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate dhcpmsg(MSG_ERROR, in_use); 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate if (ifsp->if_ack->opts[CD_DHCP_TYPE] != NULL) 3470Sstevel@tonic-gate send_decline(ifsp, in_use, &ack->pkt->yiaddr); 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate ifsp->if_bad_offers++; 3500Sstevel@tonic-gate free(target_hwaddr); 3510Sstevel@tonic-gate return (0); 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate free(target_hwaddr); 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate ifsp->if_addr.s_addr = ack->pkt->yiaddr.s_addr; 3560Sstevel@tonic-gate if (ifsp->if_addr.s_addr == htonl(INADDR_ANY)) { 3570Sstevel@tonic-gate dhcpmsg(MSG_ERROR, "configure_if: got invalid IP address"); 3580Sstevel@tonic-gate return (0); 3590Sstevel@tonic-gate } 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate (void) memset(&ifr, 0, sizeof (struct ifreq)); 3620Sstevel@tonic-gate (void) strlcpy(ifr.ifr_name, ifsp->if_name, IFNAMSIZ); 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate /* 3650Sstevel@tonic-gate * bring the interface online. note that there is no optimal 3660Sstevel@tonic-gate * order here: it is considered bad taste (and in > solaris 7, 3670Sstevel@tonic-gate * likely illegal) to bring an interface up before it has an 3680Sstevel@tonic-gate * ip address. however, due to an apparent bug in sun fddi 3690Sstevel@tonic-gate * 5.0, fddi will not obtain a network routing entry unless 3700Sstevel@tonic-gate * the interface is brought up before it has an ip address. 3710Sstevel@tonic-gate * we take the lesser of the two evils; if fddi customers have 3720Sstevel@tonic-gate * problems, they can get a newer fddi distribution which 3730Sstevel@tonic-gate * fixes the problem. 3740Sstevel@tonic-gate */ 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate /* LINTED [ifr_addr is a sockaddr which will be aligned] */ 3770Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr.ifr_addr; 3780Sstevel@tonic-gate sin->sin_family = AF_INET; 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate if (ack->opts[CD_SUBNETMASK] != NULL && 3810Sstevel@tonic-gate ack->opts[CD_SUBNETMASK]->len == sizeof (ipaddr_t)) { 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate (void) memcpy(&ifsp->if_netmask.s_addr, 3840Sstevel@tonic-gate ack->opts[CD_SUBNETMASK]->value, sizeof (ipaddr_t)); 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate } else { 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate if (ack->opts[CD_SUBNETMASK] != NULL && 3890Sstevel@tonic-gate ack->opts[CD_SUBNETMASK]->len != sizeof (ipaddr_t)) 3900Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "configure_if: specified subnet " 3910Sstevel@tonic-gate "mask length is %d instead of %d, ignoring", 3920Sstevel@tonic-gate ack->opts[CD_SUBNETMASK]->len, sizeof (ipaddr_t)); 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate /* 3950Sstevel@tonic-gate * no legitimate IP subnet mask specified.. use best 3960Sstevel@tonic-gate * guess. recall that if_addr is in network order, so 3970Sstevel@tonic-gate * imagine it's 0x11223344: then when it is read into 3980Sstevel@tonic-gate * a register on x86, it becomes 0x44332211, so we 3990Sstevel@tonic-gate * must ntohl() it to convert it to 0x11223344 in 4000Sstevel@tonic-gate * order to use the macros in <netinet/in.h>. 4010Sstevel@tonic-gate */ 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate if (IN_CLASSA(ntohl(ifsp->if_addr.s_addr))) 4040Sstevel@tonic-gate ifsp->if_netmask.s_addr = htonl(IN_CLASSA_NET); 4050Sstevel@tonic-gate else if (IN_CLASSB(ntohl(ifsp->if_addr.s_addr))) 4060Sstevel@tonic-gate ifsp->if_netmask.s_addr = htonl(IN_CLASSB_NET); 4070Sstevel@tonic-gate else if (IN_CLASSC(ntohl(ifsp->if_addr.s_addr))) 4080Sstevel@tonic-gate ifsp->if_netmask.s_addr = htonl(IN_CLASSC_NET); 4090Sstevel@tonic-gate else /* must be class d */ 4100Sstevel@tonic-gate ifsp->if_netmask.s_addr = htonl(IN_CLASSD_NET); 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "configure_if: no IP netmask specified " 4130Sstevel@tonic-gate "for %s, making best guess", ifsp->if_name); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate dhcpmsg(MSG_INFO, "setting IP netmask to %s on %s", 4170Sstevel@tonic-gate inet_ntoa(ifsp->if_netmask), ifsp->if_name); 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate sin->sin_addr = ifsp->if_netmask; 4200Sstevel@tonic-gate if (ioctl(ifsp->if_sock_fd, SIOCSIFNETMASK, &ifr) == -1) { 4210Sstevel@tonic-gate dhcpmsg(MSG_ERR, "cannot set IP netmask on %s", ifsp->if_name); 4220Sstevel@tonic-gate return (0); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate dhcpmsg(MSG_INFO, "setting IP address to %s on %s", 4260Sstevel@tonic-gate inet_ntoa(ifsp->if_addr), ifsp->if_name); 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate sin->sin_addr = ifsp->if_addr; 4290Sstevel@tonic-gate if (ioctl(ifsp->if_sock_fd, SIOCSIFADDR, &ifr) == -1) { 4300Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot set IP address on %s", 4310Sstevel@tonic-gate ifsp->if_name); 4320Sstevel@tonic-gate return (0); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate if (ack->opts[CD_BROADCASTADDR] != NULL && 4360Sstevel@tonic-gate ack->opts[CD_BROADCASTADDR]->len == sizeof (ipaddr_t)) { 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate (void) memcpy(&ifsp->if_broadcast.s_addr, 4390Sstevel@tonic-gate ack->opts[CD_BROADCASTADDR]->value, sizeof (ipaddr_t)); 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate } else { 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate if (ack->opts[CD_BROADCASTADDR] != NULL && 4440Sstevel@tonic-gate ack->opts[CD_BROADCASTADDR]->len != sizeof (ipaddr_t)) 4450Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "configure_if: specified " 4460Sstevel@tonic-gate "broadcast address length is %d instead of %d, " 4470Sstevel@tonic-gate "ignoring", ack->opts[CD_BROADCASTADDR]->len, 4480Sstevel@tonic-gate sizeof (ipaddr_t)); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate /* 4510Sstevel@tonic-gate * no legitimate IP broadcast specified. compute it 4520Sstevel@tonic-gate * from the IP address and netmask. 4530Sstevel@tonic-gate */ 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate ifsp->if_broadcast.s_addr = ifsp->if_addr.s_addr & 4560Sstevel@tonic-gate ifsp->if_netmask.s_addr | ~ifsp->if_netmask.s_addr; 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "configure_if: no IP broadcast specified " 4590Sstevel@tonic-gate "for %s, making best guess", ifsp->if_name); 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate if (ioctl(ifsp->if_sock_fd, SIOCGIFFLAGS, &ifr) == -1) { 4630Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot get interface flags for " 4640Sstevel@tonic-gate "%s", ifsp->if_name); 4650Sstevel@tonic-gate return (0); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate ifr.ifr_flags |= IFF_UP; 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate if (ioctl(ifsp->if_sock_fd, SIOCSIFFLAGS, &ifr) == -1) { 4710Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot set interface flags for " 4720Sstevel@tonic-gate "%s", ifsp->if_name); 4730Sstevel@tonic-gate return (0); 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate /* 4770Sstevel@tonic-gate * the kernel will set the broadcast address for us as part of 4780Sstevel@tonic-gate * bringing the interface up. since experience has shown that dhcp 4790Sstevel@tonic-gate * servers sometimes provide a bogus broadcast address, we let the 4800Sstevel@tonic-gate * kernel set it so that it's guaranteed to be correct. 4810Sstevel@tonic-gate * 4820Sstevel@tonic-gate * also, note any inconsistencies and save the broadcast address the 4830Sstevel@tonic-gate * kernel set so that we can watch for changes to it. 4840Sstevel@tonic-gate */ 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate if (ioctl(ifsp->if_sock_fd, SIOCGIFBRDADDR, &ifr) == -1) { 4870Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot get broadcast address " 4880Sstevel@tonic-gate "for %s", ifsp->if_name); 4890Sstevel@tonic-gate return (0); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate if (ifsp->if_broadcast.s_addr != sin->sin_addr.s_addr) { 4930Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "incorrect broadcast address %s specified " 4940Sstevel@tonic-gate "for %s; ignoring", inet_ntoa(ifsp->if_broadcast), 4950Sstevel@tonic-gate ifsp->if_name); 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate ifsp->if_broadcast = sin->sin_addr; 4990Sstevel@tonic-gate dhcpmsg(MSG_INFO, "using broadcast address %s on %s", 5000Sstevel@tonic-gate inet_ntoa(ifsp->if_broadcast), ifsp->if_name); 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate /* 5030Sstevel@tonic-gate * add each provided router; we'll clean them up when the 5040Sstevel@tonic-gate * interface goes away or when our lease expires. 5050Sstevel@tonic-gate */ 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate router_list = ack->opts[CD_ROUTER]; 5080Sstevel@tonic-gate if (router_list && (router_list->len % sizeof (ipaddr_t)) == 0) { 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate ifsp->if_nrouters = router_list->len / sizeof (ipaddr_t); 5110Sstevel@tonic-gate ifsp->if_routers = malloc(router_list->len); 5120Sstevel@tonic-gate if (ifsp->if_routers == NULL) { 5130Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot allocate " 5140Sstevel@tonic-gate "default router list, ignoring default routers"); 5150Sstevel@tonic-gate ifsp->if_nrouters = 0; 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate for (i = 0; i < ifsp->if_nrouters; i++) { 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate (void) memcpy(&ifsp->if_routers[i].s_addr, 5210Sstevel@tonic-gate router_list->value + (i * sizeof (ipaddr_t)), 5220Sstevel@tonic-gate sizeof (ipaddr_t)); 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate if (add_default_route(ifsp->if_name, 5250Sstevel@tonic-gate &ifsp->if_routers[i]) == 0) { 5260Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot add " 5270Sstevel@tonic-gate "default router %s on %s", inet_ntoa( 5280Sstevel@tonic-gate ifsp->if_routers[i]), ifsp->if_name); 5290Sstevel@tonic-gate ifsp->if_routers[i].s_addr = htonl(INADDR_ANY); 5300Sstevel@tonic-gate continue; 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate dhcpmsg(MSG_INFO, "added default router %s on %s", 5340Sstevel@tonic-gate inet_ntoa(ifsp->if_routers[i]), ifsp->if_name); 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate ifsp->if_sock_ip_fd = socket(AF_INET, SOCK_DGRAM, 0); 5390Sstevel@tonic-gate if (ifsp->if_sock_ip_fd == -1) { 5400Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot create socket on %s", 5410Sstevel@tonic-gate ifsp->if_name); 5420Sstevel@tonic-gate return (0); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate if (bind_sock(ifsp->if_sock_ip_fd, IPPORT_BOOTPC, 5460Sstevel@tonic-gate ntohl(ifsp->if_addr.s_addr)) == 0) { 5470Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot bind socket on %s", 5480Sstevel@tonic-gate ifsp->if_name); 5490Sstevel@tonic-gate return (0); 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate /* 5530Sstevel@tonic-gate * we wait until here to bind if_sock_fd because it turns out 5540Sstevel@tonic-gate * the kernel has difficulties doing binds before interfaces 5550Sstevel@tonic-gate * are up (although it may work sometimes, it doesn't work all 5560Sstevel@tonic-gate * the time.) that's okay, because we don't use if_sock_fd 5570Sstevel@tonic-gate * for receiving data until we're BOUND anyway. 5580Sstevel@tonic-gate */ 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate if (bind_sock(ifsp->if_sock_fd, IPPORT_BOOTPC, INADDR_BROADCAST) == 0) { 5610Sstevel@tonic-gate dhcpmsg(MSG_ERR, "configure_if: cannot bind broadcast socket " 5620Sstevel@tonic-gate "on %s", ifsp->if_name); 5630Sstevel@tonic-gate return (0); 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* 5670Sstevel@tonic-gate * we'll be using if_sock_fd for the remainder of the lease; 5680Sstevel@tonic-gate * blackhole if_dlpi_fd. 5690Sstevel@tonic-gate */ 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate set_packet_filter(ifsp->if_dlpi_fd, blackhole_filter, 0, "blackhole"); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate if (ack->opts[CD_DHCP_TYPE] == NULL) 5740Sstevel@tonic-gate ifsp->if_dflags |= DHCP_IF_BOOTP; 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "configure_if: bound ifsp->if_sock_ip_fd"); 5770Sstevel@tonic-gate return (1); 5780Sstevel@tonic-gate } 579