Ejemplo n.º 1
0
/*
 * Give the socket an address.
 */
static int
tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;
	struct sockaddr_in *sinp;

	COMMON_START();

	/*
	 * Must check for multicast addresses and disallow binding
	 * to them.
	 */
	sinp = (struct sockaddr_in *)nam;
	if (sinp->sin_family == AF_INET &&
	    IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
		error = EAFNOSUPPORT;
		goto out;
	}
	error = in_pcbbind(inp, nam, p);
	if (error)
		goto out;
	COMMON_END(PRU_BIND);

}
Ejemplo n.º 2
0
/*
 * Prepare to accept connections.
 */
static int
tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
{
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp = NULL;

	TCPDEBUG0;
	INP_INFO_WLOCK(&V_tcbinfo);
	inp = sotoinpcb(so);
	KASSERT(inp != NULL, ("tcp_usr_listen: inp == NULL"));
	INP_WLOCK(inp);
	if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
		error = EINVAL;
		goto out;
	}
	tp = intotcpcb(inp);
	TCPDEBUG1();
	SOCK_LOCK(so);
	error = solisten_proto_check(so);
	if (error == 0 && inp->inp_lport == 0)
		error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
	if (error == 0) {
		tp->t_state = TCPS_LISTEN;
		solisten_proto(so, backlog);
		tcp_offload_listen_open(tp);
	}
	SOCK_UNLOCK(so);

out:
	TCPDEBUG2(PRU_LISTEN);
	INP_WUNLOCK(inp);
	INP_INFO_WUNLOCK(&V_tcbinfo);
	return (error);
}
Ejemplo n.º 3
0
/*
 * Give the socket an address.
 */
static void
tcp_usr_bind(netmsg_t msg)
{
	struct socket *so = msg->bind.base.nm_so;
	struct sockaddr *nam = msg->bind.nm_nam;
	struct thread *td = msg->bind.nm_td;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
	struct sockaddr_in *sinp;

	COMMON_START(so, inp, 0);

	/*
	 * Must check for multicast addresses and disallow binding
	 * to them.
	 */
	sinp = (struct sockaddr_in *)nam;
	if (sinp->sin_family == AF_INET &&
	    IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
		error = EAFNOSUPPORT;
		goto out;
	}
	error = in_pcbbind(inp, nam, td);
	if (error)
		goto out;
	COMMON_END(PRU_BIND);

}
Ejemplo n.º 4
0
/*
 * Outer subroutine:
 * Connect from a socket to a specified address.
 * Both address and port must be specified in argument sin.
 * If don't have a local address for this socket yet,
 * then pick one.
 */
int
in_pcbconnect(struct inpcb *inp, struct mbuf *nam)
{
	struct sockaddr_in *ifaddr;
	register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
	int error;

	/*
	 *   Call inner routine, to assign local interface address.
	 */
	if ((error = in_pcbladdr(inp, nam, &ifaddr)))
		return(error);

	if (in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
	    inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
	    inp->inp_lport, 0) != NULL)
		return (EADDRINUSE);
	if (inp->inp_laddr.s_addr == INADDR_ANY) {
		if (inp->inp_lport == 0)
			(void)in_pcbbind(inp, (struct mbuf *)0);
		inp->inp_laddr = ifaddr->sin_addr;
	}
	inp->inp_faddr = sin->sin_addr;
	inp->inp_fport = sin->sin_port;
	in_pcbrehash(inp);
	return (0);
}
/*
 * Prepare to accept connections.
 */
static int
tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
{
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp = NULL;

	//printf("%s: called\n", __FUNCTION__);

	TCPDEBUG0;
	INP_INFO_WLOCK(&tcbinfo);
	inp = sotoinpcb(so);
	KASSERT(inp != NULL, ("tcp_usr_listen: inp == NULL"));
	INP_LOCK(inp);
	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
		error = EINVAL;
		goto out;
	}
	tp = intotcpcb(inp);
	TCPDEBUG1();
	SOCK_LOCK(so);
	error = solisten_proto_check(so);
	//printf("%s: error=%d\n", __FUNCTION__, error);
#ifdef MAXHE_TODO
	if (error == 0 && inp->inp_lport == 0)
		error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
#else
	if (error == 0 && inp->inp_lport == 0)
		error = in_pcbbind(inp, (struct sockaddr *)0, NULL);
#endif // MAXHE_TODO
	if (error == 0) {
		tp->t_state = TCPS_LISTEN;
		//printf("%s: solisten_proto backlog=%d\n", __FUNCTION__, backlog);
		solisten_proto(so, backlog);
	}
	SOCK_UNLOCK(so);
	//printf("%s: called done\n", __FUNCTION__);

out:
	//printf("%s: called out\n", __FUNCTION__);
	TCPDEBUG2(PRU_LISTEN);
	INP_UNLOCK(inp);
	INP_INFO_WUNLOCK(&tcbinfo);
	return (error);
}
/*
 * Give the socket an address.
 */
