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*2612Scarlsonj * Common Development and Distribution License (the "License"). 6*2612Scarlsonj * 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*2612Scarlsonj * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate * 250Sstevel@tonic-gate * ADOPTING state of the 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/types.h> 310Sstevel@tonic-gate #include <string.h> 320Sstevel@tonic-gate #include <unistd.h> 330Sstevel@tonic-gate #include <stdlib.h> 34*2612Scarlsonj #include <signal.h> 350Sstevel@tonic-gate #include <sys/sockio.h> 360Sstevel@tonic-gate #include <sys/socket.h> 370Sstevel@tonic-gate #include <netinet/in.h> 380Sstevel@tonic-gate #include <sys/systeminfo.h> 390Sstevel@tonic-gate #include <netinet/inetutil.h> 400Sstevel@tonic-gate #include <netinet/dhcp.h> 410Sstevel@tonic-gate #include <dhcpmsg.h> 420Sstevel@tonic-gate 430Sstevel@tonic-gate #include "async.h" 440Sstevel@tonic-gate #include "util.h" 450Sstevel@tonic-gate #include "packet.h" 460Sstevel@tonic-gate #include "interface.h" 470Sstevel@tonic-gate #include "states.h" 480Sstevel@tonic-gate 490Sstevel@tonic-gate 500Sstevel@tonic-gate typedef struct { 510Sstevel@tonic-gate char dk_if_name[IFNAMSIZ]; 520Sstevel@tonic-gate char dk_ack[1]; 530Sstevel@tonic-gate } dhcp_kcache_t; 540Sstevel@tonic-gate 550Sstevel@tonic-gate static int get_dhcp_kcache(dhcp_kcache_t **, size_t *); 560Sstevel@tonic-gate 570Sstevel@tonic-gate /* 580Sstevel@tonic-gate * dhcp_adopt(): adopts the interface managed by the kernel for diskless boot 590Sstevel@tonic-gate * 600Sstevel@tonic-gate * input: void 610Sstevel@tonic-gate * output: int: nonzero on success, zero on failure 620Sstevel@tonic-gate */ 630Sstevel@tonic-gate 640Sstevel@tonic-gate int 650Sstevel@tonic-gate dhcp_adopt(void) 660Sstevel@tonic-gate { 670Sstevel@tonic-gate int retval; 680Sstevel@tonic-gate dhcp_kcache_t *kcache = NULL; 690Sstevel@tonic-gate size_t kcache_size; 700Sstevel@tonic-gate PKT_LIST *plp = NULL; 710Sstevel@tonic-gate struct ifslist *ifsp; 720Sstevel@tonic-gate 730Sstevel@tonic-gate retval = get_dhcp_kcache(&kcache, &kcache_size); 740Sstevel@tonic-gate if (retval == 0 || kcache_size < sizeof (dhcp_kcache_t)) { 750Sstevel@tonic-gate dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot fetch kernel cache"); 760Sstevel@tonic-gate goto failure; 770Sstevel@tonic-gate } 780Sstevel@tonic-gate 790Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "dhcp_adopt: fetched %s kcache", kcache->dk_if_name); 800Sstevel@tonic-gate 810Sstevel@tonic-gate /* 820Sstevel@tonic-gate * convert the kernel's ACK into binary 830Sstevel@tonic-gate */ 840Sstevel@tonic-gate 850Sstevel@tonic-gate plp = calloc(1, sizeof (PKT_LIST)); 860Sstevel@tonic-gate if (plp == NULL) 870Sstevel@tonic-gate goto failure; 880Sstevel@tonic-gate 890Sstevel@tonic-gate plp->len = strlen(kcache->dk_ack) / 2; 900Sstevel@tonic-gate plp->pkt = malloc(plp->len); 910Sstevel@tonic-gate if (plp->pkt == NULL) 920Sstevel@tonic-gate goto failure; 930Sstevel@tonic-gate 940Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "dhcp_adopt: allocated ACK of %d bytes", plp->len); 950Sstevel@tonic-gate 960Sstevel@tonic-gate if (hexascii_to_octet(kcache->dk_ack, plp->len * 2, plp->pkt, &plp->len) 970Sstevel@tonic-gate != 0) { 980Sstevel@tonic-gate dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot convert kernel ACK"); 990Sstevel@tonic-gate goto failure; 1000Sstevel@tonic-gate } 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate if (dhcp_options_scan(plp, B_TRUE) != 0) { 1030Sstevel@tonic-gate dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot parse kernel ACK"); 1040Sstevel@tonic-gate goto failure; 1050Sstevel@tonic-gate } 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate /* 1080Sstevel@tonic-gate * make an interface to represent the "cached interface" in 1090Sstevel@tonic-gate * the kernel, hook up the ACK packet we made, and send out 1100Sstevel@tonic-gate * the extend request (to attempt to renew the lease). 1110Sstevel@tonic-gate * 1120Sstevel@tonic-gate * we do a send_extend() instead of doing a dhcp_init_reboot() 1130Sstevel@tonic-gate * because although dhcp_init_reboot() is more correct from a 1140Sstevel@tonic-gate * protocol perspective, it introduces a window where a 1150Sstevel@tonic-gate * diskless client has no IP address but may need to page in 1160Sstevel@tonic-gate * more of this program. we could mlockall(), but that's 1170Sstevel@tonic-gate * going to be a mess, especially with handling malloc() and 1180Sstevel@tonic-gate * stack growth, so it's easier to just renew(). the only 1190Sstevel@tonic-gate * catch here is that if we are not granted a renewal, we're 1200Sstevel@tonic-gate * totally hosed and can only bail out. 1210Sstevel@tonic-gate */ 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate ifsp = insert_ifs(kcache->dk_if_name, B_TRUE, &retval); 1240Sstevel@tonic-gate if (ifsp == NULL) 1250Sstevel@tonic-gate goto failure; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate ifsp->if_state = ADOPTING; 1280Sstevel@tonic-gate ifsp->if_dflags |= DHCP_IF_PRIMARY; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* 131*2612Scarlsonj * move to BOUND and use the information in our ACK packet. 132*2612Scarlsonj * adoption will continue after DAD via dhcp_adopt_complete. 1330Sstevel@tonic-gate */ 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate if (dhcp_bound(ifsp, plp) == 0) { 1360Sstevel@tonic-gate dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot use cached packet"); 1370Sstevel@tonic-gate goto failure; 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate free(kcache); 1410Sstevel@tonic-gate return (1); 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate failure: 1440Sstevel@tonic-gate free(kcache); 1450Sstevel@tonic-gate if (plp != NULL) 1460Sstevel@tonic-gate free(plp->pkt); 1470Sstevel@tonic-gate free(plp); 1480Sstevel@tonic-gate return (0); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* 152*2612Scarlsonj * dhcp_adopt_complete(): completes interface adoption process after kernel 153*2612Scarlsonj * duplicate address detection (DAD) is done. 154*2612Scarlsonj * 155*2612Scarlsonj * input: struct ifslist *: the interface on which a lease is being adopted 156*2612Scarlsonj * output: none 157*2612Scarlsonj */ 158*2612Scarlsonj 159*2612Scarlsonj void 160*2612Scarlsonj dhcp_adopt_complete(struct ifslist *ifsp) 161*2612Scarlsonj { 162*2612Scarlsonj dhcpmsg(MSG_DEBUG, "dhcp_adopt_complete: completing adoption"); 163*2612Scarlsonj 164*2612Scarlsonj if (async_start(ifsp, DHCP_EXTEND, B_FALSE) == 0) { 165*2612Scarlsonj dhcpmsg(MSG_CRIT, "dhcp_adopt_complete: async_start failed"); 166*2612Scarlsonj return; 167*2612Scarlsonj } 168*2612Scarlsonj 169*2612Scarlsonj if (dhcp_extending(ifsp) == 0) { 170*2612Scarlsonj dhcpmsg(MSG_CRIT, 171*2612Scarlsonj "dhcp_adopt_complete: cannot send renew request"); 172*2612Scarlsonj return; 173*2612Scarlsonj } 174*2612Scarlsonj 175*2612Scarlsonj if (grandparent != (pid_t)0) { 176*2612Scarlsonj dhcpmsg(MSG_DEBUG, "adoption complete, signalling parent (%i)" 177*2612Scarlsonj " to exit.", grandparent); 178*2612Scarlsonj (void) kill(grandparent, SIGALRM); 179*2612Scarlsonj } 180*2612Scarlsonj } 181*2612Scarlsonj 182*2612Scarlsonj /* 1830Sstevel@tonic-gate * get_dhcp_kcache(): fetches the DHCP ACK and interface name from the kernel 1840Sstevel@tonic-gate * 1850Sstevel@tonic-gate * input: dhcp_kcache_t **: a dynamically-allocated cache packet 1860Sstevel@tonic-gate * size_t *: the length of that packet (on return) 1870Sstevel@tonic-gate * output: int: nonzero on success, zero on failure 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate static int 1910Sstevel@tonic-gate get_dhcp_kcache(dhcp_kcache_t **kernel_cachep, size_t *kcache_size) 1920Sstevel@tonic-gate { 1930Sstevel@tonic-gate char dummy; 1940Sstevel@tonic-gate long size; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate size = sysinfo(SI_DHCP_CACHE, &dummy, sizeof (dummy)); 1970Sstevel@tonic-gate if (size == -1) 1980Sstevel@tonic-gate return (0); 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate *kcache_size = size; 2010Sstevel@tonic-gate *kernel_cachep = malloc(*kcache_size); 2020Sstevel@tonic-gate if (*kernel_cachep == NULL) 2030Sstevel@tonic-gate return (0); 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate (void) sysinfo(SI_DHCP_CACHE, (caddr_t)*kernel_cachep, size); 2060Sstevel@tonic-gate return (1); 2070Sstevel@tonic-gate } 208