xref: /netbsd-src/sys/lib/libsa/bootp.c (revision ae9172d6cd9432a6a1a56760d86b32c57a66c39c)
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