| @@ -1,867 +1,867 @@ | | | @@ -1,867 +1,867 @@ |
1 | /* $NetBSD: nfs_bootdhcp.c,v 1.46 2009/05/02 21:06:51 manu Exp $ */ | | 1 | /* $NetBSD: nfs_bootdhcp.c,v 1.47 2009/05/05 12:48:31 cegger Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1995, 1997 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1995, 1997 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Adam Glass and Gordon W. Ross. | | 8 | * by Adam Glass and Gordon W. Ross. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Support for NFS diskless booting with BOOTP (RFC951, RFC1048) | | 33 | * Support for NFS diskless booting with BOOTP (RFC951, RFC1048) |
34 | * | | 34 | * |
35 | * History: | | 35 | * History: |
36 | * | | 36 | * |
37 | * Tor Egge developed the initial version of this code based on | | 37 | * Tor Egge developed the initial version of this code based on |
38 | * the Sun RPC/bootparam sources nfs_boot.c and krpc_subr.c and | | 38 | * the Sun RPC/bootparam sources nfs_boot.c and krpc_subr.c and |
39 | * submitted that work to NetBSD as bugreport "kern/2351" on | | 39 | * submitted that work to NetBSD as bugreport "kern/2351" on |
40 | * 29 Apr 1996. | | 40 | * 29 Apr 1996. |
41 | * | | 41 | * |
42 | * Gordon Ross reorganized Tor's version into this form and | | 42 | * Gordon Ross reorganized Tor's version into this form and |
43 | * integrated it into the NetBSD sources during Aug 1997. | | 43 | * integrated it into the NetBSD sources during Aug 1997. |
44 | */ | | 44 | */ |
45 | | | 45 | |
46 | #include <sys/cdefs.h> | | 46 | #include <sys/cdefs.h> |
47 | __KERNEL_RCSID(0, "$NetBSD: nfs_bootdhcp.c,v 1.46 2009/05/02 21:06:51 manu Exp $"); | | 47 | __KERNEL_RCSID(0, "$NetBSD: nfs_bootdhcp.c,v 1.47 2009/05/05 12:48:31 cegger Exp $"); |
48 | | | 48 | |
49 | #ifdef _KERNEL_OPT | | 49 | #ifdef _KERNEL_OPT |
50 | #include "opt_nfs_boot.h" | | 50 | #include "opt_nfs_boot.h" |
51 | #include "opt_tftproot.h" | | 51 | #include "opt_tftproot.h" |
52 | #endif | | 52 | #endif |
53 | | | 53 | |
54 | #include <sys/param.h> | | 54 | #include <sys/param.h> |
55 | #include <sys/systm.h> | | 55 | #include <sys/systm.h> |
56 | #include <sys/kernel.h> | | 56 | #include <sys/kernel.h> |
57 | #include <sys/device.h> | | 57 | #include <sys/device.h> |
58 | #include <sys/ioctl.h> | | 58 | #include <sys/ioctl.h> |
59 | #include <sys/proc.h> | | 59 | #include <sys/proc.h> |
60 | #include <sys/mount.h> | | 60 | #include <sys/mount.h> |
61 | #include <sys/mbuf.h> | | 61 | #include <sys/mbuf.h> |
62 | #include <sys/reboot.h> | | 62 | #include <sys/reboot.h> |
63 | #include <sys/socket.h> | | 63 | #include <sys/socket.h> |
64 | #include <sys/socketvar.h> | | 64 | #include <sys/socketvar.h> |
65 | | | 65 | |
66 | #include <net/if.h> | | 66 | #include <net/if.h> |
67 | #include <net/if_types.h> | | 67 | #include <net/if_types.h> |
68 | #include <net/if_arp.h> /* ARPHRD_ETHER, etc. */ | | 68 | #include <net/if_arp.h> /* ARPHRD_ETHER, etc. */ |
69 | #include <net/if_dl.h> | | 69 | #include <net/if_dl.h> |
70 | #include <net/if_ether.h> | | 70 | #include <net/if_ether.h> |
71 | #include <net/route.h> | | 71 | #include <net/route.h> |
72 | | | 72 | |
73 | #include <netinet/in.h> | | 73 | #include <netinet/in.h> |
74 | #include <netinet/if_inarp.h> | | 74 | #include <netinet/if_inarp.h> |
75 | | | 75 | |
76 | #include <nfs/rpcv2.h> | | 76 | #include <nfs/rpcv2.h> |
77 | | | 77 | |
78 | #include <nfs/nfsproto.h> | | 78 | #include <nfs/nfsproto.h> |
79 | #include <nfs/nfs.h> | | 79 | #include <nfs/nfs.h> |
80 | #include <nfs/nfsmount.h> | | 80 | #include <nfs/nfsmount.h> |
81 | #include <nfs/nfsdiskless.h> | | 81 | #include <nfs/nfsdiskless.h> |
82 | | | 82 | |
83 | /* | | 83 | /* |
84 | * There are two implementations of NFS diskless boot. | | 84 | * There are two implementations of NFS diskless boot. |
85 | * This implementation uses BOOTP (RFC951, RFC1048), and | | 85 | * This implementation uses BOOTP (RFC951, RFC1048), and |
86 | * the other uses Sun RPC/bootparams (nfs_bootparam.c). | | 86 | * the other uses Sun RPC/bootparams (nfs_bootparam.c). |
87 | * | | 87 | * |
88 | * This method gets everything it needs with one BOOTP | | 88 | * This method gets everything it needs with one BOOTP |
89 | * request and reply. Note that this actually uses only | | 89 | * request and reply. Note that this actually uses only |
90 | * the old BOOTP functionality subset of DHCP. It is not | | 90 | * the old BOOTP functionality subset of DHCP. It is not |
91 | * clear that DHCP provides any advantage over BOOTP for | | 91 | * clear that DHCP provides any advantage over BOOTP for |
92 | * diskless boot. DHCP allows the server to assign an IP | | 92 | * diskless boot. DHCP allows the server to assign an IP |
93 | * address without any a-priori knowledge of the client, | | 93 | * address without any a-priori knowledge of the client, |
94 | * but we require that the server has a-priori knowledge | | 94 | * but we require that the server has a-priori knowledge |
95 | * of the client so it can export our (unique) NFS root. | | 95 | * of the client so it can export our (unique) NFS root. |
96 | * Given that the server needs a-priori knowledge about | | 96 | * Given that the server needs a-priori knowledge about |
97 | * the client anyway, it might as well assign a fixed IP | | 97 | * the client anyway, it might as well assign a fixed IP |
98 | * address for the client and support BOOTP. | | 98 | * address for the client and support BOOTP. |
99 | * | | 99 | * |
100 | * On the other hand, disk-FULL clients may use DHCP, but | | 100 | * On the other hand, disk-FULL clients may use DHCP, but |
101 | * in that case the DHCP client should be user-mode code, | | 101 | * in that case the DHCP client should be user-mode code, |
102 | * and has no bearing on the code below. -gwr | | 102 | * and has no bearing on the code below. -gwr |
103 | */ | | 103 | */ |
104 | | | 104 | |
105 | /* Begin stuff from bootp.h */ | | 105 | /* Begin stuff from bootp.h */ |
106 | /* Definitions from RFC951 */ | | 106 | /* Definitions from RFC951 */ |
107 | #define BP_CHADDR_LEN 16 | | 107 | #define BP_CHADDR_LEN 16 |
108 | #define BP_SNAME_LEN 64 | | 108 | #define BP_SNAME_LEN 64 |
109 | #define BP_FILE_LEN 128 | | 109 | #define BP_FILE_LEN 128 |
110 | #define BP_VEND_LEN 64 | | 110 | #define BP_VEND_LEN 64 |
111 | struct bootp { | | 111 | struct bootp { |
112 | u_int8_t bp_op; /* packet opcode type */ | | 112 | u_int8_t bp_op; /* packet opcode type */ |
113 | u_int8_t bp_htype; /* hardware addr type */ | | 113 | u_int8_t bp_htype; /* hardware addr type */ |
114 | u_int8_t bp_hlen; /* hardware addr length */ | | 114 | u_int8_t bp_hlen; /* hardware addr length */ |
115 | u_int8_t bp_hops; /* gateway hops */ | | 115 | u_int8_t bp_hops; /* gateway hops */ |
116 | u_int32_t bp_xid; /* transaction ID */ | | 116 | u_int32_t bp_xid; /* transaction ID */ |
117 | u_int16_t bp_secs; /* seconds since boot began */ | | 117 | u_int16_t bp_secs; /* seconds since boot began */ |
118 | u_int16_t bp_flags; /* RFC1532 broadcast, etc. */ | | 118 | u_int16_t bp_flags; /* RFC1532 broadcast, etc. */ |
119 | struct in_addr bp_ciaddr; /* client IP address */ | | 119 | struct in_addr bp_ciaddr; /* client IP address */ |
120 | struct in_addr bp_yiaddr; /* 'your' IP address */ | | 120 | struct in_addr bp_yiaddr; /* 'your' IP address */ |
121 | struct in_addr bp_siaddr; /* server IP address */ | | 121 | struct in_addr bp_siaddr; /* server IP address */ |
122 | struct in_addr bp_giaddr; /* gateway IP address */ | | 122 | struct in_addr bp_giaddr; /* gateway IP address */ |
123 | u_int8_t bp_chaddr[BP_CHADDR_LEN]; /* client hardware address */ | | 123 | u_int8_t bp_chaddr[BP_CHADDR_LEN]; /* client hardware address */ |
124 | char bp_sname[BP_SNAME_LEN]; /* server host name */ | | 124 | char bp_sname[BP_SNAME_LEN]; /* server host name */ |
125 | char bp_file[BP_FILE_LEN]; /* boot file name */ | | 125 | char bp_file[BP_FILE_LEN]; /* boot file name */ |
126 | u_int8_t bp_vend[BP_VEND_LEN]; /* RFC1048 options */ | | 126 | u_int8_t bp_vend[BP_VEND_LEN]; /* RFC1048 options */ |
127 | /* | | 127 | /* |
128 | * Note that BOOTP packets are allowed to be longer | | 128 | * Note that BOOTP packets are allowed to be longer |
129 | * (see RFC 1532 sect. 2.1) and common practice is to | | 129 | * (see RFC 1532 sect. 2.1) and common practice is to |
130 | * allow the option data in bp_vend to extend into the | | 130 | * allow the option data in bp_vend to extend into the |
131 | * additional space provided in longer packets. | | 131 | * additional space provided in longer packets. |
132 | */ | | 132 | */ |
133 | }; | | 133 | }; |
134 | | | 134 | |
135 | #define IPPORT_BOOTPS 67 | | 135 | #define IPPORT_BOOTPS 67 |
136 | #define IPPORT_BOOTPC 68 | | 136 | #define IPPORT_BOOTPC 68 |
137 | | | 137 | |
138 | #define BOOTREQUEST 1 | | 138 | #define BOOTREQUEST 1 |
139 | #define BOOTREPLY 2 | | 139 | #define BOOTREPLY 2 |
140 | | | 140 | |
141 | /* | | 141 | /* |
142 | * Is this available from the sockaddr_dl somehow? | | 142 | * Is this available from the sockaddr_dl somehow? |
143 | * Perhaps (struct arphdr)->ar_hrd = ARPHRD_ETHER? | | 143 | * Perhaps (struct arphdr)->ar_hrd = ARPHRD_ETHER? |
144 | * The interface has ->if_type but not the ARP fmt. | | 144 | * The interface has ->if_type but not the ARP fmt. |
145 | */ | | 145 | */ |
146 | #define HTYPE_ETHERNET 1 | | 146 | #define HTYPE_ETHERNET 1 |
147 | #define HTYPE_IEEE802 6 | | 147 | #define HTYPE_IEEE802 6 |
148 | | | 148 | |
149 | /* | | 149 | /* |
150 | * Vendor magic cookie (v_magic) for RFC1048 | | 150 | * Vendor magic cookie (v_magic) for RFC1048 |
151 | */ | | 151 | */ |
152 | static const u_int8_t vm_rfc1048[4] = { 99, 130, 83, 99 }; | | 152 | static const u_int8_t vm_rfc1048[4] = { 99, 130, 83, 99 }; |
153 | | | 153 | |
154 | /* | | 154 | /* |
155 | * Tag values used to specify what information is being supplied in | | 155 | * Tag values used to specify what information is being supplied in |
156 | * the vendor (options) data area of the packet. | | 156 | * the vendor (options) data area of the packet. |
157 | */ | | 157 | */ |
158 | /* RFC 1048 */ | | 158 | /* RFC 1048 */ |
159 | #define TAG_END ((unsigned char) 255) | | 159 | #define TAG_END ((unsigned char) 255) |
160 | #define TAG_PAD ((unsigned char) 0) | | 160 | #define TAG_PAD ((unsigned char) 0) |
161 | #define TAG_SUBNET_MASK ((unsigned char) 1) | | 161 | #define TAG_SUBNET_MASK ((unsigned char) 1) |
162 | #define TAG_TIME_OFFSET ((unsigned char) 2) | | 162 | #define TAG_TIME_OFFSET ((unsigned char) 2) |
163 | #define TAG_GATEWAY ((unsigned char) 3) | | 163 | #define TAG_GATEWAY ((unsigned char) 3) |
164 | #define TAG_TIME_SERVER ((unsigned char) 4) | | 164 | #define TAG_TIME_SERVER ((unsigned char) 4) |
165 | #define TAG_NAME_SERVER ((unsigned char) 5) | | 165 | #define TAG_NAME_SERVER ((unsigned char) 5) |
166 | #define TAG_DOMAIN_SERVER ((unsigned char) 6) | | 166 | #define TAG_DOMAIN_SERVER ((unsigned char) 6) |
167 | #define TAG_LOG_SERVER ((unsigned char) 7) | | 167 | #define TAG_LOG_SERVER ((unsigned char) 7) |
168 | #define TAG_COOKIE_SERVER ((unsigned char) 8) | | 168 | #define TAG_COOKIE_SERVER ((unsigned char) 8) |
169 | #define TAG_LPR_SERVER ((unsigned char) 9) | | 169 | #define TAG_LPR_SERVER ((unsigned char) 9) |
170 | #define TAG_IMPRESS_SERVER ((unsigned char) 10) | | 170 | #define TAG_IMPRESS_SERVER ((unsigned char) 10) |
171 | #define TAG_RLP_SERVER ((unsigned char) 11) | | 171 | #define TAG_RLP_SERVER ((unsigned char) 11) |
172 | #define TAG_HOST_NAME ((unsigned char) 12) | | 172 | #define TAG_HOST_NAME ((unsigned char) 12) |
173 | #define TAG_BOOT_SIZE ((unsigned char) 13) | | 173 | #define TAG_BOOT_SIZE ((unsigned char) 13) |
174 | /* RFC 1395 */ | | 174 | /* RFC 1395 */ |
175 | #define TAG_DUMP_FILE ((unsigned char) 14) | | 175 | #define TAG_DUMP_FILE ((unsigned char) 14) |
176 | #define TAG_DOMAIN_NAME ((unsigned char) 15) | | 176 | #define TAG_DOMAIN_NAME ((unsigned char) 15) |
177 | #define TAG_SWAP_SERVER ((unsigned char) 16) | | 177 | #define TAG_SWAP_SERVER ((unsigned char) 16) |
178 | #define TAG_ROOT_PATH ((unsigned char) 17) | | 178 | #define TAG_ROOT_PATH ((unsigned char) 17) |
179 | /* End of stuff from bootp.h */ | | 179 | /* End of stuff from bootp.h */ |
180 | | | 180 | |
181 | #ifdef NFS_BOOT_DHCP | | 181 | #ifdef NFS_BOOT_DHCP |
182 | #define TAG_REQ_ADDR ((unsigned char) 50) | | 182 | #define TAG_REQ_ADDR ((unsigned char) 50) |
183 | #define TAG_LEASETIME ((unsigned char) 51) | | 183 | #define TAG_LEASETIME ((unsigned char) 51) |
184 | #define TAG_OVERLOAD ((unsigned char) 52) | | 184 | #define TAG_OVERLOAD ((unsigned char) 52) |
185 | #define TAG_DHCP_MSGTYPE ((unsigned char) 53) | | 185 | #define TAG_DHCP_MSGTYPE ((unsigned char) 53) |
186 | #define TAG_SERVERID ((unsigned char) 54) | | 186 | #define TAG_SERVERID ((unsigned char) 54) |
187 | #define TAG_PARAM_REQ ((unsigned char) 55) | | 187 | #define TAG_PARAM_REQ ((unsigned char) 55) |
188 | #define TAG_MSG ((unsigned char) 56) | | 188 | #define TAG_MSG ((unsigned char) 56) |
189 | #define TAG_MAXSIZE ((unsigned char) 57) | | 189 | #define TAG_MAXSIZE ((unsigned char) 57) |
190 | #define TAG_T1 ((unsigned char) 58) | | 190 | #define TAG_T1 ((unsigned char) 58) |
191 | #define TAG_T2 ((unsigned char) 59) | | 191 | #define TAG_T2 ((unsigned char) 59) |
192 | #define TAG_CLASSID ((unsigned char) 60) | | 192 | #define TAG_CLASSID ((unsigned char) 60) |
193 | #define TAG_CLIENTID ((unsigned char) 61) | | 193 | #define TAG_CLIENTID ((unsigned char) 61) |
194 | #endif | | 194 | #endif |
195 | | | 195 | |
196 | #ifdef NFS_BOOT_DHCP | | 196 | #ifdef NFS_BOOT_DHCP |
197 | #define DHCPDISCOVER 1 | | 197 | #define DHCPDISCOVER 1 |
198 | #define DHCPOFFER 2 | | 198 | #define DHCPOFFER 2 |
199 | #define DHCPREQUEST 3 | | 199 | #define DHCPREQUEST 3 |
200 | #define DHCPDECLINE 4 | | 200 | #define DHCPDECLINE 4 |
201 | #define DHCPACK 5 | | 201 | #define DHCPACK 5 |
202 | #define DHCPNAK 6 | | 202 | #define DHCPNAK 6 |
203 | #define DHCPRELEASE 7 | | 203 | #define DHCPRELEASE 7 |
204 | #endif | | 204 | #endif |
205 | | | 205 | |
206 | #ifdef NFS_BOOT_DHCP | | 206 | #ifdef NFS_BOOT_DHCP |
207 | #define BOOTP_SIZE_MAX (sizeof(struct bootp)+312-64) | | 207 | #define BOOTP_SIZE_MAX (sizeof(struct bootp)+312-64) |
208 | #else | | 208 | #else |
209 | /* | | 209 | /* |
210 | * The "extended" size is somewhat arbitrary, but is | | 210 | * The "extended" size is somewhat arbitrary, but is |
211 | * constrained by the maximum message size specified | | 211 | * constrained by the maximum message size specified |
212 | * by RFC1533 (567 total). This value increases the | | 212 | * by RFC1533 (567 total). This value increases the |
213 | * space for options from 64 bytes to 256 bytes. | | 213 | * space for options from 64 bytes to 256 bytes. |
214 | */ | | 214 | */ |
215 | #define BOOTP_SIZE_MAX (sizeof(struct bootp)+256-64) | | 215 | #define BOOTP_SIZE_MAX (sizeof(struct bootp)+256-64) |
216 | #endif | | 216 | #endif |
217 | #define BOOTP_SIZE_MIN (sizeof(struct bootp)) | | 217 | #define BOOTP_SIZE_MIN (sizeof(struct bootp)) |
218 | | | 218 | |
219 | /* Convenience macro */ | | 219 | /* Convenience macro */ |
220 | #define INTOHL(ina) ((u_int32_t)ntohl((ina).s_addr)) | | 220 | #define INTOHL(ina) ((u_int32_t)ntohl((ina).s_addr)) |
221 | | | 221 | |
222 | static int bootpc_call (struct nfs_diskless *, struct lwp *, int *); | | 222 | static int bootpc_call (struct nfs_diskless *, struct lwp *, int *); |
223 | static void bootp_extract (struct bootp *, int, struct nfs_diskless *, int *); | | 223 | static void bootp_extract (struct bootp *, int, struct nfs_diskless *, int *); |
224 | | | 224 | |
225 | #ifdef DEBUG_NFS_BOOT_DHCP | | 225 | #ifdef DEBUG_NFS_BOOT_DHCP |
226 | #define DPRINTF(s) printf s | | 226 | #define DPRINTF(s) printf s |
227 | #else | | 227 | #else |
228 | #define DPRINTF(s) | | 228 | #define DPRINTF(s) |
229 | #endif | | 229 | #endif |
230 | | | 230 | |
231 | | | 231 | |
232 | /* | | 232 | /* |
233 | * Get our boot parameters using BOOTP. | | 233 | * Get our boot parameters using BOOTP. |
234 | */ | | 234 | */ |
235 | int | | 235 | int |
236 | nfs_bootdhcp(struct nfs_diskless *nd, struct lwp *lwp, int *flags) | | 236 | nfs_bootdhcp(struct nfs_diskless *nd, struct lwp *lwp, int *flags) |
237 | { | | 237 | { |
238 | struct ifnet *ifp = nd->nd_ifp; | | 238 | struct ifnet *ifp = nd->nd_ifp; |
239 | int error; | | 239 | int error; |
240 | | | 240 | |
241 | /* | | 241 | /* |
242 | * Do enough of ifconfig(8) so that the chosen interface | | 242 | * Do enough of ifconfig(8) so that the chosen interface |
243 | * can talk to the servers. Use address zero for now. | | 243 | * can talk to the servers. Use address zero for now. |
244 | */ | | 244 | */ |
245 | error = nfs_boot_setaddress(ifp, lwp, | | 245 | error = nfs_boot_setaddress(ifp, lwp, |
246 | *flags & NFS_BOOT_HAS_MYIP ? nd->nd_myip.s_addr : INADDR_ANY, | | 246 | *flags & NFS_BOOT_HAS_MYIP ? nd->nd_myip.s_addr : INADDR_ANY, |
247 | *flags & NFS_BOOT_HAS_MASK ? nd->nd_mask.s_addr : INADDR_ANY, | | 247 | *flags & NFS_BOOT_HAS_MASK ? nd->nd_mask.s_addr : INADDR_ANY, |
248 | INADDR_BROADCAST); | | 248 | INADDR_BROADCAST); |
249 | if (error) { | | 249 | if (error) { |
250 | printf("nfs_boot: set ifaddr zero, error=%d\n", error); | | 250 | printf("nfs_boot: set ifaddr zero, error=%d\n", error); |
251 | return (error); | | 251 | return (error); |
252 | } | | 252 | } |
253 | | | 253 | |
254 | /* This function call does the real send/recv work. */ | | 254 | /* This function call does the real send/recv work. */ |
255 | error = bootpc_call(nd, lwp, flags); | | 255 | error = bootpc_call(nd, lwp, flags); |
256 | | | 256 | |
257 | /* Get rid of the temporary (zero) IP address. */ | | 257 | /* Get rid of the temporary (zero) IP address. */ |
258 | (void) nfs_boot_deladdress(ifp, lwp, INADDR_ANY); | | 258 | (void) nfs_boot_deladdress(ifp, lwp, INADDR_ANY); |
259 | | | 259 | |
260 | /* NOW we can test the error from bootpc_call. */ | | 260 | /* NOW we can test the error from bootpc_call. */ |
261 | if (error) | | 261 | if (error) |
262 | goto out; | | 262 | goto out; |
263 | | | 263 | |
264 | /* | | 264 | /* |
265 | * Do ifconfig with our real IP address and mask. | | 265 | * Do ifconfig with our real IP address and mask. |
266 | */ | | 266 | */ |
267 | error = nfs_boot_setaddress(ifp, lwp, nd->nd_myip.s_addr, | | 267 | error = nfs_boot_setaddress(ifp, lwp, nd->nd_myip.s_addr, |
268 | nd->nd_mask.s_addr, INADDR_ANY); | | 268 | nd->nd_mask.s_addr, INADDR_ANY); |
269 | if (error) { | | 269 | if (error) { |
270 | printf("nfs_boot: set ifaddr real, error=%d\n", error); | | 270 | printf("nfs_boot: set ifaddr real, error=%d\n", error); |
271 | goto out; | | 271 | goto out; |
272 | } | | 272 | } |
273 | | | 273 | |
274 | if ((*flags & NFS_BOOT_ALLINFO) != NFS_BOOT_ALLINFO) { | | 274 | if ((*flags & NFS_BOOT_ALLINFO) != NFS_BOOT_ALLINFO) { |
275 | printf("nfs_boot: missing options (need IP, netmask, " | | 275 | printf("nfs_boot: missing options (need IP, netmask, " |
276 | "gateway, next-server, root-path)\n"); | | 276 | "gateway, next-server, root-path)\n"); |
277 | return EADDRNOTAVAIL; | | 277 | return EADDRNOTAVAIL; |
278 | } | | 278 | } |
279 | | | 279 | |
280 | out: | | 280 | out: |
281 | if (error) { | | 281 | if (error) { |
282 | (void) nfs_boot_ifupdown(ifp, lwp, 0); | | 282 | (void) nfs_boot_ifupdown(ifp, lwp, 0); |
283 | nfs_boot_flushrt(ifp); | | 283 | nfs_boot_flushrt(ifp); |
284 | } | | 284 | } |
285 | return (error); | | 285 | return (error); |
286 | } | | 286 | } |
287 | | | 287 | |
288 | struct bootpcontext { | | 288 | struct bootpcontext { |
289 | int xid; | | 289 | int xid; |
290 | const u_char *haddr; | | 290 | const u_char *haddr; |
291 | u_char halen; | | 291 | u_char halen; |
292 | struct bootp *replybuf; | | 292 | struct bootp *replybuf; |
293 | int replylen; | | 293 | int replylen; |
294 | #ifdef NFS_BOOT_DHCP | | 294 | #ifdef NFS_BOOT_DHCP |
295 | char expected_dhcpmsgtype, dhcp_ok; | | 295 | char expected_dhcpmsgtype, dhcp_ok; |
296 | struct in_addr dhcp_serverip; | | 296 | struct in_addr dhcp_serverip; |
297 | #endif | | 297 | #endif |
298 | }; | | 298 | }; |
299 | | | 299 | |
300 | static int bootpset (struct mbuf*, void*, int); | | 300 | static int bootpset (struct mbuf*, void*, int); |
301 | static int bootpcheck (struct mbuf*, void*); | | 301 | static int bootpcheck (struct mbuf*, void*); |
302 | | | 302 | |
303 | static int | | 303 | static int |
304 | bootpset(struct mbuf *m, void *context, int waited) | | 304 | bootpset(struct mbuf *m, void *context, int waited) |
305 | { | | 305 | { |
306 | struct bootp *bootp; | | 306 | struct bootp *bootp; |
307 | | | 307 | |
308 | /* we know it's contigous (in 1 mbuf cluster) */ | | 308 | /* we know it's contigous (in 1 mbuf cluster) */ |
309 | bootp = mtod(m, struct bootp*); | | 309 | bootp = mtod(m, struct bootp*); |
310 | | | 310 | |
311 | bootp->bp_secs = htons(waited); | | 311 | bootp->bp_secs = htons(waited); |
312 | | | 312 | |
313 | return (0); | | 313 | return (0); |
314 | } | | 314 | } |
315 | | | 315 | |
316 | static int | | 316 | static int |
317 | bootpcheck(struct mbuf *m, void *context) | | 317 | bootpcheck(struct mbuf *m, void *context) |
318 | { | | 318 | { |
319 | struct bootp *bootp; | | 319 | struct bootp *bootp; |
320 | struct bootpcontext *bpc = context; | | 320 | struct bootpcontext *bpc = context; |
321 | u_int tag, len; | | 321 | u_int tag, len; |
322 | u_char *p, *limit; | | 322 | u_char *p, *limit; |
323 | | | 323 | |
324 | /* | | 324 | /* |
325 | * Is this a valid reply? | | 325 | * Is this a valid reply? |
326 | */ | | 326 | */ |
327 | if (m->m_pkthdr.len < BOOTP_SIZE_MIN) { | | 327 | if (m->m_pkthdr.len < BOOTP_SIZE_MIN) { |
328 | DPRINTF(("bootpcheck: short packet %d < %ld\n", | | 328 | DPRINTF(("bootpcheck: short packet %d < %d\n", |
329 | m->m_pkthdr.len, BOOTP_SIZE_MIN)); | | 329 | m->m_pkthdr.len, BOOTP_SIZE_MIN)); |
330 | return (-1); | | 330 | return (-1); |
331 | } | | 331 | } |
332 | if (m->m_pkthdr.len > BOOTP_SIZE_MAX) { | | 332 | if (m->m_pkthdr.len > BOOTP_SIZE_MAX) { |
333 | DPRINTF(("Bootpcheck: long packet %d > %ld\n", | | 333 | DPRINTF(("Bootpcheck: long packet %d > %d\n", |
334 | m->m_pkthdr.len, BOOTP_SIZE_MAX)); | | 334 | m->m_pkthdr.len, BOOTP_SIZE_MAX)); |
335 | return (-1); | | 335 | return (-1); |
336 | } | | 336 | } |
337 | | | 337 | |
338 | /* | | 338 | /* |
339 | * don't make first checks more expensive than necessary | | 339 | * don't make first checks more expensive than necessary |
340 | */ | | 340 | */ |
341 | if (m->m_len < offsetof(struct bootp, bp_sname)) { | | 341 | if (m->m_len < offsetof(struct bootp, bp_sname)) { |
342 | m = m_pullup(m, offsetof(struct bootp, bp_sname)); | | 342 | m = m_pullup(m, offsetof(struct bootp, bp_sname)); |
343 | if (m == NULL) { | | 343 | if (m == NULL) { |
344 | DPRINTF(("bootpcheck: m_pullup failed\n")); | | 344 | DPRINTF(("bootpcheck: m_pullup failed\n")); |
345 | return (-1); | | 345 | return (-1); |
346 | } | | 346 | } |
347 | } | | 347 | } |
348 | bootp = mtod(m, struct bootp*); | | 348 | bootp = mtod(m, struct bootp*); |
349 | | | 349 | |
350 | if (bootp->bp_op != BOOTREPLY) { | | 350 | if (bootp->bp_op != BOOTREPLY) { |
351 | DPRINTF(("bootpcheck: op %d is not reply\n", bootp->bp_op)); | | 351 | DPRINTF(("bootpcheck: op %d is not reply\n", bootp->bp_op)); |
352 | return (-1); | | 352 | return (-1); |
353 | } | | 353 | } |
354 | if (bootp->bp_hlen != bpc->halen) { | | 354 | if (bootp->bp_hlen != bpc->halen) { |
355 | DPRINTF(("bootpcheck: hlen %d != %d\n", bootp->bp_hlen, | | 355 | DPRINTF(("bootpcheck: hlen %d != %d\n", bootp->bp_hlen, |
356 | bpc->halen)); | | 356 | bpc->halen)); |
357 | return (-1); | | 357 | return (-1); |
358 | } | | 358 | } |
359 | if (memcmp(bootp->bp_chaddr, bpc->haddr, bpc->halen)) { | | 359 | if (memcmp(bootp->bp_chaddr, bpc->haddr, bpc->halen)) { |
360 | #ifdef DEBUG_NFS_BOOT_DHCP | | 360 | #ifdef DEBUG_NFS_BOOT_DHCP |
361 | char *bp_chaddr, *haddr; | | 361 | char *bp_chaddr, *haddr; |
362 | | | 362 | |
363 | bp_chaddr = malloc(3 * bpc->halen, M_TEMP, M_WAITOK); | | 363 | bp_chaddr = malloc(3 * bpc->halen, M_TEMP, M_WAITOK); |
364 | haddr = malloc(3 * bpc->halen, M_TEMP, M_WAITOK); | | 364 | haddr = malloc(3 * bpc->halen, M_TEMP, M_WAITOK); |
365 | | | 365 | |
366 | DPRINTF(("bootpcheck: incorrect hwaddr %s != %s\n", | | 366 | DPRINTF(("bootpcheck: incorrect hwaddr %s != %s\n", |
367 | ether_snprintf(bp_chaddr, 3 * bpc->halen, | | 367 | ether_snprintf(bp_chaddr, 3 * bpc->halen, |
368 | bootp->bp_chaddr), | | 368 | bootp->bp_chaddr), |
369 | ether_snprintf(haddr, 3 * bpc->halen, bpc->haddr))); | | 369 | ether_snprintf(haddr, 3 * bpc->halen, bpc->haddr))); |
370 | | | 370 | |
371 | free(bp_chaddr, M_TEMP); | | 371 | free(bp_chaddr, M_TEMP); |
372 | free(haddr, M_TEMP); | | 372 | free(haddr, M_TEMP); |
373 | #endif | | 373 | #endif |
374 | return (-1); | | 374 | return (-1); |
375 | } | | 375 | } |
376 | if (bootp->bp_xid != bpc->xid) { | | 376 | if (bootp->bp_xid != bpc->xid) { |
377 | DPRINTF(("bootpcheck: xid %d != %d\n", bootp->bp_xid, | | 377 | DPRINTF(("bootpcheck: xid %d != %d\n", bootp->bp_xid, |
378 | bpc->xid)); | | 378 | bpc->xid)); |
379 | return (-1); | | 379 | return (-1); |
380 | } | | 380 | } |
381 | | | 381 | |
382 | /* | | 382 | /* |
383 | * OK, it's worth to look deeper. | | 383 | * OK, it's worth to look deeper. |
384 | * We copy the mbuf into a flat buffer here because | | 384 | * We copy the mbuf into a flat buffer here because |
385 | * m_pullup() is a bit limited for this purpose | | 385 | * m_pullup() is a bit limited for this purpose |
386 | * (doesn't allocate a cluster if necessary). | | 386 | * (doesn't allocate a cluster if necessary). |
387 | */ | | 387 | */ |
388 | bpc->replylen = m->m_pkthdr.len; | | 388 | bpc->replylen = m->m_pkthdr.len; |
389 | m_copydata(m, 0, bpc->replylen, (void *)bpc->replybuf); | | 389 | m_copydata(m, 0, bpc->replylen, (void *)bpc->replybuf); |
390 | bootp = bpc->replybuf; | | 390 | bootp = bpc->replybuf; |
391 | | | 391 | |
392 | /* | | 392 | /* |
393 | * Check if the IP address we get looks correct. | | 393 | * Check if the IP address we get looks correct. |
394 | * (DHCP servers can send junk to unknown clients.) | | 394 | * (DHCP servers can send junk to unknown clients.) |
395 | * XXX more checks might be needed | | 395 | * XXX more checks might be needed |
396 | */ | | 396 | */ |
397 | if (bootp->bp_yiaddr.s_addr == INADDR_ANY || | | 397 | if (bootp->bp_yiaddr.s_addr == INADDR_ANY || |
398 | bootp->bp_yiaddr.s_addr == INADDR_BROADCAST) { | | 398 | bootp->bp_yiaddr.s_addr == INADDR_BROADCAST) { |
399 | printf("nfs_boot: wrong IP addr %s", | | 399 | printf("nfs_boot: wrong IP addr %s", |
400 | inet_ntoa(bootp->bp_yiaddr)); | | 400 | inet_ntoa(bootp->bp_yiaddr)); |
401 | goto warn; | | 401 | goto warn; |
402 | } | | 402 | } |
403 | | | 403 | |
404 | /* | | 404 | /* |
405 | * Check the vendor data. | | 405 | * Check the vendor data. |
406 | */ | | 406 | */ |
407 | if (memcmp(bootp->bp_vend, vm_rfc1048, 4)) { | | 407 | if (memcmp(bootp->bp_vend, vm_rfc1048, 4)) { |
408 | printf("nfs_boot: reply missing options"); | | 408 | printf("nfs_boot: reply missing options"); |
409 | goto warn; | | 409 | goto warn; |
410 | } | | 410 | } |
411 | p = &bootp->bp_vend[4]; | | 411 | p = &bootp->bp_vend[4]; |
412 | limit = ((u_char*)bootp) + bpc->replylen; | | 412 | limit = ((u_char*)bootp) + bpc->replylen; |
413 | while (p < limit) { | | 413 | while (p < limit) { |
414 | tag = *p++; | | 414 | tag = *p++; |
415 | if (tag == TAG_END) | | 415 | if (tag == TAG_END) |
416 | break; | | 416 | break; |
417 | if (tag == TAG_PAD) | | 417 | if (tag == TAG_PAD) |
418 | continue; | | 418 | continue; |
419 | len = *p++; | | 419 | len = *p++; |
420 | if ((p + len) > limit) { | | 420 | if ((p + len) > limit) { |
421 | printf("nfs_boot: option %d too long", tag); | | 421 | printf("nfs_boot: option %d too long", tag); |
422 | goto warn; | | 422 | goto warn; |
423 | } | | 423 | } |
424 | switch (tag) { | | 424 | switch (tag) { |
425 | #ifdef NFS_BOOT_DHCP | | 425 | #ifdef NFS_BOOT_DHCP |
426 | case TAG_DHCP_MSGTYPE: | | 426 | case TAG_DHCP_MSGTYPE: |
427 | if (*p != bpc->expected_dhcpmsgtype) | | 427 | if (*p != bpc->expected_dhcpmsgtype) |
428 | return (-1); | | 428 | return (-1); |
429 | bpc->dhcp_ok = 1; | | 429 | bpc->dhcp_ok = 1; |
430 | break; | | 430 | break; |
431 | case TAG_SERVERID: | | 431 | case TAG_SERVERID: |
432 | memcpy(&bpc->dhcp_serverip.s_addr, p, | | 432 | memcpy(&bpc->dhcp_serverip.s_addr, p, |
433 | sizeof(bpc->dhcp_serverip.s_addr)); | | 433 | sizeof(bpc->dhcp_serverip.s_addr)); |
434 | break; | | 434 | break; |
435 | #endif | | 435 | #endif |
436 | default: | | 436 | default: |
437 | break; | | 437 | break; |
438 | } | | 438 | } |
439 | p += len; | | 439 | p += len; |
440 | } | | 440 | } |
441 | return (0); | | 441 | return (0); |
442 | | | 442 | |
443 | warn: | | 443 | warn: |
444 | printf(" (bad reply from %s)\n", inet_ntoa(bootp->bp_siaddr)); | | 444 | printf(" (bad reply from %s)\n", inet_ntoa(bootp->bp_siaddr)); |
445 | return (-1); | | 445 | return (-1); |
446 | } | | 446 | } |
447 | | | 447 | |
448 | static int | | 448 | static int |
449 | bootpc_call(struct nfs_diskless *nd, struct lwp *lwp, int *flags) | | 449 | bootpc_call(struct nfs_diskless *nd, struct lwp *lwp, int *flags) |
450 | { | | 450 | { |
451 | struct socket *so; | | 451 | struct socket *so; |
452 | struct ifnet *ifp = nd->nd_ifp; | | 452 | struct ifnet *ifp = nd->nd_ifp; |
453 | static u_int32_t xid = ~0xFF; | | 453 | static u_int32_t xid = ~0xFF; |
454 | struct bootp *bootp; /* request */ | | 454 | struct bootp *bootp; /* request */ |
455 | struct mbuf *m, *nam; | | 455 | struct mbuf *m, *nam; |
456 | struct sockaddr_in *sin; | | 456 | struct sockaddr_in *sin; |
457 | int error; | | 457 | int error; |
458 | const u_char *haddr; | | 458 | const u_char *haddr; |
459 | u_char hafmt, halen; | | 459 | u_char hafmt, halen; |
460 | struct bootpcontext bpc; | | 460 | struct bootpcontext bpc; |
461 | #ifdef NFS_BOOT_DHCP | | 461 | #ifdef NFS_BOOT_DHCP |
462 | char vci[64]; | | 462 | char vci[64]; |
463 | int vcilen; | | 463 | int vcilen; |
464 | #endif | | 464 | #endif |
465 | | | 465 | |
466 | error = socreate(AF_INET, &so, SOCK_DGRAM, 0, lwp, NULL); | | 466 | error = socreate(AF_INET, &so, SOCK_DGRAM, 0, lwp, NULL); |
467 | if (error) { | | 467 | if (error) { |
468 | printf("bootp: socreate, error=%d\n", error); | | 468 | printf("bootp: socreate, error=%d\n", error); |
469 | return (error); | | 469 | return (error); |
470 | } | | 470 | } |
471 | | | 471 | |
472 | /* | | 472 | /* |
473 | * Initialize to NULL anything that will hold an allocation, | | 473 | * Initialize to NULL anything that will hold an allocation, |
474 | * and free each at the end if not null. | | 474 | * and free each at the end if not null. |
475 | */ | | 475 | */ |
476 | bpc.replybuf = NULL; | | 476 | bpc.replybuf = NULL; |
477 | m = nam = NULL; | | 477 | m = nam = NULL; |
478 | | | 478 | |
479 | /* Record our H/W (Ethernet) address. */ | | 479 | /* Record our H/W (Ethernet) address. */ |
480 | { const struct sockaddr_dl *sdl = ifp->if_sadl; | | 480 | { const struct sockaddr_dl *sdl = ifp->if_sadl; |
481 | switch (sdl->sdl_type) { | | 481 | switch (sdl->sdl_type) { |
482 | case IFT_ISO88025: | | 482 | case IFT_ISO88025: |
483 | hafmt = HTYPE_IEEE802; | | 483 | hafmt = HTYPE_IEEE802; |
484 | break; | | 484 | break; |
485 | case IFT_ETHER: | | 485 | case IFT_ETHER: |
486 | case IFT_FDDI: | | 486 | case IFT_FDDI: |
487 | hafmt = HTYPE_ETHERNET; | | 487 | hafmt = HTYPE_ETHERNET; |
488 | break; | | 488 | break; |
489 | default: | | 489 | default: |
490 | printf("bootp: unsupported interface type %d\n", | | 490 | printf("bootp: unsupported interface type %d\n", |
491 | sdl->sdl_type); | | 491 | sdl->sdl_type); |
492 | error = EINVAL; | | 492 | error = EINVAL; |
493 | goto out; | | 493 | goto out; |
494 | } | | 494 | } |
495 | halen = sdl->sdl_alen; | | 495 | halen = sdl->sdl_alen; |
496 | haddr = (const unsigned char *)CLLADDR(sdl); | | 496 | haddr = (const unsigned char *)CLLADDR(sdl); |
497 | } | | 497 | } |
498 | | | 498 | |
499 | /* | | 499 | /* |
500 | * Skip the route table when sending on this socket. | | 500 | * Skip the route table when sending on this socket. |
501 | * If this is not done, ip_output finds the loopback | | 501 | * If this is not done, ip_output finds the loopback |
502 | * interface (why?) and then fails because broadcast | | 502 | * interface (why?) and then fails because broadcast |
503 | * is not supported on that interface... | | 503 | * is not supported on that interface... |
504 | */ | | 504 | */ |
505 | { int32_t opt; | | 505 | { int32_t opt; |
506 | | | 506 | |
507 | opt = 1; | | 507 | opt = 1; |
508 | error = so_setsockopt(NULL, so, SOL_SOCKET, SO_DONTROUTE, &opt, | | 508 | error = so_setsockopt(NULL, so, SOL_SOCKET, SO_DONTROUTE, &opt, |
509 | sizeof(opt)); | | 509 | sizeof(opt)); |
510 | } | | 510 | } |
511 | if (error) { | | 511 | if (error) { |
512 | DPRINTF(("bootpc_call: SO_DONTROUTE failed %d\n", error)); | | 512 | DPRINTF(("bootpc_call: SO_DONTROUTE failed %d\n", error)); |
513 | goto out; | | 513 | goto out; |
514 | } | | 514 | } |
515 | | | 515 | |
516 | /* Enable broadcast. */ | | 516 | /* Enable broadcast. */ |
517 | if ((error = nfs_boot_enbroadcast(so))) { | | 517 | if ((error = nfs_boot_enbroadcast(so))) { |
518 | DPRINTF(("bootpc_call: SO_BROADCAST failed %d\n", error)); | | 518 | DPRINTF(("bootpc_call: SO_BROADCAST failed %d\n", error)); |
519 | goto out; | | 519 | goto out; |
520 | } | | 520 | } |
521 | | | 521 | |
522 | /* | | 522 | /* |
523 | * Set some TTL so we can boot through routers. | | 523 | * Set some TTL so we can boot through routers. |
524 | * Real BOOTP forwarding agents don't need this; they obey "bp_hops" | | 524 | * Real BOOTP forwarding agents don't need this; they obey "bp_hops" |
525 | * and set "bp_giaddr", thus rewrite the packet anyway. | | 525 | * and set "bp_giaddr", thus rewrite the packet anyway. |
526 | * The "helper-address" feature of some popular router vendor seems | | 526 | * The "helper-address" feature of some popular router vendor seems |
527 | * to do simple IP forwarding and drops packets with (ip_ttl == 1). | | 527 | * to do simple IP forwarding and drops packets with (ip_ttl == 1). |
528 | */ | | 528 | */ |
529 | { u_char opt; | | 529 | { u_char opt; |
530 | | | 530 | |
531 | opt = 7; | | 531 | opt = 7; |
532 | error = so_setsockopt(NULL, so, IPPROTO_IP, IP_MULTICAST_TTL, | | 532 | error = so_setsockopt(NULL, so, IPPROTO_IP, IP_MULTICAST_TTL, |
533 | &opt, sizeof(opt)); | | 533 | &opt, sizeof(opt)); |
534 | } | | 534 | } |
535 | if (error) { | | 535 | if (error) { |
536 | DPRINTF(("bootpc_call: IP_MULTICAST_TTL failed %d\n", error)); | | 536 | DPRINTF(("bootpc_call: IP_MULTICAST_TTL failed %d\n", error)); |
537 | goto out; | | 537 | goto out; |
538 | } | | 538 | } |
539 | | | 539 | |
540 | /* Set the receive timeout for the socket. */ | | 540 | /* Set the receive timeout for the socket. */ |
541 | if ((error = nfs_boot_setrecvtimo(so))) { | | 541 | if ((error = nfs_boot_setrecvtimo(so))) { |
542 | DPRINTF(("bootpc_call: SO_RCVTIMEO failed %d\n", error)); | | 542 | DPRINTF(("bootpc_call: SO_RCVTIMEO failed %d\n", error)); |
543 | goto out; | | 543 | goto out; |
544 | } | | 544 | } |
545 | | | 545 | |
546 | /* | | 546 | /* |
547 | * Bind the local endpoint to a bootp client port. | | 547 | * Bind the local endpoint to a bootp client port. |
548 | */ | | 548 | */ |
549 | if ((error = nfs_boot_sobind_ipport(so, IPPORT_BOOTPC, lwp))) { | | 549 | if ((error = nfs_boot_sobind_ipport(so, IPPORT_BOOTPC, lwp))) { |
550 | DPRINTF(("bootpc_call: bind failed %d\n", error)); | | 550 | DPRINTF(("bootpc_call: bind failed %d\n", error)); |
551 | goto out; | | 551 | goto out; |
552 | } | | 552 | } |
553 | | | 553 | |
554 | /* | | 554 | /* |
555 | * Setup socket address for the server. | | 555 | * Setup socket address for the server. |
556 | */ | | 556 | */ |
557 | nam = m_get(M_WAIT, MT_SONAME); | | 557 | nam = m_get(M_WAIT, MT_SONAME); |
558 | sin = mtod(nam, struct sockaddr_in *); | | 558 | sin = mtod(nam, struct sockaddr_in *); |
559 | sin->sin_len = nam->m_len = sizeof(*sin); | | 559 | sin->sin_len = nam->m_len = sizeof(*sin); |
560 | sin->sin_family = AF_INET; | | 560 | sin->sin_family = AF_INET; |
561 | sin->sin_addr.s_addr = INADDR_BROADCAST; | | 561 | sin->sin_addr.s_addr = INADDR_BROADCAST; |
562 | sin->sin_port = htons(IPPORT_BOOTPS); | | 562 | sin->sin_port = htons(IPPORT_BOOTPS); |
563 | | | 563 | |
564 | /* | | 564 | /* |
565 | * Allocate buffer used for request | | 565 | * Allocate buffer used for request |
566 | */ | | 566 | */ |
567 | m = m_gethdr(M_WAIT, MT_DATA); | | 567 | m = m_gethdr(M_WAIT, MT_DATA); |
568 | m_clget(m, M_WAIT); | | 568 | m_clget(m, M_WAIT); |
569 | bootp = mtod(m, struct bootp*); | | 569 | bootp = mtod(m, struct bootp*); |
570 | m->m_pkthdr.len = m->m_len = BOOTP_SIZE_MAX; | | 570 | m->m_pkthdr.len = m->m_len = BOOTP_SIZE_MAX; |
571 | m->m_pkthdr.rcvif = NULL; | | 571 | m->m_pkthdr.rcvif = NULL; |
572 | | | 572 | |
573 | /* | | 573 | /* |
574 | * Build the BOOTP reqest message. | | 574 | * Build the BOOTP reqest message. |
575 | * Note: xid is host order! (opaque to server) | | 575 | * Note: xid is host order! (opaque to server) |
576 | */ | | 576 | */ |
577 | memset((void *)bootp, 0, BOOTP_SIZE_MAX); | | 577 | memset((void *)bootp, 0, BOOTP_SIZE_MAX); |
578 | bootp->bp_op = BOOTREQUEST; | | 578 | bootp->bp_op = BOOTREQUEST; |
579 | bootp->bp_htype = hafmt; | | 579 | bootp->bp_htype = hafmt; |
580 | bootp->bp_hlen = halen; /* Hardware address length */ | | 580 | bootp->bp_hlen = halen; /* Hardware address length */ |
581 | bootp->bp_xid = ++xid; | | 581 | bootp->bp_xid = ++xid; |
582 | memcpy(bootp->bp_chaddr, haddr, halen); | | 582 | memcpy(bootp->bp_chaddr, haddr, halen); |
583 | #ifdef NFS_BOOT_BOOTP_REQFILE | | 583 | #ifdef NFS_BOOT_BOOTP_REQFILE |
584 | strncpy(bootp->bp_file, NFS_BOOT_BOOTP_REQFILE, sizeof(bootp->bp_file)); | | 584 | strncpy(bootp->bp_file, NFS_BOOT_BOOTP_REQFILE, sizeof(bootp->bp_file)); |
585 | #endif | | 585 | #endif |
586 | /* Fill-in the vendor data. */ | | 586 | /* Fill-in the vendor data. */ |
587 | memcpy(bootp->bp_vend, vm_rfc1048, 4); | | 587 | memcpy(bootp->bp_vend, vm_rfc1048, 4); |
588 | #ifdef NFS_BOOT_DHCP | | 588 | #ifdef NFS_BOOT_DHCP |
589 | bootp->bp_vend[4] = TAG_DHCP_MSGTYPE; | | 589 | bootp->bp_vend[4] = TAG_DHCP_MSGTYPE; |
590 | bootp->bp_vend[5] = 1; | | 590 | bootp->bp_vend[5] = 1; |
591 | bootp->bp_vend[6] = DHCPDISCOVER; | | 591 | bootp->bp_vend[6] = DHCPDISCOVER; |
592 | /* | | 592 | /* |
593 | * Insert a NetBSD Vendor Class Identifier option. | | 593 | * Insert a NetBSD Vendor Class Identifier option. |
594 | */ | | 594 | */ |
595 | snprintf(vci, sizeof(vci), "%s:%s:kernel:%s", ostype, MACHINE, | | 595 | snprintf(vci, sizeof(vci), "%s:%s:kernel:%s", ostype, MACHINE, |
596 | osrelease); | | 596 | osrelease); |
597 | vcilen = strlen(vci); | | 597 | vcilen = strlen(vci); |
598 | bootp->bp_vend[7] = TAG_CLASSID; | | 598 | bootp->bp_vend[7] = TAG_CLASSID; |
599 | bootp->bp_vend[8] = vcilen; | | 599 | bootp->bp_vend[8] = vcilen; |
600 | memcpy(&bootp->bp_vend[9], vci, vcilen); | | 600 | memcpy(&bootp->bp_vend[9], vci, vcilen); |
601 | bootp->bp_vend[9 + vcilen] = TAG_END; | | 601 | bootp->bp_vend[9 + vcilen] = TAG_END; |
602 | #else | | 602 | #else |
603 | bootp->bp_vend[4] = TAG_END; | | 603 | bootp->bp_vend[4] = TAG_END; |
604 | #endif | | 604 | #endif |
605 | | | 605 | |
606 | bpc.xid = xid; | | 606 | bpc.xid = xid; |
607 | bpc.haddr = haddr; | | 607 | bpc.haddr = haddr; |
608 | bpc.halen = halen; | | 608 | bpc.halen = halen; |
609 | bpc.replybuf = malloc(BOOTP_SIZE_MAX, M_DEVBUF, M_WAITOK); | | 609 | bpc.replybuf = malloc(BOOTP_SIZE_MAX, M_DEVBUF, M_WAITOK); |
610 | if (bpc.replybuf == NULL) | | 610 | if (bpc.replybuf == NULL) |
611 | panic("nfs_boot: malloc reply buf"); | | 611 | panic("nfs_boot: malloc reply buf"); |
612 | #ifdef NFS_BOOT_DHCP | | 612 | #ifdef NFS_BOOT_DHCP |
613 | bpc.expected_dhcpmsgtype = DHCPOFFER; | | 613 | bpc.expected_dhcpmsgtype = DHCPOFFER; |
614 | bpc.dhcp_ok = 0; | | 614 | bpc.dhcp_ok = 0; |
615 | #endif | | 615 | #endif |
616 | | | 616 | |
617 | error = nfs_boot_sendrecv(so, nam, bootpset, m, | | 617 | error = nfs_boot_sendrecv(so, nam, bootpset, m, |
618 | bootpcheck, 0, 0, &bpc, lwp); | | 618 | bootpcheck, 0, 0, &bpc, lwp); |
619 | if (error) | | 619 | if (error) |
620 | goto out; | | 620 | goto out; |
621 | | | 621 | |
622 | #ifdef NFS_BOOT_DHCP | | 622 | #ifdef NFS_BOOT_DHCP |
623 | if (bpc.dhcp_ok) { | | 623 | if (bpc.dhcp_ok) { |
624 | u_int32_t leasetime; | | 624 | u_int32_t leasetime; |
625 | bootp->bp_vend[6] = DHCPREQUEST; | | 625 | bootp->bp_vend[6] = DHCPREQUEST; |
626 | bootp->bp_vend[7] = TAG_REQ_ADDR; | | 626 | bootp->bp_vend[7] = TAG_REQ_ADDR; |
627 | bootp->bp_vend[8] = 4; | | 627 | bootp->bp_vend[8] = 4; |
628 | memcpy(&bootp->bp_vend[9], &bpc.replybuf->bp_yiaddr, 4); | | 628 | memcpy(&bootp->bp_vend[9], &bpc.replybuf->bp_yiaddr, 4); |
629 | bootp->bp_vend[13] = TAG_SERVERID; | | 629 | bootp->bp_vend[13] = TAG_SERVERID; |
630 | bootp->bp_vend[14] = 4; | | 630 | bootp->bp_vend[14] = 4; |
631 | memcpy(&bootp->bp_vend[15], &bpc.dhcp_serverip.s_addr, 4); | | 631 | memcpy(&bootp->bp_vend[15], &bpc.dhcp_serverip.s_addr, 4); |
632 | bootp->bp_vend[19] = TAG_LEASETIME; | | 632 | bootp->bp_vend[19] = TAG_LEASETIME; |
633 | bootp->bp_vend[20] = 4; | | 633 | bootp->bp_vend[20] = 4; |
634 | leasetime = htonl(300); | | 634 | leasetime = htonl(300); |
635 | memcpy(&bootp->bp_vend[21], &leasetime, 4); | | 635 | memcpy(&bootp->bp_vend[21], &leasetime, 4); |
636 | bootp->bp_vend[25] = TAG_CLASSID; | | 636 | bootp->bp_vend[25] = TAG_CLASSID; |
637 | bootp->bp_vend[26] = vcilen; | | 637 | bootp->bp_vend[26] = vcilen; |
638 | memcpy(&bootp->bp_vend[27], vci, vcilen); | | 638 | memcpy(&bootp->bp_vend[27], vci, vcilen); |
639 | bootp->bp_vend[27 + vcilen] = TAG_END; | | 639 | bootp->bp_vend[27 + vcilen] = TAG_END; |
640 | | | 640 | |
641 | bpc.expected_dhcpmsgtype = DHCPACK; | | 641 | bpc.expected_dhcpmsgtype = DHCPACK; |
642 | | | 642 | |
643 | error = nfs_boot_sendrecv(so, nam, bootpset, m, | | 643 | error = nfs_boot_sendrecv(so, nam, bootpset, m, |
644 | bootpcheck, 0, 0, &bpc, lwp); | | 644 | bootpcheck, 0, 0, &bpc, lwp); |
645 | if (error) | | 645 | if (error) |
646 | goto out; | | 646 | goto out; |
647 | } | | 647 | } |
648 | #endif | | 648 | #endif |
649 | | | 649 | |
650 | /* | | 650 | /* |
651 | * bootpcheck() has copied the receive mbuf into | | 651 | * bootpcheck() has copied the receive mbuf into |
652 | * the buffer at bpc.replybuf. | | 652 | * the buffer at bpc.replybuf. |
653 | */ | | 653 | */ |
654 | #ifdef NFS_BOOT_DHCP | | 654 | #ifdef NFS_BOOT_DHCP |
655 | printf("nfs_boot: %s next-server: %s\n", | | 655 | printf("nfs_boot: %s next-server: %s\n", |
656 | (bpc.dhcp_ok ? "DHCP" : "BOOTP"), | | 656 | (bpc.dhcp_ok ? "DHCP" : "BOOTP"), |
657 | #else | | 657 | #else |
658 | printf("nfs_boot: BOOTP next-server: %s\n", | | 658 | printf("nfs_boot: BOOTP next-server: %s\n", |
659 | #endif | | 659 | #endif |
660 | inet_ntoa(bpc.replybuf->bp_siaddr)); | | 660 | inet_ntoa(bpc.replybuf->bp_siaddr)); |
661 | | | 661 | |
662 | bootp_extract(bpc.replybuf, bpc.replylen, nd, flags); | | 662 | bootp_extract(bpc.replybuf, bpc.replylen, nd, flags); |
663 | | | 663 | |
664 | out: | | 664 | out: |
665 | if (bpc.replybuf) | | 665 | if (bpc.replybuf) |
666 | free(bpc.replybuf, M_DEVBUF); | | 666 | free(bpc.replybuf, M_DEVBUF); |
667 | if (m) | | 667 | if (m) |
668 | m_freem(m); | | 668 | m_freem(m); |
669 | if (nam) | | 669 | if (nam) |
670 | m_freem(nam); | | 670 | m_freem(nam); |
671 | soclose(so); | | 671 | soclose(so); |
672 | return (error); | | 672 | return (error); |
673 | } | | 673 | } |
674 | | | 674 | |
675 | static void | | 675 | static void |
676 | bootp_extract(struct bootp *bootp, int replylen, | | 676 | bootp_extract(struct bootp *bootp, int replylen, |
677 | struct nfs_diskless *nd, int *flags) | | 677 | struct nfs_diskless *nd, int *flags) |
678 | { | | 678 | { |
679 | struct sockaddr_in *sin; | | 679 | struct sockaddr_in *sin; |
680 | struct in_addr netmask; | | 680 | struct in_addr netmask; |
681 | struct in_addr gateway; | | 681 | struct in_addr gateway; |
682 | struct in_addr rootserver; | | 682 | struct in_addr rootserver; |
683 | char *myname; /* my hostname */ | | 683 | char *myname; /* my hostname */ |
684 | char *mydomain; /* my domainname */ | | 684 | char *mydomain; /* my domainname */ |
685 | char *rootpath; | | 685 | char *rootpath; |
686 | int mynamelen; | | 686 | int mynamelen; |
687 | int mydomainlen; | | 687 | int mydomainlen; |
688 | int rootpathlen; | | 688 | int rootpathlen; |
689 | int overloaded; | | 689 | int overloaded; |
690 | u_int tag, len; | | 690 | u_int tag, len; |
691 | u_char *p, *limit; | | 691 | u_char *p, *limit; |
692 | | | 692 | |
693 | /* Default these to "unspecified". */ | | 693 | /* Default these to "unspecified". */ |
694 | netmask.s_addr = 0; | | 694 | netmask.s_addr = 0; |
695 | gateway.s_addr = 0; | | 695 | gateway.s_addr = 0; |
696 | mydomain = myname = rootpath = NULL; | | 696 | mydomain = myname = rootpath = NULL; |
697 | mydomainlen = mynamelen = rootpathlen = 0; | | 697 | mydomainlen = mynamelen = rootpathlen = 0; |
698 | | | 698 | |
699 | /* default root server to bootp next-server */ | | 699 | /* default root server to bootp next-server */ |
700 | rootserver = bootp->bp_siaddr; | | 700 | rootserver = bootp->bp_siaddr; |
701 | /* assume that server name field is not overloaded by default */ | | 701 | /* assume that server name field is not overloaded by default */ |
702 | overloaded = 0; | | 702 | overloaded = 0; |
703 | | | 703 | |
704 | p = &bootp->bp_vend[4]; | | 704 | p = &bootp->bp_vend[4]; |
705 | limit = ((u_char*)bootp) + replylen; | | 705 | limit = ((u_char*)bootp) + replylen; |
706 | while (p < limit) { | | 706 | while (p < limit) { |
707 | tag = *p++; | | 707 | tag = *p++; |
708 | if (tag == TAG_END) | | 708 | if (tag == TAG_END) |
709 | break; | | 709 | break; |
710 | if (tag == TAG_PAD) | | 710 | if (tag == TAG_PAD) |
711 | continue; | | 711 | continue; |
712 | len = *p++; | | 712 | len = *p++; |
713 | #if 0 /* already done in bootpcheck() */ | | 713 | #if 0 /* already done in bootpcheck() */ |
714 | if ((p + len) > limit) { | | 714 | if ((p + len) > limit) { |
715 | printf("nfs_boot: option %d too long\n", tag); | | 715 | printf("nfs_boot: option %d too long\n", tag); |
716 | break; | | 716 | break; |
717 | } | | 717 | } |
718 | #endif | | 718 | #endif |
719 | switch (tag) { | | 719 | switch (tag) { |
720 | case TAG_SUBNET_MASK: | | 720 | case TAG_SUBNET_MASK: |
721 | memcpy(&netmask, p, 4); | | 721 | memcpy(&netmask, p, 4); |
722 | break; | | 722 | break; |
723 | case TAG_GATEWAY: | | 723 | case TAG_GATEWAY: |
724 | /* Routers */ | | 724 | /* Routers */ |
725 | memcpy(&gateway, p, 4); | | 725 | memcpy(&gateway, p, 4); |
726 | break; | | 726 | break; |
727 | case TAG_HOST_NAME: | | 727 | case TAG_HOST_NAME: |
728 | if (len >= sizeof(hostname)) { | | 728 | if (len >= sizeof(hostname)) { |
729 | printf("nfs_boot: host name >= %lu bytes", | | 729 | printf("nfs_boot: host name >= %lu bytes", |
730 | (u_long)sizeof(hostname)); | | 730 | (u_long)sizeof(hostname)); |
731 | break; | | 731 | break; |
732 | } | | 732 | } |
733 | myname = p; | | 733 | myname = p; |
734 | mynamelen = len; | | 734 | mynamelen = len; |
735 | break; | | 735 | break; |
736 | case TAG_DOMAIN_NAME: | | 736 | case TAG_DOMAIN_NAME: |
737 | if (len >= sizeof(domainname)) { | | 737 | if (len >= sizeof(domainname)) { |
738 | printf("nfs_boot: domain name >= %lu bytes", | | 738 | printf("nfs_boot: domain name >= %lu bytes", |
739 | (u_long)sizeof(domainname)); | | 739 | (u_long)sizeof(domainname)); |
740 | break; | | 740 | break; |
741 | } | | 741 | } |
742 | mydomain = p; | | 742 | mydomain = p; |
743 | mydomainlen = len; | | 743 | mydomainlen = len; |
744 | break; | | 744 | break; |
745 | case TAG_ROOT_PATH: | | 745 | case TAG_ROOT_PATH: |
746 | /* Leave some room for the server name. */ | | 746 | /* Leave some room for the server name. */ |
747 | if (len >= (MNAMELEN-10)) { | | 747 | if (len >= (MNAMELEN-10)) { |
748 | printf("nfs_boot: rootpath >=%d bytes", | | 748 | printf("nfs_boot: rootpath >=%d bytes", |
749 | (MNAMELEN-10)); | | 749 | (MNAMELEN-10)); |
750 | break; | | 750 | break; |
751 | } | | 751 | } |
752 | rootpath = p; | | 752 | rootpath = p; |
753 | rootpathlen = len; | | 753 | rootpathlen = len; |
754 | break; | | 754 | break; |
755 | case TAG_SWAP_SERVER: | | 755 | case TAG_SWAP_SERVER: |
756 | /* override NFS server address */ | | 756 | /* override NFS server address */ |
757 | memcpy(&rootserver, p, 4); | | 757 | memcpy(&rootserver, p, 4); |
758 | break; | | 758 | break; |
759 | #ifdef NFS_BOOT_DHCP | | 759 | #ifdef NFS_BOOT_DHCP |
760 | case TAG_OVERLOAD: | | 760 | case TAG_OVERLOAD: |
761 | if (len > 0 && ((*p & 0x02) != 0)) | | 761 | if (len > 0 && ((*p & 0x02) != 0)) |
762 | /* | | 762 | /* |
763 | * The server name field in the dhcp packet | | 763 | * The server name field in the dhcp packet |
764 | * is overloaded and we can't find server | | 764 | * is overloaded and we can't find server |
765 | * name there. | | 765 | * name there. |
766 | */ | | 766 | */ |
767 | overloaded = 1; | | 767 | overloaded = 1; |
768 | break; | | 768 | break; |
769 | #endif | | 769 | #endif |
770 | default: | | 770 | default: |
771 | break; | | 771 | break; |
772 | } | | 772 | } |
773 | p += len; | | 773 | p += len; |
774 | } | | 774 | } |
775 | | | 775 | |
776 | /* | | 776 | /* |
777 | * Store and print network config info. | | 777 | * Store and print network config info. |
778 | */ | | 778 | */ |
779 | if (myname) { | | 779 | if (myname) { |
780 | myname[mynamelen] = '\0'; | | 780 | myname[mynamelen] = '\0'; |
781 | strncpy(hostname, myname, sizeof(hostname)); | | 781 | strncpy(hostname, myname, sizeof(hostname)); |
782 | hostnamelen = mynamelen; | | 782 | hostnamelen = mynamelen; |
783 | printf("nfs_boot: my_name=%s\n", hostname); | | 783 | printf("nfs_boot: my_name=%s\n", hostname); |
784 | } | | 784 | } |
785 | if (mydomain) { | | 785 | if (mydomain) { |
786 | mydomain[mydomainlen] = '\0'; | | 786 | mydomain[mydomainlen] = '\0'; |
787 | strncpy(domainname, mydomain, sizeof(domainname)); | | 787 | strncpy(domainname, mydomain, sizeof(domainname)); |
788 | domainnamelen = mydomainlen; | | 788 | domainnamelen = mydomainlen; |
789 | printf("nfs_boot: my_domain=%s\n", domainname); | | 789 | printf("nfs_boot: my_domain=%s\n", domainname); |
790 | } | | 790 | } |
791 | if (!(*flags & NFS_BOOT_HAS_MYIP)) { | | 791 | if (!(*flags & NFS_BOOT_HAS_MYIP)) { |
792 | nd->nd_myip = bootp->bp_yiaddr; | | 792 | nd->nd_myip = bootp->bp_yiaddr; |
793 | printf("nfs_boot: my_addr=%s\n", inet_ntoa(nd->nd_myip)); | | 793 | printf("nfs_boot: my_addr=%s\n", inet_ntoa(nd->nd_myip)); |
794 | *flags |= NFS_BOOT_HAS_MYIP; | | 794 | *flags |= NFS_BOOT_HAS_MYIP; |
795 | } | | 795 | } |
796 | if (!(*flags & NFS_BOOT_HAS_MASK)) { | | 796 | if (!(*flags & NFS_BOOT_HAS_MASK)) { |
797 | nd->nd_mask = netmask; | | 797 | nd->nd_mask = netmask; |
798 | printf("nfs_boot: my_mask=%s\n", inet_ntoa(nd->nd_mask)); | | 798 | printf("nfs_boot: my_mask=%s\n", inet_ntoa(nd->nd_mask)); |
799 | *flags |= NFS_BOOT_HAS_MASK; | | 799 | *flags |= NFS_BOOT_HAS_MASK; |
800 | } | | 800 | } |
801 | if (!(*flags & NFS_BOOT_HAS_GWIP)) { | | 801 | if (!(*flags & NFS_BOOT_HAS_GWIP)) { |
802 | nd->nd_gwip = gateway; | | 802 | nd->nd_gwip = gateway; |
803 | printf("nfs_boot: gateway=%s\n", inet_ntoa(nd->nd_gwip)); | | 803 | printf("nfs_boot: gateway=%s\n", inet_ntoa(nd->nd_gwip)); |
804 | *flags |= NFS_BOOT_HAS_GWIP; | | 804 | *flags |= NFS_BOOT_HAS_GWIP; |
805 | } | | 805 | } |
806 | | | 806 | |
807 | /* | | 807 | /* |
808 | * Store the information about our NFS root mount. | | 808 | * Store the information about our NFS root mount. |
809 | * The caller will print it, so be silent here. | | 809 | * The caller will print it, so be silent here. |
810 | */ | | 810 | */ |
811 | do { | | 811 | do { |
812 | struct nfs_dlmount *ndm = &nd->nd_root; | | 812 | struct nfs_dlmount *ndm = &nd->nd_root; |
813 | | | 813 | |
814 | | | 814 | |
815 | if (!(*flags & NFS_BOOT_HAS_SERVADDR)) { | | 815 | if (!(*flags & NFS_BOOT_HAS_SERVADDR)) { |
816 | /* Server IP address. */ | | 816 | /* Server IP address. */ |
817 | sin = (struct sockaddr_in *) &ndm->ndm_saddr; | | 817 | sin = (struct sockaddr_in *) &ndm->ndm_saddr; |
818 | memset((void *)sin, 0, sizeof(*sin)); | | 818 | memset((void *)sin, 0, sizeof(*sin)); |
819 | sin->sin_len = sizeof(*sin); | | 819 | sin->sin_len = sizeof(*sin); |
820 | sin->sin_family = AF_INET; | | 820 | sin->sin_family = AF_INET; |
821 | sin->sin_addr = rootserver; | | 821 | sin->sin_addr = rootserver; |
822 | *flags |= NFS_BOOT_HAS_SERVADDR; | | 822 | *flags |= NFS_BOOT_HAS_SERVADDR; |
823 | } | | 823 | } |
824 | | | 824 | |
825 | if (!(*flags & NFS_BOOT_HAS_SERVER)) { | | 825 | if (!(*flags & NFS_BOOT_HAS_SERVER)) { |
826 | /* Server name. */ | | 826 | /* Server name. */ |
827 | if (!overloaded && bootp->bp_sname[0] != 0 && | | 827 | if (!overloaded && bootp->bp_sname[0] != 0 && |
828 | !memcmp(&rootserver, &bootp->bp_siaddr, | | 828 | !memcmp(&rootserver, &bootp->bp_siaddr, |
829 | sizeof(struct in_addr))) | | 829 | sizeof(struct in_addr))) |
830 | { | | 830 | { |
831 | /* standard root server, we have the name */ | | 831 | /* standard root server, we have the name */ |
832 | strncpy(ndm->ndm_host, bootp->bp_sname, | | 832 | strncpy(ndm->ndm_host, bootp->bp_sname, |
833 | BP_SNAME_LEN-1); | | 833 | BP_SNAME_LEN-1); |
834 | *flags |= NFS_BOOT_HAS_SERVER; | | 834 | *flags |= NFS_BOOT_HAS_SERVER; |
835 | } else { | | 835 | } else { |
836 | /* Show the server IP address numerically. */ | | 836 | /* Show the server IP address numerically. */ |
837 | strncpy(ndm->ndm_host, inet_ntoa(rootserver), | | 837 | strncpy(ndm->ndm_host, inet_ntoa(rootserver), |
838 | BP_SNAME_LEN-1); | | 838 | BP_SNAME_LEN-1); |
839 | *flags |= NFS_BOOT_HAS_SERVER; | | 839 | *flags |= NFS_BOOT_HAS_SERVER; |
840 | } | | 840 | } |
841 | } | | 841 | } |
842 | | | 842 | |
843 | if (!(*flags & NFS_BOOT_HAS_ROOTPATH)) { | | 843 | if (!(*flags & NFS_BOOT_HAS_ROOTPATH)) { |
844 | len = strlen(ndm->ndm_host); | | 844 | len = strlen(ndm->ndm_host); |
845 | if (rootpath && | | 845 | if (rootpath && |
846 | len + 1 + rootpathlen + 1 <= sizeof(ndm->ndm_host)) | | 846 | len + 1 + rootpathlen + 1 <= sizeof(ndm->ndm_host)) |
847 | { | | 847 | { |
848 | ndm->ndm_host[len++] = ':'; | | 848 | ndm->ndm_host[len++] = ':'; |
849 | strncpy(ndm->ndm_host + len, | | 849 | strncpy(ndm->ndm_host + len, |
850 | rootpath, rootpathlen); | | 850 | rootpath, rootpathlen); |
851 | ndm->ndm_host[len + rootpathlen] = '\0'; | | 851 | ndm->ndm_host[len + rootpathlen] = '\0'; |
852 | *flags |= NFS_BOOT_HAS_ROOTPATH; | | 852 | *flags |= NFS_BOOT_HAS_ROOTPATH; |
853 | } /* else: upper layer will handle error */ | | 853 | } /* else: upper layer will handle error */ |
854 | } | | 854 | } |
855 | } while(0); | | 855 | } while(0); |
856 | | | 856 | |
857 | #ifdef TFTPROOT | | 857 | #ifdef TFTPROOT |
858 | #if BP_FILE_LEN > MNAMELEN | | 858 | #if BP_FILE_LEN > MNAMELEN |
859 | #define BOOTFILELEN MNAMELEN | | 859 | #define BOOTFILELEN MNAMELEN |
860 | #else | | 860 | #else |
861 | #define BOOTFILELEN BP_FILE_LEN | | 861 | #define BOOTFILELEN BP_FILE_LEN |
862 | #endif | | 862 | #endif |
863 | strncpy(nd->nd_bootfile, bootp->bp_file, BOOTFILELEN); | | 863 | strncpy(nd->nd_bootfile, bootp->bp_file, BOOTFILELEN); |
864 | nd->nd_bootfile[BOOTFILELEN - 1] = '\0'; | | 864 | nd->nd_bootfile[BOOTFILELEN - 1] = '\0'; |
865 | #undef BOOTFILELEN | | 865 | #undef BOOTFILELEN |
866 | #endif /* TFTPROOT */ | | 866 | #endif /* TFTPROOT */ |
867 | } | | 867 | } |