예제 #1
0
/*
 * 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;
}
예제 #2
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;
	}
예제 #3
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 {
예제 #4
0
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");
}
예제 #5
0
/*
 * 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);
}
예제 #6
0
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;
}
예제 #7
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;
}
예제 #8
0
/*
 * 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;
}
예제 #9
0
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;
}
예제 #10
0
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 */
}
예제 #11
0
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;
}
예제 #12
0
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;
}
예제 #13
0
/*
 * 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;
}