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: