1 /* $NetBSD: bootp.c,v 1.38 2011/05/11 16:23:40 zoltan Exp $ */
4 * Copyright (c) 1992 Regents of the University of California.
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.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
39 * @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp (LBL)
42 #include <sys/param.h>
43 #include <netinet/in.h>
44 #include <netinet/in_systm.h>
47 #include <lib/libkern/libkern.h>
56 struct in_addr servip
;
58 char linuxcmdline
[256];
59 #ifndef TAG_LINUX_CMDLINE
60 #define TAG_LINUX_CMDLINE 123
64 static n_long nmask
, smask
;
68 static char vm_rfc1048
[4] = VM_RFC1048
;
70 static char vm_cmu
[4] = VM_CMU
;
74 static ssize_t
bootpsend(struct iodesc
*, void *, size_t);
75 static ssize_t
bootprecv(struct iodesc
*, void *, size_t, saseconds_t
);
76 static int vend_rfc1048(u_char
*, u_int
);
78 static void vend_cmu(u_char
*);
82 static char expected_dhcpmsgtype
= -1, dhcp_ok
;
83 struct in_addr dhcp_serverip
;
87 * Boot programs can patch this at run-time to change the behavior
93 bootp_addvend(u_char
*area
)
99 *area
++ = TAG_PARAM_REQ
;
101 *area
++ = TAG_SUBNET_MASK
;
102 *area
++ = TAG_GATEWAY
;
103 *area
++ = TAG_HOSTNAME
;
104 *area
++ = TAG_DOMAINNAME
;
105 *area
++ = TAG_ROOTPATH
;
106 *area
++ = TAG_SWAPSERVER
;
108 /* Insert a NetBSD Vendor Class Identifier option. */
109 sprintf(vci
, "NetBSD:%s:libsa", MACHINE
);
110 vcilen
= strlen(vci
);
111 *area
++ = TAG_CLASSID
;
113 (void)memcpy(area
, vci
, vcilen
);
119 /* Fetch required bootp information */
126 u_char header
[UDP_TOTAL_HEADER_SIZE
];
130 u_char header
[UDP_TOTAL_HEADER_SIZE
];
137 printf("bootp: socket=%d\n", sock
);
142 if (!(d
= socktodesc(sock
))) {
143 printf("bootp: bad socket. %d\n", sock
);
148 printf("bootp: d=%lx\n", (long)d
);
152 (void)memset(bp
, 0, sizeof(*bp
));
154 bp
->bp_op
= BOOTREQUEST
;
155 bp
->bp_htype
= 1; /* 10Mb Ethernet (48 bits) */
157 bp
->bp_xid
= htonl(d
->xid
);
158 MACPY(d
->myea
, bp
->bp_chaddr
);
159 (void)strncpy((char *)bp
->bp_file
, bootfile
, sizeof(bp
->bp_file
));
160 (void)memcpy(bp
->bp_vend
, vm_rfc1048
, sizeof(vm_rfc1048
));
163 bp
->bp_vend
[index
++] = TAG_DHCP_MSGTYPE
;
164 bp
->bp_vend
[index
++] = 1;
165 bp
->bp_vend
[index
++] = DHCPDISCOVER
;
167 bootp_addvend(&bp
->bp_vend
[index
]);
169 d
->myip
.s_addr
= INADDR_ANY
;
170 d
->myport
= htons(IPPORT_BOOTPC
);
171 d
->destip
.s_addr
= INADDR_BROADCAST
;
172 d
->destport
= htons(IPPORT_BOOTPS
);
175 expected_dhcpmsgtype
= DHCPOFFER
;
180 bootpsend
, bp
, sizeof(*bp
),
181 bootprecv
, &rbuf
.rbootp
, sizeof(rbuf
.rbootp
))
183 printf("bootp: no reply\n");
191 bp
->bp_vend
[index
++] = DHCPREQUEST
;
192 bp
->bp_vend
[index
++] = TAG_REQ_ADDR
;
193 bp
->bp_vend
[index
++] = 4;
194 (void)memcpy(&bp
->bp_vend
[9], &rbuf
.rbootp
.bp_yiaddr
, 4);
196 bp
->bp_vend
[index
++] = TAG_SERVERID
;
197 bp
->bp_vend
[index
++] = 4;
198 (void)memcpy(&bp
->bp_vend
[index
], &dhcp_serverip
.s_addr
, 4);
200 bp
->bp_vend
[index
++] = TAG_LEASETIME
;
201 bp
->bp_vend
[index
++] = 4;
202 leasetime
= htonl(300);
203 (void)memcpy(&bp
->bp_vend
[index
], &leasetime
, 4);
205 bootp_addvend(&bp
->bp_vend
[index
]);
207 expected_dhcpmsgtype
= DHCPACK
;
210 bootpsend
, bp
, sizeof(*bp
),
211 bootprecv
, &rbuf
.rbootp
, sizeof(rbuf
.rbootp
))
213 printf("DHCPREQUEST failed\n");
219 myip
= d
->myip
= rbuf
.rbootp
.bp_yiaddr
;
220 servip
= rbuf
.rbootp
.bp_siaddr
;
221 if (rootip
.s_addr
== INADDR_ANY
)
223 (void)memcpy(bootfile
, rbuf
.rbootp
.bp_file
, sizeof(bootfile
));
224 bootfile
[sizeof(bootfile
) - 1] = '\0';
226 if (IN_CLASSA(myip
.s_addr
))
227 nmask
= IN_CLASSA_NET
;
228 else if (IN_CLASSB(myip
.s_addr
))
229 nmask
= IN_CLASSB_NET
;
231 nmask
= IN_CLASSC_NET
;
234 printf("'native netmask' is %s\n", intoa(nmask
));
237 /* Get subnet (or natural net) mask */
243 printf("mask: %s\n", intoa(netmask
));
246 /* We need a gateway if root is on a different net */
247 if (!SAMENET(myip
, rootip
, netmask
)) {
250 printf("need gateway for root ip\n");
254 /* Toss gateway if on a different net */
255 if (!SAMENET(myip
, gateip
, netmask
)) {
258 printf("gateway ip (%s) bad\n", inet_ntoa(gateip
));
265 printf("client addr: %s\n", inet_ntoa(myip
));
267 printf("subnet mask: %s\n", intoa(smask
));
268 if (gateip
.s_addr
!= 0)
269 printf("net gateway: %s\n", inet_ntoa(gateip
));
270 printf("server addr: %s\n", inet_ntoa(rootip
));
271 if (rootpath
[0] != '\0')
272 printf("server path: %s\n", rootpath
);
273 if (bootfile
[0] != '\0')
274 printf("file name: %s\n", bootfile
);
278 /* Bump xid so next request will be unique. */
282 /* Transmit a bootp request */
284 bootpsend(struct iodesc
*d
, void *pkt
, size_t len
)
290 printf("bootpsend: d=%lx called.\n", (long)d
);
294 bp
->bp_secs
= htons((u_short
)(getsecs() - bot
));
298 printf("bootpsend: calling sendudp\n");
301 return sendudp(d
, pkt
, len
);
305 bootprecv(struct iodesc
*d
, void *pkt
, size_t len
, saseconds_t tleft
)
312 printf("bootp_recvoffer: called\n");
315 n
= readudp(d
, pkt
, len
, tleft
);
316 if (n
== -1 || (size_t)n
< sizeof(struct bootp
) - BOOTP_VENDSIZE
)
319 bp
= (struct bootp
*)pkt
;
323 printf("bootprecv: checked. bp = 0x%lx, n = %d\n",
326 if (bp
->bp_xid
!= htonl(d
->xid
)) {
329 printf("bootprecv: expected xid 0x%lx, got 0x%x\n",
330 d
->xid
, ntohl(bp
->bp_xid
));
336 /* protect against bogus addresses sent by DHCP servers */
337 if (bp
->bp_yiaddr
.s_addr
== INADDR_ANY
||
338 bp
->bp_yiaddr
.s_addr
== INADDR_BROADCAST
)
343 printf("bootprecv: got one!\n");
346 /* Suck out vendor info */
347 if (memcmp(vm_rfc1048
, bp
->bp_vend
, sizeof(vm_rfc1048
)) == 0) {
348 if (vend_rfc1048(bp
->bp_vend
, sizeof(bp
->bp_vend
)) != 0)
351 #ifdef BOOTP_VEND_CMU
352 else if (memcmp(vm_cmu
, bp
->bp_vend
, sizeof(vm_cmu
)) == 0)
353 vend_cmu(bp
->bp_vend
);
356 printf("bootprecv: unknown vendor 0x%lx\n", (long)bp
->bp_vend
);
365 vend_rfc1048(u_char
*cp
, u_int len
)
373 printf("vend_rfc1048 bootp info. len=%d\n", len
);
377 /* Step over magic cookie */
386 if (tag
== TAG_SUBNET_MASK
&& size
>= sizeof(smask
)) {
387 (void)memcpy(&smask
, cp
, sizeof(smask
));
389 if (tag
== TAG_GATEWAY
&& size
>= sizeof(gateip
.s_addr
)) {
390 (void)memcpy(&gateip
.s_addr
, cp
, sizeof(gateip
.s_addr
));
392 if (tag
== TAG_SWAPSERVER
&& size
>= sizeof(rootip
.s_addr
)) {
393 /* let it override bp_siaddr */
394 (void)memcpy(&rootip
.s_addr
, cp
, sizeof(rootip
.s_addr
));
396 if (tag
== TAG_ROOTPATH
&& size
< sizeof(rootpath
)) {
397 strncpy(rootpath
, (char *)cp
, sizeof(rootpath
));
398 rootpath
[size
] = '\0';
400 if (tag
== TAG_HOSTNAME
&& size
< sizeof(hostname
)) {
401 strncpy(hostname
, (char *)cp
, sizeof(hostname
));
402 hostname
[size
] = '\0';
405 if (tag
== TAG_DHCP_MSGTYPE
) {
406 if (*cp
!= expected_dhcpmsgtype
)
410 if (tag
== TAG_SERVERID
&&
411 size
>= sizeof(dhcp_serverip
.s_addr
))
413 (void)memcpy(&dhcp_serverip
.s_addr
, cp
,
414 sizeof(dhcp_serverip
.s_addr
));
418 if (tag
== TAG_LINUX_CMDLINE
&& size
< sizeof(linuxcmdline
)) {
419 strncpy(linuxcmdline
, (char *)cp
, sizeof(linuxcmdline
));
420 linuxcmdline
[size
] = '\0';
428 #ifdef BOOTP_VEND_CMU
436 printf("vend_cmu bootp info.\n");
438 vp
= (struct cmu_vend
*)cp
;
440 if (vp
->v_smask
.s_addr
!= 0) {
441 smask
= vp
->v_smask
.s_addr
;
443 if (vp
->v_dgate
.s_addr
!= 0) {
444 gateip
= vp
->v_dgate
;