| @@ -1,82 +1,82 @@ | | | @@ -1,82 +1,82 @@ |
1 | /* $NetBSD: subr_tftproot.c,v 1.23 2019/01/20 21:26:13 bad Exp $ */ | | 1 | /* $NetBSD: subr_tftproot.c,v 1.24 2020/03/07 23:20:19 tnn Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2007 Emmanuel Dreyfus, all rights reserved. | | 4 | * Copyright (c) 2007 Emmanuel Dreyfus, all rights reserved. |
5 | * | | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | | 7 | * modification, are permitted provided that the following conditions |
8 | * are met: | | 8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright | | 9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. | | 10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright | | 11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the | | 12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. | | 13 | * documentation and/or other materials provided with the distribution. |
14 | * 3. All advertising materials mentioning features or use of this software | | 14 | * 3. All advertising materials mentioning features or use of this software |
15 | * must display the following acknowledgement: | | 15 | * must display the following acknowledgement: |
16 | * This product includes software developed by Emmanuel Dreyfus | | 16 | * This product includes software developed by Emmanuel Dreyfus |
17 | * 4. The name of the author may not be used to endorse or promote | | 17 | * 4. The name of the author may not be used to endorse or promote |
18 | * products derived from this software without specific prior written | | 18 | * products derived from this software without specific prior written |
19 | * permission. | | 19 | * permission. |
20 | * | | 20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' | | 21 | * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' |
22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | | 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
23 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 23 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS | | 24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | * POSSIBILITY OF SUCH DAMAGE. | | 31 | * POSSIBILITY OF SUCH DAMAGE. |
32 | */ | | 32 | */ |
33 | | | 33 | |
34 | /* | | 34 | /* |
35 | * Download the root RAMdisk through TFTP at root mount time | | 35 | * Download the root RAMdisk through TFTP at root mount time |
36 | */ | | 36 | */ |
37 | | | 37 | |
38 | #include "opt_tftproot.h" | | 38 | #include "opt_tftproot.h" |
39 | #include "opt_md.h" | | 39 | #include "opt_md.h" |
40 | | | 40 | |
41 | #include <sys/cdefs.h> | | 41 | #include <sys/cdefs.h> |
42 | __KERNEL_RCSID(0, "$NetBSD: subr_tftproot.c,v 1.23 2019/01/20 21:26:13 bad Exp $"); | | 42 | __KERNEL_RCSID(0, "$NetBSD: subr_tftproot.c,v 1.24 2020/03/07 23:20:19 tnn Exp $"); |
43 | | | 43 | |
44 | #include <sys/param.h> | | 44 | #include <sys/param.h> |
45 | #include <sys/types.h> | | 45 | #include <sys/types.h> |
46 | #include <sys/vnode.h> | | 46 | #include <sys/vnode.h> |
47 | #include <sys/mount.h> | | 47 | #include <sys/mount.h> |
48 | #include <sys/lwp.h> | | 48 | #include <sys/lwp.h> |
49 | #include <sys/kmem.h> | | 49 | #include <sys/kmem.h> |
50 | #include <sys/mbuf.h> | | 50 | #include <sys/mbuf.h> |
51 | #include <sys/timevar.h> | | 51 | #include <sys/timevar.h> |
52 | #include <sys/socketvar.h> | | 52 | #include <sys/socketvar.h> |
53 | | | 53 | |
54 | #include <net/if.h> | | 54 | #include <net/if.h> |
55 | | | 55 | |
56 | #include <dev/md.h> | | 56 | #include <dev/md.h> |
57 | | | 57 | |
58 | #include <netinet/in.h> | | 58 | #include <netinet/in.h> |
59 | | | 59 | |
60 | #include <nfs/rpcv2.h> | | 60 | #include <nfs/rpcv2.h> |
61 | | | 61 | |
62 | #include <nfs/nfsproto.h> | | 62 | #include <nfs/nfsproto.h> |
63 | #include <nfs/nfs.h> | | 63 | #include <nfs/nfs.h> |
64 | #include <nfs/nfsmount.h> | | 64 | #include <nfs/nfsmount.h> |
65 | #include <nfs/nfsdiskless.h> | | 65 | #include <nfs/nfsdiskless.h> |
66 | #include <nfs/nfs_var.h> | | 66 | #include <nfs/nfs_var.h> |
67 | | | 67 | |
68 | /* | | 68 | /* |
69 | * Copied from <lib/libsa/tftp.h> | | 69 | * Copied from <lib/libsa/tftp.h> |
70 | */ | | 70 | */ |
71 | | | 71 | |
72 | #define SEGSIZE 512 /* data segment size */ | | 72 | #define SEGSIZE 512 /* data segment size */ |
73 | | | 73 | |
74 | /* | | 74 | /* |
75 | * Packet types. | | 75 | * Packet types. |
76 | */ | | 76 | */ |
77 | #define RRQ 01 /* read request */ | | 77 | #define RRQ 01 /* read request */ |
78 | #define WRQ 02 /* write request */ | | 78 | #define WRQ 02 /* write request */ |
79 | #define DATA 03 /* data packet */ | | 79 | #define DATA 03 /* data packet */ |
80 | #define ACK 04 /* acknowledgement */ | | 80 | #define ACK 04 /* acknowledgement */ |
81 | #define ERROR 05 /* error code */ | | 81 | #define ERROR 05 /* error code */ |
82 | | | 82 | |
| @@ -124,27 +124,27 @@ tftproot_dhcpboot(device_t bootdv) | | | @@ -124,27 +124,27 @@ tftproot_dhcpboot(device_t bootdv) |
124 | struct nfs_diskless *nd = NULL; | | 124 | struct nfs_diskless *nd = NULL; |
125 | struct ifnet *ifp = NULL; | | 125 | struct ifnet *ifp = NULL; |
126 | struct lwp *l; | | 126 | struct lwp *l; |
127 | struct tftproot_handle trh; | | 127 | struct tftproot_handle trh; |
128 | device_t dv; | | 128 | device_t dv; |
129 | int error = -1; | | 129 | int error = -1; |
130 | | | 130 | |
131 | if (rootspec != NULL) { | | 131 | if (rootspec != NULL) { |
132 | int s = pserialize_read_enter(); | | 132 | int s = pserialize_read_enter(); |
133 | IFNET_READER_FOREACH(ifp) | | 133 | IFNET_READER_FOREACH(ifp) |
134 | if (strcmp(rootspec, ifp->if_xname) == 0) | | 134 | if (strcmp(rootspec, ifp->if_xname) == 0) |
135 | break; | | 135 | break; |
136 | pserialize_read_exit(s); | | 136 | pserialize_read_exit(s); |
137 | } | | 137 | } |
138 | | | 138 | |
139 | if ((ifp == NULL) && | | 139 | if ((ifp == NULL) && |
140 | (bootdv != NULL && device_class(bootdv) == DV_IFNET)) { | | 140 | (bootdv != NULL && device_class(bootdv) == DV_IFNET)) { |
141 | int s = pserialize_read_enter(); | | 141 | int s = pserialize_read_enter(); |
142 | IFNET_READER_FOREACH(ifp) | | 142 | IFNET_READER_FOREACH(ifp) |
143 | if (strcmp(device_xname(bootdv), ifp->if_xname) == 0) | | 143 | if (strcmp(device_xname(bootdv), ifp->if_xname) == 0) |
144 | break; | | 144 | break; |
145 | pserialize_read_exit(s); | | 145 | pserialize_read_exit(s); |
146 | } | | 146 | } |
147 | | | 147 | |
148 | if (ifp == NULL) { | | 148 | if (ifp == NULL) { |
149 | DPRINTF(("%s():%d ifp is NULL\n", __func__, __LINE__)); | | 149 | DPRINTF(("%s():%d ifp is NULL\n", __func__, __LINE__)); |
150 | goto out; | | 150 | goto out; |
| @@ -157,190 +157,190 @@ tftproot_dhcpboot(device_t bootdv) | | | @@ -157,190 +157,190 @@ tftproot_dhcpboot(device_t bootdv) |
157 | __func__, __LINE__, ifp->if_xname)); | | 157 | __func__, __LINE__, ifp->if_xname)); |
158 | goto out; | | 158 | goto out; |
159 | } | | 159 | } |
160 | | | 160 | |
161 | root_device = dv; | | 161 | root_device = dv; |
162 | | | 162 | |
163 | l = curlwp; /* XXX */ | | 163 | l = curlwp; /* XXX */ |
164 | | | 164 | |
165 | nd = kmem_zalloc(sizeof(*nd), KM_SLEEP); | | 165 | nd = kmem_zalloc(sizeof(*nd), KM_SLEEP); |
166 | nd->nd_ifp = ifp; | | 166 | nd->nd_ifp = ifp; |
167 | nd->nd_nomount = 1; | | 167 | nd->nd_nomount = 1; |
168 | | | 168 | |
169 | if ((error = nfs_boot_init(nd, l)) != 0) { | | 169 | if ((error = nfs_boot_init(nd, l)) != 0) { |
170 | DPRINTF(("%s():%d nfs_boot_init returned %d\n", | | 170 | DPRINTF(("%s():%d nfs_boot_init returned %d\n", |
171 | __func__, __LINE__, error)); | | 171 | __func__, __LINE__, error)); |
172 | goto out; | | 172 | goto out; |
173 | } | | 173 | } |
174 | | | 174 | |
175 | /* | | 175 | /* |
176 | * Strip leading "tftp:" | | 176 | * Strip leading "tftp:" |
177 | */ | | 177 | */ |
178 | #define PREFIX "tftp:" | | 178 | #define PREFIX "tftp:" |
179 | if (strstr(nd->nd_bootfile, PREFIX) == nd->nd_bootfile) | | 179 | if (strstr(nd->nd_bootfile, PREFIX) == nd->nd_bootfile) |
180 | (void)memmove(nd->nd_bootfile, | | 180 | (void)memmove(nd->nd_bootfile, |
181 | nd->nd_bootfile + (sizeof(PREFIX) - 1), | | 181 | nd->nd_bootfile + (sizeof(PREFIX) - 1), |
182 | sizeof(nd->nd_bootfile) - sizeof(PREFIX)); | | 182 | sizeof(nd->nd_bootfile) - sizeof(PREFIX)); |
183 | #undef PREFIX | | 183 | #undef PREFIX |
184 | | | 184 | |
185 | printf("tftproot: bootfile=%s\n", nd->nd_bootfile); | | 185 | printf("tftproot: bootfile=%s\n", nd->nd_bootfile); |
186 | | | 186 | |
187 | memset(&trh, 0, sizeof(trh)); | | 187 | memset(&trh, 0, sizeof(trh)); |
188 | trh.trh_nd = nd; | | 188 | trh.trh_nd = nd; |
189 | trh.trh_block = 1; | | 189 | trh.trh_block = 1; |
190 | | | 190 | |
191 | if ((error = tftproot_getfile(&trh, l)) != 0) { | | 191 | if ((error = tftproot_getfile(&trh, l)) != 0) { |
192 | DPRINTF(("%s():%d tftproot_getfile returned %d\n", | | 192 | DPRINTF(("%s():%d tftproot_getfile returned %d\n", |
193 | __func__, __LINE__, error)); | | 193 | __func__, __LINE__, error)); |
194 | goto out; | | 194 | goto out; |
195 | } | | 195 | } |
196 | | | 196 | |
197 | error = 0; | | 197 | error = 0; |
198 | | | 198 | |
199 | out: | | 199 | out: |
200 | if (nd) | | 200 | if (nd) |
201 | kmem_free(nd, sizeof(*nd)); | | 201 | kmem_free(nd, sizeof(*nd)); |
202 | | | 202 | |
203 | return error; | | 203 | return error; |
204 | } | | 204 | } |
205 | | | 205 | |
206 | static int | | 206 | static int |
207 | tftproot_getfile(struct tftproot_handle *trh, struct lwp *l) | | 207 | tftproot_getfile(struct tftproot_handle *trh, struct lwp *l) |
208 | { | | 208 | { |
209 | struct socket *so = NULL; | | 209 | struct socket *so = NULL; |
210 | struct mbuf *m_serv = NULL; | | 210 | struct mbuf *m_serv = NULL; |
211 | struct mbuf *m_outbuf = NULL; | | 211 | struct mbuf *m_outbuf = NULL; |
212 | struct sockaddr_in sin; | | 212 | struct sockaddr_in sin; |
213 | struct tftphdr *tftp; | | 213 | struct tftphdr *tftp; |
214 | size_t packetlen, namelen; | | 214 | size_t packetlen, namelen; |
215 | int error = -1; | | 215 | int error = -1; |
216 | const char octetstr[] = "octet"; | | 216 | const char octetstr[] = "octet"; |
217 | size_t hdrlen = sizeof(*tftp) - sizeof(tftp->th_data); | | 217 | size_t hdrlen = sizeof(*tftp) - sizeof(tftp->th_data); |
218 | char *cp; | | 218 | char *cp; |
219 | | | 219 | |
220 | if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, l, NULL)) != 0) { | | 220 | if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, l, NULL)) != 0) { |
221 | DPRINTF(("%s():%d socreate returned %d\n", | | 221 | DPRINTF(("%s():%d socreate returned %d\n", |
222 | __func__, __LINE__, error)); | | 222 | __func__, __LINE__, error)); |
223 | goto out; | | 223 | goto out; |
224 | } | | 224 | } |
225 | | | 225 | |
226 | /* | | 226 | /* |
227 | * Set timeout | | 227 | * Set timeout |
228 | */ | | 228 | */ |
229 | if ((error = nfs_boot_setrecvtimo(so))) { | | 229 | if ((error = nfs_boot_setrecvtimo(so))) { |
230 | DPRINTF(("%s():%d SO_RCVTIMEO failed %d\n", | | 230 | DPRINTF(("%s():%d SO_RCVTIMEO failed %d\n", |
231 | __func__, __LINE__, error)); | | 231 | __func__, __LINE__, error)); |
232 | goto out; | | 232 | goto out; |
233 | } | | 233 | } |
234 | | | 234 | |
235 | /* | | 235 | /* |
236 | * Set server address and port | | 236 | * Set server address and port |
237 | */ | | 237 | */ |
238 | memcpy(&sin, &trh->trh_nd->nd_root.ndm_saddr, sizeof(sin)); | | 238 | memcpy(&sin, &trh->trh_nd->nd_root.ndm_saddr, sizeof(sin)); |
239 | sin.sin_port = htons(IPPORT_TFTP); | | 239 | sin.sin_port = htons(IPPORT_TFTP); |
240 | | | 240 | |
241 | /* | | 241 | /* |
242 | * Set send buffer, prepare the TFTP packet | | 242 | * Set send buffer, prepare the TFTP packet |
243 | */ | | 243 | */ |
244 | namelen = strlen(trh->trh_nd->nd_bootfile) + 1; | | 244 | namelen = strlen(trh->trh_nd->nd_bootfile) + 1; |
245 | packetlen = sizeof(tftp->th_opcode) + namelen + sizeof(octetstr); | | 245 | packetlen = sizeof(tftp->th_opcode) + namelen + sizeof(octetstr); |
246 | if (packetlen > MSIZE) { | | 246 | if (packetlen > MSIZE) { |
247 | DPRINTF(("%s():%d boot filename too long (%ld bytes)\n", | | 247 | DPRINTF(("%s():%d boot filename too long (%ld bytes)\n", |
248 | __func__, __LINE__, (long)namelen)); | | 248 | __func__, __LINE__, (long)namelen)); |
249 | error = E2BIG; | | 249 | error = E2BIG; |
250 | goto out; | | 250 | goto out; |
251 | } | | 251 | } |
252 | | | 252 | |
253 | m_outbuf = m_gethdr(M_WAIT, MT_DATA); | | 253 | m_outbuf = m_gethdr(M_WAIT, MT_DATA); |
254 | m_clget(m_outbuf, M_WAIT); | | 254 | m_clget(m_outbuf, M_WAIT); |
255 | m_outbuf->m_len = packetlen; | | 255 | m_outbuf->m_len = packetlen; |
256 | m_outbuf->m_pkthdr.len = packetlen; | | 256 | m_outbuf->m_pkthdr.len = packetlen; |
257 | m_reset_rcvif(m_outbuf); | | 257 | m_reset_rcvif(m_outbuf); |
258 | | | 258 | |
259 | tftp = mtod(m_outbuf, struct tftphdr *); | | 259 | tftp = mtod(m_outbuf, struct tftphdr *); |
260 | memset(tftp, 0, packetlen); | | 260 | memset(tftp, 0, packetlen); |
261 | | | 261 | |
262 | tftp->th_opcode = htons((short)RRQ); | | 262 | tftp->th_opcode = htons((short)RRQ); |
263 | cp = tftp->th_stuff; | | 263 | cp = tftp->th_stuff; |
264 | (void)strncpy(cp, trh->trh_nd->nd_bootfile, namelen); | | 264 | (void)strncpy(cp, trh->trh_nd->nd_bootfile, namelen); |
265 | cp += namelen; | | 265 | cp += namelen; |
266 | (void)strncpy(cp, octetstr, sizeof(octetstr)); | | 266 | (void)strncpy(cp, octetstr, sizeof(octetstr)); |
267 | | | 267 | |
268 | /* | | 268 | /* |
269 | * Perform the file transfer | | 269 | * Perform the file transfer |
270 | */ | | 270 | */ |
271 | printf("tftproot: download %s:%s ", | | 271 | printf("tftproot: download %s:%s ", |
272 | inet_ntoa(sin.sin_addr), trh->trh_nd->nd_bootfile); | | 272 | inet_ntoa(sin.sin_addr), trh->trh_nd->nd_bootfile); |
273 | | | 273 | |
274 | do { | | 274 | do { |
275 | /* | | 275 | /* |
276 | * Show progress for every 200 blocks (100kB) | | 276 | * Show progress for every 200 blocks (100kB) |
277 | */ | | 277 | */ |
278 | #ifndef TFTPROOT_PROGRESS | | 278 | #ifndef TFTPROOT_PROGRESS |
279 | #define TFTPROOT_PROGRESS 200 | | 279 | #define TFTPROOT_PROGRESS 200 |
280 | #endif | | 280 | #endif |
281 | if ((trh->trh_block % TFTPROOT_PROGRESS) == 0) | | 281 | if ((trh->trh_block % TFTPROOT_PROGRESS) == 0) |
282 | twiddle(); | | 282 | twiddle(); |
283 | | | 283 | |
284 | /* | | 284 | /* |
285 | * Send the packet and receive the answer. | | 285 | * Send the packet and receive the answer. |
286 | * We get the sender address here, which should be | | 286 | * We get the sender address here, which should be |
287 | * the same server with a different port | | 287 | * the same server with a different port |
288 | */ | | 288 | */ |
289 | if ((error = nfs_boot_sendrecv(so, &sin, NULL, m_outbuf, | | 289 | if ((error = nfs_boot_sendrecv(so, &sin, NULL, m_outbuf, |
290 | tftproot_recv, NULL, &m_serv, trh, l)) != 0) { | | 290 | tftproot_recv, NULL, &m_serv, trh, l)) != 0) { |
291 | DPRINTF(("%s():%d sendrecv failed %d\n", | | 291 | DPRINTF(("%s():%d sendrecv failed %d\n", |
292 | __func__, __LINE__, error)); | | 292 | __func__, __LINE__, error)); |
293 | goto out; | | 293 | goto out; |
294 | } | | 294 | } |
295 | | | 295 | |
296 | /* | | 296 | /* |
297 | * Accommodate the packet length for acks. | | 297 | * Accommodate the packet length for acks. |
298 | * This is really needed only on first pass | | 298 | * This is really needed only on first pass |
299 | */ | | 299 | */ |
300 | m_outbuf->m_len = hdrlen; | | 300 | m_outbuf->m_len = hdrlen; |
301 | m_outbuf->m_pkthdr.len = hdrlen; | | 301 | m_outbuf->m_pkthdr.len = hdrlen; |
302 | tftp->th_opcode = htons((short)ACK); | | 302 | tftp->th_opcode = htons((short)ACK); |
303 | tftp->th_block = htons(trh->trh_block); | | 303 | tftp->th_block = htons(trh->trh_block); |
304 | | | 304 | |
305 | | | 305 | |
306 | /* | | 306 | /* |
307 | * Check for termination | | 307 | * Check for termination |
308 | */ | | 308 | */ |
309 | if (trh->trh_flags & TRH_FINISHED) | | 309 | if (trh->trh_flags & TRH_FINISHED) |
310 | break; | | 310 | break; |
311 | | | 311 | |
312 | trh->trh_block++; | | 312 | trh->trh_block++; |
313 | } while (1/* CONSTCOND */); | | 313 | } while (1/* CONSTCOND */); |
314 | | | 314 | |
315 | printf("\n"); | | 315 | printf("\n"); |
316 | | | 316 | |
317 | /* | | 317 | /* |
318 | * Ack the last block. Ignore errors, as we already have the whole | | 318 | * Ack the last block. Ignore errors, as we already have the whole |
319 | * file. | | 319 | * file. |
320 | */ | | 320 | */ |
321 | if ((error = (*so->so_send)(so, mtod(m_serv, struct sockaddr *), NULL, | | 321 | if ((error = (*so->so_send)(so, mtod(m_serv, struct sockaddr *), NULL, |
322 | m_outbuf, NULL, 0, l)) != 0) { | | 322 | m_outbuf, NULL, 0, l)) != 0) { |
323 | DPRINTF(("%s():%d tftproot: sosend returned %d\n", | | 323 | DPRINTF(("%s():%d tftproot: sosend returned %d\n", |
324 | __func__, __LINE__, error)); | | 324 | __func__, __LINE__, error)); |
325 | } | | 325 | } |
326 | | | 326 | |
327 | /* Freed by the protocol */ | | 327 | /* Freed by the protocol */ |
328 | m_outbuf = NULL; | | 328 | m_outbuf = NULL; |
329 | | | 329 | |
330 | /* | | 330 | /* |
331 | * And use it as the root ramdisk. | | 331 | * And use it as the root ramdisk. |
332 | */ | | 332 | */ |
333 | DPRINTF(("%s():%d RAMdisk loaded: %ld@%p\n", | | 333 | DPRINTF(("%s():%d RAMdisk loaded: %ld@%p\n", |
334 | __func__, __LINE__, trh->trh_len, trh->trh_base)); | | 334 | __func__, __LINE__, trh->trh_len, trh->trh_base)); |
335 | md_root_setconf(trh->trh_base, trh->trh_len); | | 335 | md_root_setconf(trh->trh_base, trh->trh_len); |
336 | | | 336 | |
337 | error = 0; | | 337 | error = 0; |
338 | out: | | 338 | out: |
339 | if (m_serv) | | 339 | if (m_serv) |
340 | m_freem(m_serv); | | 340 | m_freem(m_serv); |
341 | | | 341 | |
342 | if (m_outbuf) | | 342 | if (m_outbuf) |
343 | m_freem(m_outbuf); | | 343 | m_freem(m_outbuf); |
344 | | | 344 | |
345 | if (so) | | 345 | if (so) |
346 | soclose(so); | | 346 | soclose(so); |
| @@ -351,36 +351,36 @@ out: | | | @@ -351,36 +351,36 @@ out: |
351 | static int | | 351 | static int |
352 | tftproot_recv(struct mbuf **mp, void *ctx) | | 352 | tftproot_recv(struct mbuf **mp, void *ctx) |
353 | { | | 353 | { |
354 | struct tftproot_handle *trh = ctx; | | 354 | struct tftproot_handle *trh = ctx; |
355 | struct tftphdr *tftp; | | 355 | struct tftphdr *tftp; |
356 | struct mbuf *m = *mp; | | 356 | struct mbuf *m = *mp; |
357 | size_t newlen; | | 357 | size_t newlen; |
358 | size_t hdrlen = sizeof(*tftp) - sizeof(tftp->th_data); | | 358 | size_t hdrlen = sizeof(*tftp) - sizeof(tftp->th_data); |
359 | | | 359 | |
360 | /* | | 360 | /* |
361 | * Check for short packet | | 361 | * Check for short packet |
362 | */ | | 362 | */ |
363 | if (m->m_pkthdr.len < hdrlen) { | | 363 | if (m->m_pkthdr.len < hdrlen) { |
364 | DPRINTF(("%s():%d short reply (%d bytes)\n", | | 364 | DPRINTF(("%s():%d short reply (%d bytes)\n", |
365 | __func__, __LINE__, m->m_pkthdr.len)); | | 365 | __func__, __LINE__, m->m_pkthdr.len)); |
366 | return -1; | | 366 | return -1; |
367 | } | | 367 | } |
368 | | | 368 | |
369 | /* | | 369 | /* |
370 | * Check for packet too large for being a TFTP packet | | 370 | * Check for packet too large for being a TFTP packet |
371 | */ | | 371 | */ |
372 | if (m->m_pkthdr.len > hdrlen + SEGSIZE) { | | 372 | if (m->m_pkthdr.len > hdrlen + SEGSIZE) { |
373 | DPRINTF(("%s():%d packet too big (%d bytes)\n", | | 373 | DPRINTF(("%s():%d packet too big (%d bytes)\n", |
374 | __func__, __LINE__, m->m_pkthdr.len)); | | 374 | __func__, __LINE__, m->m_pkthdr.len)); |
375 | return -1; | | 375 | return -1; |
376 | } | | 376 | } |
377 | | | 377 | |
378 | | | 378 | |
379 | /* | | 379 | /* |
380 | * Examine the TFTP header | | 380 | * Examine the TFTP header |
381 | */ | | 381 | */ |
382 | if (m->m_len > sizeof(*tftp)) { | | 382 | if (m->m_len > sizeof(*tftp)) { |
383 | if ((m = *mp = m_pullup(m, sizeof(*tftp))) == NULL) { | | 383 | if ((m = *mp = m_pullup(m, sizeof(*tftp))) == NULL) { |
384 | DPRINTF(("%s():%d m_pullup failed\n", | | 384 | DPRINTF(("%s():%d m_pullup failed\n", |
385 | __func__, __LINE__)); | | 385 | __func__, __LINE__)); |
386 | return -1; | | 386 | return -1; |
| @@ -407,55 +407,55 @@ tftproot_recv(struct mbuf **mp, void *ct | | | @@ -407,55 +407,55 @@ tftproot_recv(struct mbuf **mp, void *ct |
407 | } | | 407 | } |
408 | errbuf[i] = tftp->th_data[i]; | | 408 | errbuf[i] = tftp->th_data[i]; |
409 | } | | 409 | } |
410 | errbuf[SEGSIZE] = '\0'; | | 410 | errbuf[SEGSIZE] = '\0'; |
411 | | | 411 | |
412 | printf("tftproot: TFTP server returned error %d, %s\n", | | 412 | printf("tftproot: TFTP server returned error %d, %s\n", |
413 | ntohs(tftp->th_code), errbuf); | | 413 | ntohs(tftp->th_code), errbuf); |
414 | | | 414 | |
415 | return -1; | | 415 | return -1; |
416 | break; | | 416 | break; |
417 | } | | 417 | } |
418 | | | 418 | |
419 | default: | | 419 | default: |
420 | DPRINTF(("%s():%d unexpected tftp reply opcode %d\n", | | 420 | DPRINTF(("%s():%d unexpected tftp reply opcode %d\n", |
421 | __func__, __LINE__, ntohs(tftp->th_opcode))); | | 421 | __func__, __LINE__, ntohs(tftp->th_opcode))); |
422 | return -1; | | 422 | return -1; |
423 | break; | | 423 | break; |
424 | } | | 424 | } |
425 | | | 425 | |
426 | /* | | 426 | /* |
427 | * Check for last packet, which does not fill the whole space | | 427 | * Check for last packet, which does not fill the whole space |
428 | */ | | 428 | */ |
429 | if (m->m_pkthdr.len < hdrlen + SEGSIZE) { | | 429 | if (m->m_pkthdr.len < hdrlen + SEGSIZE) { |
430 | DPRINTF(("%s():%d last chunk (%d bytes)\n", | | 430 | DPRINTF(("%s():%d last chunk (%d bytes)\n", |
431 | __func__, __LINE__, m->m_pkthdr.len)); | | 431 | __func__, __LINE__, m->m_pkthdr.len)); |
432 | trh->trh_flags |= TRH_FINISHED; | | 432 | trh->trh_flags |= TRH_FINISHED; |
433 | } | | 433 | } |
434 | | | 434 | |
435 | | | 435 | |
436 | if (ntohs(tftp->th_block) != trh->trh_block) { | | 436 | if (ntohs(tftp->th_block) != trh->trh_block) { |
437 | DPRINTF(("%s():%d expected block %d, got block %d\n", | | 437 | DPRINTF(("%s():%d expected block %d, got block %d\n", |
438 | __func__, __LINE__, trh->trh_block, ntohs(tftp->th_block))); | | 438 | __func__, __LINE__, trh->trh_block, ntohs(tftp->th_block))); |
439 | return -1; | | 439 | return -1; |
440 | } | | 440 | } |
441 | | | 441 | |
442 | /* | | 442 | /* |
443 | * Grow the receiving buffer to accommodate new data | | 443 | * Grow the receiving buffer to accommodate new data |
444 | */ | | 444 | */ |
445 | newlen = trh->trh_len + (m->m_pkthdr.len - hdrlen); | | 445 | newlen = trh->trh_len + (m->m_pkthdr.len - hdrlen); |
446 | if ((trh->trh_base = realloc(trh->trh_base, | | 446 | if ((trh->trh_base = realloc(trh->trh_base, |
447 | newlen, M_TEMP, M_WAITOK)) == NULL) { | | 447 | newlen, M_TEMP, M_WAITOK)) == NULL) { |
448 | DPRINTF(("%s():%d failed to realloc %ld bytes\n", | | 448 | DPRINTF(("%s():%d failed to realloc %ld bytes\n", |
449 | __func__, __LINE__, (long)newlen)); | | 449 | __func__, __LINE__, (long)newlen)); |
450 | return -1; | | 450 | return -1; |
451 | } | | 451 | } |
452 | | | 452 | |
453 | /* | | 453 | /* |
454 | * Copy the data | | 454 | * Copy the data |
455 | */ | | 455 | */ |
456 | m_copydata(m, hdrlen, m->m_pkthdr.len - hdrlen, | | 456 | m_copydata(m, hdrlen, m->m_pkthdr.len - hdrlen, |
457 | (char *)trh->trh_base + trh->trh_len); | | 457 | (char *)trh->trh_base + trh->trh_len); |
458 | trh->trh_len = newlen; | | 458 | trh->trh_len = newlen; |
459 | | | 459 | |
460 | return 0; | | 460 | return 0; |
461 | } | | 461 | } |