bootp.c revision 92913
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 * 3. All advertising materials mentioning features or use of this software 2038451Smsmith * must display the following acknowledgement: 2138451Smsmith * This product includes software developed by the University of 2238451Smsmith * California, Lawrence Berkeley Laboratory and its contributors. 2338451Smsmith * 4. Neither the name of the University nor the names of its contributors 2438451Smsmith * may be used to endorse or promote products derived from this software 2538451Smsmith * without specific prior written permission. 2638451Smsmith * 2738451Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2838451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2938451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3038451Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3138451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3238451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3338451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3438451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3538451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3638451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3738451Smsmith * SUCH DAMAGE. 3838451Smsmith * 3938451Smsmith * @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp (LBL) 4038451Smsmith */ 4138451Smsmith 4284221Sdillon#include <sys/cdefs.h> 4384221Sdillon__FBSDID("$FreeBSD: head/lib/libstand/bootp.c 92913 2002-03-21 23:39:28Z obrien $"); 4484221Sdillon 4538451Smsmith#include <sys/types.h> 4638451Smsmith#include <netinet/in.h> 4738451Smsmith#include <netinet/in_systm.h> 4838451Smsmith 4938451Smsmith#include <string.h> 5038451Smsmith 5138451Smsmith#define BOOTP_DEBUGxx 5238451Smsmith#define SUPPORT_DHCP 5338451Smsmith 5438451Smsmith#include "stand.h" 5538451Smsmith#include "net.h" 5638451Smsmith#include "netif.h" 5738451Smsmith#include "bootp.h" 5838451Smsmith 5938451Smsmith 6038451Smsmithstruct in_addr servip; 6138451Smsmith 6238451Smsmithstatic n_long nmask, smask; 6338451Smsmith 6438451Smsmithstatic time_t bot; 6538451Smsmith 6638451Smsmithstatic char vm_rfc1048[4] = VM_RFC1048; 6738451Smsmith#ifdef BOOTP_VEND_CMU 6838451Smsmithstatic char vm_cmu[4] = VM_CMU; 6938451Smsmith#endif 7038451Smsmith 7138451Smsmith/* Local forwards */ 7238451Smsmithstatic ssize_t bootpsend(struct iodesc *, void *, size_t); 7338451Smsmithstatic ssize_t bootprecv(struct iodesc *, void *, size_t, time_t); 7438451Smsmithstatic int vend_rfc1048(u_char *, u_int); 7538451Smsmith#ifdef BOOTP_VEND_CMU 7638451Smsmithstatic void vend_cmu(u_char *); 7738451Smsmith#endif 7838451Smsmith 7938451Smsmith#ifdef SUPPORT_DHCP 8038451Smsmithstatic char expected_dhcpmsgtype = -1, dhcp_ok; 8138451Smsmithstruct in_addr dhcp_serverip; 8238451Smsmith#endif 8338451Smsmith 8438451Smsmith/* Fetch required bootp infomation */ 8538451Smsmithvoid 8664527Spsbootp(sock, flag) 8738451Smsmith int sock; 8864527Sps int flag; 8938451Smsmith{ 9038451Smsmith struct iodesc *d; 9192913Sobrien struct bootp *bp; 9238451Smsmith struct { 9338451Smsmith u_char header[HEADER_SIZE]; 9438451Smsmith struct bootp wbootp; 9538451Smsmith } wbuf; 9638451Smsmith struct { 9738451Smsmith u_char header[HEADER_SIZE]; 9838451Smsmith struct bootp rbootp; 9938451Smsmith } rbuf; 10038451Smsmith 10138451Smsmith#ifdef BOOTP_DEBUG 10238451Smsmith if (debug) 10338451Smsmith printf("bootp: socket=%d\n", sock); 10438451Smsmith#endif 10538451Smsmith if (!bot) 10638451Smsmith bot = getsecs(); 10738451Smsmith 10838451Smsmith if (!(d = socktodesc(sock))) { 10938451Smsmith printf("bootp: bad socket. %d\n", sock); 11038451Smsmith return; 11138451Smsmith } 11238451Smsmith#ifdef BOOTP_DEBUG 11338451Smsmith if (debug) 11438451Smsmith printf("bootp: d=%lx\n", (long)d); 11538451Smsmith#endif 11638451Smsmith 11738451Smsmith bp = &wbuf.wbootp; 11838451Smsmith bzero(bp, sizeof(*bp)); 11938451Smsmith 12038451Smsmith bp->bp_op = BOOTREQUEST; 12138451Smsmith bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ 12238451Smsmith bp->bp_hlen = 6; 12338451Smsmith bp->bp_xid = htonl(d->xid); 12438451Smsmith MACPY(d->myea, bp->bp_chaddr); 12538451Smsmith strncpy(bp->bp_file, bootfile, sizeof(bp->bp_file)); 12638451Smsmith bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)); 12738451Smsmith#ifdef SUPPORT_DHCP 12838451Smsmith bp->bp_vend[4] = TAG_DHCP_MSGTYPE; 12938451Smsmith bp->bp_vend[5] = 1; 13038451Smsmith bp->bp_vend[6] = DHCPDISCOVER; 13164527Sps 13264527Sps /* 13364527Sps * If we are booting from PXE, we want to send the string 13464527Sps * 'PXEClient' to the DHCP server so you have the option of 13564527Sps * only responding to PXE aware dhcp requests. 13664527Sps */ 13764527Sps if (flag & BOOTP_PXE) { 13864527Sps bp->bp_vend[7] = TAG_CLASSID; 13964527Sps bp->bp_vend[8] = 9; 14064527Sps bcopy("PXEClient", &bp->bp_vend[9], 9); 14164527Sps bp->bp_vend[18] = TAG_END; 14264527Sps } else 14364527Sps bp->bp_vend[7] = TAG_END; 14438451Smsmith#else 14538451Smsmith bp->bp_vend[4] = TAG_END; 14638451Smsmith#endif 14738451Smsmith 14838451Smsmith d->myip.s_addr = INADDR_ANY; 14938451Smsmith d->myport = htons(IPPORT_BOOTPC); 15038451Smsmith d->destip.s_addr = INADDR_BROADCAST; 15138451Smsmith d->destport = htons(IPPORT_BOOTPS); 15238451Smsmith 15338451Smsmith#ifdef SUPPORT_DHCP 15438451Smsmith expected_dhcpmsgtype = DHCPOFFER; 15538451Smsmith dhcp_ok = 0; 15638451Smsmith#endif 15738451Smsmith 15838451Smsmith if(sendrecv(d, 15938451Smsmith bootpsend, bp, sizeof(*bp), 16038451Smsmith bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) 16138451Smsmith == -1) { 16238451Smsmith printf("bootp: no reply\n"); 16338451Smsmith return; 16438451Smsmith } 16538451Smsmith 16638451Smsmith#ifdef SUPPORT_DHCP 16738451Smsmith if(dhcp_ok) { 16838451Smsmith u_int32_t leasetime; 16938451Smsmith bp->bp_vend[6] = DHCPREQUEST; 17038451Smsmith bp->bp_vend[7] = TAG_REQ_ADDR; 17138451Smsmith bp->bp_vend[8] = 4; 17238451Smsmith bcopy(&rbuf.rbootp.bp_yiaddr, &bp->bp_vend[9], 4); 17338451Smsmith bp->bp_vend[13] = TAG_SERVERID; 17438451Smsmith bp->bp_vend[14] = 4; 17538451Smsmith bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); 17638451Smsmith bp->bp_vend[19] = TAG_LEASETIME; 17738451Smsmith bp->bp_vend[20] = 4; 17838451Smsmith leasetime = htonl(300); 17938451Smsmith bcopy(&leasetime, &bp->bp_vend[21], 4); 18064527Sps if (flag & BOOTP_PXE) { 18164527Sps bp->bp_vend[25] = TAG_CLASSID; 18264527Sps bp->bp_vend[26] = 9; 18364527Sps bcopy("PXEClient", &bp->bp_vend[27], 9); 18464527Sps bp->bp_vend[36] = TAG_END; 18564527Sps } else 18664527Sps bp->bp_vend[25] = TAG_END; 18738451Smsmith 18838451Smsmith expected_dhcpmsgtype = DHCPACK; 18938451Smsmith 19038451Smsmith if(sendrecv(d, 19138451Smsmith bootpsend, bp, sizeof(*bp), 19238451Smsmith bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) 19338451Smsmith == -1) { 19438451Smsmith printf("DHCPREQUEST failed\n"); 19538451Smsmith return; 19638451Smsmith } 19738451Smsmith } 19838451Smsmith#endif 19938451Smsmith 20038451Smsmith myip = d->myip = rbuf.rbootp.bp_yiaddr; 20138451Smsmith servip = rbuf.rbootp.bp_siaddr; 20238451Smsmith if(rootip.s_addr == INADDR_ANY) rootip = servip; 20338451Smsmith bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile)); 20438451Smsmith bootfile[sizeof(bootfile) - 1] = '\0'; 20538451Smsmith 20666134Sps if (IN_CLASSA(ntohl(myip.s_addr))) 20738451Smsmith nmask = htonl(IN_CLASSA_NET); 20866134Sps else if (IN_CLASSB(ntohl(myip.s_addr))) 20938451Smsmith nmask = htonl(IN_CLASSB_NET); 21038451Smsmith else 21138451Smsmith nmask = htonl(IN_CLASSC_NET); 21238451Smsmith#ifdef BOOTP_DEBUG 21338451Smsmith if (debug) 21438451Smsmith printf("'native netmask' is %s\n", intoa(nmask)); 21538451Smsmith#endif 21638451Smsmith 21738451Smsmith /* Check subnet mask against net mask; toss if bogus */ 21838451Smsmith if ((nmask & smask) != nmask) { 21938451Smsmith#ifdef BOOTP_DEBUG 22038451Smsmith if (debug) 22138451Smsmith printf("subnet mask (%s) bad\n", intoa(smask)); 22238451Smsmith#endif 22338451Smsmith smask = 0; 22438451Smsmith } 22538451Smsmith 22638451Smsmith /* Get subnet (or natural net) mask */ 22738451Smsmith netmask = nmask; 22838451Smsmith if (smask) 22938451Smsmith netmask = smask; 23038451Smsmith#ifdef BOOTP_DEBUG 23138451Smsmith if (debug) 23238451Smsmith printf("mask: %s\n", intoa(netmask)); 23338451Smsmith#endif 23438451Smsmith 23538451Smsmith /* We need a gateway if root is on a different net */ 23638451Smsmith if (!SAMENET(myip, rootip, netmask)) { 23738451Smsmith#ifdef BOOTP_DEBUG 23838451Smsmith if (debug) 23938451Smsmith printf("need gateway for root ip\n"); 24038451Smsmith#endif 24138451Smsmith } 24238451Smsmith 24338451Smsmith /* Toss gateway if on a different net */ 24438451Smsmith if (!SAMENET(myip, gateip, netmask)) { 24538451Smsmith#ifdef BOOTP_DEBUG 24638451Smsmith if (debug) 24738451Smsmith printf("gateway ip (%s) bad\n", inet_ntoa(gateip)); 24838451Smsmith#endif 24938451Smsmith gateip.s_addr = 0; 25038451Smsmith } 25138451Smsmith 25238451Smsmith /* Bump xid so next request will be unique. */ 25338451Smsmith ++d->xid; 25438451Smsmith} 25538451Smsmith 25638451Smsmith/* Transmit a bootp request */ 25738451Smsmithstatic ssize_t 25838451Smsmithbootpsend(d, pkt, len) 25992913Sobrien struct iodesc *d; 26092913Sobrien void *pkt; 26192913Sobrien size_t len; 26238451Smsmith{ 26392913Sobrien struct bootp *bp; 26438451Smsmith 26538451Smsmith#ifdef BOOTP_DEBUG 26638451Smsmith if (debug) 26738451Smsmith printf("bootpsend: d=%lx called.\n", (long)d); 26838451Smsmith#endif 26938451Smsmith 27038451Smsmith bp = pkt; 27138451Smsmith bp->bp_secs = htons((u_short)(getsecs() - bot)); 27238451Smsmith 27338451Smsmith#ifdef BOOTP_DEBUG 27438451Smsmith if (debug) 27538451Smsmith printf("bootpsend: calling sendudp\n"); 27638451Smsmith#endif 27738451Smsmith 27838451Smsmith return (sendudp(d, pkt, len)); 27938451Smsmith} 28038451Smsmith 28138451Smsmithstatic ssize_t 28238451Smsmithbootprecv(d, pkt, len, tleft) 28392913Sobrienstruct iodesc *d; 28492913Sobrienvoid *pkt; 28592913Sobriensize_t len; 28638451Smsmithtime_t tleft; 28738451Smsmith{ 28892913Sobrien ssize_t n; 28992913Sobrien struct bootp *bp; 29038451Smsmith 29138451Smsmith#ifdef BOOTP_DEBUGx 29238451Smsmith if (debug) 29338451Smsmith printf("bootp_recvoffer: called\n"); 29438451Smsmith#endif 29538451Smsmith 29638451Smsmith n = readudp(d, pkt, len, tleft); 29738451Smsmith if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE) 29838451Smsmith goto bad; 29938451Smsmith 30038451Smsmith bp = (struct bootp *)pkt; 30138451Smsmith 30238451Smsmith#ifdef BOOTP_DEBUG 30338451Smsmith if (debug) 30438451Smsmith printf("bootprecv: checked. bp = 0x%lx, n = %d\n", 30538451Smsmith (long)bp, (int)n); 30638451Smsmith#endif 30738451Smsmith if (bp->bp_xid != htonl(d->xid)) { 30838451Smsmith#ifdef BOOTP_DEBUG 30938451Smsmith if (debug) { 31038451Smsmith printf("bootprecv: expected xid 0x%lx, got 0x%x\n", 31138451Smsmith d->xid, ntohl(bp->bp_xid)); 31238451Smsmith } 31338451Smsmith#endif 31438451Smsmith goto bad; 31538451Smsmith } 31638451Smsmith 31738451Smsmith#ifdef BOOTP_DEBUG 31838451Smsmith if (debug) 31938451Smsmith printf("bootprecv: got one!\n"); 32038451Smsmith#endif 32138451Smsmith 32238451Smsmith /* Suck out vendor info */ 32338451Smsmith if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) { 32438451Smsmith if(vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)) != 0) 32538451Smsmith goto bad; 32638451Smsmith } 32738451Smsmith#ifdef BOOTP_VEND_CMU 32838451Smsmith else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0) 32938451Smsmith vend_cmu(bp->bp_vend); 33038451Smsmith#endif 33138451Smsmith else 33238451Smsmith printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend); 33338451Smsmith 33438451Smsmith return(n); 33538451Smsmithbad: 33638451Smsmith errno = 0; 33738451Smsmith return (-1); 33838451Smsmith} 33938451Smsmith 34038451Smsmithstatic int 34138451Smsmithvend_rfc1048(cp, len) 34292913Sobrien u_char *cp; 34338451Smsmith u_int len; 34438451Smsmith{ 34592913Sobrien u_char *ep; 34692913Sobrien int size; 34792913Sobrien u_char tag; 34838451Smsmith 34938451Smsmith#ifdef BOOTP_DEBUG 35038451Smsmith if (debug) 35138451Smsmith printf("vend_rfc1048 bootp info. len=%d\n", len); 35238451Smsmith#endif 35338451Smsmith ep = cp + len; 35438451Smsmith 35538451Smsmith /* Step over magic cookie */ 35638451Smsmith cp += sizeof(int); 35738451Smsmith 35838451Smsmith while (cp < ep) { 35938451Smsmith tag = *cp++; 36038451Smsmith size = *cp++; 36138451Smsmith if (tag == TAG_END) 36238451Smsmith break; 36338451Smsmith 36438451Smsmith if (tag == TAG_SUBNET_MASK) { 36538451Smsmith bcopy(cp, &smask, sizeof(smask)); 36638451Smsmith } 36738451Smsmith if (tag == TAG_GATEWAY) { 36838451Smsmith bcopy(cp, &gateip.s_addr, sizeof(gateip.s_addr)); 36938451Smsmith } 37038451Smsmith if (tag == TAG_SWAPSERVER) { 37138451Smsmith /* let it override bp_siaddr */ 37238451Smsmith bcopy(cp, &rootip.s_addr, sizeof(swapip.s_addr)); 37338451Smsmith } 37438451Smsmith if (tag == TAG_ROOTPATH) { 37538451Smsmith strncpy(rootpath, (char *)cp, sizeof(rootpath)); 37638451Smsmith rootpath[size] = '\0'; 37738451Smsmith } 37838451Smsmith if (tag == TAG_HOSTNAME) { 37938451Smsmith strncpy(hostname, (char *)cp, sizeof(hostname)); 38038451Smsmith hostname[size] = '\0'; 38138451Smsmith } 38238451Smsmith#ifdef SUPPORT_DHCP 38338451Smsmith if (tag == TAG_DHCP_MSGTYPE) { 38438451Smsmith if(*cp != expected_dhcpmsgtype) 38538451Smsmith return(-1); 38638451Smsmith dhcp_ok = 1; 38738451Smsmith } 38838451Smsmith if (tag == TAG_SERVERID) { 38938451Smsmith bcopy(cp, &dhcp_serverip.s_addr, 39038451Smsmith sizeof(dhcp_serverip.s_addr)); 39138451Smsmith } 39238451Smsmith#endif 39338451Smsmith cp += size; 39438451Smsmith } 39538451Smsmith return(0); 39638451Smsmith} 39738451Smsmith 39838451Smsmith#ifdef BOOTP_VEND_CMU 39938451Smsmithstatic void 40038451Smsmithvend_cmu(cp) 40138451Smsmith u_char *cp; 40238451Smsmith{ 40392913Sobrien struct cmu_vend *vp; 40438451Smsmith 40538451Smsmith#ifdef BOOTP_DEBUG 40638451Smsmith if (debug) 40738451Smsmith printf("vend_cmu bootp info.\n"); 40838451Smsmith#endif 40938451Smsmith vp = (struct cmu_vend *)cp; 41038451Smsmith 41138451Smsmith if (vp->v_smask.s_addr != 0) { 41238451Smsmith smask = vp->v_smask.s_addr; 41338451Smsmith } 41438451Smsmith if (vp->v_dgate.s_addr != 0) { 41538451Smsmith gateip = vp->v_dgate; 41638451Smsmith } 41738451Smsmith} 41838451Smsmith#endif 419