static int
tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp = NULL;
	struct sockaddr_in *sinp;

	sinp = (struct sockaddr_in *)nam;
	if (nam->sa_len != sizeof (*sinp))
		return (EINVAL);
	//printf("%s: called 0.5\n", __FUNCTION__);
	/*
	 * Must check for multicast addresses and disallow binding
	 * to them.
	 */
	if (sinp->sin_family == AF_INET &&
	    IN_MULTICAST(ntohl(sinp->sin_addr.s_addr)))
		return (EAFNOSUPPORT);

	TCPDEBUG0;
	INP_INFO_WLOCK(&tcbinfo);
	inp = sotoinpcb(so);
	KASSERT(inp != NULL, ("tcp_usr_bind: inp == NULL"));
	INP_LOCK(inp);
	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
		error = EINVAL;
		goto out;
	}
	tp = intotcpcb(inp);
	TCPDEBUG1();
#ifdef MAXHE_TODO
	error = in_pcbbind(inp, nam, td->td_ucred);
#else
	error = in_pcbbind(inp, nam, NULL);
#endif
out:
	TCPDEBUG2(PRU_BIND);
	INP_UNLOCK(inp);
	INP_INFO_WUNLOCK(&tcbinfo);

	return (error);
}
Ejemplo n.º 7
0
/*
 * Prepare to accept connections.
 */
static void
tcp_usr_listen(netmsg_t msg)
{
	struct socket *so = msg->listen.base.nm_so;
	struct thread *td = msg->listen.nm_td;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
#ifdef SMP
	struct netmsg_inswildcard nm;
#endif

	COMMON_START(so, inp, 0);

	if (tp->t_flags & TF_LISTEN)
		goto out;

	if (inp->inp_lport == 0) {
		error = in_pcbbind(inp, NULL, td);
		if (error)
			goto out;
	}

	tp->t_state = TCPS_LISTEN;
	tp->t_flags |= TF_LISTEN;
	tp->tt_msg = NULL; /* Catch any invalid timer usage */

#ifdef SMP
	if (ncpus > 1) {
		/*
		 * We have to set the flag because we can't have other cpus
		 * messing with our inp's flags.
		 */
		KASSERT(!(inp->inp_flags & INP_CONNECTED),
			("already on connhash\n"));
		KASSERT(!(inp->inp_flags & INP_WILDCARD),
			("already on wildcardhash\n"));
		KASSERT(!(inp->inp_flags & INP_WILDCARD_MP),
			("already on MP wildcardhash\n"));
		inp->inp_flags |= INP_WILDCARD_MP;

		KKASSERT(so->so_port == cpu_portfn(0));
		KKASSERT(&curthread->td_msgport == cpu_portfn(0));
		KKASSERT(inp->inp_pcbinfo == &tcbinfo[0]);

		netmsg_init(&nm.base, NULL, &curthread->td_msgport,
			    MSGF_PRIORITY, in_pcbinswildcardhash_handler);
		nm.nm_inp = inp;
		lwkt_domsg(cpu_portfn(1), &nm.base.lmsg, 0);
	}
#endif
	in_pcbinswildcardhash(inp);
	COMMON_END(PRU_LISTEN);
}
Ejemplo n.º 8
0
static int
tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp = NULL;
	struct sockaddr_in6 *sin6p;

	sin6p = (struct sockaddr_in6 *)nam;
	if (nam->sa_len != sizeof (*sin6p))
		return (EINVAL);
	/*
	 * Must check for multicast addresses and disallow binding
	 * to them.
	 */
	if (sin6p->sin6_family == AF_INET6 &&
	    IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
		return (EAFNOSUPPORT);

	TCPDEBUG0;
	INP_INFO_WLOCK(&V_tcbinfo);
	inp = sotoinpcb(so);
	KASSERT(inp != NULL, ("tcp6_usr_bind: inp == NULL"));
	INP_WLOCK(inp);
	if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
		error = EINVAL;
		goto out;
	}
	tp = intotcpcb(inp);
	TCPDEBUG1();
	inp->inp_vflag &= ~INP_IPV4;
	inp->inp_vflag |= INP_IPV6;
	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
		if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr))
			inp->inp_vflag |= INP_IPV4;
		else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
			struct sockaddr_in sin;

			in6_sin6_2_sin(&sin, sin6p);
			inp->inp_vflag |= INP_IPV4;
			inp->inp_vflag &= ~INP_IPV6;
			error = in_pcbbind(inp, (struct sockaddr *)&sin,
			    td->td_ucred);
			goto out;
		}
	}
	error = in6_pcbbind(inp, nam, td->td_ucred);
