/* * Call portmap to lookup a port number for a particular rpc program * Returns non-zero error on failure. */ int krpc_portmap(struct sockaddr_in *sin, u_int prog, u_int vers, u_int16_t *portp) { struct sdata { u_int32_t prog; /* call program */ u_int32_t vers; /* call version */ u_int32_t proto; /* call protocol */ u_int32_t port; /* call port (unused) */ } *sdata; struct rdata { u_int16_t pad; u_int16_t port; } *rdata; struct mbuf *m; int error; /* The portmapper port is fixed. */ if (prog == PMAPPROG) { *portp = htons(PMAPPORT); return 0; } m = m_get(M_WAIT, MT_DATA); sdata = mtod(m, struct sdata *); m->m_len = sizeof(*sdata); /* Do the RPC to get it. */ sdata->prog = txdr_unsigned(prog); sdata->vers = txdr_unsigned(vers); sdata->proto = txdr_unsigned(IPPROTO_UDP); sdata->port = 0; sin->sin_port = htons(PMAPPORT); error = krpc_call(sin, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, &m, NULL, -1); if (error) return error; if (m->m_len < sizeof(*rdata)) { m = m_pullup(m, sizeof(*rdata)); if (m == NULL) return ENOBUFS; } rdata = mtod(m, struct rdata *); *portp = rdata->port; m_freem(m); return 0; }
/* * Generate the rpc reply header * siz arg. is used to decide if adding a cluster is worthwhile */ struct mbuf * nfs_rephead(int siz, struct nfsrv_descript *nd, int err, struct mbuf **mbp, caddr_t *bposp) { u_int32_t *tl; struct mbuf *mreq; caddr_t bpos; struct mbuf *mb; if (err == EBADRPC) return (NULL); nd->nd_repstat = err; if (err && (nd->nd_flag & ND_NFSV3) == 0) /* XXX recheck */ siz = 0; MGET(mreq, M_WAITOK, MT_DATA); /* * If this is a big reply, use a cluster */ mreq->m_len = 0; if (siz >= MINCLSIZE) { MCLGET(mreq, M_WAITOK); } mb = mreq; bpos = mtod(mb, caddr_t); if (err != NFSERR_RETVOID) { tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); if (err) *tl = txdr_unsigned(nfsrv_errmap(nd, err)); else *tl = 0; }
int md_lookup_swap(struct sockaddr_in *mdsin, /* mountd server address */ char *path, u_char *fhp, int *fhsizep, struct nfs_args *args, struct thread *td) { struct mbuf *m; int error; int size = -1; int attribs_present; int status; union { u_int32_t v2[17]; u_int32_t v3[21]; } fattribs; m = m_get(MB_WAIT,MT_DATA); if (m == NULL) return ENOBUFS; if ((args->flags & NFSMNT_NFSV3) != 0) { *mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep); bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep); m->m_len = *fhsizep + sizeof(u_int32_t); } else {
void rpcclnt_init(void) { /* RPC constants how about actually using more than one of these! */ rpc_reply = txdr_unsigned(RPC_REPLY); rpc_vers = txdr_unsigned(RPC_VER2); rpc_call = txdr_unsigned(RPC_CALL); rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); rpc_mismatch = txdr_unsigned(RPC_MISMATCH); rpc_autherr = txdr_unsigned(RPC_AUTHERR); rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); rpc_auth_null = txdr_unsigned(RPCAUTH_NULL); fvdbg("RPC initialized\n"); }
/* * Copy a string into mbuf(s). * Return the number of bytes output, including XDR overheads. */ APPLESTATIC int nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz) { mbuf_t m2; int xfer, left; mbuf_t m1; int rem, bytesize; u_int32_t *tl; char *cp2; NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(siz); rem = NFSM_RNDUP(siz) - siz; bytesize = NFSX_UNSIGNED + siz + rem; m2 = nd->nd_mb; cp2 = nd->nd_bpos; left = M_TRAILINGSPACE(m2); /* * Loop around copying the string to mbuf(s). */ while (siz > 0) { if (left == 0) { if (siz > ncl_mbuf_mlen) NFSMCLGET(m1, M_WAITOK); else NFSMGET(m1); mbuf_setlen(m1, 0); mbuf_setnext(m2, m1); m2 = m1; cp2 = NFSMTOD(m2, caddr_t); left = M_TRAILINGSPACE(m2); } if (left >= siz) xfer = siz; else xfer = left; NFSBCOPY(cp, cp2, xfer); cp += xfer; mbuf_setlen(m2, mbuf_len(m2) + xfer); siz -= xfer; left -= xfer; if (siz == 0 && rem) { if (left < rem) panic("nfsm_strtom"); NFSBZERO(cp2 + xfer, rem); mbuf_setlen(m2, mbuf_len(m2) + rem); } } nd->nd_mb = m2; nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); return (bytesize); }
static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch, uint32_t xid, int prog, int vers, int procid) { /* Format the call header */ ch->rp_xid = txdr_unsigned(xid); ch->rp_direction = rpc_call; ch->rp_rpcvers = rpc_vers; ch->rp_prog = txdr_unsigned(prog); ch->rp_vers = txdr_unsigned(vers); ch->rp_proc = txdr_unsigned(procid); /* rpc_auth part (auth_null) */ ch->rpc_auth.authtype = rpc_auth_null; ch->rpc_auth.authlen = 0; /* rpc_verf part (auth_null) */ ch->rpc_verf.authtype = rpc_auth_null; ch->rpc_verf.authlen = 0; }
/* * Called once to initialize data structures... */ static int nfsrv_modevent(module_t mod, int type, void *data) { int error = 0; switch (type) { case MOD_LOAD: mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF); nfsrv_nfs_true = txdr_unsigned(TRUE); nfsrv_nfs_false = txdr_unsigned(FALSE); nfsrv_nfs_xdrneg1 = txdr_unsigned(-1); nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000; if (nfsrv_ticks < 1) nfsrv_ticks = 1; NFSD_LOCK(); nfsrv_init(0); /* Init server data structures */ NFSD_UNLOCK(); nfsd_call_nfsserver = nfssvc_nfsserver; break; case MOD_UNLOAD: if (nfsrv_numnfsd != 0) { error = EBUSY; break; } nfsd_call_nfsserver = NULL; callout_drain(&nfsrv_callout); mtx_destroy(&nfsd_mtx); break; default: error = EOPNOTSUPP; break; } return error; }
/* * Called once to initialize data structures... */ APPLESTATIC void newnfs_init(void) { static int nfs_inited = 0; if (nfs_inited) return; nfs_inited = 1; newnfs_true = txdr_unsigned(TRUE); newnfs_false = txdr_unsigned(FALSE); newnfs_xdrneg1 = txdr_unsigned(-1); nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000; if (nfscl_ticks < 1) nfscl_ticks = 1; NFSSETBOOTTIME(nfsboottime); /* * Initialize reply list and start timer */ TAILQ_INIT(&nfsd_reqq); NFS_TIMERINIT; }
bool bootpc_init(bool update_files, bool forever) { struct bootp_packet call; struct bootp_packet reply; static u_int32_t xid = ~0xFF; struct ifreq ireq; struct ifnet *ifp; struct socket *so; int j; int error; struct sockaddr_in myaddr; struct ifaddr *ifa; struct sockaddr_dl *sdl = NULL; char *delim; struct proc *procp = NULL; /* * If already filled in, don't touch it here */ if (nfs_diskless_valid) return true; /* * If we are to update the files create the root * file structure. */ if (update_files) if (rtems_create_root_fs () < 0) { printf("Error creating the root filesystem.\nFile not created.\n"); update_files = 0; } if (dhcp_hostname != NULL) { /* free it */ dhcp_hostname=bootp_strdup_realloc(dhcp_hostname,0); } /* * Find a network interface. */ for (ifp = ifnet; ifp != 0; ifp = ifp->if_next) if ((ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) break; if (ifp == NULL) { printf("bootpc_init: no suitable interface\n"); return false; } bzero(&ireq,sizeof(ireq)); sprintf(ireq.ifr_name, "%s%d", ifp->if_name,ifp->if_unit); printf("bootpc_init: using network interface '%s'\n", ireq.ifr_name); if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)) != 0) { printf("bootpc_init: socreate, error=%d", error); return false; } if (bootpc_fakeup_interface(&ireq,so,procp) != 0) { soclose(so); return false; } /* Get HW address */ for (ifa = ifp->if_addrlist;ifa; ifa = ifa->ifa_next) if (ifa->ifa_addr->sa_family == AF_LINK && (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) && sdl->sdl_type == IFT_ETHER) break; if (!sdl) { printf("bootpc: Unable to find HW address\n"); soclose(so); return false; } if (sdl->sdl_alen != EALEN ) { printf("bootpc: HW address len is %d, expected value is %d\n", sdl->sdl_alen,EALEN); soclose(so); return false; } printf("bootpc hw address is "); delim=""; for (j=0;j<sdl->sdl_alen;j++) { printf("%s%x",delim,((unsigned char *)LLADDR(sdl))[j]); delim=":"; } printf("\n"); #if 0 bootpboot_p_iflist(); bootpboot_p_rtlist(); #endif while (true) { bzero((caddr_t) &call, sizeof(call)); /* bootpc part */ call.op = 1; /* BOOTREQUEST */ call.htype= 1; /* 10mb ethernet */ call.hlen=sdl->sdl_alen; /* Hardware address length */ call.hops=0; xid++; call.xid = txdr_unsigned(xid); bcopy(LLADDR(sdl),&call.chaddr,sdl->sdl_alen); call.vend[0]=99; call.vend[1]=130; call.vend[2]=83; call.vend[3]=99; call.vend[4]=255; call.secs = 0; call.flags = htons(0x8000); /* We need an broadcast answer */ error = bootpc_call(&call,&reply,procp); if (!error) break; printf("BOOTP call failed -- error %d", error); if (!forever) { soclose(so); return false; } } /* * Initialize network address structures */ bzero(&myaddr,sizeof(myaddr)); bzero(&dhcp_netmask,sizeof(dhcp_netmask)); bzero(&dhcp_gw,sizeof(dhcp_gw)); myaddr.sin_len = sizeof(myaddr); myaddr.sin_family = AF_INET; dhcp_netmask.sin_len = sizeof(dhcp_netmask); dhcp_netmask.sin_family = AF_INET; dhcp_gw.sin_len = sizeof(dhcp_gw); dhcp_gw.sin_family= AF_INET; /* * Set our address */ myaddr.sin_addr = reply.yiaddr; printip("My ip address",myaddr.sin_addr); /* * Process BOOTP/DHCP options */ if (reply.vend[0]==99 && reply.vend[1]==130 && reply.vend[2]==83 && reply.vend[3]==99) { processOptions (&reply.vend[4], sizeof(reply.vend) - 4); } if (dhcpOptionOverload & 1) { processOptions ((unsigned char *)reply.file, sizeof reply.file); } else { if (reply.file[0]) rtems_bsdnet_bootp_boot_file_name = bootp_strdup_realloc(rtems_bsdnet_bootp_boot_file_name,reply.file); } if (dhcpOptionOverload & 2) { processOptions ((unsigned char *)reply.sname, sizeof reply.sname); } else { if (reply.sname[0]) rtems_bsdnet_bootp_server_name = bootp_strdup_realloc(rtems_bsdnet_bootp_server_name,reply.sname); } if (rtems_bsdnet_bootp_server_name) printf ("Server name is %s\n", rtems_bsdnet_bootp_server_name); if (rtems_bsdnet_bootp_boot_file_name) printf ("Boot file is %s\n", rtems_bsdnet_bootp_boot_file_name); if (rtems_bsdnet_bootp_cmdline) printf ("Command line is %s\n", rtems_bsdnet_bootp_cmdline); /* * Use defaults if values were not supplied by BOOTP/DHCP options */ if (!dhcp_gotnetmask) { if (IN_CLASSA(ntohl(myaddr.sin_addr.s_addr))) dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET); else if (IN_CLASSB(ntohl(myaddr.sin_addr.s_addr))) dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET); else dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET); } printip ("Subnet mask", dhcp_netmask.sin_addr); if (!dhcp_gotserver) rtems_bsdnet_bootp_server_address = reply.siaddr; printip ("Server ip address" ,rtems_bsdnet_bootp_server_address); if (!dhcp_gotgw) dhcp_gw.sin_addr = reply.giaddr; printip ("Gateway ip address", dhcp_gw.sin_addr); if (!dhcp_gotlogserver) rtems_bsdnet_log_host_address = rtems_bsdnet_bootp_server_address; printip ("Log server ip address", rtems_bsdnet_log_host_address); /* * Update the files if we are asked too. */ if (update_files) { char *dn = rtems_bsdnet_domain_name; char *hn = dhcp_hostname; if (!dn) dn = "mydomain"; if (!hn) hn = "me"; rtems_rootfs_append_host_rec(myaddr.sin_addr.s_addr, hn, dn); /* * Should the given domainname be used here ? */ if (dhcp_gotserver) { if (rtems_bsdnet_bootp_server_name) hn = rtems_bsdnet_bootp_server_name; else hn = "bootps"; rtems_rootfs_append_host_rec(rtems_bsdnet_bootp_server_address.s_addr, hn, dn); } if (dhcp_gotlogserver) { rtems_rootfs_append_host_rec(rtems_bsdnet_log_host_address.s_addr, "logs", dn); } /* * Setup the DNS configuration file /etc/resolv.conf. */ if (rtems_bsdnet_nameserver_count) { int i; char buf[64]; const char *bufl[1]; bufl[0] = buf; #define MKFILE_MODE (S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH) if (rtems_bsdnet_domain_name && (strlen(rtems_bsdnet_domain_name) < (sizeof(buf) - 1))) { strcpy(buf, "search "); strcat(buf, rtems_bsdnet_domain_name); strcat(buf, "\n"); rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl); } for (i = 0; i < rtems_bsdnet_nameserver_count; i++) { strcpy(buf, "nameserver "); strcat(buf, inet_ntoa(rtems_bsdnet_nameserver[i])); strcat(buf, "\n"); if (rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl)) break; } } } /* * Configure the interface with the new settings */ error = bootpc_adjust_interface(&ireq,so, &myaddr,&dhcp_netmask,&dhcp_gw,procp); soclose(so); return true; }
static void bootpc_compose_query(struct bootpc_ifcontext *ifctx, struct bootpc_globalcontext *gctx, struct thread *td) { unsigned char *vendp; unsigned char vendor_client[64]; uint32_t leasetime; uint8_t vendor_client_len; ifctx->gotrootpath = 0; bzero((caddr_t) &ifctx->call, sizeof(ifctx->call)); /* bootpc part */ ifctx->call.op = BOOTP_REQUEST; /* BOOTREQUEST */ ifctx->call.htype = 1; /* 10mb ethernet */ ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */ ifctx->call.hops = 0; if (bootpc_ifctx_isunresolved(ifctx) != 0) ifctx->xid++; ifctx->call.xid = txdr_unsigned(ifctx->xid); bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen); vendp = ifctx->call.vend; *vendp++ = 99; /* RFC1048 cookie */ *vendp++ = 130; *vendp++ = 83; *vendp++ = 99; *vendp++ = TAG_MAXMSGSIZE; *vendp++ = 2; *vendp++ = (sizeof(struct bootp_packet) >> 8) & 255; *vendp++ = sizeof(struct bootp_packet) & 255; snprintf(vendor_client, sizeof(vendor_client), "%s:%s:%s", ostype, MACHINE, osrelease); vendor_client_len = strlen(vendor_client); *vendp++ = TAG_VENDOR_INDENTIFIER; *vendp++ = vendor_client_len; memcpy(vendp, vendor_client, vendor_client_len); vendp += vendor_client_len; ifctx->dhcpquerytype = DHCP_NOMSG; switch (ifctx->state) { case IF_DHCP_UNRESOLVED: *vendp++ = TAG_DHCP_MSGTYPE; *vendp++ = 1; *vendp++ = DHCP_DISCOVER; ifctx->dhcpquerytype = DHCP_DISCOVER; ifctx->gotdhcpserver = 0; break; case IF_DHCP_OFFERED: *vendp++ = TAG_DHCP_MSGTYPE; *vendp++ = 1; *vendp++ = DHCP_REQUEST; ifctx->dhcpquerytype = DHCP_REQUEST; *vendp++ = TAG_DHCP_REQ_ADDR; *vendp++ = 4; memcpy(vendp, &ifctx->reply.yiaddr, 4); vendp += 4; if (ifctx->gotdhcpserver != 0) { *vendp++ = TAG_DHCP_SERVERID; *vendp++ = 4; memcpy(vendp, &ifctx->dhcpserver, 4); vendp += 4; } *vendp++ = TAG_DHCP_LEASETIME; *vendp++ = 4; leasetime = htonl(300); memcpy(vendp, &leasetime, 4); vendp += 4; break; default: break; } *vendp = TAG_END; ifctx->call.secs = 0; ifctx->call.flags = htons(0x8000); /* We need a broadcast answer */ }
int rpcclnt_umount(struct rpcclnt *rpc) { struct sockaddr *saddr; struct sockaddr_in *sa; union { struct rpc_call_pmap sdata; struct rpc_call_umount mountd; } request; union { struct rpc_reply_pmap rdata; struct rpc_reply_umount mdata; } response; int error; int ret; saddr = rpc->rc_name; sa = (FAR struct sockaddr_in *)saddr; /* Do the RPC to get a dynamic bounding with the server using ppmap. * Get port number for MOUNTD. */ sa->sin_port = htons(PMAPPORT); ret = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); if (ret < 0) { error = get_errno(); fdbg("ERROR: psock_connect failed [port=%d]: %d\n", ntohs(sa->sin_port), error); goto bad; } request.sdata.pmap.prog = txdr_unsigned(RPCPROG_MNT); request.sdata.pmap.vers = txdr_unsigned(RPCMNT_VER1); request.sdata.pmap.proc = txdr_unsigned(IPPROTO_UDP); request.sdata.pmap.port = 0; error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS, (FAR void *)&request.sdata, sizeof(struct call_args_pmap), (FAR void *)&response.rdata, sizeof(struct rpc_reply_pmap)); if (error != 0) { fdbg("ERROR: rpcclnt_request failed: %d\n", error); goto bad; } sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port)); ret = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); if (ret < 0) { error = get_errno(); fdbg("ERROR: psock_connect failed [port=%d]: %d\n", ntohs(sa->sin_port), error); goto bad; } /* Do RPC to umountd. */ strncpy(request.mountd.umount.rpath, rpc->rc_path, 92); request.mountd.umount.len = txdr_unsigned(sizeof(request.mountd.umount.rpath)); error = rpcclnt_request(rpc, RPCMNT_UMOUNT, RPCPROG_MNT, RPCMNT_VER1, (FAR void *)&request.mountd, sizeof(struct call_args_umount), (FAR void *)&response.mdata, sizeof(struct rpc_reply_umount)); if (error != 0) { fdbg("ERROR: rpcclnt_request failed: %d\n", error); goto bad; } return OK; bad: rpcclnt_disconnect(rpc); return error; }
int rpcclnt_connect(struct rpcclnt *rpc) { struct socket *so; int error; struct sockaddr *saddr; struct sockaddr_in sin; struct sockaddr_in *sa; union { struct rpc_call_pmap sdata; struct rpc_call_mount mountd; } request; union { struct rpc_reply_pmap rdata; struct rpc_reply_mount mdata; } response; struct timeval tv; uint16_t tport; int errval; fvdbg("Connecting\n"); /* Create the socket */ saddr = rpc->rc_name; /* Create an instance of the socket state structure */ so = (struct socket *)kmm_zalloc(sizeof(struct socket)); if (!so) { fdbg("ERROR: Failed to allocate socket structure\n"); return ENOMEM; } error = psock_socket(saddr->sa_family, rpc->rc_sotype, IPPROTO_UDP, so); if (error < 0) { errval = get_errno(); fdbg("ERROR: psock_socket failed: %d", errval); return error; } so->s_crefs = 1; rpc->rc_so = so; /* Always set receive timeout to detect server crash and reconnect. * Otherwise, we can get stuck in psock_receive forever. */ tv.tv_sec = 1; tv.tv_usec = 0; error = psock_setsockopt(rpc->rc_so, SOL_SOCKET, SO_RCVTIMEO, (const void *)&tv, sizeof(tv)); if (error < 0) { errval = get_errno(); fdbg("ERROR: psock_setsockopt failed: %d\n", errval); goto bad; } /* Some servers require that the client port be a reserved port * number. We always allocate a reserved port, as this prevents * filehandle disclosure through UDP port capture. */ sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; tport = 1024; errval = 0; do { tport--; sin.sin_port = htons(tport); error = psock_bind(rpc->rc_so, (struct sockaddr *)&sin, sizeof(sin)); if (error < 0) { errval = get_errno(); fdbg("ERROR: psock_bind failed: %d\n", errval); } } while (errval == EADDRINUSE && tport > 1024 / 2); if (error) { fdbg("ERROR: psock_bind failed: %d\n", errval); goto bad; } /* Protocols that do not require connections may be optionally left * unconnected for servers that reply from a port other than * NFS_PORT. */ error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); if (error < 0) { errval = get_errno(); fdbg("ERROR: psock_connect to PMAP port failed: %d", errval); goto bad; } /* Do the RPC to get a dynamic bounding with the server using ppmap. * Get port number for MOUNTD. */ request.sdata.pmap.prog = txdr_unsigned(RPCPROG_MNT); request.sdata.pmap.vers = txdr_unsigned(RPCMNT_VER1); request.sdata.pmap.proc = txdr_unsigned(IPPROTO_UDP); request.sdata.pmap.port = 0; error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS, (FAR void *)&request.sdata, sizeof(struct call_args_pmap), (FAR void *)&response.rdata, sizeof(struct rpc_reply_pmap)); if (error != 0) { fdbg("ERROR: rpcclnt_request failed: %d\n", error); goto bad; } sa = (FAR struct sockaddr_in *)saddr; sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port)); error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); if (error < 0) { errval = get_errno(); fdbg("ERROR: psock_connect MOUNTD port failed: %d\n", errval); goto bad; } /* Do RPC to mountd. */ strncpy(request.mountd.mount.rpath, rpc->rc_path, 90); request.mountd.mount.len = txdr_unsigned(sizeof(request.mountd.mount.rpath)); error = rpcclnt_request(rpc, RPCMNT_MOUNT, RPCPROG_MNT, RPCMNT_VER1, (FAR void *)&request.mountd, sizeof(struct call_args_mount), (FAR void *)&response.mdata, sizeof(struct rpc_reply_mount)); if (error != 0) { fdbg("ERROR: rpcclnt_request failed: %d\n", error); goto bad; } error = fxdr_unsigned(uint32_t, response.mdata.mount.status); if (error != 0) { fdbg("ERROR: Bad mount status: %d\n", error); goto bad; } memcpy(&rpc->rc_fh, &response.mdata.mount.fhandle, sizeof(nfsfh_t)); /* Do the RPC to get a dynamic bounding with the server using PMAP. * NFS port in the socket. */ sa->sin_port = htons(PMAPPORT); error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); if (error < 0) { errval = get_errno(); fdbg("ERROR: psock_connect PMAP port failed: %d\n", errval); goto bad; } request.sdata.pmap.prog = txdr_unsigned(NFS_PROG); request.sdata.pmap.vers = txdr_unsigned(NFS_VER3); request.sdata.pmap.proc = txdr_unsigned(IPPROTO_UDP); request.sdata.pmap.port = 0; error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS, (FAR void *)&request.sdata, sizeof(struct call_args_pmap), (FAR void *)&response.rdata, sizeof(struct rpc_reply_pmap)); if (error != 0) { fdbg("ERROR: rpcclnt_request failed: %d\n", error); goto bad; } sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port)); error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); if (error) { fdbg("psock_connect NFS port returns %d\n", error); goto bad; } return OK; bad: rpcclnt_disconnect(rpc); return error; }
/* * 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. * data: input/output * from_p: output */ int krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func, struct mbuf **data, struct mbuf **from_p, int retries) { struct socket *so; struct sockaddr_in *sin; struct mbuf *m, *nam, *mhead, *from, *mopt; struct rpc_call *call; struct rpc_reply *reply; struct uio auio; int error, rcvflg, timo, secs, len; static u_int32_t xid = 0; char addr[INET_ADDRSTRLEN]; int *ip; struct timeval tv; /* * Validate address family. * Sorry, this is INET specific... */ if (sa->sin_family != AF_INET) return (EAFNOSUPPORT); /* Free at end if not null. */ nam = mhead = NULL; from = NULL; /* * Create socket and set its receive timeout. */ if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0))) goto out; m = m_get(M_WAIT, MT_SOOPTS); tv.tv_sec = 1; tv.tv_usec = 0; memcpy(mtod(m, struct timeval *), &tv, sizeof tv); m->m_len = sizeof(tv); if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m))) goto out; /* * Enable broadcast if necessary. */ if (from_p) { int32_t *on; m = m_get(M_WAIT, MT_SOOPTS); on = mtod(m, int32_t *); m->m_len = sizeof(*on); *on = 1; if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m))) goto out; } /* * Bind the local endpoint to a reserved port, * because some NFS servers refuse requests from * non-reserved (non-privileged) ports. */ MGET(mopt, M_WAIT, MT_SOOPTS); mopt->m_len = sizeof(int); ip = mtod(mopt, int *); *ip = IP_PORTRANGE_LOW; error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt); if (error) goto out; MGET(m, M_WAIT, MT_SONAME); sin = mtod(m, struct sockaddr_in *); sin->sin_len = m->m_len = sizeof (struct sockaddr_in); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; sin->sin_port = htons(0); error = sobind(so, m, &proc0); m_freem(m); if (error) { printf("bind failed\n"); goto out; } MGET(mopt, M_WAIT, MT_SOOPTS); mopt->m_len = sizeof(int); ip = mtod(mopt, int *); *ip = IP_PORTRANGE_DEFAULT; error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt); if (error) goto out; /* * Setup socket address for the server. */ nam = m_get(M_WAIT, MT_SONAME); sin = mtod(nam, struct sockaddr_in *); bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sin_len)); /* * Prepend RPC message header. */ mhead = m_gethdr(M_WAIT, MT_DATA); mhead->m_next = *data; call = mtod(mhead, struct rpc_call *); mhead->m_len = sizeof(*call); bzero((caddr_t)call, sizeof(*call)); /* rpc_call part */ xid = krpc_get_xid(); call->rp_xid = txdr_unsigned(xid); /* call->rp_direction = 0; */ call->rp_rpcvers = txdr_unsigned(2); call->rp_prog = txdr_unsigned(prog); call->rp_vers = txdr_unsigned(vers); call->rp_proc = txdr_unsigned(func); /* rpc_auth part (auth_unix as root) */ call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX); call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix)); /* rpc_verf part (auth_null) */ call->rpc_verf.authtype = 0; call->rpc_verf.authlen = 0; /* * Setup packet header */ len = 0; m = mhead; while (m) { len += m->m_len; m = m->m_next; } mhead->m_pkthdr.len = len; mhead->m_pkthdr.rcvif = NULL; /* * Send it, repeatedly, until a reply is received, * but delay each re-send by an increasing amount. * If the delay hits the maximum, start complaining. */ for (timo = 0; retries; retries--) { /* Send RPC request (or re-send). */ m = m_copym(mhead, 0, M_COPYALL, M_WAIT); if (m == NULL) { error = ENOBUFS; goto out; } error = sosend(so, nam, NULL, m, NULL, 0); if (error) { printf("krpc_call: sosend: %d\n", error); goto out; } m = NULL; /* Determine new timeout. */ if (timo < MAX_RESEND_DELAY) timo++; else printf("RPC timeout for server %s (0x%x) prog %u\n", inet_ntop(AF_INET, &sin->sin_addr, addr, sizeof(addr)), ntohl(sin->sin_addr.s_addr), prog); /* * Wait for up to timo seconds for a reply. * The socket receive timeout was set to 1 second. */ 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; auio.uio_procp = NULL; rcvflg = 0; error = soreceive(so, &from, &auio, &m, NULL, &rcvflg, 0); if (error == EWOULDBLOCK) { secs--; continue; } if (error) goto out; len -= auio.uio_resid; /* 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 != txdr_unsigned(RPC_REPLY)) continue; if (reply->rp_xid != txdr_unsigned(xid)) continue; /* Was RPC accepted? (authorization OK) */ if (reply->rp_astatus != 0) { error = fxdr_unsigned(u_int32_t, reply->rp_errno); printf("rpc denied, error=%d\n", error); continue; } /* Did the call succeed? */ if (reply->rp_status != 0) { error = fxdr_unsigned(u_int32_t, reply->rp_status); printf("rpc denied, status=%d\n", error); continue; } goto gotreply; /* break two levels */ } /* while secs */ } /* forever send/receive */ error = ETIMEDOUT; goto out; gotreply: /* * Get RPC reply header into first mbuf, * get its length, then strip it off. */ len = sizeof(*reply); if (m->m_len < len) { m = m_pullup(m, len); if (m == NULL) { error = ENOBUFS; goto out; } } reply = mtod(m, struct rpc_reply *); if (reply->rp_auth.authtype != 0) { len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen); len = (len + 3) & ~3; /* XXX? */ } m_adj(m, len); /* result */ *data = m; if (from_p && error == 0) { *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; }