]>
Commit | Line | Data |
---|---|---|
cbd8a35c WD |
1 | /* |
2 | * NFS support driver - based on etherboot and U-BOOT's tftp.c | |
3 | * | |
4 | * Masami Komiya <[email protected]> 2004 | |
5 | * | |
6 | */ | |
7 | ||
8 | /* NOTE: the NFS code is heavily inspired by the NetBSD netboot code (read: | |
9 | * large portions are copied verbatim) as distributed in OSKit 0.97. A few | |
10 | * changes were necessary to adapt the code to Etherboot and to fix several | |
11 | * inconsistencies. Also the RPC message preparation is done "by hand" to | |
12 | * avoid adding netsprintf() which I find hard to understand and use. */ | |
13 | ||
14 | /* NOTE 2: Etherboot does not care about things beyond the kernel image, so | |
15 | * it loads the kernel image off the boot server (ARP_SERVER) and does not | |
16 | * access the client root disk (root-path in dhcpd.conf), which would use | |
17 | * ARP_ROOTSERVER. The root disk is something the operating system we are | |
18 | * about to load needs to use. This is different from the OSKit 0.97 logic. */ | |
19 | ||
20 | /* NOTE 3: Symlink handling introduced by Anselm M Hoffmeister, 2003-July-14 | |
21 | * If a symlink is encountered, it is followed as far as possible (recursion | |
22 | * possible, maximum 16 steps). There is no clearing of ".."'s inside the | |
23 | * path, so please DON'T DO THAT. thx. */ | |
24 | ||
b0baca98 GG |
25 | /* NOTE 4: NFSv3 support added by Guillaume GARDET, 2016-June-20. |
26 | * NFSv2 is still used by default. But if server does not support NFSv2, then | |
27 | * NFSv3 is used, if available on NFS server. */ | |
28 | ||
e4bd95bb TR |
29 | /* NOTE 5: NFSv1 support added by Christian Gmeiner, Thomas Rienoessl, |
30 | * September 27, 2018. As of now, NFSv3 is the default choice. If the server | |
31 | * does not support NFSv3, we fall back to versions 2 or 1. */ | |
32 | ||
cbd8a35c WD |
33 | #include <common.h> |
34 | #include <command.h> | |
4e4bf944 | 35 | #include <display_options.h> |
17ead040 | 36 | #ifdef CONFIG_SYS_DIRECT_FLASH_NFS |
0ee48252 | 37 | #include <flash.h> |
17ead040 | 38 | #endif |
8e8ccfe1 | 39 | #include <image.h> |
f7ae49fc | 40 | #include <log.h> |
cbd8a35c WD |
41 | #include <net.h> |
42 | #include <malloc.h> | |
55d5fd9a | 43 | #include <mapmem.h> |
cbd8a35c WD |
44 | #include "nfs.h" |
45 | #include "bootp.h" | |
1045315d | 46 | #include <time.h> |
cbd8a35c | 47 | |
cbd8a35c | 48 | #define HASHES_PER_LINE 65 /* Number of "loading" hashes per line */ |
fe891ecf | 49 | #define NFS_RETRY_COUNT 30 |
cbd8a35c | 50 | |
fa84fa70 MB |
51 | #define NFS_RPC_ERR 1 |
52 | #define NFS_RPC_DROP 124 | |
53 | ||
c9f6c91b JH |
54 | static int fs_mounted; |
55 | static unsigned long rpc_id; | |
cbd8a35c WD |
56 | static int nfs_offset = -1; |
57 | static int nfs_len; | |
eeda762a | 58 | static const ulong nfs_timeout = CONFIG_NFS_TIMEOUT; |
cbd8a35c | 59 | |
b0baca98 | 60 | static char dirfh[NFS_FHSIZE]; /* NFSv2 / NFSv3 file handle of directory */ |
5280c769 | 61 | static char filefh[NFS3_FHSIZE]; /* NFSv2 / NFSv3 file handle */ |
bdbf7a05 | 62 | static unsigned int filefh3_length; /* (variable) length of filefh when NFSv3 */ |
cbd8a35c | 63 | |
22f6e99d | 64 | static enum net_loop_state nfs_download_state; |
049a95a7 | 65 | static struct in_addr nfs_server_ip; |
68c76a3a JH |
66 | static int nfs_server_mount_port; |
67 | static int nfs_server_port; | |
68 | static int nfs_our_port; | |
69 | static int nfs_timeout_count; | |
70 | static int nfs_state; | |
cbd8a35c WD |
71 | #define STATE_PRCLOOKUP_PROG_MOUNT_REQ 1 |
72 | #define STATE_PRCLOOKUP_PROG_NFS_REQ 2 | |
73 | #define STATE_MOUNT_REQ 3 | |
74 | #define STATE_UMOUNT_REQ 4 | |
75 | #define STATE_LOOKUP_REQ 5 | |
76 | #define STATE_READ_REQ 6 | |
77 | #define STATE_READLINK_REQ 7 | |
78 | ||
cbd8a35c WD |
79 | static char *nfs_filename; |
80 | static char *nfs_path; | |
81 | static char nfs_path_buff[2048]; | |
82 | ||
948d7a60 TR |
83 | enum nfs_version { |
84 | NFS_UNKOWN = 0, | |
e4bd95bb | 85 | NFS_V1 = 1, |
948d7a60 TR |
86 | NFS_V2 = 2, |
87 | NFS_V3 = 3, | |
88 | }; | |
b0baca98 | 89 | |
948d7a60 | 90 | static enum nfs_version choosen_nfs_version = NFS_V3; |
68c76a3a | 91 | static inline int store_block(uchar *src, unsigned offset, unsigned len) |
cbd8a35c | 92 | { |
a084f7da | 93 | ulong newsize = offset + len; |
6d0f6bcf | 94 | #ifdef CONFIG_SYS_DIRECT_FLASH_NFS |
cbd8a35c WD |
95 | int i, rc = 0; |
96 | ||
c9f6c91b | 97 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { |
cbd8a35c | 98 | /* start address in flash? */ |
bb872dd9 | 99 | if (image_load_addr + offset >= flash_info[i].start[0]) { |
cbd8a35c WD |
100 | rc = 1; |
101 | break; | |
102 | } | |
103 | } | |
104 | ||
105 | if (rc) { /* Flash is destination for this packet */ | |
bb872dd9 SG |
106 | rc = flash_write((uchar *)src, (ulong)image_load_addr + offset, |
107 | len); | |
cbd8a35c | 108 | if (rc) { |
c9f6c91b | 109 | flash_perror(rc); |
23a7a32d | 110 | return -1; |
cbd8a35c WD |
111 | } |
112 | } else | |
6d0f6bcf | 113 | #endif /* CONFIG_SYS_DIRECT_FLASH_NFS */ |
cbd8a35c | 114 | { |
bb872dd9 | 115 | void *ptr = map_sysmem(image_load_addr + offset, len); |
55d5fd9a JH |
116 | |
117 | memcpy(ptr, src, len); | |
118 | unmap_sysmem(ptr); | |
cbd8a35c | 119 | } |
a084f7da | 120 | |
1411157d JH |
121 | if (net_boot_file_size < (offset + len)) |
122 | net_boot_file_size = newsize; | |
23a7a32d | 123 | return 0; |
cbd8a35c WD |
124 | } |
125 | ||
68c76a3a | 126 | static char *basename(char *path) |
cbd8a35c WD |
127 | { |
128 | char *fname; | |
129 | ||
130 | fname = path + strlen(path) - 1; | |
131 | while (fname >= path) { | |
132 | if (*fname == '/') { | |
133 | fname++; | |
134 | break; | |
135 | } | |
136 | fname--; | |
137 | } | |
138 | return fname; | |
139 | } | |
140 | ||
68c76a3a | 141 | static char *dirname(char *path) |
cbd8a35c WD |
142 | { |
143 | char *fname; | |
144 | ||
c9f6c91b | 145 | fname = basename(path); |
cbd8a35c WD |
146 | --fname; |
147 | *fname = '\0'; | |
148 | return path; | |
149 | } | |
150 | ||
cbd8a35c WD |
151 | /************************************************************************** |
152 | RPC_ADD_CREDENTIALS - Add RPC authentication/verifier entries | |
153 | **************************************************************************/ | |
e4ead4a2 | 154 | static uint32_t *rpc_add_credentials(uint32_t *p) |
cbd8a35c | 155 | { |
cbd8a35c WD |
156 | /* Here's the executive summary on authentication requirements of the |
157 | * various NFS server implementations: Linux accepts both AUTH_NONE | |
158 | * and AUTH_UNIX authentication (also accepts an empty hostname field | |
159 | * in the AUTH_UNIX scheme). *BSD refuses AUTH_NONE, but accepts | |
160 | * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX | |
161 | * scheme). To be safe, use AUTH_UNIX and pass the hostname if we have | |
162 | * it (if the BOOTP/DHCP reply didn't give one, just use an empty | |
163 | * hostname). */ | |
164 | ||
cbd8a35c WD |
165 | /* Provide an AUTH_UNIX credential. */ |
166 | *p++ = htonl(1); /* AUTH_UNIX */ | |
1ff65d44 JH |
167 | *p++ = htonl(20); /* auth length */ |
168 | *p++ = 0; /* stamp */ | |
169 | *p++ = 0; /* hostname string */ | |
cbd8a35c WD |
170 | *p++ = 0; /* uid */ |
171 | *p++ = 0; /* gid */ | |
172 | *p++ = 0; /* auxiliary gid list */ | |
173 | ||
174 | /* Provide an AUTH_NONE verifier. */ | |
175 | *p++ = 0; /* AUTH_NONE */ | |
176 | *p++ = 0; /* auth length */ | |
177 | ||
178 | return p; | |
179 | } | |
180 | ||
181 | /************************************************************************** | |
182 | RPC_LOOKUP - Lookup RPC Port numbers | |
183 | **************************************************************************/ | |
a73588fe | 184 | static void rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen) |
cbd8a35c | 185 | { |
a73588fe | 186 | struct rpc_t rpc_pkt; |
cbd8a35c | 187 | unsigned long id; |
a73588fe | 188 | uint32_t *p; |
cbd8a35c WD |
189 | int pktlen; |
190 | int sport; | |
191 | ||
c3f9d493 | 192 | id = ++rpc_id; |
a73588fe JH |
193 | rpc_pkt.u.call.id = htonl(id); |
194 | rpc_pkt.u.call.type = htonl(MSG_CALL); | |
195 | rpc_pkt.u.call.rpcvers = htonl(2); /* use RPC version 2 */ | |
196 | rpc_pkt.u.call.prog = htonl(rpc_prog); | |
b0baca98 GG |
197 | switch (rpc_prog) { |
198 | case PROG_NFS: | |
948d7a60 | 199 | switch (choosen_nfs_version) { |
e4bd95bb | 200 | case NFS_V1: |
948d7a60 TR |
201 | case NFS_V2: |
202 | rpc_pkt.u.call.vers = htonl(2); | |
203 | break; | |
204 | ||
205 | case NFS_V3: | |
206 | rpc_pkt.u.call.vers = htonl(3); | |
207 | break; | |
208 | ||
209 | case NFS_UNKOWN: | |
210 | /* nothing to do */ | |
211 | break; | |
212 | } | |
b0baca98 | 213 | break; |
b0baca98 | 214 | case PROG_MOUNT: |
e4bd95bb TR |
215 | switch (choosen_nfs_version) { |
216 | case NFS_V1: | |
217 | rpc_pkt.u.call.vers = htonl(1); | |
218 | break; | |
219 | ||
220 | case NFS_V2: | |
221 | rpc_pkt.u.call.vers = htonl(2); | |
222 | break; | |
223 | ||
224 | case NFS_V3: | |
225 | rpc_pkt.u.call.vers = htonl(3); | |
226 | break; | |
227 | ||
228 | case NFS_UNKOWN: | |
229 | /* nothing to do */ | |
230 | break; | |
231 | } | |
232 | break; | |
233 | case PROG_PORTMAP: | |
b0baca98 | 234 | default: |
a73588fe | 235 | rpc_pkt.u.call.vers = htonl(2); /* portmapper is version 2 */ |
b0baca98 | 236 | } |
a73588fe | 237 | rpc_pkt.u.call.proc = htonl(rpc_proc); |
15eea9a1 | 238 | p = rpc_pkt.u.call.data; |
a73588fe JH |
239 | |
240 | if (datalen) | |
15eea9a1 | 241 | memcpy(p, data, datalen * sizeof(uint32_t)); |
a73588fe JH |
242 | |
243 | pktlen = (char *)p + datalen * sizeof(uint32_t) - (char *)&rpc_pkt; | |
cbd8a35c | 244 | |
a73588fe JH |
245 | memcpy((char *)net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE, |
246 | &rpc_pkt.u.data[0], pktlen); | |
cbd8a35c WD |
247 | |
248 | if (rpc_prog == PROG_PORTMAP) | |
249 | sport = SUNRPC_PORT; | |
250 | else if (rpc_prog == PROG_MOUNT) | |
68c76a3a | 251 | sport = nfs_server_mount_port; |
cbd8a35c | 252 | else |
68c76a3a | 253 | sport = nfs_server_port; |
cbd8a35c | 254 | |
1203fcce | 255 | net_send_udp_packet(net_server_ethaddr, nfs_server_ip, sport, |
68c76a3a | 256 | nfs_our_port, pktlen); |
cbd8a35c WD |
257 | } |
258 | ||
259 | /************************************************************************** | |
260 | RPC_LOOKUP - Lookup RPC Port numbers | |
261 | **************************************************************************/ | |
68c76a3a | 262 | static void rpc_lookup_req(int prog, int ver) |
cbd8a35c | 263 | { |
a73588fe | 264 | uint32_t data[16]; |
cbd8a35c WD |
265 | |
266 | data[0] = 0; data[1] = 0; /* auth credential */ | |
267 | data[2] = 0; data[3] = 0; /* auth verifier */ | |
268 | data[4] = htonl(prog); | |
269 | data[5] = htonl(ver); | |
270 | data[6] = htonl(17); /* IP_UDP */ | |
271 | data[7] = 0; | |
a73588fe | 272 | rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, data, 8); |
cbd8a35c WD |
273 | } |
274 | ||
275 | /************************************************************************** | |
276 | NFS_MOUNT - Mount an NFS Filesystem | |
277 | **************************************************************************/ | |
68c76a3a | 278 | static void nfs_mount_req(char *path) |
cbd8a35c | 279 | { |
a73588fe | 280 | uint32_t data[1024]; |
cbd8a35c WD |
281 | uint32_t *p; |
282 | int len; | |
283 | int pathlen; | |
284 | ||
c9f6c91b | 285 | pathlen = strlen(path); |
cbd8a35c | 286 | |
a73588fe | 287 | p = &(data[0]); |
e4ead4a2 | 288 | p = rpc_add_credentials(p); |
cbd8a35c WD |
289 | |
290 | *p++ = htonl(pathlen); | |
c9f6c91b JH |
291 | if (pathlen & 3) |
292 | *(p + pathlen / 4) = 0; | |
293 | memcpy(p, path, pathlen); | |
cbd8a35c WD |
294 | p += (pathlen + 3) / 4; |
295 | ||
a73588fe | 296 | len = (uint32_t *)p - (uint32_t *)&(data[0]); |
cbd8a35c | 297 | |
a73588fe | 298 | rpc_req(PROG_MOUNT, MOUNT_ADDENTRY, data, len); |
cbd8a35c WD |
299 | } |
300 | ||
301 | /************************************************************************** | |
302 | NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server | |
303 | **************************************************************************/ | |
68c76a3a | 304 | static void nfs_umountall_req(void) |
cbd8a35c | 305 | { |
a73588fe | 306 | uint32_t data[1024]; |
cbd8a35c WD |
307 | uint32_t *p; |
308 | int len; | |
309 | ||
68c76a3a | 310 | if ((nfs_server_mount_port == -1) || (!fs_mounted)) |
cbd8a35c WD |
311 | /* Nothing mounted, nothing to umount */ |
312 | return; | |
cbd8a35c | 313 | |
a73588fe | 314 | p = &(data[0]); |
e4ead4a2 | 315 | p = rpc_add_credentials(p); |
cbd8a35c | 316 | |
a73588fe | 317 | len = (uint32_t *)p - (uint32_t *)&(data[0]); |
cbd8a35c | 318 | |
a73588fe | 319 | rpc_req(PROG_MOUNT, MOUNT_UMOUNTALL, data, len); |
cbd8a35c WD |
320 | } |
321 | ||
322 | /*************************************************************************** | |
323 | * NFS_READLINK (AH 2003-07-14) | |
324 | * This procedure is called when read of the first block fails - | |
325 | * this probably happens when it's a directory or a symlink | |
326 | * In case of successful readlink(), the dirname is manipulated, | |
327 | * so that inside the nfs() function a recursion can be done. | |
328 | **************************************************************************/ | |
68c76a3a | 329 | static void nfs_readlink_req(void) |
cbd8a35c | 330 | { |
a73588fe | 331 | uint32_t data[1024]; |
cbd8a35c WD |
332 | uint32_t *p; |
333 | int len; | |
334 | ||
a73588fe | 335 | p = &(data[0]); |
e4ead4a2 | 336 | p = rpc_add_credentials(p); |
cbd8a35c | 337 | |
e4bd95bb | 338 | if (choosen_nfs_version != NFS_V3) { |
b0baca98 GG |
339 | memcpy(p, filefh, NFS_FHSIZE); |
340 | p += (NFS_FHSIZE / 4); | |
948d7a60 | 341 | } else { /* NFS_V3 */ |
b0baca98 | 342 | *p++ = htonl(filefh3_length); |
5280c769 | 343 | memcpy(p, filefh, filefh3_length); |
b0baca98 GG |
344 | p += (filefh3_length / 4); |
345 | } | |
cbd8a35c | 346 | |
a73588fe | 347 | len = (uint32_t *)p - (uint32_t *)&(data[0]); |
cbd8a35c | 348 | |
a73588fe | 349 | rpc_req(PROG_NFS, NFS_READLINK, data, len); |
cbd8a35c WD |
350 | } |
351 | ||
352 | /************************************************************************** | |
353 | NFS_LOOKUP - Lookup Pathname | |
354 | **************************************************************************/ | |
68c76a3a | 355 | static void nfs_lookup_req(char *fname) |
cbd8a35c | 356 | { |
a73588fe | 357 | uint32_t data[1024]; |
cbd8a35c WD |
358 | uint32_t *p; |
359 | int len; | |
360 | int fnamelen; | |
361 | ||
c9f6c91b | 362 | fnamelen = strlen(fname); |
cbd8a35c | 363 | |
a73588fe | 364 | p = &(data[0]); |
e4ead4a2 | 365 | p = rpc_add_credentials(p); |
cbd8a35c | 366 | |
e4bd95bb | 367 | if (choosen_nfs_version != NFS_V3) { |
b0baca98 GG |
368 | memcpy(p, dirfh, NFS_FHSIZE); |
369 | p += (NFS_FHSIZE / 4); | |
370 | *p++ = htonl(fnamelen); | |
371 | if (fnamelen & 3) | |
372 | *(p + fnamelen / 4) = 0; | |
373 | memcpy(p, fname, fnamelen); | |
374 | p += (fnamelen + 3) / 4; | |
375 | ||
a73588fe | 376 | len = (uint32_t *)p - (uint32_t *)&(data[0]); |
b0baca98 | 377 | |
a73588fe | 378 | rpc_req(PROG_NFS, NFS_LOOKUP, data, len); |
948d7a60 | 379 | } else { /* NFS_V3 */ |
b0baca98 GG |
380 | *p++ = htonl(NFS_FHSIZE); /* Dir handle length */ |
381 | memcpy(p, dirfh, NFS_FHSIZE); | |
382 | p += (NFS_FHSIZE / 4); | |
383 | *p++ = htonl(fnamelen); | |
384 | if (fnamelen & 3) | |
385 | *(p + fnamelen / 4) = 0; | |
386 | memcpy(p, fname, fnamelen); | |
387 | p += (fnamelen + 3) / 4; | |
388 | ||
a73588fe | 389 | len = (uint32_t *)p - (uint32_t *)&(data[0]); |
b0baca98 | 390 | |
a73588fe | 391 | rpc_req(PROG_NFS, NFS3PROC_LOOKUP, data, len); |
b0baca98 | 392 | } |
cbd8a35c WD |
393 | } |
394 | ||
395 | /************************************************************************** | |
396 | NFS_READ - Read File on NFS Server | |
397 | **************************************************************************/ | |
68c76a3a | 398 | static void nfs_read_req(int offset, int readlen) |
cbd8a35c | 399 | { |
a73588fe | 400 | uint32_t data[1024]; |
cbd8a35c WD |
401 | uint32_t *p; |
402 | int len; | |
403 | ||
a73588fe | 404 | p = &(data[0]); |
e4ead4a2 | 405 | p = rpc_add_credentials(p); |
cbd8a35c | 406 | |
e4bd95bb | 407 | if (choosen_nfs_version != NFS_V3) { |
b0baca98 GG |
408 | memcpy(p, filefh, NFS_FHSIZE); |
409 | p += (NFS_FHSIZE / 4); | |
410 | *p++ = htonl(offset); | |
411 | *p++ = htonl(readlen); | |
412 | *p++ = 0; | |
948d7a60 | 413 | } else { /* NFS_V3 */ |
b0baca98 | 414 | *p++ = htonl(filefh3_length); |
5280c769 | 415 | memcpy(p, filefh, filefh3_length); |
b0baca98 GG |
416 | p += (filefh3_length / 4); |
417 | *p++ = htonl(0); /* offset is 64-bit long, so fill with 0 */ | |
418 | *p++ = htonl(offset); | |
419 | *p++ = htonl(readlen); | |
420 | *p++ = 0; | |
421 | } | |
cbd8a35c | 422 | |
a73588fe | 423 | len = (uint32_t *)p - (uint32_t *)&(data[0]); |
cbd8a35c | 424 | |
a73588fe | 425 | rpc_req(PROG_NFS, NFS_READ, data, len); |
cbd8a35c WD |
426 | } |
427 | ||
428 | /************************************************************************** | |
429 | RPC request dispatcher | |
430 | **************************************************************************/ | |
68c76a3a | 431 | static void nfs_send(void) |
cbd8a35c | 432 | { |
0ebf04c6 | 433 | debug("%s\n", __func__); |
cbd8a35c | 434 | |
68c76a3a | 435 | switch (nfs_state) { |
cbd8a35c | 436 | case STATE_PRCLOOKUP_PROG_MOUNT_REQ: |
e4bd95bb | 437 | if (choosen_nfs_version != NFS_V3) |
b0baca98 | 438 | rpc_lookup_req(PROG_MOUNT, 1); |
948d7a60 | 439 | else /* NFS_V3 */ |
b0baca98 | 440 | rpc_lookup_req(PROG_MOUNT, 3); |
cbd8a35c WD |
441 | break; |
442 | case STATE_PRCLOOKUP_PROG_NFS_REQ: | |
e4bd95bb | 443 | if (choosen_nfs_version != NFS_V3) |
b0baca98 | 444 | rpc_lookup_req(PROG_NFS, 2); |
948d7a60 | 445 | else /* NFS_V3 */ |
b0baca98 | 446 | rpc_lookup_req(PROG_NFS, 3); |
cbd8a35c WD |
447 | break; |
448 | case STATE_MOUNT_REQ: | |
c9f6c91b | 449 | nfs_mount_req(nfs_path); |
cbd8a35c WD |
450 | break; |
451 | case STATE_UMOUNT_REQ: | |
c9f6c91b | 452 | nfs_umountall_req(); |
cbd8a35c WD |
453 | break; |
454 | case STATE_LOOKUP_REQ: | |
c9f6c91b | 455 | nfs_lookup_req(nfs_filename); |
cbd8a35c WD |
456 | break; |
457 | case STATE_READ_REQ: | |
c9f6c91b | 458 | nfs_read_req(nfs_offset, nfs_len); |
cbd8a35c WD |
459 | break; |
460 | case STATE_READLINK_REQ: | |
c9f6c91b | 461 | nfs_readlink_req(); |
cbd8a35c WD |
462 | break; |
463 | } | |
464 | } | |
465 | ||
466 | /************************************************************************** | |
467 | Handlers for the reply from server | |
468 | **************************************************************************/ | |
469 | ||
791a43ea TR |
470 | static int rpc_handle_error(struct rpc_t *rpc_pkt) |
471 | { | |
472 | if (rpc_pkt->u.reply.rstatus || | |
473 | rpc_pkt->u.reply.verifier || | |
474 | rpc_pkt->u.reply.astatus || | |
475 | rpc_pkt->u.reply.data[0]) { | |
476 | switch (ntohl(rpc_pkt->u.reply.astatus)) { | |
477 | case NFS_RPC_SUCCESS: /* Not an error */ | |
478 | break; | |
479 | case NFS_RPC_PROG_MISMATCH: { | |
480 | /* Remote can't support NFS version */ | |
481 | const int min = ntohl(rpc_pkt->u.reply.data[0]); | |
482 | const int max = ntohl(rpc_pkt->u.reply.data[1]); | |
483 | ||
e4bd95bb | 484 | if (max < NFS_V1 || max > NFS_V3 || min > NFS_V3) { |
791a43ea TR |
485 | puts("*** ERROR: NFS version not supported"); |
486 | debug(": Requested: V%d, accepted: min V%d - max V%d\n", | |
487 | choosen_nfs_version, | |
488 | ntohl(rpc_pkt->u.reply.data[0]), | |
489 | ntohl(rpc_pkt->u.reply.data[1])); | |
490 | puts("\n"); | |
491 | choosen_nfs_version = NFS_UNKOWN; | |
492 | break; | |
493 | } | |
494 | ||
495 | debug("*** Warning: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n", | |
496 | choosen_nfs_version, | |
497 | ntohl(rpc_pkt->u.reply.data[0]), | |
498 | ntohl(rpc_pkt->u.reply.data[1])); | |
499 | debug("Will retry with NFSv%d\n", min); | |
500 | choosen_nfs_version = min; | |
501 | return -NFS_RPC_PROG_MISMATCH; | |
502 | } | |
503 | case NFS_RPC_PROG_UNAVAIL: | |
504 | case NFS_RPC_PROC_UNAVAIL: | |
505 | case NFS_RPC_GARBAGE_ARGS: | |
506 | case NFS_RPC_SYSTEM_ERR: | |
507 | default: /* Unknown error on 'accept state' flag */ | |
508 | debug("*** ERROR: accept state error (%d)\n", | |
509 | ntohl(rpc_pkt->u.reply.astatus)); | |
510 | break; | |
511 | } | |
512 | return -1; | |
513 | } | |
514 | ||
515 | return 0; | |
516 | } | |
517 | ||
68c76a3a | 518 | static int rpc_lookup_reply(int prog, uchar *pkt, unsigned len) |
cbd8a35c WD |
519 | { |
520 | struct rpc_t rpc_pkt; | |
521 | ||
0517cc45 | 522 | memcpy(&rpc_pkt.u.data[0], pkt, len); |
cbd8a35c | 523 | |
0ebf04c6 | 524 | debug("%s\n", __func__); |
cbd8a35c | 525 | |
fa84fa70 MB |
526 | if (ntohl(rpc_pkt.u.reply.id) > rpc_id) |
527 | return -NFS_RPC_ERR; | |
528 | else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) | |
529 | return -NFS_RPC_DROP; | |
c3f9d493 | 530 | |
cbd8a35c WD |
531 | if (rpc_pkt.u.reply.rstatus || |
532 | rpc_pkt.u.reply.verifier || | |
c9f6c91b | 533 | rpc_pkt.u.reply.astatus) |
c3f9d493 | 534 | return -1; |
cbd8a35c WD |
535 | |
536 | switch (prog) { | |
537 | case PROG_MOUNT: | |
68c76a3a | 538 | nfs_server_mount_port = ntohl(rpc_pkt.u.reply.data[0]); |
cbd8a35c WD |
539 | break; |
540 | case PROG_NFS: | |
68c76a3a | 541 | nfs_server_port = ntohl(rpc_pkt.u.reply.data[0]); |
cbd8a35c WD |
542 | break; |
543 | } | |
544 | ||
545 | return 0; | |
546 | } | |
547 | ||
68c76a3a | 548 | static int nfs_mount_reply(uchar *pkt, unsigned len) |
cbd8a35c WD |
549 | { |
550 | struct rpc_t rpc_pkt; | |
1b6064b3 | 551 | int ret; |
cbd8a35c | 552 | |
0ebf04c6 | 553 | debug("%s\n", __func__); |
cbd8a35c | 554 | |
0517cc45 | 555 | memcpy(&rpc_pkt.u.data[0], pkt, len); |
cbd8a35c | 556 | |
fa84fa70 MB |
557 | if (ntohl(rpc_pkt.u.reply.id) > rpc_id) |
558 | return -NFS_RPC_ERR; | |
559 | else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) | |
560 | return -NFS_RPC_DROP; | |
c3f9d493 | 561 | |
1b6064b3 TR |
562 | ret = rpc_handle_error(&rpc_pkt); |
563 | if (ret) | |
564 | return ret; | |
cbd8a35c WD |
565 | |
566 | fs_mounted = 1; | |
b0baca98 | 567 | /* NFSv2 and NFSv3 use same structure */ |
c9f6c91b | 568 | memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); |
cbd8a35c WD |
569 | |
570 | return 0; | |
571 | } | |
572 | ||
68c76a3a | 573 | static int nfs_umountall_reply(uchar *pkt, unsigned len) |
cbd8a35c WD |
574 | { |
575 | struct rpc_t rpc_pkt; | |
576 | ||
0ebf04c6 | 577 | debug("%s\n", __func__); |
cbd8a35c | 578 | |
0517cc45 | 579 | memcpy(&rpc_pkt.u.data[0], pkt, len); |
cbd8a35c | 580 | |
fa84fa70 MB |
581 | if (ntohl(rpc_pkt.u.reply.id) > rpc_id) |
582 | return -NFS_RPC_ERR; | |
583 | else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) | |
584 | return -NFS_RPC_DROP; | |
c3f9d493 | 585 | |
cbd8a35c WD |
586 | if (rpc_pkt.u.reply.rstatus || |
587 | rpc_pkt.u.reply.verifier || | |
c9f6c91b | 588 | rpc_pkt.u.reply.astatus) |
cbd8a35c | 589 | return -1; |
cbd8a35c WD |
590 | |
591 | fs_mounted = 0; | |
c9f6c91b | 592 | memset(dirfh, 0, sizeof(dirfh)); |
cbd8a35c WD |
593 | |
594 | return 0; | |
595 | } | |
596 | ||
68c76a3a | 597 | static int nfs_lookup_reply(uchar *pkt, unsigned len) |
cbd8a35c WD |
598 | { |
599 | struct rpc_t rpc_pkt; | |
791a43ea | 600 | int ret; |
cbd8a35c | 601 | |
0ebf04c6 | 602 | debug("%s\n", __func__); |
cbd8a35c | 603 | |
0517cc45 | 604 | memcpy(&rpc_pkt.u.data[0], pkt, len); |
cbd8a35c | 605 | |
fa84fa70 MB |
606 | if (ntohl(rpc_pkt.u.reply.id) > rpc_id) |
607 | return -NFS_RPC_ERR; | |
608 | else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) | |
609 | return -NFS_RPC_DROP; | |
c3f9d493 | 610 | |
791a43ea TR |
611 | ret = rpc_handle_error(&rpc_pkt); |
612 | if (ret) | |
613 | return ret; | |
cbd8a35c | 614 | |
e4bd95bb | 615 | if (choosen_nfs_version != NFS_V3) { |
5d14ee4e | 616 | if (((uchar *)&(rpc_pkt.u.reply.data[0]) - (uchar *)(&rpc_pkt) + NFS_FHSIZE) > len) |
617 | return -NFS_RPC_DROP; | |
b0baca98 | 618 | memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); |
948d7a60 | 619 | } else { /* NFS_V3 */ |
b0baca98 GG |
620 | filefh3_length = ntohl(rpc_pkt.u.reply.data[1]); |
621 | if (filefh3_length > NFS3_FHSIZE) | |
622 | filefh3_length = NFS3_FHSIZE; | |
5280c769 | 623 | memcpy(filefh, rpc_pkt.u.reply.data + 2, filefh3_length); |
b0baca98 | 624 | } |
cbd8a35c WD |
625 | |
626 | return 0; | |
627 | } | |
628 | ||
051ed9af JH |
629 | static int nfs3_get_attributes_offset(uint32_t *data) |
630 | { | |
15eea9a1 | 631 | if (data[1]) { |
051ed9af | 632 | /* 'attributes_follow' flag is TRUE, |
c629c45f | 633 | * so we have attributes on 21 dwords */ |
051ed9af JH |
634 | /* Skip unused values : |
635 | type; 32 bits value, | |
636 | mode; 32 bits value, | |
637 | nlink; 32 bits value, | |
638 | uid; 32 bits value, | |
639 | gid; 32 bits value, | |
640 | size; 64 bits value, | |
641 | used; 64 bits value, | |
642 | rdev; 64 bits value, | |
643 | fsid; 64 bits value, | |
644 | fileid; 64 bits value, | |
645 | atime; 64 bits value, | |
646 | mtime; 64 bits value, | |
647 | ctime; 64 bits value, | |
648 | */ | |
649 | return 22; | |
650 | } else { | |
651 | /* 'attributes_follow' flag is FALSE, | |
652 | * so we don't have any attributes */ | |
653 | return 1; | |
654 | } | |
655 | } | |
656 | ||
68c76a3a | 657 | static int nfs_readlink_reply(uchar *pkt, unsigned len) |
cbd8a35c WD |
658 | { |
659 | struct rpc_t rpc_pkt; | |
660 | int rlen; | |
051ed9af | 661 | int nfsv3_data_offset = 0; |
cbd8a35c | 662 | |
0ebf04c6 | 663 | debug("%s\n", __func__); |
cbd8a35c | 664 | |
c9f6c91b | 665 | memcpy((unsigned char *)&rpc_pkt, pkt, len); |
cbd8a35c | 666 | |
fa84fa70 MB |
667 | if (ntohl(rpc_pkt.u.reply.id) > rpc_id) |
668 | return -NFS_RPC_ERR; | |
669 | else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) | |
670 | return -NFS_RPC_DROP; | |
c3f9d493 | 671 | |
cbd8a35c WD |
672 | if (rpc_pkt.u.reply.rstatus || |
673 | rpc_pkt.u.reply.verifier || | |
674 | rpc_pkt.u.reply.astatus || | |
c9f6c91b | 675 | rpc_pkt.u.reply.data[0]) |
cbd8a35c | 676 | return -1; |
cbd8a35c | 677 | |
948d7a60 | 678 | if (choosen_nfs_version == NFS_V3) { |
051ed9af JH |
679 | nfsv3_data_offset = |
680 | nfs3_get_attributes_offset(rpc_pkt.u.reply.data); | |
681 | } | |
b0baca98 | 682 | |
051ed9af JH |
683 | /* new path length */ |
684 | rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]); | |
685 | ||
cf3a4f1e | 686 | if (((uchar *)&(rpc_pkt.u.reply.data[0]) - (uchar *)(&rpc_pkt) + rlen) > len) |
687 | return -NFS_RPC_DROP; | |
688 | ||
051ed9af JH |
689 | if (*((char *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset])) != '/') { |
690 | int pathlen; | |
691 | ||
692 | strcat(nfs_path, "/"); | |
693 | pathlen = strlen(nfs_path); | |
694 | memcpy(nfs_path + pathlen, | |
695 | (uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]), | |
696 | rlen); | |
697 | nfs_path[pathlen + rlen] = 0; | |
698 | } else { | |
699 | memcpy(nfs_path, | |
700 | (uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]), | |
701 | rlen); | |
702 | nfs_path[rlen] = 0; | |
cbd8a35c WD |
703 | } |
704 | return 0; | |
705 | } | |
706 | ||
68c76a3a | 707 | static int nfs_read_reply(uchar *pkt, unsigned len) |
cbd8a35c WD |
708 | { |
709 | struct rpc_t rpc_pkt; | |
710 | int rlen; | |
b0baca98 | 711 | uchar *data_ptr; |
cbd8a35c | 712 | |
0ebf04c6 | 713 | debug("%s\n", __func__); |
cbd8a35c | 714 | |
0517cc45 | 715 | memcpy(&rpc_pkt.u.data[0], pkt, sizeof(rpc_pkt.u.reply)); |
cbd8a35c | 716 | |
fa84fa70 MB |
717 | if (ntohl(rpc_pkt.u.reply.id) > rpc_id) |
718 | return -NFS_RPC_ERR; | |
719 | else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) | |
720 | return -NFS_RPC_DROP; | |
c3f9d493 | 721 | |
cbd8a35c WD |
722 | if (rpc_pkt.u.reply.rstatus || |
723 | rpc_pkt.u.reply.verifier || | |
724 | rpc_pkt.u.reply.astatus || | |
725 | rpc_pkt.u.reply.data[0]) { | |
c9f6c91b | 726 | if (rpc_pkt.u.reply.rstatus) |
cbd8a35c | 727 | return -9999; |
c9f6c91b | 728 | if (rpc_pkt.u.reply.astatus) |
cbd8a35c | 729 | return -9999; |
c9f6c91b | 730 | return -ntohl(rpc_pkt.u.reply.data[0]); |
cbd8a35c WD |
731 | } |
732 | ||
c9f6c91b JH |
733 | if ((nfs_offset != 0) && !((nfs_offset) % |
734 | (NFS_READ_SIZE / 2 * 10 * HASHES_PER_LINE))) | |
735 | puts("\n\t "); | |
736 | if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10))) | |
737 | putc('#'); | |
cbd8a35c | 738 | |
e4bd95bb | 739 | if (choosen_nfs_version != NFS_V3) { |
b0baca98 GG |
740 | rlen = ntohl(rpc_pkt.u.reply.data[18]); |
741 | data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19]); | |
948d7a60 | 742 | } else { /* NFS_V3 */ |
051ed9af JH |
743 | int nfsv3_data_offset = |
744 | nfs3_get_attributes_offset(rpc_pkt.u.reply.data); | |
745 | ||
746 | /* count value */ | |
747 | rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]); | |
748 | /* Skip unused values : | |
749 | EOF: 32 bits value, | |
750 | data_size: 32 bits value, | |
751 | */ | |
752 | data_ptr = (uchar *) | |
753 | &(rpc_pkt.u.reply.data[4 + nfsv3_data_offset]); | |
b0baca98 GG |
754 | } |
755 | ||
aa207cf3 | 756 | if (((uchar *)&(rpc_pkt.u.reply.data[0]) - (uchar *)(&rpc_pkt) + rlen) > len) |
757 | return -9999; | |
758 | ||
b0baca98 GG |
759 | if (store_block(data_ptr, nfs_offset, rlen)) |
760 | return -9999; | |
cbd8a35c WD |
761 | |
762 | return rlen; | |
763 | } | |
764 | ||
765 | /************************************************************************** | |
766 | Interfaces of U-BOOT | |
767 | **************************************************************************/ | |
68c76a3a | 768 | static void nfs_timeout_handler(void) |
a5725fab | 769 | { |
68c76a3a | 770 | if (++nfs_timeout_count > NFS_RETRY_COUNT) { |
c9f6c91b | 771 | puts("\nRetry count exceeded; starting again\n"); |
bc0571fc | 772 | net_start_again(); |
aabb8cb0 ES |
773 | } else { |
774 | puts("T "); | |
bc0571fc | 775 | net_set_timeout_handler(nfs_timeout + |
eeda762a | 776 | nfs_timeout * nfs_timeout_count, |
bc0571fc | 777 | nfs_timeout_handler); |
68c76a3a | 778 | nfs_send(); |
fe891ecf | 779 | } |
a5725fab WD |
780 | } |
781 | ||
049a95a7 JH |
782 | static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip, |
783 | unsigned src, unsigned len) | |
cbd8a35c WD |
784 | { |
785 | int rlen; | |
fa84fa70 | 786 | int reply; |
cbd8a35c | 787 | |
0ebf04c6 | 788 | debug("%s\n", __func__); |
cbd8a35c | 789 | |
741a8a08 | 790 | if (len > sizeof(struct rpc_t)) |
791 | return; | |
792 | ||
68c76a3a | 793 | if (dest != nfs_our_port) |
c9f6c91b | 794 | return; |
cbd8a35c | 795 | |
68c76a3a | 796 | switch (nfs_state) { |
cbd8a35c | 797 | case STATE_PRCLOOKUP_PROG_MOUNT_REQ: |
fa84fa70 MB |
798 | if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP) |
799 | break; | |
68c76a3a JH |
800 | nfs_state = STATE_PRCLOOKUP_PROG_NFS_REQ; |
801 | nfs_send(); | |
cbd8a35c WD |
802 | break; |
803 | ||
804 | case STATE_PRCLOOKUP_PROG_NFS_REQ: | |
fa84fa70 MB |
805 | if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP) |
806 | break; | |
68c76a3a JH |
807 | nfs_state = STATE_MOUNT_REQ; |
808 | nfs_send(); | |
cbd8a35c WD |
809 | break; |
810 | ||
811 | case STATE_MOUNT_REQ: | |
fa84fa70 | 812 | reply = nfs_mount_reply(pkt, len); |
68c76a3a | 813 | if (reply == -NFS_RPC_DROP) { |
fa84fa70 | 814 | break; |
68c76a3a | 815 | } else if (reply == -NFS_RPC_ERR) { |
c9f6c91b | 816 | puts("*** ERROR: Cannot mount\n"); |
cbd8a35c | 817 | /* just to be sure... */ |
68c76a3a JH |
818 | nfs_state = STATE_UMOUNT_REQ; |
819 | nfs_send(); | |
1b6064b3 TR |
820 | } else if (reply == -NFS_RPC_PROG_MISMATCH && |
821 | choosen_nfs_version != NFS_UNKOWN) { | |
822 | nfs_state = STATE_MOUNT_REQ; | |
823 | nfs_send(); | |
cbd8a35c | 824 | } else { |
68c76a3a JH |
825 | nfs_state = STATE_LOOKUP_REQ; |
826 | nfs_send(); | |
cbd8a35c WD |
827 | } |
828 | break; | |
829 | ||
830 | case STATE_UMOUNT_REQ: | |
fa84fa70 | 831 | reply = nfs_umountall_reply(pkt, len); |
68c76a3a | 832 | if (reply == -NFS_RPC_DROP) { |
fa84fa70 | 833 | break; |
68c76a3a | 834 | } else if (reply == -NFS_RPC_ERR) { |
d89ff2df | 835 | debug("*** ERROR: Cannot umount\n"); |
22f6e99d | 836 | net_set_state(NETLOOP_FAIL); |
cbd8a35c | 837 | } else { |
c9f6c91b | 838 | puts("\ndone\n"); |
22f6e99d | 839 | net_set_state(nfs_download_state); |
cbd8a35c WD |
840 | } |
841 | break; | |
842 | ||
843 | case STATE_LOOKUP_REQ: | |
fa84fa70 | 844 | reply = nfs_lookup_reply(pkt, len); |
68c76a3a | 845 | if (reply == -NFS_RPC_DROP) { |
fa84fa70 | 846 | break; |
68c76a3a | 847 | } else if (reply == -NFS_RPC_ERR) { |
c9f6c91b | 848 | puts("*** ERROR: File lookup fail\n"); |
68c76a3a JH |
849 | nfs_state = STATE_UMOUNT_REQ; |
850 | nfs_send(); | |
347a9015 | 851 | } else if (reply == -NFS_RPC_PROG_MISMATCH && |
948d7a60 | 852 | choosen_nfs_version != NFS_UNKOWN) { |
b0baca98 GG |
853 | /* umount */ |
854 | nfs_state = STATE_UMOUNT_REQ; | |
855 | nfs_send(); | |
856 | /* And retry with another supported version */ | |
857 | nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ; | |
858 | nfs_send(); | |
cbd8a35c | 859 | } else { |
68c76a3a | 860 | nfs_state = STATE_READ_REQ; |
cbd8a35c WD |
861 | nfs_offset = 0; |
862 | nfs_len = NFS_READ_SIZE; | |
68c76a3a | 863 | nfs_send(); |
cbd8a35c WD |
864 | } |
865 | break; | |
866 | ||
867 | case STATE_READLINK_REQ: | |
fa84fa70 | 868 | reply = nfs_readlink_reply(pkt, len); |
68c76a3a | 869 | if (reply == -NFS_RPC_DROP) { |
fa84fa70 | 870 | break; |
68c76a3a | 871 | } else if (reply == -NFS_RPC_ERR) { |
c9f6c91b | 872 | puts("*** ERROR: Symlink fail\n"); |
68c76a3a JH |
873 | nfs_state = STATE_UMOUNT_REQ; |
874 | nfs_send(); | |
cbd8a35c | 875 | } else { |
0ebf04c6 | 876 | debug("Symlink --> %s\n", nfs_path); |
c9f6c91b JH |
877 | nfs_filename = basename(nfs_path); |
878 | nfs_path = dirname(nfs_path); | |
cbd8a35c | 879 | |
68c76a3a JH |
880 | nfs_state = STATE_MOUNT_REQ; |
881 | nfs_send(); | |
cbd8a35c WD |
882 | } |
883 | break; | |
884 | ||
885 | case STATE_READ_REQ: | |
c9f6c91b | 886 | rlen = nfs_read_reply(pkt, len); |
d48d40a0 VK |
887 | if (rlen == -NFS_RPC_DROP) |
888 | break; | |
bc0571fc | 889 | net_set_timeout_handler(nfs_timeout, nfs_timeout_handler); |
cbd8a35c WD |
890 | if (rlen > 0) { |
891 | nfs_offset += rlen; | |
68c76a3a | 892 | nfs_send(); |
c9f6c91b | 893 | } else if ((rlen == -NFSERR_ISDIR) || (rlen == -NFSERR_INVAL)) { |
cbd8a35c | 894 | /* symbolic link */ |
68c76a3a JH |
895 | nfs_state = STATE_READLINK_REQ; |
896 | nfs_send(); | |
cbd8a35c | 897 | } else { |
c9f6c91b | 898 | if (!rlen) |
22f6e99d | 899 | nfs_download_state = NETLOOP_SUCCESS; |
b0baca98 | 900 | if (rlen < 0) |
d89ff2df | 901 | debug("NFS READ error (%d)\n", rlen); |
68c76a3a JH |
902 | nfs_state = STATE_UMOUNT_REQ; |
903 | nfs_send(); | |
cbd8a35c WD |
904 | } |
905 | break; | |
906 | } | |
907 | } | |
908 | ||
cbd8a35c | 909 | |
68c76a3a | 910 | void nfs_start(void) |
cbd8a35c | 911 | { |
0ebf04c6 | 912 | debug("%s\n", __func__); |
22f6e99d | 913 | nfs_download_state = NETLOOP_FAIL; |
cbd8a35c | 914 | |
049a95a7 | 915 | nfs_server_ip = net_server_ip; |
cbd8a35c WD |
916 | nfs_path = (char *)nfs_path_buff; |
917 | ||
918 | if (nfs_path == NULL) { | |
22f6e99d | 919 | net_set_state(NETLOOP_FAIL); |
faecf84a | 920 | printf("*** ERROR: Fail allocate memory\n"); |
cbd8a35c WD |
921 | return; |
922 | } | |
923 | ||
6ab12830 JH |
924 | if (!net_parse_bootfile(&nfs_server_ip, nfs_path, |
925 | sizeof(nfs_path_buff))) { | |
f8b26c7a | 926 | sprintf(nfs_path, "/nfsroot/%02X%02X%02X%02X.img", |
049a95a7 JH |
927 | net_ip.s_addr & 0xFF, |
928 | (net_ip.s_addr >> 8) & 0xFF, | |
929 | (net_ip.s_addr >> 16) & 0xFF, | |
930 | (net_ip.s_addr >> 24) & 0xFF); | |
cbd8a35c | 931 | |
faecf84a JH |
932 | printf("*** Warning: no boot file name; using '%s'\n", |
933 | nfs_path); | |
cbd8a35c WD |
934 | } |
935 | ||
c9f6c91b JH |
936 | nfs_filename = basename(nfs_path); |
937 | nfs_path = dirname(nfs_path); | |
cbd8a35c | 938 | |
faecf84a | 939 | printf("Using %s device\n", eth_get_name()); |
cbd8a35c | 940 | |
faecf84a JH |
941 | printf("File transfer via NFS from server %pI4; our IP address is %pI4", |
942 | &nfs_server_ip, &net_ip); | |
cbd8a35c WD |
943 | |
944 | /* Check if we need to send across this subnet */ | |
049a95a7 JH |
945 | if (net_gateway.s_addr && net_netmask.s_addr) { |
946 | struct in_addr our_net; | |
947 | struct in_addr server_net; | |
cbd8a35c | 948 | |
049a95a7 | 949 | our_net.s_addr = net_ip.s_addr & net_netmask.s_addr; |
347e32b0 | 950 | server_net.s_addr = nfs_server_ip.s_addr & net_netmask.s_addr; |
049a95a7 | 951 | if (our_net.s_addr != server_net.s_addr) |
faecf84a JH |
952 | printf("; sending through gateway %pI4", |
953 | &net_gateway); | |
cbd8a35c | 954 | } |
faecf84a | 955 | printf("\nFilename '%s/%s'.", nfs_path, nfs_filename); |
cbd8a35c | 956 | |
1411157d | 957 | if (net_boot_file_expected_size_in_blocks) { |
faecf84a JH |
958 | printf(" Size is 0x%x Bytes = ", |
959 | net_boot_file_expected_size_in_blocks << 9); | |
1411157d | 960 | print_size(net_boot_file_expected_size_in_blocks << 9, ""); |
cbd8a35c | 961 | } |
bb872dd9 | 962 | printf("\nLoad address: 0x%lx\nLoading: *\b", image_load_addr); |
cbd8a35c | 963 | |
bc0571fc | 964 | net_set_timeout_handler(nfs_timeout, nfs_timeout_handler); |
049a95a7 | 965 | net_set_udp_handler(nfs_handler); |
cbd8a35c | 966 | |
68c76a3a JH |
967 | nfs_timeout_count = 0; |
968 | nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ; | |
cbd8a35c | 969 | |
68c76a3a | 970 | /*nfs_our_port = 4096 + (get_ticks() % 3072);*/ |
cbd8a35c | 971 | /*FIX ME !!!*/ |
68c76a3a | 972 | nfs_our_port = 1000; |
cbd8a35c WD |
973 | |
974 | /* zero out server ether in case the server ip has changed */ | |
0adb5b76 | 975 | memset(net_server_ethaddr, 0, 6); |
cbd8a35c | 976 | |
68c76a3a | 977 | nfs_send(); |
cbd8a35c | 978 | } |