|
@@ -1,6 +1,7 @@
|
1
|
|
-#ifdef DOWNLOAD_PROTO_NFS
|
2
|
|
-
|
3
|
1
|
#include "etherboot.h"
|
|
2
|
+#include "init.h"
|
|
3
|
+#include "proto.h"
|
|
4
|
+#include "in.h"
|
4
|
5
|
#include "nic.h"
|
5
|
6
|
|
6
|
7
|
/* NOTE: the NFS code is heavily inspired by the NetBSD netboot code (read:
|
|
@@ -24,15 +25,14 @@
|
24
|
25
|
#define OPORT_SWEEP 200 /* make sure we don't leave secure range */
|
25
|
26
|
|
26
|
27
|
static int oport = START_OPORT;
|
27
|
|
-static int mount_port = -1;
|
28
|
|
-static int nfs_port = -1;
|
29
|
|
-static int fs_mounted = 0;
|
|
28
|
+static struct sockaddr_in mount_server;
|
|
29
|
+static struct sockaddr_in nfs_server;
|
30
|
30
|
static unsigned long rpc_id;
|
31
|
31
|
|
32
|
32
|
/**************************************************************************
|
33
|
33
|
RPC_INIT - set up the ID counter to something fairly random
|
34
|
34
|
**************************************************************************/
|
35
|
|
-void rpc_init(void)
|
|
35
|
+static void rpc_init(void)
|
36
|
36
|
{
|
37
|
37
|
unsigned long t;
|
38
|
38
|
|
|
@@ -40,7 +40,6 @@ void rpc_init(void)
|
40
|
40
|
rpc_id = t ^ (t << 8) ^ (t << 16);
|
41
|
41
|
}
|
42
|
42
|
|
43
|
|
-
|
44
|
43
|
/**************************************************************************
|
45
|
44
|
RPC_PRINTERROR - Print a low level RPC error message
|
46
|
45
|
**************************************************************************/
|
|
@@ -50,9 +49,9 @@ static void rpc_printerror(struct rpc_t *rpc)
|
50
|
49
|
rpc->u.reply.astatus) {
|
51
|
50
|
/* rpc_printerror() is called for any RPC related error,
|
52
|
51
|
* suppress output if no low level RPC error happened. */
|
53
|
|
- printf("RPC error: (%d,%d,%d)\n", ntohl(rpc->u.reply.rstatus),
|
54
|
|
- ntohl(rpc->u.reply.verifier),
|
55
|
|
- ntohl(rpc->u.reply.astatus));
|
|
52
|
+ DBG("RPC error: (%d,%d,%d)\n", ntohl(rpc->u.reply.rstatus),
|
|
53
|
+ ntohl(rpc->u.reply.verifier),
|
|
54
|
+ ntohl(rpc->u.reply.astatus));
|
56
|
55
|
}
|
57
|
56
|
}
|
58
|
57
|
|
|
@@ -60,7 +59,8 @@ static void rpc_printerror(struct rpc_t *rpc)
|
60
|
59
|
AWAIT_RPC - Wait for an rpc packet
|
61
|
60
|
**************************************************************************/
|
62
|
61
|
static int await_rpc(int ival, void *ptr,
|
63
|
|
- unsigned short ptype, struct iphdr *ip, struct udphdr *udp)
|
|
62
|
+ unsigned short ptype __unused, struct iphdr *ip,
|
|
63
|
+ struct udphdr *udp, struct tcphdr *tcp __unused)
|
64
|
64
|
{
|
65
|
65
|
struct rpc_t *rpc;
|
66
|
66
|
if (!udp)
|
|
@@ -82,7 +82,7 @@ static int await_rpc(int ival, void *ptr,
|
82
|
82
|
/**************************************************************************
|
83
|
83
|
RPC_LOOKUP - Lookup RPC Port numbers
|
84
|
84
|
**************************************************************************/
|
85
|
|
-static int rpc_lookup(int addr, int prog, int ver, int sport)
|
|
85
|
+static int rpc_lookup(struct sockaddr_in *addr, int prog, int ver, int sport)
|
86
|
86
|
{
|
87
|
87
|
struct rpc_t buf, *rpc;
|
88
|
88
|
unsigned long id;
|
|
@@ -103,9 +103,12 @@ static int rpc_lookup(int addr, int prog, int ver, int sport)
|
103
|
103
|
*p++ = htonl(ver);
|
104
|
104
|
*p++ = htonl(IP_UDP);
|
105
|
105
|
*p++ = 0;
|
|
106
|
+ if ( ! addr->sin_port ) {
|
|
107
|
+ addr->sin_port = SUNRPC_PORT;
|
|
108
|
+ }
|
106
|
109
|
for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
|
107
|
110
|
long timeout;
|
108
|
|
- udp_transmit(arptable[addr].ipaddr.s_addr, sport, SUNRPC_PORT,
|
|
111
|
+ udp_transmit(addr->sin_addr.s_addr, sport, addr->sin_port,
|
109
|
112
|
(char *)p - (char *)&buf, &buf);
|
110
|
113
|
timeout = rfc2131_sleep_interval(TIMEOUT, retries);
|
111
|
114
|
if (await_reply(await_rpc, sport, &id, timeout)) {
|
|
@@ -113,13 +116,13 @@ static int rpc_lookup(int addr, int prog, int ver, int sport)
|
113
|
116
|
if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
|
114
|
117
|
rpc->u.reply.astatus) {
|
115
|
118
|
rpc_printerror(rpc);
|
116
|
|
- return -1;
|
|
119
|
+ return 0;
|
117
|
120
|
} else {
|
118
|
121
|
return ntohl(rpc->u.reply.data[0]);
|
119
|
122
|
}
|
120
|
123
|
}
|
121
|
124
|
}
|
122
|
|
- return -1;
|
|
125
|
+ return 0;
|
123
|
126
|
}
|
124
|
127
|
|
125
|
128
|
/**************************************************************************
|
|
@@ -197,7 +200,7 @@ static void nfs_printerror(int err)
|
197
|
200
|
/**************************************************************************
|
198
|
201
|
NFS_MOUNT - Mount an NFS Filesystem
|
199
|
202
|
**************************************************************************/
|
200
|
|
-static int nfs_mount(int server, int port, char *path, char *fh, int sport)
|
|
203
|
+static int nfs_mount(struct sockaddr_in *server, char *path, char *fh, int sport)
|
201
|
204
|
{
|
202
|
205
|
struct rpc_t buf, *rpc;
|
203
|
206
|
unsigned long id;
|
|
@@ -221,7 +224,7 @@ static int nfs_mount(int server, int port, char *path, char *fh, int sport)
|
221
|
224
|
p += (pathlen + 3) / 4;
|
222
|
225
|
for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
|
223
|
226
|
long timeout;
|
224
|
|
- udp_transmit(arptable[server].ipaddr.s_addr, sport, port,
|
|
227
|
+ udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
|
225
|
228
|
(char *)p - (char *)&buf, &buf);
|
226
|
229
|
timeout = rfc2131_sleep_interval(TIMEOUT, retries);
|
227
|
230
|
if (await_reply(await_rpc, sport, &id, timeout)) {
|
|
@@ -239,7 +242,6 @@ static int nfs_mount(int server, int port, char *path, char *fh, int sport)
|
239
|
242
|
}
|
240
|
243
|
return -ntohl(rpc->u.reply.data[0]);
|
241
|
244
|
} else {
|
242
|
|
- fs_mounted = 1;
|
243
|
245
|
memcpy(fh, rpc->u.reply.data + 1, NFS_FHSIZE);
|
244
|
246
|
return 0;
|
245
|
247
|
}
|
|
@@ -251,21 +253,13 @@ static int nfs_mount(int server, int port, char *path, char *fh, int sport)
|
251
|
253
|
/**************************************************************************
|
252
|
254
|
NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server
|
253
|
255
|
**************************************************************************/
|
254
|
|
-void nfs_umountall(int server)
|
|
256
|
+static void nfs_umountall(struct sockaddr_in *server)
|
255
|
257
|
{
|
256
|
258
|
struct rpc_t buf, *rpc;
|
257
|
259
|
unsigned long id;
|
258
|
260
|
int retries;
|
259
|
261
|
long *p;
|
260
|
262
|
|
261
|
|
- if (!arptable[server].ipaddr.s_addr) {
|
262
|
|
- /* Haven't sent a single UDP packet to this server */
|
263
|
|
- return;
|
264
|
|
- }
|
265
|
|
- if ((mount_port == -1) || (!fs_mounted)) {
|
266
|
|
- /* Nothing mounted, nothing to umount */
|
267
|
|
- return;
|
268
|
|
- }
|
269
|
263
|
id = rpc_id++;
|
270
|
264
|
buf.u.call.id = htonl(id);
|
271
|
265
|
buf.u.call.type = htonl(MSG_CALL);
|
|
@@ -276,7 +270,7 @@ void nfs_umountall(int server)
|
276
|
270
|
p = rpc_add_credentials((long *)buf.u.call.data);
|
277
|
271
|
for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
|
278
|
272
|
long timeout = rfc2131_sleep_interval(TIMEOUT, retries);
|
279
|
|
- udp_transmit(arptable[server].ipaddr.s_addr, oport, mount_port,
|
|
273
|
+ udp_transmit(server->sin_addr.s_addr, oport, server->sin_port,
|
280
|
274
|
(char *)p - (char *)&buf, &buf);
|
281
|
275
|
if (await_reply(await_rpc, oport, &id, timeout)) {
|
282
|
276
|
rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
|
|
@@ -284,11 +278,24 @@ void nfs_umountall(int server)
|
284
|
278
|
rpc->u.reply.astatus) {
|
285
|
279
|
rpc_printerror(rpc);
|
286
|
280
|
}
|
287
|
|
- fs_mounted = 0;
|
288
|
|
- return;
|
|
281
|
+ break;
|
289
|
282
|
}
|
290
|
283
|
}
|
291
|
284
|
}
|
|
285
|
+
|
|
286
|
+/**************************************************************************
|
|
287
|
+NFS_RESET - Reset the NFS subsystem
|
|
288
|
+**************************************************************************/
|
|
289
|
+static void nfs_reset ( void ) {
|
|
290
|
+ /* If we have a mount server, call nfs_umountall() */
|
|
291
|
+ if ( mount_server.sin_addr.s_addr ) {
|
|
292
|
+ nfs_umountall ( &mount_server );
|
|
293
|
+ }
|
|
294
|
+ /* Zero the data structures */
|
|
295
|
+ memset ( &mount_server, 0, sizeof ( mount_server ) );
|
|
296
|
+ memset ( &nfs_server, 0, sizeof ( nfs_server ) );
|
|
297
|
+}
|
|
298
|
+
|
292
|
299
|
/***************************************************************************
|
293
|
300
|
* NFS_READLINK (AH 2003-07-14)
|
294
|
301
|
* This procedure is called when read of the first block fails -
|
|
@@ -296,8 +303,8 @@ void nfs_umountall(int server)
|
296
|
303
|
* In case of successful readlink(), the dirname is manipulated,
|
297
|
304
|
* so that inside the nfs() function a recursion can be done.
|
298
|
305
|
**************************************************************************/
|
299
|
|
-static int nfs_readlink(int server, int port, char *fh, char *path, char *nfh,
|
300
|
|
- int sport)
|
|
306
|
+static int nfs_readlink(struct sockaddr_in *server, char *fh __unused,
|
|
307
|
+ char *path, char *nfh, int sport)
|
301
|
308
|
{
|
302
|
309
|
struct rpc_t buf, *rpc;
|
303
|
310
|
unsigned long id;
|
|
@@ -317,7 +324,7 @@ static int nfs_readlink(int server, int port, char *fh, char *path, char *nfh,
|
317
|
324
|
p += (NFS_FHSIZE / 4);
|
318
|
325
|
for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
|
319
|
326
|
long timeout = rfc2131_sleep_interval(TIMEOUT, retries);
|
320
|
|
- udp_transmit(arptable[server].ipaddr.s_addr, sport, port,
|
|
327
|
+ udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
|
321
|
328
|
(char *)p - (char *)&buf, &buf);
|
322
|
329
|
if (await_reply(await_rpc, sport, &id, timeout)) {
|
323
|
330
|
rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
|
|
@@ -361,7 +368,7 @@ static int nfs_readlink(int server, int port, char *fh, char *path, char *nfh,
|
361
|
368
|
/**************************************************************************
|
362
|
369
|
NFS_LOOKUP - Lookup Pathname
|
363
|
370
|
**************************************************************************/
|
364
|
|
-static int nfs_lookup(int server, int port, char *fh, char *path, char *nfh,
|
|
371
|
+static int nfs_lookup(struct sockaddr_in *server, char *fh, char *path, char *nfh,
|
365
|
372
|
int sport)
|
366
|
373
|
{
|
367
|
374
|
struct rpc_t buf, *rpc;
|
|
@@ -388,7 +395,7 @@ static int nfs_lookup(int server, int port, char *fh, char *path, char *nfh,
|
388
|
395
|
p += (pathlen + 3) / 4;
|
389
|
396
|
for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
|
390
|
397
|
long timeout = rfc2131_sleep_interval(TIMEOUT, retries);
|
391
|
|
- udp_transmit(arptable[server].ipaddr.s_addr, sport, port,
|
|
398
|
+ udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
|
392
|
399
|
(char *)p - (char *)&buf, &buf);
|
393
|
400
|
if (await_reply(await_rpc, sport, &id, timeout)) {
|
394
|
401
|
rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
|
|
@@ -416,7 +423,7 @@ static int nfs_lookup(int server, int port, char *fh, char *path, char *nfh,
|
416
|
423
|
/**************************************************************************
|
417
|
424
|
NFS_READ - Read File on NFS Server
|
418
|
425
|
**************************************************************************/
|
419
|
|
-static int nfs_read(int server, int port, char *fh, int offset, int len,
|
|
426
|
+static int nfs_read(struct sockaddr_in *server, char *fh, int offset, int len,
|
420
|
427
|
int sport)
|
421
|
428
|
{
|
422
|
429
|
struct rpc_t buf, *rpc;
|
|
@@ -450,7 +457,7 @@ static int nfs_read(int server, int port, char *fh, int offset, int len,
|
450
|
457
|
if (tokens >= 2)
|
451
|
458
|
timeout = TICKS_PER_SEC/2;
|
452
|
459
|
|
453
|
|
- udp_transmit(arptable[server].ipaddr.s_addr, sport, port,
|
|
460
|
+ udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
|
454
|
461
|
(char *)p - (char *)&buf, &buf);
|
455
|
462
|
if (await_reply(await_rpc, sport, &id, timeout)) {
|
456
|
463
|
if (tokens < 256)
|
|
@@ -480,8 +487,12 @@ static int nfs_read(int server, int port, char *fh, int offset, int len,
|
480
|
487
|
/**************************************************************************
|
481
|
488
|
NFS - Download extended BOOTP data, or kernel image from NFS server
|
482
|
489
|
**************************************************************************/
|
483
|
|
-int nfs(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
|
484
|
|
-{
|
|
490
|
+static int nfs ( char *url __unused,
|
|
491
|
+ struct sockaddr_in *server,
|
|
492
|
+ char *name,
|
|
493
|
+ int ( * process ) ( unsigned char *data,
|
|
494
|
+ unsigned int blocknum,
|
|
495
|
+ unsigned int len, int eof ) ) {
|
485
|
496
|
static int recursion = 0;
|
486
|
497
|
int sport;
|
487
|
498
|
int err, namelen = strlen(name);
|
|
@@ -492,19 +503,33 @@ int nfs(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int
|
492
|
503
|
int rlen, size, offs, len;
|
493
|
504
|
struct rpc_t *rpc;
|
494
|
505
|
|
495
|
|
- rx_qdrain();
|
496
|
|
-
|
497
|
506
|
sport = oport++;
|
498
|
507
|
if (oport > START_OPORT+OPORT_SWEEP) {
|
499
|
508
|
oport = START_OPORT;
|
500
|
509
|
}
|
|
510
|
+
|
|
511
|
+ mount_server.sin_addr = nfs_server.sin_addr = server->sin_addr;
|
|
512
|
+ mount_server.sin_port = rpc_lookup(server, PROG_MOUNT, 1, sport);
|
|
513
|
+ if ( ! mount_server.sin_port ) {
|
|
514
|
+ DBG ( "Cannot get mount port from %!:%d\n",
|
|
515
|
+ server->sin_addr.s_addr, server->sin_port );
|
|
516
|
+ return 0;
|
|
517
|
+ }
|
|
518
|
+ nfs_server.sin_port = rpc_lookup(server, PROG_NFS, 2, sport);
|
|
519
|
+ if ( ! mount_server.sin_port ) {
|
|
520
|
+ DBG ( "Cannot get nfs port from %!:%d\n",
|
|
521
|
+ server->sin_addr.s_addr, server->sin_port );
|
|
522
|
+ return 0;
|
|
523
|
+ }
|
|
524
|
+
|
501
|
525
|
if ( name != dirname ) {
|
502
|
526
|
memcpy(dirname, name, namelen + 1);
|
503
|
527
|
}
|
504
|
528
|
recursion = 0;
|
505
|
529
|
nfssymlink:
|
506
|
530
|
if ( recursion > NFS_MAXLINKDEPTH ) {
|
507
|
|
- printf ( "\nRecursion: More than %d symlinks followed. Abort.\n", NFS_MAXLINKDEPTH );
|
|
531
|
+ DBG ( "\nRecursion: More than %d symlinks followed. Abort.\n",
|
|
532
|
+ NFS_MAXLINKDEPTH );
|
508
|
533
|
return 0;
|
509
|
534
|
}
|
510
|
535
|
recursion++;
|
|
@@ -518,36 +543,24 @@ nfssymlink:
|
518
|
543
|
fname--;
|
519
|
544
|
}
|
520
|
545
|
if (fname < dirname) {
|
521
|
|
- printf("can't parse file name %s\n", name);
|
|
546
|
+ DBG("can't parse file name %s\n", name);
|
522
|
547
|
return 0;
|
523
|
548
|
}
|
524
|
549
|
|
525
|
|
- if (mount_port == -1) {
|
526
|
|
- mount_port = rpc_lookup(ARP_SERVER, PROG_MOUNT, 1, sport);
|
527
|
|
- }
|
528
|
|
- if (nfs_port == -1) {
|
529
|
|
- nfs_port = rpc_lookup(ARP_SERVER, PROG_NFS, 2, sport);
|
530
|
|
- }
|
531
|
|
- if (nfs_port == -1 || mount_port == -1) {
|
532
|
|
- printf("can't get nfs/mount ports from portmapper\n");
|
533
|
|
- return 0;
|
534
|
|
- }
|
535
|
|
-
|
536
|
|
-
|
537
|
|
- err = nfs_mount(ARP_SERVER, mount_port, dirname, dirfh, sport);
|
|
550
|
+ err = nfs_mount(&mount_server, dirname, dirfh, sport);
|
538
|
551
|
if (err) {
|
539
|
|
- printf("mounting %s: ", dirname);
|
|
552
|
+ DBG("mounting %s: ", dirname);
|
540
|
553
|
nfs_printerror(err);
|
541
|
554
|
/* just to be sure... */
|
542
|
|
- nfs_umountall(ARP_SERVER);
|
|
555
|
+ nfs_reset();
|
543
|
556
|
return 0;
|
544
|
557
|
}
|
545
|
558
|
|
546
|
|
- err = nfs_lookup(ARP_SERVER, nfs_port, dirfh, fname, filefh, sport);
|
|
559
|
+ err = nfs_lookup(&nfs_server, dirfh, fname, filefh, sport);
|
547
|
560
|
if (err) {
|
548
|
|
- printf("looking up %s: ", fname);
|
|
561
|
+ DBG("looking up %s: ", fname);
|
549
|
562
|
nfs_printerror(err);
|
550
|
|
- nfs_umountall(ARP_SERVER);
|
|
563
|
+ nfs_reset();
|
551
|
564
|
return 0;
|
552
|
565
|
}
|
553
|
566
|
|
|
@@ -556,25 +569,25 @@ nfssymlink:
|
556
|
569
|
size = -1; /* will be set properly with the first reply */
|
557
|
570
|
len = NFS_READ_SIZE; /* first request is always full size */
|
558
|
571
|
do {
|
559
|
|
- err = nfs_read(ARP_SERVER, nfs_port, filefh, offs, len, sport);
|
|
572
|
+ err = nfs_read(&nfs_server, filefh, offs, len, sport);
|
560
|
573
|
if ((err <= -NFSERR_ISDIR)&&(err >= -NFSERR_INVAL) && (offs == 0)) {
|
561
|
574
|
// An error occured. NFS servers tend to sending
|
562
|
575
|
// errors 21 / 22 when symlink instead of real file
|
563
|
576
|
// is requested. So check if it's a symlink!
|
564
|
|
- block = nfs_readlink(ARP_SERVER, nfs_port, dirfh, dirname,
|
|
577
|
+ block = nfs_readlink(&nfs_server, dirfh, dirname,
|
565
|
578
|
filefh, sport);
|
566
|
579
|
if ( 0 == block ) {
|
567
|
580
|
printf("\nLoading symlink:%s ..",dirname);
|
568
|
581
|
goto nfssymlink;
|
569
|
582
|
}
|
570
|
583
|
nfs_printerror(err);
|
571
|
|
- nfs_umountall(ARP_SERVER);
|
|
584
|
+ nfs_reset();
|
572
|
585
|
return 0;
|
573
|
586
|
}
|
574
|
587
|
if (err) {
|
575
|
588
|
printf("reading at offset %d: ", offs);
|
576
|
589
|
nfs_printerror(err);
|
577
|
|
- nfs_umountall(ARP_SERVER);
|
|
590
|
+ nfs_reset();
|
578
|
591
|
return 0;
|
579
|
592
|
}
|
580
|
593
|
|
|
@@ -589,10 +602,10 @@ nfssymlink:
|
589
|
602
|
rlen = len; /* shouldn't happen... */
|
590
|
603
|
}
|
591
|
604
|
|
592
|
|
- err = fnc((char *)&rpc->u.reply.data[19], block, rlen,
|
|
605
|
+ err = process((char *)&rpc->u.reply.data[19], block, rlen,
|
593
|
606
|
(offs+rlen == size));
|
594
|
607
|
if (err <= 0) {
|
595
|
|
- nfs_umountall(ARP_SERVER);
|
|
608
|
+ nfs_reset();
|
596
|
609
|
return err;
|
597
|
610
|
}
|
598
|
611
|
|
|
@@ -607,4 +620,8 @@ nfssymlink:
|
607
|
620
|
return 1;
|
608
|
621
|
}
|
609
|
622
|
|
610
|
|
-#endif /* DOWNLOAD_PROTO_NFS */
|
|
623
|
+INIT_FN ( INIT_RPC, rpc_init, nfs_reset, nfs_reset );
|
|
624
|
+
|
|
625
|
+static struct protocol nfs_protocol __protocol = {
|
|
626
|
+ "nfs", nfs
|
|
627
|
+};
|