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. 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)
36 * $FreeBSD: src/lib/libstand/bootp.c,v 1.1.1.1.6.2 2000/09/20 18:37:25 ps Exp $
37 * $DragonFly: src/lib/libstand/bootp.c,v 1.5 2005/12/11 02:27:26 swildner Exp $
40 #include <sys/param.h>
41 #include <netinet/in.h>
42 #include <netinet/in_systm.h>
55 struct in_addr servip
;
57 static n_long nmask
, smask
;
61 static char vm_rfc1048
[4] = VM_RFC1048
;
63 static char vm_cmu
[4] = VM_CMU
;
67 static ssize_t
bootpsend(struct iodesc
*, void *, size_t);
68 static ssize_t
bootprecv(struct iodesc
*, void *, size_t, time_t);
69 static int vend_rfc1048(u_char
*, u_int
);
71 static void vend_cmu(u_char
*);
75 static char expected_dhcpmsgtype
= -1, dhcp_ok
;
76 struct in_addr dhcp_serverip
;
79 /* Fetch required bootp infomation */
81 bootp(int sock
, int flag
)
86 u_char header
[HEADER_SIZE
];
90 u_char header
[HEADER_SIZE
];
96 printf("bootp: socket=%d\n", sock
);
101 if (!(d
= socktodesc(sock
))) {
102 printf("bootp: bad socket. %d\n", sock
);
107 printf("bootp: d=%lx\n", (long)d
);
111 bzero(bp
, sizeof(*bp
));
113 bp
->bp_op
= BOOTREQUEST
;
114 bp
->bp_htype
= 1; /* 10Mb Ethernet (48 bits) */
116 bp
->bp_xid
= htonl(d
->xid
);
117 MACPY(d
->myea
, bp
->bp_chaddr
);
118 strncpy(bp
->bp_file
, bootfile
, sizeof(bp
->bp_file
));
119 bcopy(vm_rfc1048
, bp
->bp_vend
, sizeof(vm_rfc1048
));
121 bp
->bp_vend
[4] = TAG_DHCP_MSGTYPE
;
123 bp
->bp_vend
[6] = DHCPDISCOVER
;
126 * If we are booting from PXE, we want to send the string
127 * 'PXEClient' to the DHCP server so you have the option of
128 * only responding to PXE aware dhcp requests.
130 if (flag
& BOOTP_PXE
) {
131 bp
->bp_vend
[7] = TAG_CLASSID
;
133 bcopy("PXEClient", &bp
->bp_vend
[9], 9);
134 bp
->bp_vend
[18] = TAG_END
;
136 bp
->bp_vend
[7] = TAG_END
;
138 bp
->bp_vend
[4] = TAG_END
;
141 d
->myip
.s_addr
= INADDR_ANY
;
142 d
->myport
= htons(IPPORT_BOOTPC
);
143 d
->destip
.s_addr
= INADDR_BROADCAST
;
144 d
->destport
= htons(IPPORT_BOOTPS
);
147 expected_dhcpmsgtype
= DHCPOFFER
;
152 bootpsend
, bp
, sizeof(*bp
),
153 bootprecv
, &rbuf
.rbootp
, sizeof(rbuf
.rbootp
))
155 printf("bootp: no reply\n");
162 bp
->bp_vend
[6] = DHCPREQUEST
;
163 bp
->bp_vend
[7] = TAG_REQ_ADDR
;
165 bcopy(&rbuf
.rbootp
.bp_yiaddr
, &bp
->bp_vend
[9], 4);
166 bp
->bp_vend
[13] = TAG_SERVERID
;
168 bcopy(&dhcp_serverip
.s_addr
, &bp
->bp_vend
[15], 4);
169 bp
->bp_vend
[19] = TAG_LEASETIME
;
171 leasetime
= htonl(300);
172 bcopy(&leasetime
, &bp
->bp_vend
[21], 4);
173 if (flag
& BOOTP_PXE
) {
174 bp
->bp_vend
[25] = TAG_CLASSID
;
176 bcopy("PXEClient", &bp
->bp_vend
[27], 9);
177 bp
->bp_vend
[36] = TAG_END
;
179 bp
->bp_vend
[25] = TAG_END
;
181 expected_dhcpmsgtype
= DHCPACK
;
184 bootpsend
, bp
, sizeof(*bp
),
185 bootprecv
, &rbuf
.rbootp
, sizeof(rbuf
.rbootp
))
187 printf("DHCPREQUEST failed\n");
193 myip
= d
->myip
= rbuf
.rbootp
.bp_yiaddr
;
194 servip
= rbuf
.rbootp
.bp_siaddr
;
195 if(rootip
.s_addr
== INADDR_ANY
) rootip
= servip
;
196 bcopy(rbuf
.rbootp
.bp_file
, bootfile
, sizeof(bootfile
));
197 bootfile
[sizeof(bootfile
) - 1] = '\0';
199 if (IN_CLASSA(ntohl(myip
.s_addr
)))
200 nmask
= htonl(IN_CLASSA_NET
);
201 else if (IN_CLASSB(ntohl(myip
.s_addr
)))
202 nmask
= htonl(IN_CLASSB_NET
);
204 nmask
= htonl(IN_CLASSC_NET
);
207 printf("'native netmask' is %s\n", intoa(nmask
));
210 /* Check subnet mask against net mask; toss if bogus */
211 if ((nmask
& smask
) != nmask
) {
214 printf("subnet mask (%s) bad\n", intoa(smask
));
219 /* Get subnet (or natural net) mask */
225 printf("mask: %s\n", intoa(netmask
));
228 /* We need a gateway if root is on a different net */
229 if (!SAMENET(myip
, rootip
, netmask
)) {
232 printf("need gateway for root ip\n");
236 /* Toss gateway if on a different net */
237 if (!SAMENET(myip
, gateip
, netmask
)) {
240 printf("gateway ip (%s) bad\n", inet_ntoa(gateip
));
245 /* Bump xid so next request will be unique. */
249 /* Transmit a bootp request */
251 bootpsend(struct iodesc
*d
, void *pkt
, size_t len
)
257 printf("bootpsend: d=%lx called.\n", (long)d
);
261 bp
->bp_secs
= htons((u_short
)(getsecs() - bot
));
265 printf("bootpsend: calling sendudp\n");
268 return (sendudp(d
, pkt
, len
));
272 bootprecv(struct iodesc
*d
, void *pkt
, size_t len
, time_t tleft
)
279 printf("bootp_recvoffer: called\n");
282 n
= readudp(d
, pkt
, len
, tleft
);
283 if (n
== -1 || n
< sizeof(struct bootp
) - BOOTP_VENDSIZE
)
286 bp
= (struct bootp
*)pkt
;
290 printf("bootprecv: checked. bp = 0x%lx, n = %d\n",
293 if (bp
->bp_xid
!= htonl(d
->xid
)) {
296 printf("bootprecv: expected xid 0x%lx, got 0x%x\n",
297 d
->xid
, ntohl(bp
->bp_xid
));
305 printf("bootprecv: got one!\n");
308 /* Suck out vendor info */
309 if (bcmp(vm_rfc1048
, bp
->bp_vend
, sizeof(vm_rfc1048
)) == 0) {
310 if(vend_rfc1048(bp
->bp_vend
, sizeof(bp
->bp_vend
)) != 0)
313 #ifdef BOOTP_VEND_CMU
314 else if (bcmp(vm_cmu
, bp
->bp_vend
, sizeof(vm_cmu
)) == 0)
315 vend_cmu(bp
->bp_vend
);
318 printf("bootprecv: unknown vendor 0x%lx\n", (long)bp
->bp_vend
);
327 vend_rfc1048(u_char
*cp
, u_int len
)
335 printf("vend_rfc1048 bootp info. len=%d\n", len
);
339 /* Step over magic cookie */
348 if (tag
== TAG_SUBNET_MASK
) {
349 bcopy(cp
, &smask
, sizeof(smask
));
351 if (tag
== TAG_GATEWAY
) {
352 bcopy(cp
, &gateip
.s_addr
, sizeof(gateip
.s_addr
));
354 if (tag
== TAG_SWAPSERVER
) {
355 /* let it override bp_siaddr */
356 bcopy(cp
, &rootip
.s_addr
, sizeof(swapip
.s_addr
));
358 if (tag
== TAG_ROOTPATH
) {
359 strncpy(rootpath
, (char *)cp
, sizeof(rootpath
));
360 rootpath
[size
] = '\0';
362 if (tag
== TAG_HOSTNAME
) {
363 strncpy(hostname
, (char *)cp
, sizeof(hostname
));
364 hostname
[size
] = '\0';
367 if (tag
== TAG_DHCP_MSGTYPE
) {
368 if(*cp
!= expected_dhcpmsgtype
)
372 if (tag
== TAG_SERVERID
) {
373 bcopy(cp
, &dhcp_serverip
.s_addr
,
374 sizeof(dhcp_serverip
.s_addr
));
382 #ifdef BOOTP_VEND_CMU
390 printf("vend_cmu bootp info.\n");
392 vp
= (struct cmu_vend
*)cp
;
394 if (vp
->v_smask
.s_addr
!= 0) {
395 smask
= vp
->v_smask
.s_addr
;
397 if (vp
->v_dgate
.s_addr
!= 0) {
398 gateip
= vp
->v_dgate
;