Home | History | Annotate | Line # | Download | only in libsa
bootp.c revision 1.2
      1 /*	$NetBSD: bootp.c,v 1.2 1994/10/26 05:44:38 cgd Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1992 Regents of the University of California.
      5  * All rights reserved.
      6  *
      7  * This software was developed by the Computer Systems Engineering group
      8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
      9  * contributed to Berkeley.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *	This product includes software developed by the University of
     22  *	California, Lawrence Berkeley Laboratory and its contributors.
     23  * 4. Neither the name of the University nor the names of its contributors
     24  *    may be used to endorse or promote products derived from this software
     25  *    without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     37  * SUCH DAMAGE.
     38  *
     39  * @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp  (LBL)
     40  */
     41 
     42 #include <sys/types.h>
     43 #include <netinet/in.h>
     44 #include <netinet/in_systm.h>
     45 
     46 #include <string.h>
     47 
     48 #include "stand.h"
     49 #include "net.h"
     50 #include "netif.h"
     51 #include "bootp.h"
     52 
     53 static n_long	nmask, smask;
     54 
     55 static time_t	bot;
     56 
     57 static	char vm_rfc1048[4] = VM_RFC1048;
     58 static	char vm_cmu[4] = VM_CMU;
     59 
     60 /* Local forwards */
     61 static	int bootpsend __P((struct iodesc *, void *, int));
     62 static	int bootprecv __P((struct iodesc*, void *, int));
     63 static	void vend_cmu __P((u_char *));
     64 static	void vend_rfc1048 __P((u_char *, u_int));
     65 
     66 /* Fetch required bootp infomation */
     67 void
     68 bootp(sock)
     69 	int sock;
     70 {
     71 	struct iodesc *d;
     72 	register struct bootp *bp;
     73 	register void *pkt;
     74 	struct {
     75 		u_char header[HEADER_SIZE];
     76 		struct bootp wbootp;
     77 	} wbuf;
     78 	union {
     79 		u_char buffer[RECV_SIZE];
     80 		struct {
     81 			u_char header[HEADER_SIZE];
     82 			struct bootp xrbootp;
     83 		}xrbuf;
     84 #define rbootp  xrbuf.xrbootp
     85 	} rbuf;
     86 
     87 #ifdef BOOTP_DEBUG
     88  	if (debug)
     89 		printf("bootp: socket=%d\n", sock);
     90 #endif
     91 	if (!bot)
     92 		bot = getsecs();
     93 
     94 	if (!(d = socktodesc(sock))) {
     95 		printf("bootp: bad socket. %d\n", sock);
     96 		return;
     97 	}
     98 #ifdef BOOTP_DEBUG
     99  	if (debug)
    100 		printf("bootp: d=%x\n", (u_int)d);
    101 #endif
    102 	bp = &wbuf.wbootp;
    103 	pkt = &rbuf.rbootp;
    104 	pkt -= HEADER_SIZE;
    105 
    106 	bzero(bp, sizeof(*bp));
    107 
    108 	bp->bp_op = BOOTREQUEST;
    109 	bp->bp_htype = 1;		/* 10Mb Ethernet (48 bits) */
    110 	bp->bp_hlen = 6;
    111 	MACPY(d->myea, bp->bp_chaddr);
    112 
    113 	d->xid = 0;
    114 	d->myip = myip;
    115 	d->myport = IPPORT_BOOTPC;
    116 	d->destip = INADDR_BROADCAST;
    117 	d->destport = IPPORT_BOOTPS;
    118 
    119 	(void)sendrecv(d,
    120 		       bootpsend, bp, sizeof(*bp),
    121 		       bootprecv, pkt, RECV_SIZE);
    122 }
    123 
    124 /* Transmit a bootp request */
    125 static int
    126 bootpsend(d, pkt, len)
    127 	register struct iodesc *d;
    128 	register void *pkt;
    129 	register int len;
    130 {
    131 	register struct bootp *bp;
    132 
    133 #ifdef BOOTP_DEBUG
    134 	if (debug)
    135 		printf("bootpsend: d=%x called.\n", (u_int)d);
    136 #endif
    137 	bp = pkt;
    138 	bzero(bp->bp_file, sizeof(bp->bp_file));
    139 	bcopy(vm_rfc1048, bp->bp_vend, sizeof(long));
    140 	bp->bp_xid = d->xid;
    141 	bp->bp_secs = (u_long)(getsecs() - bot);
    142 #ifdef BOOTP_DEBUG
    143 	if (debug)
    144 	    printf("bootpsend: calling sendudp\n");
    145 #endif
    146 	return (sendudp(d, pkt, len));
    147 }
    148 
    149 /* Returns 0 if this is the packet we're waiting for else -1 (and errno == 0) */
    150 static int
    151 bootprecv(d, pkt, len)
    152 	register struct iodesc *d;
    153 	register void *pkt;
    154 	int len;
    155 {
    156 	register struct bootp *bp;
    157 
    158 #ifdef BOOTP_DEBUG
    159 	if (debug)
    160 	    printf("bootprecv: called\n");
    161 #endif
    162 	bp = (struct bootp *)checkudp(d, pkt, &len);
    163 #ifdef BOOTP_DEBUG
    164 	if (debug)
    165 		printf("bootprecv: checked.  bp = 0x%x, len = %d\n",
    166 		    (unsigned)bp, len);
    167 #endif
    168 	if (bp == NULL || len < sizeof(*bp) || bp->bp_xid != d->xid) {
    169 #ifdef BOOTP_DEBUG
    170 		if (debug) {
    171 			printf("bootprecv: not for us.\n");
    172 			if (bp == NULL)
    173 				printf("bootprecv: bp null\n");
    174 			else {
    175 				if (len < sizeof(*bp))
    176 					printf("bootprecv: expected %d bytes, got %d\n",
    177 					    sizeof(*bp), len);
    178 				if (bp->bp_xid != d->xid)
    179 					printf("bootprecv: expected xid 0x%x, got 0x%x\n",
    180 					    d->xid, bp->bp_xid);
    181 			}
    182 		}
    183 #endif
    184 		errno = 0;
    185 		return (-1);
    186 	}
    187 
    188 	/* Bump xid so next request will be unique */
    189 	++d->xid;
    190 
    191 #ifdef BOOTP_DEBUG
    192 	if (debug)
    193 	    printf("bootprecv: got one!\n");
    194 #endif
    195 
    196 	/* Pick up our ip address (and natural netmask) */
    197 	myip = d->myip = ntohl(bp->bp_yiaddr.s_addr);
    198 #ifdef BOOTP_DEBUG
    199 	if (debug)
    200 		printf("our ip address is %s\n", intoa(d->myip));
    201 #endif
    202 	if (IN_CLASSA(d->myip))
    203 		nmask = IN_CLASSA_NET;
    204 	else if (IN_CLASSB(d->myip))
    205 		nmask = IN_CLASSB_NET;
    206 	else
    207 		nmask = IN_CLASSC_NET;
    208 #ifdef BOOTP_DEBUG
    209 	if (debug)
    210 		printf("'native netmask' is %s\n", intoa(nmask));
    211 #endif
    212 
    213 	/* Pick up root or swap server address and file spec */
    214 	if (bp->bp_siaddr.s_addr != 0) {
    215 		rootip = ntohl(bp->bp_siaddr.s_addr);
    216 	}
    217 	if (bp->bp_file[0] != '\0') {
    218 		strncpy(bootfile, (char *)bp->bp_file,
    219 			sizeof(bootfile));
    220 		bootfile[sizeof(bootfile) - 1] = '\0';
    221 	}
    222 
    223 	/* Suck out vendor info */
    224 	if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0)
    225 		vend_cmu(bp->bp_vend);
    226 	else if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0)
    227 		vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend));
    228 	else
    229 		printf("bootprecv: unknown vendor 0x%x\n", (int)bp->bp_vend);
    230 
    231 	/* Check subnet mask against net mask; toss if bogus */
    232 	if ((nmask & smask) != nmask) {
    233 #ifdef BOOTP_DEBUG
    234 		if (debug)
    235 			printf("subnet mask (%s) bad\n", intoa(smask));
    236 #endif
    237 		smask = 0;
    238 	}
    239 
    240 	/* Get subnet (or natural net) mask */
    241 	mask = nmask;
    242 	if (smask)
    243 		mask = smask;
    244 #ifdef BOOTP_DEBUG
    245 	if (debug)
    246 		printf("mask: %s\n", intoa(mask));
    247 #endif
    248 
    249 	/* We need a gateway if root or swap is on a different net */
    250 	if (!SAMENET(d->myip, rootip, mask)) {
    251 #ifdef BOOTP_DEBUG
    252 		if (debug)
    253 			printf("need gateway for root ip\n");
    254 #endif
    255 	}
    256 	if (!SAMENET(d->myip, swapip, mask)) {
    257 #ifdef BOOTP_DEBUG
    258 		if (debug)
    259 			printf("need gateway for swap ip\n");
    260 #endif
    261 	}
    262 
    263 	/* Toss gateway if on a different net */
    264 	if (!SAMENET(d->myip, gateip, mask)) {
    265 #ifdef BOOTP_DEBUG
    266 		if (debug)
    267 			printf("gateway ip (%s) bad\n", intoa(gateip));
    268 #endif
    269 		gateip = 0;
    270 	}
    271 	return (0);
    272 }
    273 
    274 static void
    275 vend_cmu(cp)
    276 	u_char *cp;
    277 {
    278 	register struct cmu_vend *vp;
    279 
    280 #ifdef BOOTP_DEBUG
    281 	if (debug)
    282 		printf("vend_cmu bootp info.\n");
    283 #endif
    284 	vp = (struct cmu_vend *)cp;
    285 
    286 	if (vp->v_smask.s_addr != 0) {
    287 		smask = ntohl(vp->v_smask.s_addr);
    288 	}
    289 	if (vp->v_dgate.s_addr != 0) {
    290 		gateip = ntohl(vp->v_dgate.s_addr);
    291 	}
    292 }
    293 
    294 static void
    295 vend_rfc1048(cp, len)
    296 	register u_char *cp;
    297 	u_int len;
    298 {
    299 	register u_char *ep;
    300 	register int size;
    301 	register u_char tag;
    302 
    303 #ifdef BOOTP_DEBUG
    304 	if (debug)
    305 		printf("vend_rfc1048 bootp info. len=%d\n", len);
    306 #endif
    307 	ep = cp + len;
    308 
    309 	/* Step over magic cookie */
    310 	cp += sizeof(long);
    311 
    312 	while (cp < ep) {
    313 		tag = *cp++;
    314 		size = *cp++;
    315 		if (tag == TAG_END)
    316 			break;
    317 
    318 		if (tag == TAG_SUBNET_MASK) {
    319 			bcopy(cp, &smask, sizeof(smask));
    320 			smask = ntohl(smask);
    321 		}
    322 		if (tag == TAG_GATEWAY) {
    323 			bcopy(cp, &gateip, sizeof(gateip));
    324 			gateip = ntohl(gateip);
    325 		}
    326 		if (tag == TAG_SWAPSERVER) {
    327 			bcopy(cp, &swapip, sizeof(swapip));
    328 			swapip = ntohl(swapip);
    329 		}
    330 		if (tag == TAG_DOMAIN_SERVER) {
    331 			bcopy(cp, &nameip, sizeof(nameip));
    332 			nameip = ntohl(nameip);
    333 		}
    334 		if (tag == TAG_ROOTPATH) {
    335 			strncpy(rootpath, cp, sizeof(rootpath));
    336 			rootpath[size] = '\0';
    337 		}
    338 		if (tag == TAG_HOSTNAME) {
    339 			strncpy(hostname, cp, sizeof(hostname));
    340 			hostname[size] = '\0';
    341 		}
    342 		if (tag == TAG_DOMAINNAME) {
    343 			strncpy(domainname, cp, sizeof(domainname));
    344 			domainname[size] = '\0';
    345 		}
    346 		cp += size;
    347 	}
    348 }
    349