out:
	TCPDEBUG2(PRU_BIND);
	INP_WUNLOCK(inp);
	INP_INFO_WUNLOCK(&V_tcbinfo);
	return (error);
}
Ejemplo n.º 9
0
/*
 * Common subroutine to open a TCP connection to remote host specified
 * by struct sockaddr_in in mbuf *nam.  Call in_pcbbind to assign a local
 * port number if needed.  Call in_pcbconnect_setup to do the routing and
 * to choose a local host address (interface).  If there is an existing
 * incarnation of the same connection in TIME-WAIT state and if the remote
 * host was sending CC options and if the connection duration was < MSL, then
 * truncate the previous TIME-WAIT state and proceed.
 * Initialize connection parameters and enter SYN-SENT state.
 */
static int
tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
{
	struct inpcb *inp = tp->t_inpcb, *oinp;
	struct socket *so = inp->inp_socket;
	struct in_addr laddr;
	u_short lport;
	int error;

	INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
	INP_WLOCK_ASSERT(inp);

	if (inp->inp_lport == 0) {
		error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
		if (error)
			return error;
	}

	/*
	 * Cannot simply call in_pcbconnect, because there might be an
	 * earlier incarnation of this same connection still in
	 * TIME_WAIT state, creating an ADDRINUSE error.
	 */
	laddr = inp->inp_laddr;
	lport = inp->inp_lport;
	error = in_pcbconnect_setup(inp, nam, &laddr.s_addr, &lport,
	    &inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, td->td_ucred);
	if (error && oinp == NULL)
		return error;
	if (oinp)
		return EADDRINUSE;
	inp->inp_laddr = laddr;
	in_pcbrehash(inp);

	/*
	 * Compute window scaling to request:
	 * Scale to fit into sweet spot.  See tcp_syncache.c.
	 * XXX: This should move to tcp_output().
	 */
	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
	    (TCP_MAXWIN << tp->request_r_scale) < sb_max)
		tp->request_r_scale++;

	soisconnecting(so);
	TCPSTAT_INC(tcps_connattempt);
	tp->t_state = TCPS_SYN_SENT;
	tcp_timer_activate(tp, TT_KEEP, tcp_keepinit);
	tp->iss = tcp_new_isn(tp);
	tp->t_bw_rtseq = tp->iss;
	tcp_sendseqinit(tp);

	return 0;
}
Ejemplo n.º 10
0
/*
 * Prepare to accept connections.
 */
static int
tcp_usr_listen(struct socket *so, struct proc *p)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;

	COMMON_START();
	if (inp->inp_lport == 0)
		error = in_pcbbind(inp, (struct sockaddr *)0, p);
	if (error == 0)
		tp->t_state = TCPS_LISTEN;
	COMMON_END(PRU_LISTEN);
}
Ejemplo n.º 11
0
static int
udp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
	struct inpcb *inp;
	struct inpcbinfo *pcbinfo;
	int error;

	pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
	inp = sotoinpcb(so);
	KASSERT(inp != NULL, ("udp_bind: inp == NULL"));
	INP_WLOCK(inp);
	INP_HASH_WLOCK(pcbinfo);
	error = in_pcbbind(inp, nam, td->td_ucred);
	INP_HASH_WUNLOCK(pcbinfo);
	INP_WUNLOCK(inp);
	return (error);
}
Ejemplo n.º 12
0
static int
udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
	struct inpcb *inp;
	struct inpcbinfo *pcbinfo;
	int error;

	pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol);
	inp = sotoinpcb(so);
	KASSERT(inp != NULL, ("udp6_bind: inp == NULL"));

	INP_WLOCK(inp);
	INP_HASH_WLOCK(pcbinfo);
	inp->inp_vflag &= ~INP_IPV4;
	inp->inp_vflag |= INP_IPV6;
	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
		struct sockaddr_in6 *sin6_p;

		sin6_p = (struct sockaddr_in6 *)nam;

		if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr))
			inp->inp_vflag |= INP_IPV4;
#ifdef INET
		else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
			struct sockaddr_in sin;

			in6_sin6_2_sin(&sin, sin6_p);
			inp->inp_vflag |= INP_IPV4;
			inp->inp_vflag &= ~INP_IPV6;
			error = in_pcbbind(inp, (struct sockaddr *)&sin,
			    td->td_ucred);
			goto out;
		}
#endif
	}

	error = in6_pcbbind(inp, nam, td->td_ucred);
