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 * 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)
40 * $FreeBSD: src/lib/libstand/bootp.c,v 1.1.1.1.6.2 2000/09/20 18:37:25 ps Exp $
41 * $DragonFly: src/lib/libstand/bootp.c,v 1.5 2005/12/11 02:27:26 swildner Exp $
44 #include <sys/param.h>
45 #include <netinet/in.h>
46 #include <netinet/in_systm.h>
59 struct in_addr servip
;
61 static n_long nmask
, smask
;
65 static char vm_rfc1048
[4] = VM_RFC1048
;
67 static char vm_cmu
[4] = VM_CMU
;
71 static ssize_t
bootpsend(struct iodesc
*, void *, size_t);
72 static ssize_t
bootprecv(struct iodesc
*, void *, size_t, time_t);
73 static int vend_rfc1048(u_char
*, u_int
);
75 static void vend_cmu(u_char
*);
79 static char expected_dhcpmsgtype
= -1, dhcp_ok
;
80 struct in_addr dhcp_serverip
;
83 /* Fetch required bootp infomation */
85 bootp(int sock
, int flag
)
90 u_char header
[HEADER_SIZE
];
94 u_char header
[HEADER_SIZE
];
100 printf("bootp: socket=%d\n", sock
);
105 if (!(d
= socktodesc(sock
))) {
106 printf("bootp: bad socket. %d\n", sock
);
111 printf("bootp: d=%lx\n", (long)d
);
115 bzero(bp
, sizeof(*bp
));
117 bp
->bp_op
= BOOTREQUEST
;
118 bp
->bp_htype
= 1; /* 10Mb Ethernet (48 bits) */
120 bp
->bp_xid
= htonl(d
->xid
);
121 MACPY(d
->myea
, bp
->bp_chaddr
);
122 strncpy(bp
->bp_file
, bootfile
, sizeof(bp
->bp_file
));
123 bcopy(vm_rfc1048
, bp
->bp_vend
, sizeof(vm_rfc1048
));
125 bp
->bp_vend
[4] = TAG_DHCP_MSGTYPE
;
127 bp
->bp_vend
[6] = DHCPDISCOVER
;
130 * If we are booting from PXE, we want to send the string
131 * 'PXEClient' to the DHCP server so you have the option of
132 * only responding to PXE aware dhcp requests.
134 if (flag
& BOOTP_PXE
) {
135 bp
->bp_vend
[7] = TAG_CLASSID
;
137 bcopy("PXEClient", &bp
->bp_vend
[9], 9);
138 bp
->bp_vend
[18] = TAG_END
;
140 bp
->bp_vend
[7] = TAG_END
;
142 bp
->bp_vend
[4] = TAG_END
;
145 d
->myip
.s_addr
= INADDR_ANY
;
146 d
->myport
= htons(IPPORT_BOOTPC
);
147 d
->destip
.s_addr
= INADDR_BROADCAST
;
148 d
->destport
= htons(IPPORT_BOOTPS
);
151 expected_dhcpmsgtype
= DHCPOFFER
;
156 bootpsend
, bp
, sizeof(*bp
),
157 bootprecv
, &rbuf
.rbootp
, sizeof(rbuf
.rbootp
))
159 printf("bootp: no reply\n");
166 bp
->bp_vend
[6] = DHCPREQUEST
;
167 bp
->bp_vend
[7] = TAG_REQ_ADDR
;
169 bcopy(&rbuf
.rbootp
.bp_yiaddr
, &bp
->bp_vend
[9], 4);
170 bp
->bp_vend
[13] = TAG_SERVERID
;
172 bcopy(&dhcp_serverip
.s_addr
, &bp
->bp_vend
[15], 4);
173 bp
->bp_vend
[19] = TAG_LEASETIME
;
175 leasetime
= htonl(300);
176 bcopy(&leasetime
, &bp
->bp_vend
[21], 4);
177 if (flag
& BOOTP_PXE
) {
178 bp
->bp_vend
[25] = TAG_CLASSID
;
180 bcopy("PXEClient", &bp
->bp_vend
[27], 9);
181 bp
->bp_vend
[36] = TAG_END
;
183 bp
->bp_vend
[25] = TAG_END
;
185 expected_dhcpmsgtype
= DHCPACK
;
188 bootpsend
, bp
, sizeof(*bp
),
189 bootprecv
, &rbuf
.rbootp
, sizeof(rbuf
.rbootp
))
191 printf("DHCPREQUEST failed\n");
197 myip
= d
->myip
= rbuf
.rbootp
.bp_yiaddr
;
198 servip
= rbuf
.rbootp
.bp_siaddr
;
199 if(rootip
.s_addr
== INADDR_ANY
) rootip
= servip
;
200 bcopy(rbuf
.rbootp
.bp_file
, bootfile
, sizeof(bootfile
));
201 bootfile
[sizeof(bootfile
) - 1] = '\0';
203 if (IN_CLASSA(ntohl(myip
.s_addr
)))
204 nmask
= htonl(IN_CLASSA_NET
);
205 else if (IN_CLASSB(ntohl(myip
.s_addr
)))
206 nmask
= htonl(IN_CLASSB_NET
);
208 nmask
= htonl(IN_CLASSC_NET
);
211 printf("'native netmask' is %s\n", intoa(nmask
));
214 /* Check subnet mask against net mask; toss if bogus */
215 if ((nmask
& smask
) != nmask
) {
218 printf("subnet mask (%s) bad\n", intoa(smask
));
223 /* Get subnet (or natural net) mask */
229 printf("mask: %s\n", intoa(netmask
));
232 /* We need a gateway if root is on a different net */
233 if (!SAMENET(myip
, rootip
, netmask
)) {
236 printf("need gateway for root ip\n");
240 /* Toss gateway if on a different net */
241 if (!SAMENET(myip
, gateip
, netmask
)) {
244 printf("gateway ip (%s) bad\n", inet_ntoa(gateip
));
249 /* Bump xid so next request will be unique. */
253 /* Transmit a bootp request */
255 bootpsend(struct iodesc
*d
, void *pkt
, size_t len
)
261 printf("bootpsend: d=%lx called.\n", (long)d
);
265 bp
->bp_secs
= htons((u_short
)(getsecs() - bot
));
269 printf("bootpsend: calling sendudp\n");
272 return (sendudp(d
, pkt
, len
));
276 bootprecv(struct iodesc
*d
, void *pkt
, size_t len
, time_t tleft
)
283 printf("bootp_recvoffer: called\n");
286 n
= readudp(d
, pkt
, len
, tleft
);
287 if (n
== -1 || n
< sizeof(struct bootp
) - BOOTP_VENDSIZE
)
290 bp
= (struct bootp
*)pkt
;
294 printf("bootprecv: checked. bp = 0x%lx, n = %d\n",
297 if (bp
->bp_xid
!= htonl(d
->xid
)) {
300 printf("bootprecv: expected xid 0x%lx, got 0x%x\n",
301 d
->xid
, ntohl(bp
->bp_xid
));
309 printf("bootprecv: got one!\n");
312 /* Suck out vendor info */
313 if (bcmp(vm_rfc1048
, bp
->bp_vend
, sizeof(vm_rfc1048
)) == 0) {
314 if(vend_rfc1048(bp
->bp_vend
, sizeof(bp
->bp_vend
)) != 0)
317 #ifdef BOOTP_VEND_CMU
318 else if (bcmp(vm_cmu
, bp
->bp_vend
, sizeof(vm_cmu
)) == 0)
319 vend_cmu(bp
->bp_vend
);
322 printf("bootprecv: unknown vendor 0x%lx\n", (long)bp
->bp_vend
);
331 vend_rfc1048(u_char
*cp
, u_int len
)
339 printf("vend_rfc1048 bootp info. len=%d\n", len
);
343 /* Step over magic cookie */
352 if (tag
== TAG_SUBNET_MASK
) {
353 bcopy(cp
, &smask
, sizeof(smask
));
355 if (tag
== TAG_GATEWAY
) {
356 bcopy(cp
, &gateip
.s_addr
, sizeof(gateip
.s_addr
));
358 if (tag
== TAG_SWAPSERVER
) {
359 /* let it override bp_siaddr */
360 bcopy(cp
, &rootip
.s_addr
, sizeof(swapip
.s_addr
));
362 if (tag
== TAG_ROOTPATH
) {
363 strncpy(rootpath
, (char *)cp
, sizeof(rootpath
));
364 rootpath
[size
] = '\0';
366 if (tag
== TAG_HOSTNAME
) {
367 strncpy(hostname
, (char *)cp
, sizeof(hostname
));
368 hostname
[size
] = '\0';
371 if (tag
== TAG_DHCP_MSGTYPE
) {
372 if(*cp
!= expected_dhcpmsgtype
)
376 if (tag
== TAG_SERVERID
) {
377 bcopy(cp
, &dhcp_serverip
.s_addr
,
378 sizeof(dhcp_serverip
.s_addr
));
386 #ifdef BOOTP_VEND_CMU
394 printf("vend_cmu bootp info.\n");
396 vp
= (struct cmu_vend
*)cp
;
398 if (vp
->v_smask
.s_addr
!= 0) {
399 smask
= vp
->v_smask
.s_addr
;
401 if (vp
->v_dgate
.s_addr
!= 0) {
402 gateip
= vp
->v_dgate
;