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