#ifdef INET
out:
#endif
	INP_HASH_WUNLOCK(pcbinfo);
	INP_WUNLOCK(inp);
	return (error);
}
Ejemplo n.º 13
0
static void
tcp6_usr_bind(netmsg_t msg)
{
	struct socket *so = msg->bind.base.nm_so;
	struct sockaddr *nam = msg->bind.nm_nam;
	struct thread *td = msg->bind.nm_td;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
	struct sockaddr_in6 *sin6p;

	COMMON_START(so, inp, 0);

	/*
	 * Must check for multicast addresses and disallow binding
	 * to them.
	 */
	sin6p = (struct sockaddr_in6 *)nam;
	if (sin6p->sin6_family == AF_INET6 &&
	    IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
		error = EAFNOSUPPORT;
		goto out;
	}
	inp->inp_vflag &= ~INP_IPV4;
	inp->inp_vflag |= INP_IPV6;
	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
		if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr))
			inp->inp_vflag |= INP_IPV4;
		else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
			struct sockaddr_in sin;

			in6_sin6_2_sin(&sin, sin6p);
			inp->inp_vflag |= INP_IPV4;
			inp->inp_vflag &= ~INP_IPV6;
			error = in_pcbbind(inp, (struct sockaddr *)&sin, td);
			goto out;
		}
	}
	error = in6_pcbbind(inp, nam, td);
	if (error)
		goto out;
	COMMON_END(PRU_BIND);
}
Ejemplo n.º 14
0
static int
tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;
	struct sockaddr_in6 *sin6p;

	COMMON_START();

	/*
	 * Must check for multicast addresses and disallow binding
	 * to them.
	 */
	sin6p = (struct sockaddr_in6 *)nam;
	if (sin6p->sin6_family == AF_INET6 &&
	    IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
		error = EAFNOSUPPORT;
		goto out;
	}
	inp->inp_vflag &= ~INP_IPV4;
	inp->inp_vflag |= INP_IPV6;
	if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
		if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr))
			inp->inp_vflag |= INP_IPV4;
		else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
			struct sockaddr_in sin;

			in6_sin6_2_sin(&sin, sin6p);
			inp->inp_vflag |= INP_IPV4;
			inp->inp_vflag &= ~INP_IPV6;
			error = in_pcbbind(inp, (struct sockaddr *)&sin, p);
			goto out;
		}
	}
	error = in6_pcbbind(inp, nam, p);
	if (error)
		goto out;
	COMMON_END(PRU_BIND);
}
Ejemplo n.º 15
0
int
tcp_usrreq(struct socket * so, 
   struct mbuf *  m,
   struct mbuf *  nam)
{
   struct inpcb * inp;
   struct tcpcb * tp;
   int   error =  0;
   int   req;

#ifdef DO_TCPTRACE
   int   ostate;
#endif

   req = so->so_req;    /* get request from socket struct */
   inp = sotoinpcb(so);
   /*
    * When a TCP is attached to a socket, then there will be
    * a (struct inpcb) pointed at by the socket, and this
    * structure will point at a subsidary (struct tcpcb).
    */
   if (inp == 0 && req != PRU_ATTACH) 
   {
      return (EINVAL);
   }

   if (inp)
      tp = intotcpcb(inp);
   else  /* inp and tp not set, make sure this is OK: */
   { 
      if (req == PRU_ATTACH)
         tp = NULL;  /* stifle compiler warnings about using unassigned tp*/
      else
      {
         dtrap(); /* programming error? */
         return EINVAL;
      }
   }

