Subject: lib/1732: libnetboot does not work on little endian machines and with some NFS servers
To: None <gnats-bugs@gnats.netbsd.org>
From: None <jtp@cs.hut.fi>
List: netbsd-bugs
Date: 11/06/1995 10:40:55
>Number: 1732
>Category: lib
>Synopsis: libnetboot does not work on little endian machines and with some NFS servers
>Confidential: no
>Severity: serious
>Priority: low
>Responsible: lib-bug-people (Library Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Nov 6 03:50:01 1995
>Last-Modified:
>Originator: Jukka Partanen
>Organization:
Helsinki University of Technology
>Release: NetBSD-current around Oct 25
>Environment:
System: NetBSD tsuubi-duubi-duu.cs.hut.fi 1.1_ALPHA NetBSD 1.1_ALPHA (TSUUBI) #2: Sun Oct 29 11:35:35 EET 1995 jtp@tsuubi-duubi-duu.cs.hut.fi:/u/netbsd/src/sys/arch/i386/compile/TSUUBI i386
>Description:
Libnetboot does not work on little endian machines (e.g. i386).
All NFS servers I have access to (including NetBSD) require
RPCAUTH_UNIX in most operations.
With the patches below I'm actually able to use libnetboot for
bootp and NFS downloading.
>How-To-Repeat:
Try to use it on a little endian machine and with an NFS server.
>Fix:
*** ../libnetboot.orig/arp.c Wed Oct 25 15:25:53 1995
--- arp.c Mon Nov 6 10:10:15 1995
***************
*** 76,81 ****
--- 76,82 ----
register struct iodesc *d;
n_long addr;
{
+ n_long myip;
register int i;
register struct ether_arp *ah;
register struct arp_list *al;
***************
*** 117,123 ****
ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */
ah->arp_op = htons(ARPOP_REQUEST);
MACPY(d->myea, ah->arp_sha);
! bcopy(&d->myip, ah->arp_spa, sizeof(ah->arp_spa));
bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa));
/* Store ip address in cache */
--- 118,125 ----
ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */
ah->arp_op = htons(ARPOP_REQUEST);
MACPY(d->myea, ah->arp_sha);
! myip = htonl(d->myip);
! bcopy(&myip, ah->arp_spa, sizeof(ah->arp_spa));
bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa));
/* Store ip address in cache */
***************
*** 156,161 ****
--- 158,164 ----
{
register struct ether_header *eh;
register struct ether_arp *ah;
+ n_long myip;
#ifdef DEBUG
if (debug)
***************
*** 175,180 ****
--- 178,189 ----
return (-1);
}
+ /* But not from us */
+ if (bcmp(d->myea, eh->ether_shost, 6) == 0) {
+ errno = 0;
+ return (-1);
+ }
+
if (ntohs(eh->ether_type) != ETHERTYPE_ARP) {
errno = 0;
return (-1);
***************
*** 190,197 ****
errno = 0;
return (-1);
}
! if (bcmp(&arp_list[arp_num].addr, ah->arp_spa, sizeof(long)) != 0 ||
! bcmp(&d->myip, ah->arp_tpa, sizeof(d->myip)) != 0) {
errno = 0;
return (-1);
}
--- 199,207 ----
errno = 0;
return (-1);
}
! myip = htonl(d->myip);
! if (bcmp(&arp_list[arp_num].addr, ah->arp_spa, sizeof(n_long)) != 0 ||
! bcmp(&myip, ah->arp_tpa, sizeof(myip)) != 0) {
errno = 0;
return (-1);
}
*** ../libnetboot.orig/bootp.c Wed Oct 25 15:25:55 1995
--- bootp.c Mon Nov 6 10:11:04 1995
***************
*** 229,238 ****
}
/* Pick up root or swap server address and file spec */
! if (bp->bp_giaddr.s_addr != 0 && bp->bp_file[0] != '\0') {
if ((have & BOOT_ROOT) == 0) {
have |= BOOT_ROOT;
! rootip = ntohl(bp->bp_giaddr.s_addr);
#ifdef DEBUG
if (debug)
printf("root ip address is %s\n", intoa(rootip));
--- 229,238 ----
}
/* Pick up root or swap server address and file spec */
! if (bp->bp_siaddr.s_addr != 0 && bp->bp_file[0] != '\0') {
if ((have & BOOT_ROOT) == 0) {
have |= BOOT_ROOT;
! rootip = ntohl(bp->bp_siaddr.s_addr);
#ifdef DEBUG
if (debug)
printf("root ip address is %s\n", intoa(rootip));
***************
*** 245,251 ****
++d->xid;
} else if ((have & BOOT_SWAP) == 0) {
have |= BOOT_SWAP;
! swapip = ntohl(bp->bp_giaddr.s_addr);
#ifdef DEBUG
if (debug)
printf("swap ip address is %s\n", intoa(swapip));
--- 245,251 ----
++d->xid;
} else if ((have & BOOT_SWAP) == 0) {
have |= BOOT_SWAP;
! swapip = ntohl(bp->bp_siaddr.s_addr);
#ifdef DEBUG
if (debug)
printf("swap ip address is %s\n", intoa(swapip));
*** ../libnetboot.orig/net.c Wed Oct 25 15:26:02 1995
--- net.c Sun Oct 29 10:56:30 1995
***************
*** 107,113 ****
*ip = tip;
if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 ||
! mask == 0 || SAMENET(ip->ip_src.s_addr, ip->ip_dst.s_addr, mask))
ea = arpwhohas(d, ip->ip_dst.s_addr);
else
ea = arpwhohas(d, htonl(gateip));
--- 107,113 ----
*ip = tip;
if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 ||
! mask == 0 || SAMENET(d->myip, d->destip, mask))
ea = arpwhohas(d, ip->ip_dst.s_addr);
else
ea = arpwhohas(d, htonl(gateip));
*** ../libnetboot.orig/rpc.c Wed Oct 25 15:26:05 1995
--- rpc.c Mon Nov 6 10:00:13 1995
***************
*** 47,53 ****
#include <nfs/rpcv2.h>
#include <nfs/nfsv2.h>
- #undef NFSX_FATTR
#include <errno.h>
#include "salibc.h"
--- 47,52 ----
***************
*** 75,80 ****
--- 74,90 ----
u_long rp_alen; /* zero (size of auth struct) */
};
+ /* Unix auth info */
+ struct auth_unix {
+ int rp_atype; /* RPCAUTH_UNIX */
+ u_long rp_alen; /* 5 */
+ u_long rp_stamp; /* 0 */
+ u_long rp_hostname; /* 0 */
+ u_long rp_uid; /* 0 */
+ u_long rp_gid; /* 0 */
+ u_long rp_grpsize; /* 0 */
+ };
+
/* Generic rpc call header */
struct rpc_call {
u_long rp_xid; /* request transaction id */
***************
*** 87,92 ****
--- 97,113 ----
struct auth_info rp_verf; /* AUTH_NULL */
};
+ struct rpc_authcall {
+ u_long rp_xid; /* request transaction id */
+ int rp_direction; /* call direction */
+ u_long rp_rpcvers; /* rpc version (2) */
+ u_long rp_prog; /* program */
+ u_long rp_vers; /* version */
+ u_long rp_proc; /* procedure */
+ struct auth_unix rp_auth; /* AUTH_UNIX */
+ struct auth_info rp_verf; /* AUTH_NULL */
+ };
+
/* Generic rpc reply header */
struct rpc_reply {
u_long rp_xid; /* request transaction id */
***************
*** 136,142 ****
static int recvrpc __P((struct iodesc *, void *, int));
static u_short getport __P((struct iodesc *, u_long, u_long));
! /* Make a rpc call; return length of answer */
static int
callrpc(d, prog, vers, proc, sdata, slen, rdata, rlen)
register struct iodesc *d;
--- 157,163 ----
static int recvrpc __P((struct iodesc *, void *, int));
static u_short getport __P((struct iodesc *, u_long, u_long));
! /* Make an rpc call; return length of answer */
static int
callrpc(d, prog, vers, proc, sdata, slen, rdata, rlen)
register struct iodesc *d;
***************
*** 182,188 ****
--- 203,275 ----
rpc->rp_vers = htonl(vers);
rpc->rp_proc = htonl(proc);
bcopy(sdata, wbuf.data, slen);
+ cc = sendrecv(d, sendudp, rpc, sizeof(*rpc) + slen, recvrpc,
+ ((u_char *)&rbuf.rrpc) - HEADER_SIZE, sizeof(rbuf) - HEADER_SIZE);
+ if (cc < rlen) {
+ /* Check for an error return */
+ if (cc >= sizeof(rbuf.ru.errno) && rbuf.ru.errno != 0) {
+ errno = ntohl(rbuf.ru.errno);
+ return (-1);
+ }
+ panic("callrpc: missing data (%d < %d)", cc, rlen);
+ }
+ if (cc > sizeof(rbuf.ru.data))
+ panic("callrpc: huge return (%d > %d)",
+ cc, sizeof(rbuf.ru.data));
+ bcopy(rbuf.ru.data, rdata, cc);
+ return (cc);
+ }
+
+ /* Make an "authenticated" rpc call; return length of answer */
+ static int
+ callauthrpc(d, prog, vers, proc, sdata, slen, rdata, rlen)
+ register struct iodesc *d;
+ register u_long prog, vers, proc;
+ register void *sdata;
+ register int slen;
+ register void *rdata;
+ register int rlen;
+ {
+ register int cc;
+ register struct rpc_authcall *rpc;
+ struct {
+ u_char header[HEADER_SIZE];
+ struct rpc_authcall wrpc;
+ u_char data[sizeof(struct nfs_reply_data)]; /* XXX */
+ } wbuf;
+ struct {
+ u_char header[HEADER_SIZE];
+ struct rpc_reply rrpc;
+ union {
+ u_long errno;
+ u_char data[sizeof(struct nfs_reply_data)];
+ } ru;
+ } rbuf;
+
+ #ifdef DEBUG
+ if (debug)
+ printf("callauthrpc: called\n");
+ #endif
+ if (rlen > sizeof(rbuf.ru.data))
+ panic("callrpc: huge read (%d > %d)",
+ rlen, sizeof(rbuf.ru.data));
+
+ d->destport = getport(d, prog, vers);
+
+ rpc = &wbuf.wrpc;
+
+ bzero(rpc, sizeof(*rpc));
+
+ rpc->rp_xid = d->xid;
+ rpc->rp_rpcvers = htonl(RPC_MSG_VERSION);
+ rpc->rp_prog = htonl(prog);
+ rpc->rp_vers = htonl(vers);
+ rpc->rp_proc = htonl(proc);
+ bcopy(sdata, wbuf.data, slen);
+ /* fake authentication info (uid 0, gid 0) */
+ rpc->rp_auth.rp_atype = htonl(RPCAUTH_UNIX);
+ rpc->rp_auth.rp_alen = htonl(5);
cc = sendrecv(d, sendudp, rpc, sizeof(*rpc) + slen, recvrpc,
((u_char *)&rbuf.rrpc) - HEADER_SIZE, sizeof(rbuf) - HEADER_SIZE);
***************
*** 280,289 ****
pl->addr = d->destip;
pl->prog = prog;
pl->vers = vers;
! pl->port = port;
++pmap_num;
! return ((u_short)port);
}
/* Fetch file handle */
--- 367,376 ----
pl->addr = d->destip;
pl->prog = prog;
pl->vers = vers;
! pl->port = ntohl(port);
++pmap_num;
! return ((u_short)pl->port);
}
/* Fetch file handle */
***************
*** 340,355 ****
if (debug)
printf("getnfsinfo: called\n");
#endif
! rlen = sizeof(rdata);
! #if 0
! #ifdef NFSX_FATTR
! #if NFSX_FATTR(1) > NFSX_FATTR(0)
! /* nqnfs makes this more painful than it needs to be */
! rlen -= NFSX_FATTR(1) - NFSX_FATTR(0);
! #endif
! #endif
! #endif
! if (callrpc(d, NFS_PROG, NFS_VER2, NFSPROC_GETATTR,
d->fh, NFS_FHSIZE, &rdata, rlen) < 0)
panic("getnfsinfo: %m");
--- 427,434 ----
if (debug)
printf("getnfsinfo: called\n");
#endif
! rlen = NFSX_FATTR(0) + sizeof(u_long);
! if (callauthrpc(d, NFS_PROG, NFS_VER2, NFSPROC_GETATTR,
d->fh, NFS_FHSIZE, &rdata, rlen) < 0)
panic("getnfsinfo: %m");
***************
*** 399,415 ****
bcopy(name, sdata.name, len);
sdata.len = htonl(len);
len = sizeof(sdata) - sizeof(sdata.name) + roundup(len, sizeof(long));
!
! rlen = sizeof(rdata);
! #if 0
! #ifdef NFSX_FATTR
! #if NFSX_FATTR(1) > NFSX_FATTR(0)
! /* nqnfs makes this more painful than it needs to be */
! rlen -= NFSX_FATTR(1) - NFSX_FATTR(0);
! #endif
! #endif
! #endif
! if (callrpc(d, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
&sdata, len, &rdata, rlen) < 0)
return (-1);
--- 478,485 ----
bcopy(name, sdata.name, len);
sdata.len = htonl(len);
len = sizeof(sdata) - sizeof(sdata.name) + roundup(len, sizeof(long));
! rlen = NFSX_FATTR(0) + sizeof(u_long) + NFS_FHSIZE;
! if (callauthrpc(d, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
&sdata, len, &rdata, rlen) < 0)
return (-1);
***************
*** 447,453 ****
{
register int i;
register u_long cc;
! register struct rpc_call *rpc;
register struct nfs_call_data *nfs;
register struct nfsstate *ns;
--- 517,523 ----
{
register int i;
register u_long cc;
! register struct rpc_authcall *rpc;
register struct nfs_call_data *nfs;
register struct nfsstate *ns;
***************
*** 532,540 ****
panic("recvreaddata: less than nfs sized %d", len);
len -= sizeof(*nfs) - sizeof(nfs->data);
! if (len < nfs->count)
! panic("recvreaddata: short read (%d < %d)", len, nfs->count);
! len = nfs->count;
if (len > ns->len)
panic("recvreaddata: huge read (%d > %d)", len, ns->len);
--- 602,610 ----
panic("recvreaddata: less than nfs sized %d", len);
len -= sizeof(*nfs) - sizeof(nfs->data);
! if (len < ntohl(nfs->count))
! panic("recvreaddata: short read (%d < %d)", len, ntohl(nfs->count));
! len = ntohl(nfs->count);
if (len > ns->len)
panic("recvreaddata: huge read (%d > %d)", len, ns->len);
***************
*** 576,586 ****
register u_long len;
{
register int i, cc;
! register struct rpc_call *rpc;
register struct nfsstate *ns;
struct {
u_char header[HEADER_SIZE];
! struct rpc_call rpc;
struct nfs_call_data nfs;
} sdata;
struct {
--- 646,656 ----
register u_long len;
{
register int i, cc;
! register struct rpc_authcall *rpc;
register struct nfsstate *ns;
struct {
u_char header[HEADER_SIZE];
! struct rpc_authcall rpc;
struct nfs_call_data nfs;
} sdata;
struct {
***************
*** 632,643 ****
rpc->rp_prog = htonl(NFS_PROG);
rpc->rp_vers = htonl(NFS_VER2);
rpc->rp_proc = htonl(NFSPROC_READ);
bcopy(d->fh, sdata.nfs.fh, sizeof(sdata.nfs.fh));
nfscc = 0;
cc = sendrecv(d, sendreaddata,
&sdata.rpc,
! sizeof(struct rpc_call) + sizeof(struct nfs_call_data),
recvreaddata,
((u_char *)&rdata.rpc) - HEADER_SIZE, HEADER_SIZE +
sizeof(struct rpc_call) + sizeof(struct nfs_reply_data));
--- 702,716 ----
rpc->rp_prog = htonl(NFS_PROG);
rpc->rp_vers = htonl(NFS_VER2);
rpc->rp_proc = htonl(NFSPROC_READ);
+ /* fake authentication info (uid 0, gid 0) */
+ rpc->rp_auth.rp_atype = htonl(RPCAUTH_UNIX);
+ rpc->rp_auth.rp_alen = htonl(5);
bcopy(d->fh, sdata.nfs.fh, sizeof(sdata.nfs.fh));
nfscc = 0;
cc = sendrecv(d, sendreaddata,
&sdata.rpc,
! sizeof(struct rpc_authcall) + sizeof(struct nfs_call_data),
recvreaddata,
((u_char *)&rdata.rpc) - HEADER_SIZE, HEADER_SIZE +
sizeof(struct rpc_call) + sizeof(struct nfs_reply_data));
***************
*** 652,668 ****
i = 0;
while (size > 0) {
cc = readdata(d, off, (void *)addr, size);
! if (cc <= 0) {
/* XXX maybe should retry on certain errors */
! if (cc < 0)
! panic("\nreadseg: read: %s",
! strerror(errno));
! panic("\nreadseg: hit EOF unexpectantly");
}
! off += cc;
! addr += cc;
! size -= cc;
! i = ~i;
! printf("%c\010", i ? '-' : '=');
}
}
--- 725,740 ----
i = 0;
while (size > 0) {
cc = readdata(d, off, (void *)addr, size);
! if (cc < 0) {
/* XXX maybe should retry on certain errors */
! panic("\nreadseg: read: %s", strerror(errno));
}
! if (nfscc == 0)
! panic("\nreadseg: hit EOF unexpectantly");
! off += nfscc;
! addr += nfscc;
! size -= nfscc;
! printf("%c\010", "-\\|/"[i++]);
! i &= 3;
}
}
>Audit-Trail:
>Unformatted: