Example #1
0
/*
 * tcp_detach is called when the socket layer loses its final reference
 * to the socket, be it a file descriptor reference, a reference from TCP,
 * etc.  At this point, there is only one case in which we will keep around
 * inpcb state: time wait.
 *
 * This function can probably be re-absorbed back into tcp_usr_detach() now
 * that there is a single detach path.
 */
static void
tcp_detach(struct socket *so, struct inpcb *inp)
{
	struct tcpcb *tp;

	INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
	INP_WLOCK_ASSERT(inp);

	KASSERT(so->so_pcb == inp, ("tcp_detach: so_pcb != inp"));
	KASSERT(inp->inp_socket == so, ("tcp_detach: inp_socket != so"));

	tp = intotcpcb(inp);

	if (inp->inp_flags & INP_TIMEWAIT) {
		/*
		 * There are two cases to handle: one in which the time wait
		 * state is being discarded (INP_DROPPED), and one in which
		 * this connection will remain in timewait.  In the former,
		 * it is time to discard all state (except tcptw, which has
		 * already been discarded by the timewait close code, which
		 * should be further up the call stack somewhere).  In the
		 * latter case, we detach from the socket, but leave the pcb
		 * present until timewait ends.
		 *
		 * XXXRW: Would it be cleaner to free the tcptw here?
		 */
		if (inp->inp_flags & INP_DROPPED) {
			KASSERT(tp == NULL, ("tcp_detach: INP_TIMEWAIT && "
			    "INP_DROPPED && tp != NULL"));
			in_pcbdetach(inp);
			in_pcbfree(inp);
		} else {
			in_pcbdetach(inp);
			INP_WUNLOCK(inp);
		}
	} else {
		/*
		 * If the connection is not in timewait, we consider two
		 * two conditions: one in which no further processing is
		 * necessary (dropped || embryonic), and one in which TCP is
		 * not yet done, but no longer requires the socket, so the
		 * pcb will persist for the time being.
		 *
		 * XXXRW: Does the second case still occur?
		 */
		if (inp->inp_flags & INP_DROPPED ||
		    tp->t_state < TCPS_SYN_SENT) {
			tcp_discardcb(tp);
			in_pcbdetach(inp);
			in_pcbfree(inp);
		} else
			in_pcbdetach(inp);
	}
}
Example #2
0
/* FUNCTION: tcp_close()
 *
 * Close a TCP control block:
 *   discard all space held by the tcp
 *   discard internet protocol block
 *   wake up any sleepers
 *
 * 
 * PARAM1: struct tcpcb *tp
 *
 * RETURNS: 
 */
struct tcpcb * 
tcp_close(struct tcpcb *tp)
{
   struct tcpiphdr *t;
   struct inpcb *inp = tp->t_inpcb;
   struct socket *so = inp->inp_socket;

   t = tp->seg_next;
   while (t != (struct tcpiphdr *)tp) 
   {
      struct mbuf *m;

      t = (struct tcpiphdr *)t->ti_next;
      m = dtom(t->ti_prev);
      remque(t->ti_prev);
      M_FREEM(m);
   }
   if (tp->t_template)
      TPH_FREE(tp->t_template);
   TCB_FREE(tp);
   inp->inp_ppcb = (char *)NULL;
   soisdisconnected(so);
   in_pcbdetach(inp);
   tcpstat.tcps_closed++;
   return ((struct tcpcb *)NULL);
}
Example #3
0
int
tcp_attach(struct socket * so)
{
   struct tcpcb * tp;
   struct inpcb * inp;
   int   error;

   if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) 
   {
      error = soreserve(so, tcp_sendspace, tcp_recvspace);
      if (error)
         return (error);
   }
   error = in_pcballoc(so, &tcb);
   if (error)
      return (error);
   inp = sotoinpcb(so);
   tp = tcp_newtcpcb(inp);
   if (tp == 0) 
   {
      int   nofd  =  so->so_state   &  SS_NOFDREF; /* XXX */

      so->so_state &= ~SS_NOFDREF;     /* don't free the socket yet */
      in_pcbdetach(inp);
      so->so_state |= nofd;
      return (ENOBUFS);
   }
   tp->t_state = TCPS_CLOSED;
   return (0);
}
/*
 * Attach TCP protocol to socket, allocating
 * internet protocol control block, tcp control block,
 * bufer space, and entering LISTEN state if to accept connections.
 */