   switch (req) 
   {
   /*
    * TCP attaches to socket via PRU_ATTACH, reserving space,
    * and an internet control block.
    */
   case PRU_ATTACH:
      if (inp) 
      {
         error = EISCONN;
         break;
      }
      error = tcp_attach(so);
      if (error)
         break;
      if ((so->so_options & SO_LINGER) && so->so_linger == 0)
         so->so_linger = TCP_LINGERTIME;
#ifdef   DO_TCPTRACE
      SETTP(tp, sototcpcb(so));
#endif
      break;

   /*
    * PRU_DETACH detaches the TCP protocol from the socket.
    * If the protocol state is non-embryonic, then can't
    * do this directly: have to initiate a PRU_DISCONNECT,
    * which may finish later; embryonic TCB's can just
    * be discarded here.
    */
   case PRU_DETACH:
      if (tp->t_state > TCPS_LISTEN)
         SETTP(tp, tcp_disconnect(tp));
      else
         SETTP(tp, tcp_close(tp));
      break;

   /*
    * Give the socket an address.
    */
   case PRU_BIND:

      /* bind is quite different for IPv4 and v6, so we use two 
       * seperate pcbbind routines. so_domain was checked for 
       * validity way up in t_bind()
       */
#ifdef IP_V4
      if(inp->inp_socket->so_domain == AF_INET)
      {
         error = in_pcbbind(inp, nam);
         break;
      }
#endif /* IP_V4 */
#ifdef IP_V6
      if(inp->inp_socket->so_domain == AF_INET6)
      {
         error = ip6_pcbbind(inp, nam);
         break;
      }
#endif /* IP_V6 */
      dtrap();    /* not v4 or v6? */
      error = EINVAL;
      break;
   /*
    * Prepare to accept connections.
    */
   case PRU_LISTEN:
      if (inp->inp_lport == 0)
         error = in_pcbbind(inp, (struct mbuf *)0);
      if (error == 0)
         tp->t_state = TCPS_LISTEN;
      break;

   /*
    * Initiate connection to peer.
    * Create a template for use in transmissions on this connection.
    * Enter SYN_SENT state, and mark socket as connecting.
    * Start keep-alive timer, and seed output sequence space.
    * Send initial segment on connection.
    */
   case PRU_CONNECT:
      if (inp->inp_lport == 0) 
      {

#ifdef IP_V4
#ifndef IP_V6  /* v4 only */
      error = in_pcbbind(inp, (struct mbuf *)0);
#else    /* dual mode */
      if(so->so_domain == AF_INET)
         error = in_pcbbind(inp, (struct mbuf *)0);
      else
         error = ip6_pcbbind(inp, (struct mbuf *)0);
#endif   /* end dual mode code */
#else    /* no v4, v6 only */
      error = ip6_pcbbind(inp, (struct mbuf *)0);
#endif   /* end v6 only */

         if (error)
            break;
      }

#ifdef IP_V4
#ifndef IP_V6  /* v4 only */
      error = in_pcbconnect(inp, nam);
#else    /* dual mode */
      if(so->so_domain == AF_INET)
         error = in_pcbconnect(inp, nam);
      else
         error = ip6_pcbconnect(inp, nam);
#endif   /* end dual mode code */
#else    /* no v4, v6 only */
      error = ip6_pcbconnect(inp, nam);
#endif   /* end v6 only */

      if (error)
         break;
      tp->t_template = tcp_template(tp);
      if (tp->t_template == 0) 
      {

#ifdef IP_V4
#ifndef IP_V6  /* v4 only */
         in_pcbdisconnect(inp);
#else    /* dual mode */
         if(so->so_domain == AF_INET)
            in_pcbdisconnect(inp);
         else
            ip6_pcbdisconnect(inp);
#endif   /* end dual mode code */
#else    /* no v4, v6 only */
         ip6_pcbdisconnect(inp);
#endif   /* end v6 only */

         error = ENOBUFS;
         break;
      }

      soisconnecting(so);
      tcpstat.tcps_connattempt++;
      tp->t_state = TCPS_SYN_SENT;
      tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
      tp->iss = tcp_iss; 
      tcp_iss += (tcp_seq)(TCP_ISSINCR/2);
      tcp_sendseqinit(tp);
      error = tcp_output(tp);
      if (!error)
         TCP_MIB_INC(tcpActiveOpens);     /* keep MIB stats */
      break;

   /*
    * Create a TCP connection between two sockets.
    */
   case PRU_CONNECT2:
      error = EOPNOTSUPP;
      break;

   /*
    * Initiate disconnect from peer.
    * If connection never passed embryonic stage, just drop;
    * else if don't need to let data drain, then can just drop anyways,
    * else have to begin TCP shutdown process: mark socket disconnecting,
    * drain unread data, state switch to reflect user close, and
    * send segment (e.g. FIN) to peer.  Socket will be really disconnected
    * when peer sends FIN and acks ours.
    *
    * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
    */
   case PRU_DISCONNECT:
      SETTP(tp, tcp_disconnect(tp));
      break;

   /*
    * Accept a connection.  Essentially all the work is
    * done at higher levels; just return the address
    * of the peer, storing through addr.
    */
   case PRU_ACCEPT: 
   {
         struct sockaddr_in * sin   =  mtod(nam,   struct sockaddr_in *);
#ifdef IP_V6
         struct sockaddr_in6 * sin6 = mtod(nam,   struct sockaddr_in6 *);
#endif

#ifdef IP_V6
         if (so->so_domain == AF_INET6)
         {
            nam->m_len = sizeof (struct sockaddr_in6);
            sin6->sin6_port = inp->inp_fport;
            sin6->sin6_family = AF_INET6;
            IP6CPY(&sin6->sin6_addr, &inp->ip6_faddr);
         }
#endif

#ifdef IP_V4
         if (so->so_domain == AF_INET)
         {
            nam->m_len = sizeof (struct sockaddr_in);
            sin->sin_family = AF_INET;
            sin->sin_port = inp->inp_fport;
            sin->sin_addr = inp->inp_faddr;
         }
#endif
         if ( !(so->so_domain == AF_INET) &&
              !(so->so_domain == AF_INET6)
             )
         {
            dprintf("*** PRU_ACCEPT bad domain = %d\n", so->so_domain);
            dtrap();
         } 
         TCP_MIB_INC(tcpPassiveOpens);    /* keep MIB stats */
         break;
      }

   /*
    * Mark the connection as being incapable of further output.
    */
   case PRU_SHUTDOWN:
      socantsendmore(so);
      tp = tcp_usrclosed(tp);
      if (tp)
         error = tcp_output(tp);
      break;

   /*
    * After a receive, possibly send window update to peer.
    */
   case PRU_RCVD:
      (void) tcp_output(tp);
      break;

   /*
    * Do a send by putting data in output queue and updating urgent
    * marker if URG set.  Possibly send more data.
    */
   case PRU_SEND:
      if (so->so_pcb == NULL)
      {                    /* Return EPIPE error if socket is not connected */
         error = EPIPE;
         break;
      }
      sbappend(&so->so_snd, m);
      error = tcp_output(tp);
      if (error == ENOBUFS)
         sbdropend(&so->so_snd,m);  /* Remove data from socket buffer */
      break;

   /*
    * Abort the TCP.
    */
   case PRU_ABORT:
      SETTP(tp, tcp_drop(tp, ECONNABORTED));
      break;

   case PRU_SENSE:
      /*      ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; */
      dtrap();    /* does this ever happen? */
      return (0);

   case PRU_RCVOOB:
      if ((so->so_oobmark == 0 &&
          (so->so_state & SS_RCVATMARK) == 0) ||
#ifdef SO_OOBINLINE
       so->so_options & SO_OOBINLINE ||
#endif
       tp->t_oobflags & TCPOOB_HADDATA) 
       {
         error = EINVAL;
         break;
      }
      if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) 
      {
         error = EWOULDBLOCK;
         break;
      }
      m->m_len = 1;
      *mtod(m, char *) = tp->t_iobc;
      if ((MBUF2LONG(nam) & MSG_PEEK) == 0)
         tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
      break;

