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