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