   case PRU_SENDOOB:
      if (so->so_pcb == NULL)
      {                    /* Return EPIPE error if socket is not connected */
         error = EPIPE;
         break;
      }
      if (sbspace(&so->so_snd) == 0) 
      {
         m_freem(m);
         error = ENOBUFS;
         break;
      }
      /*
       * According to RFC961 (Assigned Protocols),
       * the urgent pointer points to the last octet
       * of urgent data.  We continue, however,
       * to consider it to indicate the first octet
       * of data past the urgent section.
       * Otherwise, snd_up should be one lower.
       */
      sbappend(&so->so_snd, m);
      tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
      tp->t_force = 1;
      error = tcp_output(tp);
      if (error == ENOBUFS)
         sbdropend(&so->so_snd,m);  /* Remove data from socket buffer */
      tp->t_force = 0;
      break;

   case PRU_SOCKADDR:

   /* sockaddr and peeraddr have to switch based on IP type */
#ifdef IP_V4
#ifndef IP_V6  /* v4 only */
      in_setsockaddr(inp, nam);
#else /* dual mode */
      if(so->so_domain == AF_INET6)
         ip6_setsockaddr(inp, nam);
      else
         in_setsockaddr(inp, nam);
#endif   /* dual mode */
#else    /* IP_V6 */
         ip6_setsockaddr(inp, nam);
#endif
      break;         

   case PRU_PEERADDR:
#ifdef IP_V4
#ifndef IP_V6  /* v4 only */
      in_setpeeraddr(inp, nam);
#else /* dual mode */
      if(so->so_domain == AF_INET6)
         ip6_setpeeraddr(inp, nam);
      else
         in_setpeeraddr(inp, nam);
#endif   /* dual mode */
#else    /* IP_V6 */
         ip6_setpeeraddr(inp, nam);
#endif
      break;

   case PRU_SLOWTIMO:
      SETTP(tp, tcp_timers(tp, (int)MBUF2LONG(nam)));
#ifdef DO_TCPTRACE
      req |= (long)nam << 8;        /* for debug's sake */
#endif
      break;

      default:
      panic("tcp_usrreq");
   }
#ifdef DO_TCPTRACE
   if (tp && (so->so_options & SO_DEBUG))
      tcp_trace("usrreq: state: %d, tcpcb: %x, req: %d",
    ostate, tp, req);
