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