static int
tcp_attach(struct socket *so)
{
	struct tcpcb *tp;
	struct inpcb *inp;
	int error;
#ifdef INET6
	int isipv6 = INP_CHECK_SOCKAF(so, AF_INET6) != 0;
#endif

	//printf("tcp_attach: called so->so_snd=0x%lx\n", (long)&so->so_snd);
	//printf("tcp_attach: called so->so_rcv=0x%lx\n", (long)&so->so_rcv);
	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
	//printf("tcp_attach: called 2\n");
		error = soreserve(so, tcp_sendspace, tcp_recvspace);
		if (error)
			return (error);
	}
	//printf("tcp_attach: called 2\n");
	so->so_rcv.sb_flags |= SB_AUTOSIZE;
	so->so_snd.sb_flags |= SB_AUTOSIZE;
	INP_INFO_WLOCK(&tcbinfo);
	error = in_pcballoc(so, &tcbinfo);
	if (error) {
		INP_INFO_WUNLOCK(&tcbinfo);
		return (error);
	}
	inp = sotoinpcb(so);
#ifdef INET6
	if (isipv6) {
		inp->inp_vflag |= INP_IPV6;
		inp->in6p_hops = -1;	/* use kernel default */
	}
	else
#endif
	inp->inp_vflag |= INP_IPV4;
	//printf("tcp_attach: called 5\n");
	tp = tcp_newtcpcb(inp);
	if (tp == NULL) {
#ifdef INET6
		if (isipv6) {
			in6_pcbdetach(inp);
			in6_pcbfree(inp);
		} else {
#endif
			in_pcbdetach(inp);
			in_pcbfree(inp);
#ifdef INET6
		}
#endif
		INP_INFO_WUNLOCK(&tcbinfo);
		return (ENOBUFS);
	}
	tp->t_state = TCPS_CLOSED;
	INP_UNLOCK(inp);
	INP_INFO_WUNLOCK(&tcbinfo);
	//printf("tcp_attach: called 10\n");
	return (0);
}
Example #5
0
void
ip6_pcbdisconnect(struct inpcb *inp)
{
   MEMSET(&inp->ip6_faddr, 0, sizeof(inp->ip6_faddr));
   inp->inp_fport = 0;
   if (inp->inp_socket->so_state & SS_NOFDREF)
      in_pcbdetach (inp);
}
Example #6
0
/*
 * Attach TCP protocol to socket, allocating internet protocol control
 * block, tcp control block, bufer space, and entering LISTEN state
 * if to accept connections.
 */
static int
tcp_attach(struct socket *so, struct pru_attach_info *ai)
{
	struct tcpcb *tp;
	struct inpcb *inp;
	int error;
	int cpu;
#ifdef INET6
	int isipv6 = INP_CHECK_SOCKAF(so, AF_INET6) != 0;
#endif

	if (so->so_snd.ssb_hiwat == 0 || so->so_rcv.ssb_hiwat == 0) {
		lwkt_gettoken(&so->so_rcv.ssb_token);
		error = soreserve(so, tcp_sendspace, tcp_recvspace,
				  ai->sb_rlimit);
		lwkt_reltoken(&so->so_rcv.ssb_token);
		if (error)
			return (error);
	}
	atomic_set_int(&so->so_rcv.ssb_flags, SSB_AUTOSIZE);
	atomic_set_int(&so->so_snd.ssb_flags, SSB_AUTOSIZE);
	cpu = mycpu->gd_cpuid;

	/*
	 * Set the default port for protocol processing. This will likely
	 * change when we connect.
	 */
	error = in_pcballoc(so, &tcbinfo[cpu]);
	if (error)
		return (error);
	inp = so->so_pcb;
#ifdef INET6
	if (isipv6) {
		inp->inp_vflag |= INP_IPV6;
		inp->in6p_hops = -1;	/* use kernel default */
	}
	else
#endif
	inp->inp_vflag |= INP_IPV4;
	tp = tcp_newtcpcb(inp);
	if (tp == NULL) {
		/*
		 * Make sure the socket is destroyed by the pcbdetach.
		 */
		soreference(so);
#ifdef INET6
		if (isipv6)
			in6_pcbdetach(inp);
		else
#endif
		in_pcbdetach(inp);
		sofree(so);	/* from ref above */
		return (ENOBUFS);
	}
	tp->t_state = TCPS_CLOSED;
	return (0);
}
void
in_pcbdisconnect(struct inpcb *inp)
{

	inp->inp_faddr.s_addr = INADDR_ANY;
	inp->inp_fport = 0;
	in_pcbrehash(inp);
	if (inp->inp_socket->so_state & SS_NOFDREF)
		in_pcbdetach(inp);
}
Example #8
0
static int
udp6_attach(struct socket *so, int proto, 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_attach: inp != NULL"));

	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
		error = soreserve(so, udp_sendspace, udp_recvspace);
		if (error)
			return (error);
	}
	INP_INFO_WLOCK(pcbinfo);
	error = in_pcballoc(so, pcbinfo);
	if (error) {
		INP_INFO_WUNLOCK(pcbinfo);
		return (error);
	}
	inp = (struct inpcb *)so->so_pcb;
	inp->inp_vflag |= INP_IPV6;
	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
		inp->inp_vflag |= INP_IPV4;
	inp->in6p_hops = -1;	/* use kernel default */
	inp->in6p_cksum = -1;	/* just to be sure */
	/*
	 * XXX: ugly!!
	 * IPv4 TTL initialization is necessary for an IPv6 socket as well,
	 * because the socket may be bound to an IPv6 wildcard address,
	 * which may match an IPv4-mapped IPv6 address.
	 */
	inp->inp_ip_ttl = V_ip_defttl;

	error = udp_newudpcb(inp);
	if (error) {
		in_pcbdetach(inp);
		in_pcbfree(inp);
		INP_INFO_WUNLOCK(pcbinfo);
		return (error);
	}
	INP_WUNLOCK(inp);
	INP_INFO_WUNLOCK(pcbinfo);
	return (0);
}
Example #9
0
static void
udp6_detach(struct socket *so)
{
	struct inpcb *inp;
	struct inpcbinfo *pcbinfo;
	struct udpcb *up;

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

	INP_INFO_WLOCK(pcbinfo);
	INP_WLOCK(inp);
	up = intoudpcb(inp);
	KASSERT(up != NULL, ("%s: up == NULL", __func__));
	in_pcbdetach(inp);
	in_pcbfree(inp);
	INP_INFO_WUNLOCK(pcbinfo);
	udp_discardcb(up);
}
Example #10
0
/*
 * Attach TCP protocol to socket, allocating
 * internet protocol control block, tcp control block,
 * bufer space, and entering LISTEN state if to accept connections.
 */
