138451Smsmith/* $NetBSD: bootp.c,v 1.14 1998/02/16 11:10:54 drochner Exp $ */ 238451Smsmith 338451Smsmith/* 438451Smsmith * Copyright (c) 1992 Regents of the University of California. 538451Smsmith * All rights reserved. 638451Smsmith * 738451Smsmith * This software was developed by the Computer Systems Engineering group 838451Smsmith * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 938451Smsmith * contributed to Berkeley. 1038451Smsmith * 1138451Smsmith * Redistribution and use in source and binary forms, with or without 1238451Smsmith * modification, are permitted provided that the following conditions 1338451Smsmith * are met: 1438451Smsmith * 1. Redistributions of source code must retain the above copyright 1538451Smsmith * notice, this list of conditions and the following disclaimer. 1638451Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1738451Smsmith * notice, this list of conditions and the following disclaimer in the 1838451Smsmith * documentation and/or other materials provided with the distribution. 1938451Smsmith * 4. Neither the name of the University nor the names of its contributors 2038451Smsmith * may be used to endorse or promote products derived from this software 2138451Smsmith * without specific prior written permission. 2238451Smsmith * 2338451Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2438451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2538451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2638451Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2738451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2838451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2938451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3038451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3138451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3238451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3338451Smsmith * SUCH DAMAGE. 3438451Smsmith * 3538451Smsmith * @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp (LBL) 3638451Smsmith */ 3738451Smsmith 3884221Sdillon#include <sys/cdefs.h> 3984221Sdillon__FBSDID("$FreeBSD$"); 4084221Sdillon 4138451Smsmith#include <sys/types.h> 4238451Smsmith#include <netinet/in.h> 4338451Smsmith#include <netinet/in_systm.h> 4438451Smsmith 4538451Smsmith#include <string.h> 4638451Smsmith 4738451Smsmith#define BOOTP_DEBUGxx 4838451Smsmith#define SUPPORT_DHCP 4938451Smsmith 50185643Sluigi#define DHCP_ENV_NOVENDOR 1 /* do not parse vendor options */ 51185643Sluigi#define DHCP_ENV_PXE 10 /* assume pxe vendor options */ 52193189Sed#define DHCP_ENV_FREEBSD 11 /* assume freebsd vendor options */ 53185643Sluigi/* set DHCP_ENV to one of the values above to export dhcp options to kenv */ 54185643Sluigi#define DHCP_ENV DHCP_ENV_NO_VENDOR 55185643Sluigi 5638451Smsmith#include "stand.h" 5738451Smsmith#include "net.h" 5838451Smsmith#include "netif.h" 5938451Smsmith#include "bootp.h" 6038451Smsmith 6138451Smsmith 6238451Smsmithstruct in_addr servip; 6338451Smsmith 6438451Smsmithstatic n_long nmask, smask; 6538451Smsmith 6638451Smsmithstatic time_t bot; 6738451Smsmith 6838451Smsmithstatic char vm_rfc1048[4] = VM_RFC1048; 6938451Smsmith#ifdef BOOTP_VEND_CMU 7038451Smsmithstatic char vm_cmu[4] = VM_CMU; 7138451Smsmith#endif 7238451Smsmith 7338451Smsmith/* Local forwards */ 7438451Smsmithstatic ssize_t bootpsend(struct iodesc *, void *, size_t); 7538451Smsmithstatic ssize_t bootprecv(struct iodesc *, void *, size_t, time_t); 7638451Smsmithstatic int vend_rfc1048(u_char *, u_int); 7738451Smsmith#ifdef BOOTP_VEND_CMU 7838451Smsmithstatic void vend_cmu(u_char *); 7938451Smsmith#endif 8038451Smsmith 81185643Sluigi#ifdef DHCP_ENV /* export the dhcp response to kenv */ 82185643Sluigistruct dhcp_opt; 83185643Sluigistatic void setenv_(u_char *cp, u_char *ep, struct dhcp_opt *opts); 84185643Sluigi#else 85185643Sluigi#define setenv_(a, b, c) 86185643Sluigi#endif 87185643Sluigi 8838451Smsmith#ifdef SUPPORT_DHCP 8938451Smsmithstatic char expected_dhcpmsgtype = -1, dhcp_ok; 9038451Smsmithstruct in_addr dhcp_serverip; 9138451Smsmith#endif 9238451Smsmith 9338451Smsmith/* Fetch required bootp infomation */ 9438451Smsmithvoid 9564527Spsbootp(sock, flag) 9638451Smsmith int sock; 9764527Sps int flag; 9838451Smsmith{ 9938451Smsmith struct iodesc *d; 10092913Sobrien struct bootp *bp; 10138451Smsmith struct { 10238451Smsmith u_char header[HEADER_SIZE]; 10338451Smsmith struct bootp wbootp; 10438451Smsmith } wbuf; 10538451Smsmith struct { 10638451Smsmith u_char header[HEADER_SIZE]; 10738451Smsmith struct bootp rbootp; 10838451Smsmith } rbuf; 10938451Smsmith 11038451Smsmith#ifdef BOOTP_DEBUG 11138451Smsmith if (debug) 11238451Smsmith printf("bootp: socket=%d\n", sock); 11338451Smsmith#endif 11438451Smsmith if (!bot) 11538451Smsmith bot = getsecs(); 11638451Smsmith 11738451Smsmith if (!(d = socktodesc(sock))) { 11838451Smsmith printf("bootp: bad socket. %d\n", sock); 11938451Smsmith return; 12038451Smsmith } 12138451Smsmith#ifdef BOOTP_DEBUG 12238451Smsmith if (debug) 12338451Smsmith printf("bootp: d=%lx\n", (long)d); 12438451Smsmith#endif 12538451Smsmith 12638451Smsmith bp = &wbuf.wbootp; 12738451Smsmith bzero(bp, sizeof(*bp)); 12838451Smsmith 12938451Smsmith bp->bp_op = BOOTREQUEST; 13038451Smsmith bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ 13138451Smsmith bp->bp_hlen = 6; 13238451Smsmith bp->bp_xid = htonl(d->xid); 13338451Smsmith MACPY(d->myea, bp->bp_chaddr); 13438451Smsmith strncpy(bp->bp_file, bootfile, sizeof(bp->bp_file)); 13538451Smsmith bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)); 13638451Smsmith#ifdef SUPPORT_DHCP 13738451Smsmith bp->bp_vend[4] = TAG_DHCP_MSGTYPE; 13838451Smsmith bp->bp_vend[5] = 1; 13938451Smsmith bp->bp_vend[6] = DHCPDISCOVER; 14064527Sps 14164527Sps /* 14264527Sps * If we are booting from PXE, we want to send the string 14364527Sps * 'PXEClient' to the DHCP server so you have the option of 14464527Sps * only responding to PXE aware dhcp requests. 14564527Sps */ 14664527Sps if (flag & BOOTP_PXE) { 14764527Sps bp->bp_vend[7] = TAG_CLASSID; 14864527Sps bp->bp_vend[8] = 9; 14964527Sps bcopy("PXEClient", &bp->bp_vend[9], 9); 15064527Sps bp->bp_vend[18] = TAG_END; 15164527Sps } else 15264527Sps bp->bp_vend[7] = TAG_END; 15338451Smsmith#else 15438451Smsmith bp->bp_vend[4] = TAG_END; 15538451Smsmith#endif 15638451Smsmith 15738451Smsmith d->myip.s_addr = INADDR_ANY; 15838451Smsmith d->myport = htons(IPPORT_BOOTPC); 15938451Smsmith d->destip.s_addr = INADDR_BROADCAST; 16038451Smsmith d->destport = htons(IPPORT_BOOTPS); 16138451Smsmith 16238451Smsmith#ifdef SUPPORT_DHCP 16338451Smsmith expected_dhcpmsgtype = DHCPOFFER; 16438451Smsmith dhcp_ok = 0; 16538451Smsmith#endif 16638451Smsmith 16738451Smsmith if(sendrecv(d, 16838451Smsmith bootpsend, bp, sizeof(*bp), 16938451Smsmith bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) 17038451Smsmith == -1) { 17138451Smsmith printf("bootp: no reply\n"); 17238451Smsmith return; 17338451Smsmith } 17438451Smsmith 17538451Smsmith#ifdef SUPPORT_DHCP 17638451Smsmith if(dhcp_ok) { 17738451Smsmith u_int32_t leasetime; 17838451Smsmith bp->bp_vend[6] = DHCPREQUEST; 17938451Smsmith bp->bp_vend[7] = TAG_REQ_ADDR; 18038451Smsmith bp->bp_vend[8] = 4; 18138451Smsmith bcopy(&rbuf.rbootp.bp_yiaddr, &bp->bp_vend[9], 4); 18238451Smsmith bp->bp_vend[13] = TAG_SERVERID; 18338451Smsmith bp->bp_vend[14] = 4; 18438451Smsmith bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); 18538451Smsmith bp->bp_vend[19] = TAG_LEASETIME; 18638451Smsmith bp->bp_vend[20] = 4; 18738451Smsmith leasetime = htonl(300); 18838451Smsmith bcopy(&leasetime, &bp->bp_vend[21], 4); 18964527Sps if (flag & BOOTP_PXE) { 19064527Sps bp->bp_vend[25] = TAG_CLASSID; 19164527Sps bp->bp_vend[26] = 9; 19264527Sps bcopy("PXEClient", &bp->bp_vend[27], 9); 19364527Sps bp->bp_vend[36] = TAG_END; 19464527Sps } else 19564527Sps bp->bp_vend[25] = TAG_END; 19638451Smsmith 19738451Smsmith expected_dhcpmsgtype = DHCPACK; 19838451Smsmith 19938451Smsmith if(sendrecv(d, 20038451Smsmith bootpsend, bp, sizeof(*bp), 20138451Smsmith bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) 20238451Smsmith == -1) { 20338451Smsmith printf("DHCPREQUEST failed\n"); 20438451Smsmith return; 20538451Smsmith } 20638451Smsmith } 20738451Smsmith#endif 20838451Smsmith 20938451Smsmith myip = d->myip = rbuf.rbootp.bp_yiaddr; 21038451Smsmith servip = rbuf.rbootp.bp_siaddr; 21138451Smsmith if(rootip.s_addr == INADDR_ANY) rootip = servip; 21238451Smsmith bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile)); 21338451Smsmith bootfile[sizeof(bootfile) - 1] = '\0'; 21438451Smsmith 21566134Sps if (IN_CLASSA(ntohl(myip.s_addr))) 21638451Smsmith nmask = htonl(IN_CLASSA_NET); 21766134Sps else if (IN_CLASSB(ntohl(myip.s_addr))) 21838451Smsmith nmask = htonl(IN_CLASSB_NET); 21938451Smsmith else 22038451Smsmith nmask = htonl(IN_CLASSC_NET); 22138451Smsmith#ifdef BOOTP_DEBUG 22238451Smsmith if (debug) 22338451Smsmith printf("'native netmask' is %s\n", intoa(nmask)); 22438451Smsmith#endif 22538451Smsmith 22638451Smsmith /* Check subnet mask against net mask; toss if bogus */ 22738451Smsmith if ((nmask & smask) != nmask) { 22838451Smsmith#ifdef BOOTP_DEBUG 22938451Smsmith if (debug) 23038451Smsmith printf("subnet mask (%s) bad\n", intoa(smask)); 23138451Smsmith#endif 23238451Smsmith smask = 0; 23338451Smsmith } 23438451Smsmith 23538451Smsmith /* Get subnet (or natural net) mask */ 23638451Smsmith netmask = nmask; 23738451Smsmith if (smask) 23838451Smsmith netmask = smask; 23938451Smsmith#ifdef BOOTP_DEBUG 24038451Smsmith if (debug) 24138451Smsmith printf("mask: %s\n", intoa(netmask)); 24238451Smsmith#endif 24338451Smsmith 24438451Smsmith /* We need a gateway if root is on a different net */ 24538451Smsmith if (!SAMENET(myip, rootip, netmask)) { 24638451Smsmith#ifdef BOOTP_DEBUG 24738451Smsmith if (debug) 24838451Smsmith printf("need gateway for root ip\n"); 24938451Smsmith#endif 25038451Smsmith } 25138451Smsmith 25238451Smsmith /* Toss gateway if on a different net */ 25338451Smsmith if (!SAMENET(myip, gateip, netmask)) { 25438451Smsmith#ifdef BOOTP_DEBUG 25538451Smsmith if (debug) 25638451Smsmith printf("gateway ip (%s) bad\n", inet_ntoa(gateip)); 25738451Smsmith#endif 25838451Smsmith gateip.s_addr = 0; 25938451Smsmith } 26038451Smsmith 26138451Smsmith /* Bump xid so next request will be unique. */ 26238451Smsmith ++d->xid; 26338451Smsmith} 26438451Smsmith 26538451Smsmith/* Transmit a bootp request */ 26638451Smsmithstatic ssize_t 26738451Smsmithbootpsend(d, pkt, len) 26892913Sobrien struct iodesc *d; 26992913Sobrien void *pkt; 27092913Sobrien size_t len; 27138451Smsmith{ 27292913Sobrien struct bootp *bp; 27338451Smsmith 27438451Smsmith#ifdef BOOTP_DEBUG 27538451Smsmith if (debug) 27638451Smsmith printf("bootpsend: d=%lx called.\n", (long)d); 27738451Smsmith#endif 27838451Smsmith 27938451Smsmith bp = pkt; 28038451Smsmith bp->bp_secs = htons((u_short)(getsecs() - bot)); 28138451Smsmith 28238451Smsmith#ifdef BOOTP_DEBUG 28338451Smsmith if (debug) 28438451Smsmith printf("bootpsend: calling sendudp\n"); 28538451Smsmith#endif 28638451Smsmith 28738451Smsmith return (sendudp(d, pkt, len)); 28838451Smsmith} 28938451Smsmith 29038451Smsmithstatic ssize_t 29138451Smsmithbootprecv(d, pkt, len, tleft) 29292913Sobrienstruct iodesc *d; 29392913Sobrienvoid *pkt; 29492913Sobriensize_t len; 29538451Smsmithtime_t tleft; 29638451Smsmith{ 29792913Sobrien ssize_t n; 29892913Sobrien struct bootp *bp; 29938451Smsmith 30038451Smsmith#ifdef BOOTP_DEBUGx 30138451Smsmith if (debug) 30238451Smsmith printf("bootp_recvoffer: called\n"); 30338451Smsmith#endif 30438451Smsmith 30538451Smsmith n = readudp(d, pkt, len, tleft); 30638451Smsmith if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE) 30738451Smsmith goto bad; 30838451Smsmith 30938451Smsmith bp = (struct bootp *)pkt; 31038451Smsmith 31138451Smsmith#ifdef BOOTP_DEBUG 31238451Smsmith if (debug) 31338451Smsmith printf("bootprecv: checked. bp = 0x%lx, n = %d\n", 31438451Smsmith (long)bp, (int)n); 31538451Smsmith#endif 31638451Smsmith if (bp->bp_xid != htonl(d->xid)) { 31738451Smsmith#ifdef BOOTP_DEBUG 31838451Smsmith if (debug) { 31938451Smsmith printf("bootprecv: expected xid 0x%lx, got 0x%x\n", 32038451Smsmith d->xid, ntohl(bp->bp_xid)); 32138451Smsmith } 32238451Smsmith#endif 32338451Smsmith goto bad; 32438451Smsmith } 32538451Smsmith 32638451Smsmith#ifdef BOOTP_DEBUG 32738451Smsmith if (debug) 32838451Smsmith printf("bootprecv: got one!\n"); 32938451Smsmith#endif 33038451Smsmith 33138451Smsmith /* Suck out vendor info */ 33238451Smsmith if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) { 33338451Smsmith if(vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)) != 0) 33438451Smsmith goto bad; 33538451Smsmith } 33638451Smsmith#ifdef BOOTP_VEND_CMU 33738451Smsmith else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0) 33838451Smsmith vend_cmu(bp->bp_vend); 33938451Smsmith#endif 34038451Smsmith else 34138451Smsmith printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend); 34238451Smsmith 34338451Smsmith return(n); 34438451Smsmithbad: 34538451Smsmith errno = 0; 34638451Smsmith return (-1); 34738451Smsmith} 34838451Smsmith 34938451Smsmithstatic int 35038451Smsmithvend_rfc1048(cp, len) 35192913Sobrien u_char *cp; 35238451Smsmith u_int len; 35338451Smsmith{ 35492913Sobrien u_char *ep; 35592913Sobrien int size; 35692913Sobrien u_char tag; 35738451Smsmith 35838451Smsmith#ifdef BOOTP_DEBUG 35938451Smsmith if (debug) 36038451Smsmith printf("vend_rfc1048 bootp info. len=%d\n", len); 36138451Smsmith#endif 36238451Smsmith ep = cp + len; 36338451Smsmith 36438451Smsmith /* Step over magic cookie */ 36538451Smsmith cp += sizeof(int); 36638451Smsmith 367185643Sluigi setenv_(cp, ep, NULL); 368185643Sluigi 36938451Smsmith while (cp < ep) { 37038451Smsmith tag = *cp++; 37138451Smsmith size = *cp++; 37238451Smsmith if (tag == TAG_END) 37338451Smsmith break; 37438451Smsmith 37538451Smsmith if (tag == TAG_SUBNET_MASK) { 37638451Smsmith bcopy(cp, &smask, sizeof(smask)); 37738451Smsmith } 37838451Smsmith if (tag == TAG_GATEWAY) { 37938451Smsmith bcopy(cp, &gateip.s_addr, sizeof(gateip.s_addr)); 38038451Smsmith } 38138451Smsmith if (tag == TAG_SWAPSERVER) { 38238451Smsmith /* let it override bp_siaddr */ 38338451Smsmith bcopy(cp, &rootip.s_addr, sizeof(swapip.s_addr)); 38438451Smsmith } 38538451Smsmith if (tag == TAG_ROOTPATH) { 38638451Smsmith strncpy(rootpath, (char *)cp, sizeof(rootpath)); 38738451Smsmith rootpath[size] = '\0'; 38838451Smsmith } 38938451Smsmith if (tag == TAG_HOSTNAME) { 39038451Smsmith strncpy(hostname, (char *)cp, sizeof(hostname)); 39138451Smsmith hostname[size] = '\0'; 39238451Smsmith } 39338451Smsmith#ifdef SUPPORT_DHCP 39438451Smsmith if (tag == TAG_DHCP_MSGTYPE) { 39538451Smsmith if(*cp != expected_dhcpmsgtype) 39638451Smsmith return(-1); 39738451Smsmith dhcp_ok = 1; 39838451Smsmith } 39938451Smsmith if (tag == TAG_SERVERID) { 40038451Smsmith bcopy(cp, &dhcp_serverip.s_addr, 40138451Smsmith sizeof(dhcp_serverip.s_addr)); 40238451Smsmith } 40338451Smsmith#endif 40438451Smsmith cp += size; 40538451Smsmith } 40638451Smsmith return(0); 40738451Smsmith} 40838451Smsmith 40938451Smsmith#ifdef BOOTP_VEND_CMU 41038451Smsmithstatic void 41138451Smsmithvend_cmu(cp) 41238451Smsmith u_char *cp; 41338451Smsmith{ 41492913Sobrien struct cmu_vend *vp; 41538451Smsmith 41638451Smsmith#ifdef BOOTP_DEBUG 41738451Smsmith if (debug) 41838451Smsmith printf("vend_cmu bootp info.\n"); 41938451Smsmith#endif 42038451Smsmith vp = (struct cmu_vend *)cp; 42138451Smsmith 42238451Smsmith if (vp->v_smask.s_addr != 0) { 42338451Smsmith smask = vp->v_smask.s_addr; 42438451Smsmith } 42538451Smsmith if (vp->v_dgate.s_addr != 0) { 42638451Smsmith gateip = vp->v_dgate; 42738451Smsmith } 42838451Smsmith} 42938451Smsmith#endif 430185643Sluigi 431185643Sluigi#ifdef DHCP_ENV 432185643Sluigi/* 433185643Sluigi * Parse DHCP options and store them into kenv variables. 434185643Sluigi * Original code from Danny Braniss, modifications by Luigi Rizzo. 435185643Sluigi * 436185643Sluigi * The parser is driven by tables which specify the type and name of 437185643Sluigi * each dhcp option and how it appears in kenv. 438185643Sluigi * The first entry in the list contains the prefix used to set the kenv 439185643Sluigi * name (including the . if needed), the last entry must have a 0 tag. 440185643Sluigi * Entries do not need to be sorted though it helps for readability. 441185643Sluigi * 442185643Sluigi * Certain vendor-specific tables can be enabled according to DHCP_ENV. 443185643Sluigi * Set it to 0 if you don't want any. 444185643Sluigi */ 445185643Sluigienum opt_fmt { __NONE = 0, 446185643Sluigi __8 = 1, __16 = 2, __32 = 4, /* Unsigned fields, value=size */ 447185643Sluigi __IP, /* IPv4 address */ 448185643Sluigi __TXT, /* C string */ 449185643Sluigi __BYTES, /* byte sequence, printed %02x */ 450185643Sluigi __INDIR, /* name=value */ 451185643Sluigi __ILIST, /* name=value;name=value ... */ 452185643Sluigi __VE, /* vendor specific, recurse */ 453185643Sluigi}; 454185643Sluigi 455185643Sluigistruct dhcp_opt { 456185643Sluigi uint8_t tag; 457185643Sluigi uint8_t fmt; 458185643Sluigi const char *desc; 459185643Sluigi}; 460185643Sluigi 461185643Sluigistatic struct dhcp_opt vndr_opt[] = { /* Vendor Specific Options */ 462185643Sluigi#if DHCP_ENV == DHCP_ENV_FREEBSD /* FreeBSD table in the original code */ 463185643Sluigi {0, 0, "FreeBSD"}, /* prefix */ 464185643Sluigi {1, __TXT, "kernel"}, 465185643Sluigi {2, __TXT, "kernelname"}, 466185643Sluigi {3, __TXT, "kernel_options"}, 467185643Sluigi {4, __IP, "usr-ip"}, 468185643Sluigi {5, __TXT, "conf-path"}, 469185643Sluigi {6, __TXT, "rc.conf0"}, 470185643Sluigi {7, __TXT, "rc.conf1"}, 471185643Sluigi {8, __TXT, "rc.conf2"}, 472185643Sluigi {9, __TXT, "rc.conf3"}, 473185643Sluigi {10, __TXT, "rc.conf4"}, 474185643Sluigi {11, __TXT, "rc.conf5"}, 475185643Sluigi {12, __TXT, "rc.conf6"}, 476185643Sluigi {13, __TXT, "rc.conf7"}, 477185643Sluigi {14, __TXT, "rc.conf8"}, 478185643Sluigi {15, __TXT, "rc.conf9"}, 479185643Sluigi 480185643Sluigi {20, __TXT, "boot.nfsroot.options"}, 481185643Sluigi 482185643Sluigi {245, __INDIR, ""}, 483185643Sluigi {246, __INDIR, ""}, 484185643Sluigi {247, __INDIR, ""}, 485185643Sluigi {248, __INDIR, ""}, 486185643Sluigi {249, __INDIR, ""}, 487185643Sluigi {250, __INDIR, ""}, 488185643Sluigi {251, __INDIR, ""}, 489185643Sluigi {252, __INDIR, ""}, 490185643Sluigi {253, __INDIR, ""}, 491185643Sluigi {254, __INDIR, ""}, 492185643Sluigi 493185643Sluigi#elif DHCP_ENV == DHCP_ENV_PXE /* some pxe options, RFC4578 */ 494185643Sluigi {0, 0, "pxe"}, /* prefix */ 495185643Sluigi {93, __16, "system-architecture"}, 496185643Sluigi {94, __BYTES, "network-interface"}, 497185643Sluigi {97, __BYTES, "machine-identifier"}, 498185643Sluigi#else /* default (empty) table */ 499186799Sluigi {0, 0, "dhcp.vendor."}, /* prefix */ 500185643Sluigi#endif 501185643Sluigi {0, __TXT, "%soption-%d"} 502185643Sluigi}; 503185643Sluigi 504185643Sluigistatic struct dhcp_opt dhcp_opt[] = { 505185643Sluigi /* DHCP Option names, formats and codes, from RFC2132. */ 506185643Sluigi {0, 0, "dhcp."}, // prefix 507185643Sluigi {1, __IP, "subnet-mask"}, 508185643Sluigi {2, __32, "time-offset"}, /* this is signed */ 509185643Sluigi {3, __IP, "routers"}, 510185643Sluigi {4, __IP, "time-servers"}, 511185643Sluigi {5, __IP, "ien116-name-servers"}, 512185643Sluigi {6, __IP, "domain-name-servers"}, 513185643Sluigi {7, __IP, "log-servers"}, 514185643Sluigi {8, __IP, "cookie-servers"}, 515185643Sluigi {9, __IP, "lpr-servers"}, 516185643Sluigi {10, __IP, "impress-servers"}, 517185643Sluigi {11, __IP, "resource-location-servers"}, 518185643Sluigi {12, __TXT, "host-name"}, 519185643Sluigi {13, __16, "boot-size"}, 520185643Sluigi {14, __TXT, "merit-dump"}, 521185643Sluigi {15, __TXT, "domain-name"}, 522185643Sluigi {16, __IP, "swap-server"}, 523185643Sluigi {17, __TXT, "root-path"}, 524185643Sluigi {18, __TXT, "extensions-path"}, 525185643Sluigi {19, __8, "ip-forwarding"}, 526185643Sluigi {20, __8, "non-local-source-routing"}, 527185643Sluigi {21, __IP, "policy-filter"}, 528185643Sluigi {22, __16, "max-dgram-reassembly"}, 529185643Sluigi {23, __8, "default-ip-ttl"}, 530185643Sluigi {24, __32, "path-mtu-aging-timeout"}, 531185643Sluigi {25, __16, "path-mtu-plateau-table"}, 532185643Sluigi {26, __16, "interface-mtu"}, 533185643Sluigi {27, __8, "all-subnets-local"}, 534185643Sluigi {28, __IP, "broadcast-address"}, 535185643Sluigi {29, __8, "perform-mask-discovery"}, 536185643Sluigi {30, __8, "mask-supplier"}, 537185643Sluigi {31, __8, "perform-router-discovery"}, 538185643Sluigi {32, __IP, "router-solicitation-address"}, 539185643Sluigi {33, __IP, "static-routes"}, 540185643Sluigi {34, __8, "trailer-encapsulation"}, 541185643Sluigi {35, __32, "arp-cache-timeout"}, 542185643Sluigi {36, __8, "ieee802-3-encapsulation"}, 543185643Sluigi {37, __8, "default-tcp-ttl"}, 544185643Sluigi {38, __32, "tcp-keepalive-interval"}, 545185643Sluigi {39, __8, "tcp-keepalive-garbage"}, 546185643Sluigi {40, __TXT, "nis-domain"}, 547185643Sluigi {41, __IP, "nis-servers"}, 548185643Sluigi {42, __IP, "ntp-servers"}, 549185643Sluigi {43, __VE, "vendor-encapsulated-options"}, 550185643Sluigi {44, __IP, "netbios-name-servers"}, 551185643Sluigi {45, __IP, "netbios-dd-server"}, 552185643Sluigi {46, __8, "netbios-node-type"}, 553185643Sluigi {47, __TXT, "netbios-scope"}, 554185643Sluigi {48, __IP, "x-font-servers"}, 555185643Sluigi {49, __IP, "x-display-managers"}, 556185643Sluigi {50, __IP, "dhcp-requested-address"}, 557185643Sluigi {51, __32, "dhcp-lease-time"}, 558185643Sluigi {52, __8, "dhcp-option-overload"}, 559185643Sluigi {53, __8, "dhcp-message-type"}, 560185643Sluigi {54, __IP, "dhcp-server-identifier"}, 561185643Sluigi {55, __8, "dhcp-parameter-request-list"}, 562185643Sluigi {56, __TXT, "dhcp-message"}, 563185643Sluigi {57, __16, "dhcp-max-message-size"}, 564185643Sluigi {58, __32, "dhcp-renewal-time"}, 565185643Sluigi {59, __32, "dhcp-rebinding-time"}, 566185643Sluigi {60, __TXT, "vendor-class-identifier"}, 567185643Sluigi {61, __TXT, "dhcp-client-identifier"}, 568185643Sluigi {64, __TXT, "nisplus-domain"}, 569185643Sluigi {65, __IP, "nisplus-servers"}, 570185643Sluigi {66, __TXT, "tftp-server-name"}, 571185643Sluigi {67, __TXT, "bootfile-name"}, 572185643Sluigi {68, __IP, "mobile-ip-home-agent"}, 573185643Sluigi {69, __IP, "smtp-server"}, 574185643Sluigi {70, __IP, "pop-server"}, 575185643Sluigi {71, __IP, "nntp-server"}, 576185643Sluigi {72, __IP, "www-server"}, 577185643Sluigi {73, __IP, "finger-server"}, 578185643Sluigi {74, __IP, "irc-server"}, 579185643Sluigi {75, __IP, "streettalk-server"}, 580185643Sluigi {76, __IP, "streettalk-directory-assistance-server"}, 581185643Sluigi {77, __TXT, "user-class"}, 582185643Sluigi {85, __IP, "nds-servers"}, 583185643Sluigi {86, __TXT, "nds-tree-name"}, 584185643Sluigi {87, __TXT, "nds-context"}, 585185643Sluigi {210, __TXT, "authenticate"}, 586185643Sluigi 587185643Sluigi /* use the following entries for arbitrary variables */ 588185643Sluigi {246, __ILIST, ""}, 589185643Sluigi {247, __ILIST, ""}, 590185643Sluigi {248, __ILIST, ""}, 591185643Sluigi {249, __ILIST, ""}, 592185643Sluigi {250, __INDIR, ""}, 593185643Sluigi {251, __INDIR, ""}, 594185643Sluigi {252, __INDIR, ""}, 595185643Sluigi {253, __INDIR, ""}, 596185643Sluigi {254, __INDIR, ""}, 597185643Sluigi {0, __TXT, "%soption-%d"} 598185643Sluigi}; 599185643Sluigi 600185643Sluigi/* 601185643Sluigi * parse a dhcp response, set environment variables translating options 602185643Sluigi * names and values according to the tables above. Also set dhcp.tags 603185643Sluigi * to the list of selected tags. 604185643Sluigi */ 605185643Sluigistatic void 606185643Sluigisetenv_(u_char *cp, u_char *ep, struct dhcp_opt *opts) 607185643Sluigi{ 608185643Sluigi u_char *ncp; 609185643Sluigi u_char tag; 610185643Sluigi char tags[512], *tp; /* the list of tags */ 611185643Sluigi 612185643Sluigi#define FLD_SEP ',' /* separator in list of elements */ 613185643Sluigi ncp = cp; 614185643Sluigi tp = tags; 615185643Sluigi if (opts == NULL) 616185643Sluigi opts = dhcp_opt; 617185643Sluigi 618185643Sluigi while (ncp < ep) { 619185643Sluigi unsigned int size; /* option size */ 620185643Sluigi char *vp, *endv, buf[256]; /* the value buffer */ 621185643Sluigi struct dhcp_opt *op; 622185643Sluigi 623185643Sluigi tag = *ncp++; /* extract tag and size */ 624185643Sluigi size = *ncp++; 625185643Sluigi cp = ncp; /* current payload */ 626185643Sluigi ncp += size; /* point to the next option */ 627185643Sluigi 628185643Sluigi if (tag == TAG_END) 629185643Sluigi break; 630185643Sluigi if (tag == 0) 631185643Sluigi continue; 632185643Sluigi 633185643Sluigi for (op = opts+1; op->tag && op->tag != tag; op++) 634185643Sluigi ; 635185643Sluigi /* if not found we end up on the default entry */ 636185643Sluigi 637185643Sluigi /* 638185643Sluigi * Copy data into the buffer. libstand does not have snprintf so we 639185643Sluigi * need to be careful with sprintf(). With strings, the source is 640185643Sluigi * always <256 char so shorter than the buffer so we are safe; with 641185643Sluigi * other arguments, the longest string is inet_ntoa which is 16 bytes 642185643Sluigi * so we make sure to have always enough room in the string before 643185643Sluigi * trying an sprint. 644185643Sluigi */ 645185643Sluigi vp = buf; 646185643Sluigi *vp = '\0'; 647185643Sluigi endv = buf + sizeof(buf) - 1 - 16; /* last valid write position */ 648185643Sluigi 649185643Sluigi switch(op->fmt) { 650185643Sluigi case __NONE: 651185643Sluigi break; /* should not happen */ 652185643Sluigi 653185643Sluigi case __VE: /* recurse, vendor specific */ 654185643Sluigi setenv_(cp, cp+size, vndr_opt); 655185643Sluigi break; 656185643Sluigi 657185643Sluigi case __IP: /* ip address */ 658185643Sluigi for (; size > 0 && vp < endv; size -= 4, cp += 4) { 659185643Sluigi struct in_addr in_ip; /* ip addresses */ 660185643Sluigi if (vp != buf) 661185643Sluigi *vp++ = FLD_SEP; 662185643Sluigi bcopy(cp, &in_ip.s_addr, sizeof(in_ip.s_addr)); 663185643Sluigi sprintf(vp, "%s", inet_ntoa(in_ip)); 664185643Sluigi vp += strlen(vp); 665185643Sluigi } 666185643Sluigi break; 667185643Sluigi 668185643Sluigi case __BYTES: /* opaque byte string */ 669185643Sluigi for (; size > 0 && vp < endv; size -= 1, cp += 1) { 670185643Sluigi sprintf(vp, "%02x", *cp); 671185643Sluigi vp += strlen(vp); 672185643Sluigi } 673185643Sluigi break; 674185643Sluigi 675185643Sluigi case __TXT: 676185643Sluigi bcopy(cp, buf, size); /* cannot overflow */ 677185643Sluigi buf[size] = 0; 678185643Sluigi break; 679185643Sluigi 680185643Sluigi case __32: 681185643Sluigi case __16: 682185643Sluigi case __8: /* op->fmt is also the length of each field */ 683185643Sluigi for (; size > 0 && vp < endv; size -= op->fmt, cp += op->fmt) { 684185643Sluigi uint32_t v; 685185643Sluigi if (op->fmt == __32) 686185643Sluigi v = (cp[0]<<24) + (cp[1]<<16) + (cp[2]<<8) + cp[3]; 687185643Sluigi else if (op->fmt == __16) 688185643Sluigi v = (cp[0]<<8) + cp[1]; 689185643Sluigi else 690185643Sluigi v = cp[0]; 691185643Sluigi if (vp != buf) 692185643Sluigi *vp++ = FLD_SEP; 693185643Sluigi sprintf(vp, "%u", v); 694185643Sluigi vp += strlen(vp); 695185643Sluigi } 696185643Sluigi break; 697185643Sluigi 698185643Sluigi case __INDIR: /* name=value */ 699185643Sluigi case __ILIST: /* name=value;name=value... */ 700185643Sluigi bcopy(cp, buf, size); /* cannot overflow */ 701185643Sluigi buf[size] = '\0'; 702185643Sluigi for (endv = buf; endv; endv = vp) { 703185643Sluigi u_char *s = NULL; /* semicolon ? */ 704185643Sluigi 705185643Sluigi /* skip leading whitespace */ 706229403Sed while (*endv && strchr(" \t\n\r", *endv)) 707185643Sluigi endv++; 708229403Sed vp = strchr(endv, '='); /* find name=value separator */ 709185643Sluigi if (!vp) 710185643Sluigi break; 711185643Sluigi *vp++ = 0; 712229403Sed if (op->fmt == __ILIST && (s = strchr(vp, ';'))) 713185643Sluigi *s++ = '\0'; 714185643Sluigi setenv(endv, vp, 1); 715185643Sluigi vp = s; /* prepare for next round */ 716185643Sluigi } 717185643Sluigi buf[0] = '\0'; /* option already done */ 718185643Sluigi } 719185643Sluigi 720185643Sluigi if (tp - tags < sizeof(tags) - 5) { /* add tag to the list */ 721185643Sluigi if (tp != tags) 722185643Sluigi *tp++ = FLD_SEP; 723185643Sluigi sprintf(tp, "%d", tag); 724185643Sluigi tp += strlen(tp); 725185643Sluigi } 726185643Sluigi if (buf[0]) { 727185643Sluigi char env[128]; /* the string name */ 728185643Sluigi 729185643Sluigi if (op->tag == 0) 730185643Sluigi sprintf(env, op->desc, opts[0].desc, tag); 731185643Sluigi else 732185643Sluigi sprintf(env, "%s%s", opts[0].desc, op->desc); 733185643Sluigi setenv(env, buf, 1); 734185643Sluigi } 735185643Sluigi } 736185643Sluigi if (tp != tags) { 737185643Sluigi char env[128]; /* the string name */ 738185643Sluigi sprintf(env, "%stags", opts[0].desc); 739185643Sluigi setenv(env, tags, 1); 740185643Sluigi } 741185643Sluigi} 742185643Sluigi#endif /* additional dhcp */ 743