#endif
   return (error);
}
Ejemplo n.º 16
0
static void
udp_send(netmsg_t msg)
{
	struct socket *so = msg->send.base.nm_so;
	struct mbuf *m = msg->send.nm_m;
	struct sockaddr *dstaddr = msg->send.nm_addr;
	int pru_flags = msg->send.nm_flags;
	struct inpcb *inp = so->so_pcb;
	struct thread *td = msg->send.nm_td;
	int flags;

	struct udpiphdr *ui;
	int len = m->m_pkthdr.len;
	struct sockaddr_in *sin;	/* really is initialized before use */
	int error = 0, cpu;

	KKASSERT(msg->send.nm_control == NULL);

	logudp(send_beg, inp);

	if (inp == NULL) {
		error = EINVAL;
		goto release;
	}

	if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
		error = EMSGSIZE;
		goto release;
	}

	if (inp->inp_lport == 0) {	/* unbound socket */
		boolean_t forwarded;

		error = in_pcbbind(inp, NULL, td);
		if (error)
			goto release;

		/*
		 * Need to call udp_send again, after this inpcb is
		 * inserted into wildcard hash table.
		 */
		msg->send.base.lmsg.ms_flags |= MSGF_UDP_SEND;
		forwarded = udp_inswildcardhash(inp, &msg->send.base, 0);
		if (forwarded) {
			/*
			 * The message is further forwarded, so we are
			 * done here.
			 */
			logudp(send_inswildcard, inp);
			return;
		}
	}

	if (dstaddr != NULL) {		/* destination address specified */
		if (inp->inp_faddr.s_addr != INADDR_ANY) {
			/* already connected */
			error = EISCONN;
			goto release;
		}
		sin = (struct sockaddr_in *)dstaddr;
		if (!prison_remote_ip(td, (struct sockaddr *)&sin)) {
			error = EAFNOSUPPORT; /* IPv6 only jail */
			goto release;
		}
	} else {
		if (inp->inp_faddr.s_addr == INADDR_ANY) {
			/* no destination specified and not already connected */
			error = ENOTCONN;
			goto release;
		}
		sin = NULL;
	}

	/*
	 * Calculate data length and get a mbuf
	 * for UDP and IP headers.
	 */
	M_PREPEND(m, sizeof(struct udpiphdr), M_NOWAIT);
	if (m == NULL) {
		error = ENOBUFS;
		goto release;
	}

	/*
	 * Fill in mbuf with extended UDP header
	 * and addresses and length put into network format.
	 */
	ui = mtod(m, struct udpiphdr *);
	bzero(ui->ui_x1, sizeof ui->ui_x1);	/* XXX still needed? */
	ui->ui_pr = IPPROTO_UDP;

	/*
	 * Set destination address.
	 */
	if (dstaddr != NULL) {			/* use specified destination */
		ui->ui_dst = sin->sin_addr;
		ui->ui_dport = sin->sin_port;
	} else {				/* use connected destination */
		ui->ui_dst = inp->inp_faddr;
		ui->ui_dport = inp->inp_fport;
	}

	/*
	 * Set source address.
	 */
	if (inp->inp_laddr.s_addr == INADDR_ANY ||
	    IN_MULTICAST(ntohl(inp->inp_laddr.s_addr))) {
		struct sockaddr_in *if_sin;

		if (dstaddr == NULL) {	
			/*
			 * connect() had (or should have) failed because
			 * the interface had no IP address, but the
			 * application proceeded to call send() anyways.
			 */
			error = ENOTCONN;
			goto release;
		}

		/* Look up outgoing interface. */
		error = in_pcbladdr_find(inp, dstaddr, &if_sin, td, 1);
		if (error)
			goto release;
		ui->ui_src = if_sin->sin_addr;	/* use address of interface */
	} else {
		ui->ui_src = inp->inp_laddr;	/* use non-null bound address */
	}
	ui->ui_sport = inp->inp_lport;
	KASSERT(inp->inp_lport != 0, ("inp lport should have been bound"));

	/*
	 * Release the original thread, since it is no longer used
	 */
	if (pru_flags & PRUS_HELDTD) {
		lwkt_rele(td);
		pru_flags &= ~PRUS_HELDTD;
	}
	/*
	 * Free the dest address, since it is no longer needed
	 */
	if (pru_flags & PRUS_FREEADDR) {
		kfree(dstaddr, M_SONAME);
		pru_flags &= ~PRUS_FREEADDR;
	}

	ui->ui_ulen = htons((u_short)len + sizeof(struct udphdr));

	/*
	 * Set up checksum and output datagram.
	 */
	if (udpcksum) {
		ui->ui_sum = in_pseudo(ui->ui_src.s_addr, ui->ui_dst.s_addr,
		    htons((u_short)len + sizeof(struct udphdr) + IPPROTO_UDP));
		m->m_pkthdr.csum_flags = CSUM_UDP;
		m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
		m->m_pkthdr.csum_thlen = sizeof(struct udphdr);
	} else {
Ejemplo n.º 17
0
/*
 * Common subroutine to open a TCP connection to remote host specified
 * by struct sockaddr_in in mbuf *nam.  Call in_pcbbind to assign a local
 * port number if needed.  Call in_pcbladdr to do the routing and to choose
 * a local host address (interface).
 * Initialize connection parameters and enter SYN-SENT state.
 */
static void
tcp_connect(netmsg_t msg)
{
	struct socket *so = msg->connect.base.nm_so;
	struct sockaddr *nam = msg->connect.nm_nam;
	struct thread *td = msg->connect.nm_td;
	struct sockaddr_in *sin = (struct sockaddr_in *)nam;
	struct sockaddr_in *if_sin;
	struct inpcb *inp;
	struct tcpcb *tp;
	int error, calc_laddr = 1;
#ifdef SMP
	lwkt_port_t port;
#endif

	COMMON_START(so, inp, 0);

	/*
	 * Reconnect our pcb if we have to
	 */
	if (msg->connect.nm_reconnect & NMSG_RECONNECT_RECONNECT) {
		msg->connect.nm_reconnect &= ~NMSG_RECONNECT_RECONNECT;
		in_pcblink(so->so_pcb, &tcbinfo[mycpu->gd_cpuid]);
	}

	/*
	 * Bind if we have to
	 */
	if (inp->inp_lport == 0) {
		if (tcp_lport_extension) {
			KKASSERT(inp->inp_laddr.s_addr == INADDR_ANY);

			error = in_pcbladdr(inp, nam, &if_sin, td);
			if (error)
				goto out;
			inp->inp_laddr.s_addr = if_sin->sin_addr.s_addr;

			error = in_pcbconn_bind(inp, nam, td);
			if (error)
				goto out;

			calc_laddr = 0;
		} else {
			error = in_pcbbind(inp, NULL, td);
			if (error)
				goto out;
		}
	}

	if (calc_laddr) {
		/*
		 * Calculate the correct protocol processing thread.  The
		 * connect operation must run there.  Set the forwarding
		 * port before we forward the message or it will get bounced
		 * right back to us.
		 */
		error = in_pcbladdr(inp, nam, &if_sin, td);
		if (error)
			goto out;
	}
	KKASSERT(inp->inp_socket == so);

#ifdef SMP
	port = tcp_addrport(sin->sin_addr.s_addr, sin->sin_port,
			    (inp->inp_laddr.s_addr ?
			     inp->inp_laddr.s_addr : if_sin->sin_addr.s_addr),
			    inp->inp_lport);

	if (port != &curthread->td_msgport) {
		struct route *ro = &inp->inp_route;

		/*
		 * in_pcbladdr() may have allocated a route entry for us
		 * on the current CPU, but we need a route entry on the
		 * inpcb's owner CPU, so free it here.
		 */
		if (ro->ro_rt != NULL)
			RTFREE(ro->ro_rt);
		bzero(ro, sizeof(*ro));

		/*
		 * We are moving the protocol processing port the socket
		 * is on, we have to unlink here and re-link on the
		 * target cpu.
		 */
		in_pcbunlink(so->so_pcb, &tcbinfo[mycpu->gd_cpuid]);
		sosetport(so, port);
		msg->connect.nm_reconnect |= NMSG_RECONNECT_RECONNECT;
		msg->connect.base.nm_dispatch = tcp_connect;

		lwkt_forwardmsg(port, &msg->connect.base.lmsg);
		/* msg invalid now */
		return;
	}
#else
	KKASSERT(so->so_port == &curthread->td_msgport);
#endif
	error = tcp_connect_oncpu(tp, msg->connect.nm_flags,
				  msg->connect.nm_m, sin, if_sin);
	msg->connect.nm_m = NULL;
out:
	if (msg->connect.nm_m) {
		m_freem(msg->connect.nm_m);
		msg->connect.nm_m = NULL;
	}
	if (msg->connect.nm_reconnect & NMSG_RECONNECT_NAMALLOC) {
		kfree(msg->connect.nm_nam, M_LWKTMSG);
		msg->connect.nm_nam = NULL;
	}
	lwkt_replymsg(&msg->connect.base.lmsg, error);
	/* msg invalid now */
}
Ejemplo n.º 18
0
/*
 * Prepare to accept connections.
 */
static void
tcp_usr_listen(netmsg_t msg)
{
	struct socket *so = msg->listen.base.nm_so;
	struct thread *td = msg->listen.nm_td;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
	struct netmsg_inswildcard nm;
	lwkt_port_t port0 = netisr_cpuport(0);

	COMMON_START(so, inp, 0);

	if (&curthread->td_msgport != port0) {
		lwkt_msg_t lmsg = &msg->listen.base.lmsg;

		KASSERT((msg->listen.nm_flags & PRUL_RELINK) == 0,
		    ("already asked to relink"));

		in_pcbunlink(so->so_pcb, &tcbinfo[mycpuid]);
		msg->listen.nm_flags |= PRUL_RELINK;

		/* See the related comment in tcp_connect() */
		lwkt_setmsg_receipt(lmsg, tcp_sosetport);
		lwkt_forwardmsg(port0, lmsg);
		/* msg invalid now */
		return;
	}
	KASSERT(so->so_port == port0, ("so_port is not netisr0"));

	if (msg->listen.nm_flags & PRUL_RELINK) {
		msg->listen.nm_flags &= ~PRUL_RELINK;
		in_pcblink(so->so_pcb, &tcbinfo[mycpuid]);
	}
	KASSERT(inp->inp_pcbinfo == &tcbinfo[0], ("pcbinfo is not tcbinfo0"));

	if (tp->t_flags & TF_LISTEN)
		goto out;

	if (inp->inp_lport == 0) {
		error = in_pcbbind(inp, NULL, td);
		if (error)
			goto out;
	}

	tp->t_state = TCPS_LISTEN;
	tp->t_flags |= TF_LISTEN;
	tp->tt_msg = NULL; /* Catch any invalid timer usage */

	if (ncpus2 > 1) {
		/*
		 * Put this inpcb into wildcard hash on other cpus.
		 */
		ASSERT_INP_NOTINHASH(inp);
		netmsg_init(&nm.base, NULL, &curthread->td_msgport,
			    MSGF_PRIORITY, in_pcbinswildcardhash_handler);
		nm.nm_inp = inp;
		lwkt_domsg(netisr_cpuport(1), &nm.base.lmsg, 0);
	}
	in_pcbinswildcardhash(inp);
	COMMON_END(PRU_LISTEN);
}