1 /* $NetBSD: bootp.c,v 1.14 1998/02/16 11:10:54 drochner 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 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp (LBL)
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
41 #include <sys/types.h>
42 #include <netinet/in.h>
43 #include <netinet/in_systm.h>
56 struct in_addr servip
;
58 static n_long nmask
, smask
;
62 static char vm_rfc1048
[4] = VM_RFC1048
;
64 static char vm_cmu
[4] = VM_CMU
;
68 static ssize_t
bootpsend(struct iodesc
*, void *, size_t);
69 static ssize_t
bootprecv(struct iodesc
*, void *, size_t, time_t);
70 static int vend_rfc1048(u_char
*, u_int
);
72 static void vend_cmu(u_char
*);
76 static char expected_dhcpmsgtype
= -1, dhcp_ok
;
77 struct in_addr dhcp_serverip
;
80 /* Fetch required bootp infomation */
89 u_char header
[HEADER_SIZE
];
93 u_char header
[HEADER_SIZE
];
99 printf("bootp: socket=%d\n", sock
);
104 if (!(d
= socktodesc(sock
))) {
105 printf("bootp: bad socket. %d\n", sock
);
110 printf("bootp: d=%lx\n", (long)d
);
114 bzero(bp
, sizeof(*bp
));
116 bp
->bp_op
= BOOTREQUEST
;
117 bp
->bp_htype
= 1; /* 10Mb Ethernet (48 bits) */
119 bp
->bp_xid
= htonl(d
->xid
);
120 MACPY(d
->myea
, bp
->bp_chaddr
);
121 strncpy(bp
->bp_file
, bootfile
, sizeof(bp
->bp_file
));
122 bcopy(vm_rfc1048
, bp
->bp_vend
, sizeof(vm_rfc1048
));
124 bp
->bp_vend
[4] = TAG_DHCP_MSGTYPE
;
126 bp
->bp_vend
[6] = DHCPDISCOVER
;
129 * If we are booting from PXE, we want to send the string
130 * 'PXEClient' to the DHCP server so you have the option of
131 * only responding to PXE aware dhcp requests.
133 if (flag
& BOOTP_PXE
) {
134 bp
->bp_vend
[7] = TAG_CLASSID
;
136 bcopy("PXEClient", &bp
->bp_vend
[9], 9);
137 bp
->bp_vend
[18] = TAG_END
;
139 bp
->bp_vend
[7] = TAG_END
;
141 bp
->bp_vend
[4] = TAG_END
;
144 d
->myip
.s_addr
= INADDR_ANY
;
145 d
->myport
= htons(IPPORT_BOOTPC
);
146 d
->destip
.s_addr
= INADDR_BROADCAST
;
147 d
->destport
= htons(IPPORT_BOOTPS
);
150 expected_dhcpmsgtype
= DHCPOFFER
;
155 bootpsend
, bp
, sizeof(*bp
),
156 bootprecv
, &rbuf
.rbootp
, sizeof(rbuf
.rbootp
))
158 printf("bootp: no reply\n");
165 bp
->bp_vend
[6] = DHCPREQUEST
;
166 bp
->bp_vend
[7] = TAG_REQ_ADDR
;
168 bcopy(&rbuf
.rbootp
.bp_yiaddr
, &bp
->bp_vend
[9], 4);
169 bp
->bp_vend
[13] = TAG_SERVERID
;
171 bcopy(&dhcp_serverip
.s_addr
, &bp
->bp_vend
[15], 4);
172 bp
->bp_vend
[19] = TAG_LEASETIME
;
174 leasetime
= htonl(300);
175 bcopy(&leasetime
, &bp
->bp_vend
[21], 4);
176 if (flag
& BOOTP_PXE
) {
177 bp
->bp_vend
[25] = TAG_CLASSID
;
179 bcopy("PXEClient", &bp
->bp_vend
[27], 9);
180 bp
->bp_vend
[36] = TAG_END
;
182 bp
->bp_vend
[25] = TAG_END
;
184 expected_dhcpmsgtype
= DHCPACK
;
187 bootpsend
, bp
, sizeof(*bp
),
188 bootprecv
, &rbuf
.rbootp
, sizeof(rbuf
.rbootp
))
190 printf("DHCPREQUEST failed\n");
196 myip
= d
->myip
= rbuf
.rbootp
.bp_yiaddr
;
197 servip
= rbuf
.rbootp
.bp_siaddr
;
198 if(rootip
.s_addr
== INADDR_ANY
) rootip
= servip
;
199 bcopy(rbuf
.rbootp
.bp_file
, bootfile
, sizeof(bootfile
));
200 bootfile
[sizeof(bootfile
) - 1] = '\0';
202 if (IN_CLASSA(ntohl(myip
.s_addr
)))
203 nmask
= htonl(IN_CLASSA_NET
);
204 else if (IN_CLASSB(ntohl(myip
.s_addr
)))
205 nmask
= htonl(IN_CLASSB_NET
);
207 nmask
= htonl(IN_CLASSC_NET
);
210 printf("'native netmask' is %s\n", intoa(nmask
));
213 /* Check subnet mask against net mask; toss if bogus */
214 if ((nmask
& smask
) != nmask
) {
217 printf("subnet mask (%s) bad\n", intoa(smask
));
222 /* Get subnet (or natural net) mask */
228 printf("mask: %s\n", intoa(netmask
));
231 /* We need a gateway if root is on a different net */
232 if (!SAMENET(myip
, rootip
, netmask
)) {
235 printf("need gateway for root ip\n");
239 /* Toss gateway if on a different net */
240 if (!SAMENET(myip
, gateip
, netmask
)) {
243 printf("gateway ip (%s) bad\n", inet_ntoa(gateip
));
248 /* Bump xid so next request will be unique. */
252 /* Transmit a bootp request */
254 bootpsend(d
, pkt
, len
)
263 printf("bootpsend: d=%lx called.\n", (long)d
);
267 bp
->bp_secs
= htons((u_short
)(getsecs() - bot
));
271 printf("bootpsend: calling sendudp\n");
274 return (sendudp(d
, pkt
, len
));
278 bootprecv(d
, pkt
, len
, tleft
)
289 printf("bootp_recvoffer: called\n");
292 n
= readudp(d
, pkt
, len
, tleft
);
293 if (n
== -1 || n
< sizeof(struct bootp
) - BOOTP_VENDSIZE
)
296 bp
= (struct bootp
*)pkt
;
300 printf("bootprecv: checked. bp = 0x%lx, n = %d\n",
303 if (bp
->bp_xid
!= htonl(d
->xid
)) {
306 printf("bootprecv: expected xid 0x%lx, got 0x%x\n",
307 d
->xid
, ntohl(bp
->bp_xid
));
315 printf("bootprecv: got one!\n");
318 /* Suck out vendor info */
319 if (bcmp(vm_rfc1048
, bp
->bp_vend
, sizeof(vm_rfc1048
)) == 0) {
320 if(vend_rfc1048(bp
->bp_vend
, sizeof(bp
->bp_vend
)) != 0)
323 #ifdef BOOTP_VEND_CMU
324 else if (bcmp(vm_cmu
, bp
->bp_vend
, sizeof(vm_cmu
)) == 0)
325 vend_cmu(bp
->bp_vend
);
328 printf("bootprecv: unknown vendor 0x%lx\n", (long)bp
->bp_vend
);
337 vend_rfc1048(cp
, len
)
347 printf("vend_rfc1048 bootp info. len=%d\n", len
);
351 /* Step over magic cookie */
360 if (tag
== TAG_SUBNET_MASK
) {
361 bcopy(cp
, &smask
, sizeof(smask
));
363 if (tag
== TAG_GATEWAY
) {
364 bcopy(cp
, &gateip
.s_addr
, sizeof(gateip
.s_addr
));
366 if (tag
== TAG_SWAPSERVER
) {
367 /* let it override bp_siaddr */
368 bcopy(cp
, &rootip
.s_addr
, sizeof(swapip
.s_addr
));
370 if (tag
== TAG_ROOTPATH
) {
371 strncpy(rootpath
, (char *)cp
, sizeof(rootpath
));
372 rootpath
[size
] = '\0';
374 if (tag
== TAG_HOSTNAME
) {
375 strncpy(hostname
, (char *)cp
, sizeof(hostname
));
376 hostname
[size
] = '\0';
379 if (tag
== TAG_DHCP_MSGTYPE
) {
380 if(*cp
!= expected_dhcpmsgtype
)
384 if (tag
== TAG_SERVERID
) {
385 bcopy(cp
, &dhcp_serverip
.s_addr
,
386 sizeof(dhcp_serverip
.s_addr
));
394 #ifdef BOOTP_VEND_CMU
403 printf("vend_cmu bootp info.\n");
405 vp
= (struct cmu_vend
*)cp
;
407 if (vp
->v_smask
.s_addr
!= 0) {
408 smask
= vp
->v_smask
.s_addr
;
410 if (vp
->v_dgate
.s_addr
!= 0) {
411 gateip
= vp
->v_dgate
;