From 62f18b1dda15da597b07208921639b40f1b54597 Mon Sep 17 00:00:00 2001 From: gwr Date: Mon, 26 Sep 1994 16:42:29 +0000 Subject: [PATCH] Do the first BOOTPARAM RPC call to the broadcast address instead of using the address of the RARP server because a BOOTPARAM server might not be running on the machine that sent the RARP reply. --- sys/nfs/krpc.h | 33 +++++++++++ sys/nfs/krpc_subr.c | 141 ++++++++++++++++++++++++++------------------ sys/nfs/nfs_boot.c | 140 ++++++++++++++++++++++++++----------------- 3 files changed, 204 insertions(+), 110 deletions(-) create mode 100644 sys/nfs/krpc.h diff --git a/sys/nfs/krpc.h b/sys/nfs/krpc.h new file mode 100644 index 000000000000..90af2e2ba2ae --- /dev/null +++ b/sys/nfs/krpc.h @@ -0,0 +1,33 @@ + +#include + +int krpc_call __P((struct sockaddr_in *sin, \ + u_long prog, u_long vers, u_long func, \ + struct mbuf **data, struct mbuf **from)); + +int krpc_portmap __P((struct sockaddr_in *sin, \ + u_long prog, u_long vers, u_short *portp)); + + +/* + * RPC definitions for the portmapper + */ +#define PMAPPORT 111 +#define PMAPPROG 100000 +#define PMAPVERS 2 +#define PMAPPROC_NULL 0 +#define PMAPPROC_SET 1 +#define PMAPPROC_UNSET 2 +#define PMAPPROC_GETPORT 3 +#define PMAPPROC_DUMP 4 +#define PMAPPROC_CALLIT 5 + + +/* + * RPC definitions for bootparamd + */ +#define BOOTPARAM_PROG 100026 +#define BOOTPARAM_VERS 1 +#define BOOTPARAM_WHOAMI 1 +#define BOOTPARAM_GETFILE 2 + diff --git a/sys/nfs/krpc_subr.c b/sys/nfs/krpc_subr.c index 30860db1ac40..6f2348b1e37e 100644 --- a/sys/nfs/krpc_subr.c +++ b/sys/nfs/krpc_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: krpc_subr.c,v 1.6 1994/08/12 04:31:51 cgd Exp $ */ +/* $NetBSD: krpc_subr.c,v 1.7 1994/09/26 16:42:31 gwr Exp $ */ /* * Copyright (c) 1994 Gordon Ross, Adam Glass @@ -56,6 +56,7 @@ #include #include +#include /* * Kernel support for Sun RPC @@ -65,11 +66,6 @@ * Note: will not work on variable-sized rpc args/results. * implicit size-limit of an mbuf. */ - -#define PMAPPORT 111 -#define PMAPPROG 100000 -#define PMAPVERS 2 -#define PMAPPROC_GETPORT 3 /* * Generic RPC headers @@ -119,8 +115,8 @@ struct rpc_reply { * Returns non-zero error on failure. */ int -krpc_portmap(sa, prog, vers, portp) - struct sockaddr *sa; /* server address */ +krpc_portmap(sin, prog, vers, portp) + struct sockaddr_in *sin; /* server address */ u_long prog, vers; /* host order */ u_short *portp; /* network order */ { @@ -156,8 +152,9 @@ krpc_portmap(sa, prog, vers, portp) sdata->proto = htonl(IPPROTO_UDP); sdata->port = 0; - error = krpc_call(sa, PMAPPROG, PMAPVERS, - PMAPPROC_GETPORT, &m); + sin->sin_port = htons(PMAPPORT); + error = krpc_call(sin, PMAPPROG, PMAPVERS, + PMAPPROC_GETPORT, &m, NULL); if (error) return error; @@ -170,17 +167,19 @@ krpc_portmap(sa, prog, vers, portp) /* * Do a remote procedure call (RPC) and wait for its reply. + * If from_p is non-null, then we are doing broadcast, and + * the address from whence the response came is saved there. */ int -krpc_call(sa, prog, vers, func, data) - struct sockaddr *sa; +krpc_call(sa, prog, vers, func, data, from_p) + struct sockaddr_in *sa; u_long prog, vers, func; struct mbuf **data; /* input/output */ + struct mbuf **from_p; /* output */ { struct socket *so; struct sockaddr_in *sin; - struct timeval *tv; - struct mbuf *m, *nam, *mhead; + struct mbuf *m, *nam, *mhead, *from; struct rpc_call *call; struct rpc_reply *reply; struct uio auio; @@ -192,11 +191,12 @@ krpc_call(sa, prog, vers, func, data) * Validate address family. * Sorry, this is INET specific... */ - if (sa->sa_family != AF_INET) + if (sa->sin_family != AF_INET) return (EAFNOSUPPORT); /* Free at end if not null. */ nam = mhead = NULL; + from = NULL; /* * Create socket and set its recieve timeout. @@ -208,13 +208,32 @@ krpc_call(sa, prog, vers, func, data) if (m == NULL) { error = ENOBUFS; goto out; + } else { + struct timeval *tv; + tv = mtod(m, struct timeval *); + m->m_len = sizeof(*tv); + tv->tv_sec = 1; + tv->tv_usec = 0; + if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m))) + goto out; + } + + /* + * Enable broadcast if necessary. + */ + if (from_p) { + int *on; + m = m_get(M_WAIT, MT_SOOPTS); + if (m == NULL) { + error = ENOBUFS; + goto out; + } + on = mtod(m, int *); + m->m_len = sizeof(*on); + *on = 1; + if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m))) + goto out; } - tv = mtod(m, struct timeval *); - m->m_len = sizeof(*tv); - tv->tv_sec = 1; - tv->tv_usec = 0; - if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m))) - goto out; /* * Bind the local endpoint to a reserved port, @@ -248,13 +267,7 @@ krpc_call(sa, prog, vers, func, data) goto out; } sin = mtod(nam, struct sockaddr_in *); - bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sa_len)); - - /* - * Set the port number that the request will use. - */ - if ((error = krpc_portmap(sa, prog, vers, &sin->sin_port))) - goto out; + bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sin_len)); /* * Prepend RPC message header. @@ -280,7 +293,8 @@ krpc_call(sa, prog, vers, func, data) */ call = mtod(mhead, struct rpc_call *); bzero((caddr_t)call, sizeof(*call)); - call->rp_xid = ++xid; /* no need to put in network order */ + xid++; + call->rp_xid = htonl(xid); /* call->rp_direction = 0; */ call->rp_rpcvers = htonl(2); call->rp_prog = htonl(prog); @@ -322,9 +336,17 @@ krpc_call(sa, prog, vers, func, data) */ secs = timo; while (secs > 0) { + if (from) { + m_freem(from); + from = NULL; + } + if (m) { + m_freem(m); + m = NULL; + } auio.uio_resid = len = 1<<16; rcvflg = 0; - error = soreceive(so, NULL, &auio, &m, NULL, &rcvflg); + error = soreceive(so, &from, &auio, &m, NULL, &rcvflg); if (error == EWOULDBLOCK) { secs--; continue; @@ -333,20 +355,35 @@ krpc_call(sa, prog, vers, func, data) goto out; len -= auio.uio_resid; - /* Is the reply complete and the right one? */ - if (len < MIN_REPLY_HDR) { - m_freem(m); + /* Does the reply contain at least a header? */ + if (len < MIN_REPLY_HDR) + continue; + if (m->m_len < MIN_REPLY_HDR) + continue; + reply = mtod(m, struct rpc_reply *); + + /* Is it the right reply? */ + if (reply->rp_direction != htonl(RPC_REPLY)) + continue; + + if (reply->rp_xid != htonl(xid)) + continue; + + /* Was RPC accepted? (authorization OK) */ + if (reply->rp_astatus != 0) { + error = ntohl(reply->rp_u.rpu_errno); + printf("rpc denied, error=%d\n", error); continue; } - if (m->m_len < MIN_REPLY_HDR) { - m = m_pullup(m, MIN_REPLY_HDR); - if (!m) - continue; + + /* Did the call succeed? */ + if ((error = ntohl(reply->rp_u.rpu_ok.rp_rstatus)) != 0) { + printf("rpc status=%d\n", error); + continue; } - reply = mtod(m, struct rpc_reply *); - if ((reply->rp_direction == htonl(RPC_REPLY)) && - (reply->rp_xid == xid)) - goto gotreply; /* break two levels */ + + goto gotreply; /* break two levels */ + } /* while secs */ } /* forever send/receive */ @@ -373,22 +410,7 @@ krpc_call(sa, prog, vers, func, data) error = ENOBUFS; goto out; } - } - reply = mtod(m, struct rpc_reply *); - - /* - * Check RPC acceptance and status. - */ - if (reply->rp_astatus != 0) { - error = ntohl(reply->rp_u.rpu_errno); - printf("rpc denied, error=%d\n", error); - m_freem(m); - goto out; - } - if ((error = ntohl(reply->rp_u.rpu_ok.rp_rstatus)) != 0) { - printf("rpc status=%d\n", error); - m_freem(m); - goto out; + reply = mtod(m, struct rpc_reply *); } /* @@ -403,10 +425,15 @@ krpc_call(sa, prog, vers, func, data) /* result */ *data = m; + if (from_p) { + *from_p = from; + from = NULL; + } out: if (nam) m_freem(nam); if (mhead) m_freem(mhead); + if (from) m_freem(from); soclose(so); return error; } diff --git a/sys/nfs/nfs_boot.c b/sys/nfs/nfs_boot.c index f946edb49560..3727c7678fa7 100644 --- a/sys/nfs/nfs_boot.c +++ b/sys/nfs/nfs_boot.c @@ -1,4 +1,4 @@ -/* $NetBSD: nfs_boot.c,v 1.10 1994/08/11 23:47:51 mycroft Exp $ */ +/* $NetBSD: nfs_boot.c,v 1.11 1994/09/26 16:42:33 gwr Exp $ */ /* * Copyright (c) 1994 Adam Glass, Gordon Ross @@ -48,9 +48,19 @@ #include #include #include +#include #include "ether.h" -#if NETHER > 0 +#if NETHER == 0 + +int nfs_boot_init(nd, procp) + struct nfs_diskless *nd; + struct proc *procp; +{ + panic("nfs_boot_init: no ether"); +} + +#else /* NETHER */ /* * Support for NFS diskless booting, specifically getting information @@ -96,7 +106,7 @@ nfs_boot_init(nd, procp) struct proc *procp; { struct ifreq ireq; - struct in_addr my_ip, srv_ip, gw_ip; + struct in_addr my_ip, gw_ip; struct sockaddr_in bp_sin; struct sockaddr_in *sin; struct ifnet *ifp; @@ -149,10 +159,9 @@ nfs_boot_init(nd, procp) * Do RARP for the interface address. Also * save the server address for bootparam RPC. */ - if ((error = revarpwhoarewe(ifp, &srv_ip, &my_ip)) != 0) + if ((error = revarpwhoami(&my_ip, ifp)) != 0) panic("revarp failed, error=%d", error); - printf("nfs_boot: client=0x%x, server=0x%x\n", - ntohl(my_ip.s_addr), ntohl(srv_ip.s_addr)); + printf("nfs_boot: client_addr=0x%x\n", ntohl(my_ip.s_addr)); /* * Do enough of ifconfig(8) so that the chosen interface can @@ -173,17 +182,21 @@ nfs_boot_init(nd, procp) /* * Get client name and gateway address. * RPC: bootparam/whoami + * XXX - Using old broadcast addr. for WHOAMI, + * then it is replaced with the BP server addr. */ bzero((caddr_t)&bp_sin, sizeof(bp_sin)); bp_sin.sin_len = sizeof(bp_sin); bp_sin.sin_family = AF_INET; - bp_sin.sin_addr.s_addr = srv_ip.s_addr; + bp_sin.sin_addr.s_addr = ~0; /* XXX */ hostnamelen = MAXHOSTNAMELEN; /* this returns gateway IP address */ error = bp_whoami(&bp_sin, &my_ip, &gw_ip); if (error) panic("nfs_boot: bootparam whoami, error=%d", error); + printf("nfs_boot: server_addr=0x%x\n", + ntohl(bp_sin.sin_addr.s_addr)); printf("nfs_boot: hostname=%s\n", hostname); #ifdef NFS_BOOT_GATEWAY @@ -315,16 +328,6 @@ struct bp_inaddr { }; -/* - * RPC definitions for bootparamd - * (XXX - move to a header file?) - */ -#define BOOTPARAM_PROG 100026 -#define BOOTPARAM_VERS 1 -#define BOOTPARAM_WHOAMI 1 -#define BOOTPARAM_GETFILE 2 - - /* * RPC: bootparam/whoami * Given client IP address, get: @@ -334,6 +337,12 @@ struct bp_inaddr { * * Setting the hostname and domainname here may be somewhat * controvercial, but it is so easy to do it here. -gwr + * + * Note - bpsin is initialized to the broadcast address, + * and will be replaced with the bootparam server address + * after this call is complete. Have to use PMAP_PROC_CALL + * to make sure we get responses only from a servers that + * know about us (don't want to broadcast a getport call). */ static int bp_whoami(bpsin, my_ip, gw_ip) @@ -341,42 +350,55 @@ bp_whoami(bpsin, my_ip, gw_ip) struct in_addr *my_ip; struct in_addr *gw_ip; { - /* The RPC structures */ - struct bp_inaddr *bia; + /* RPC structures for PMAPPROC_CALLIT */ + struct whoami_call { + u_long call_prog; + u_long call_vers; + u_long call_proc; + u_long call_arglen; + struct bp_inaddr call_ia; + } *call; + struct rpc_string *str; - struct mbuf *m; + struct bp_inaddr *bia; + struct mbuf *m, *from; struct sockaddr_in *sin; int error, msg_len; int cn_len, dn_len; u_char *p; + long *lp; /* * Get message buffer of sufficient size. */ - msg_len = sizeof(*bia); + msg_len = sizeof(*call); m = m_get_len(msg_len); if (m == NULL) return ENOBUFS; /* - * Build request message. + * Build request message for PMAPPROC_CALLIT. */ - /* client IP address */ - bia = mtod(m, struct bp_inaddr *); - bia->atype = htonl(1); - p = (u_char*)my_ip; /* ugh! */ - bia->addr[0] = htonl(*p); - p++; - bia->addr[1] = htonl(*p); - p++; - bia->addr[2] = htonl(*p); - p++; - bia->addr[3] = htonl(*p); - p++; + call = mtod(m, struct whoami_call *); + call->call_prog = BOOTPARAM_PROG; + call->call_vers = BOOTPARAM_VERS; + call->call_proc = BOOTPARAM_WHOAMI; + call->call_arglen = sizeof(struct bp_inaddr); - /* RPC: bootparam/whoami */ - error = krpc_call((struct sockaddr *)bpsin, - BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_WHOAMI, &m); + /* client IP address */ + call->call_ia.atype = htonl(1); + p = (u_char*)my_ip; + lp = call->call_ia.addr; + *lp++ = htonl(*p); p++; + *lp++ = htonl(*p); p++; + *lp++ = htonl(*p); p++; + *lp++ = htonl(*p); p++; + + /* RPC: portmap/callit */ + bpsin->sin_port = htons(PMAPPORT); + from = NULL; + error = krpc_call(bpsin, PMAPPROG, PMAPVERS, + PMAPPROC_CALLIT, &m, &from); if (error) return error; @@ -384,7 +406,21 @@ bp_whoami(bpsin, my_ip, gw_ip) * Parse result message. */ msg_len = m->m_len; - p = mtod(m, char *); + lp = mtod(m, long *); + + /* bootparam server port (also grab from address). */ + if (msg_len < sizeof(*lp)) + goto bad; + msg_len -= sizeof(*lp); + bpsin->sin_port = (short) *lp++; + sin = mtod(from, struct sockaddr_in *); + bpsin->sin_addr.s_addr = sin->sin_addr.s_addr; + + /* length of encapsulated results */ + if (msg_len < (*lp + sizeof(*lp))) + goto bad; + msg_len = *lp++; + p = (char*)lp; /* client name */ if (msg_len < sizeof(*str)) @@ -434,6 +470,8 @@ bad: error = EBADRPC; out: + if (from) + m_freem(from); m_freem(m); return(error); } @@ -490,8 +528,8 @@ bp_getfile(bpsin, key, md_sin, serv_name, pathname) bcopy(key, str->data, key_len); /* RPC: bootparam/getfile */ - error = krpc_call((struct sockaddr *)bpsin, - BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, &m); + error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS, + BOOTPARAM_GETFILE, &m, NULL); if (error) return error; @@ -576,6 +614,11 @@ md_mount(mdsin, path, fhp) struct mbuf *m; int error, mlen, slen; + /* Get port number for MOUNTD. */ + error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, + &mdsin->sin_port); + if (error) return error; + slen = strlen(path); mlen = RPC_STR_SIZE(slen); @@ -587,8 +630,8 @@ md_mount(mdsin, path, fhp) bcopy(path, str->data, slen); /* Do RPC to mountd. */ - error = krpc_call((struct sockaddr *)mdsin, - RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, &m); + error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, + RPCMNT_MOUNT, &m, NULL); if (error) return error; /* message already freed */ @@ -602,8 +645,8 @@ md_mount(mdsin, path, fhp) bcopy(rdata->fh, fhp, NFS_FHSIZE); /* Set port number for NFS use. */ - error = krpc_portmap((struct sockaddr *)mdsin, - NFS_PROG, NFS_VER2, &mdsin->sin_port); + error = krpc_portmap(mdsin, NFS_PROG, NFS_VER2, + &mdsin->sin_port); goto out; bad: @@ -614,13 +657,4 @@ out: return error; } -#else /* NETHER */ - -int nfs_boot_init(nd, procp) - struct nfs_diskless *nd; - struct proc *procp; -{ - panic("nfs_boot_init: no ether"); -} - #endif /* NETHER */