static int
tcp_attach(struct socket *so)
{
	struct tcpcb *tp;
	struct inpcb *inp;
	int error;

	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
		error = soreserve(so, tcp_sendspace, tcp_recvspace);
		if (error)
			return (error);
	}
	so->so_rcv.sb_flags |= SB_AUTOSIZE;
	so->so_snd.sb_flags |= SB_AUTOSIZE;
	INP_INFO_WLOCK(&V_tcbinfo);
	error = in_pcballoc(so, &V_tcbinfo);
	if (error) {
		INP_INFO_WUNLOCK(&V_tcbinfo);
		return (error);
	}
	inp = sotoinpcb(so);
#ifdef INET6
	if (inp->inp_vflag & INP_IPV6PROTO) {
		inp->inp_vflag |= INP_IPV6;
		inp->in6p_hops = -1;	/* use kernel default */
	}
	else
#endif
	inp->inp_vflag |= INP_IPV4;
	tp = tcp_newtcpcb(inp);
	if (tp == NULL) {
		in_pcbdetach(inp);
		in_pcbfree(inp);
		INP_INFO_WUNLOCK(&V_tcbinfo);
		return (ENOBUFS);
	}
	tp->t_state = TCPS_CLOSED;
	INP_WUNLOCK(inp);
	INP_INFO_WUNLOCK(&V_tcbinfo);
	return (0);
}
Example #11
0
static void
udp_detach(struct socket *so)
{
	struct inpcb *inp;
	struct inpcbinfo *pcbinfo;
	struct udpcb *up;

	pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol);
	inp = sotoinpcb(so);
	KASSERT(inp != NULL, ("udp_detach: inp == NULL"));
	KASSERT(inp->inp_faddr.s_addr == INADDR_ANY,
	    ("udp_detach: not disconnected"));
	INP_INFO_WLOCK(pcbinfo);
	INP_WLOCK(inp);
	up = intoudpcb(inp);
	KASSERT(up != NULL, ("%s: up == NULL", __func__));
	inp->inp_ppcb = NULL;
	in_pcbdetach(inp);
	in_pcbfree(inp);
	INP_INFO_WUNLOCK(pcbinfo);
	udp_discardcb(up);
}
Example #12
0
static int
udp_attach(struct socket *so, int proto, 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_attach: inp != NULL"));
	error = soreserve(so, udp_sendspace, udp_recvspace);
	if (error)
		return (error);
	INP_INFO_WLOCK(pcbinfo);
	error = in_pcballoc(so, pcbinfo);
	if (error) {
		INP_INFO_WUNLOCK(pcbinfo);
		return (error);
	}

	inp = sotoinpcb(so);
	inp->inp_vflag |= INP_IPV4;
	inp->inp_ip_ttl = V_ip_defttl;

	error = udp_newudpcb(inp);
	if (error) {
		in_pcbdetach(inp);
		in_pcbfree(inp);
		INP_INFO_WUNLOCK(pcbinfo);
		return (error);
	}

	INP_WUNLOCK(inp);
	INP_INFO_WUNLOCK(pcbinfo);
	return (0);
}