Пример #1
0
/*
  in6_pcblookup_local_and_cleanup does everything
  in6_pcblookup_local does but it checks for a socket
  that's going away. Since we know that the lock is
  held read+write when this function is called, we
  can safely dispose of this socket like the slow
  timer would usually do and return NULL. This is
  great for bind.
*/
static struct inpcb*
in6_pcblookup_local_and_cleanup(
	struct inpcbinfo *pcbinfo,
	struct in6_addr *laddr,
	u_int lport_arg,
	int wild_okay)
{
	struct inpcb *inp;
	
	/* Perform normal lookup */
	inp = in6_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay);
	
	/* Check if we found a match but it's waiting to be disposed */
	if (inp && inp->inp_wantcnt == WNT_STOPUSING) {
		struct socket *so = inp->inp_socket;
		
		lck_mtx_lock(&inp->inpcb_mtx);
		
		if (so->so_usecount == 0) {
			if (inp->inp_state != INPCB_STATE_DEAD)
				in6_pcbdetach(inp);
			in_pcbdispose(inp);
			inp = NULL;
		}
		else {
			lck_mtx_unlock(&inp->inpcb_mtx);
		}
	}
	
	return inp;
}
/*
 * 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);
}
Пример #3
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);
}
Пример #4
0
void
in6_pcbdisconnect(struct in6pcb *in6p)
{
	bzero((void *)&in6p->in6p_faddr, sizeof(in6p->in6p_faddr));
	in6p->in6p_fport = 0;
	in6_pcbstate(in6p, IN6P_BOUND);
	in6p->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
#if defined(IPSEC) || defined(FAST_IPSEC)
	ipsec_pcbdisconn(in6p->in6p_sp);
#endif
	if (in6p->in6p_socket->so_state & SS_NOFDREF)
		in6_pcbdetach(in6p);
}
Пример #5
0
static void
udp6_detach(netmsg_t msg)
{
	struct socket *so = msg->detach.base.nm_so;
	struct inpcb *inp;
	int error;

	inp = so->so_pcb;
	if (inp) {
		in6_pcbdetach(inp);
		error = 0;
	} else {
		error = EINVAL;
	}
	lwkt_replymsg(&msg->detach.base.lmsg, error);
}
Пример #6
0
/*
 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
 *	 will sofree() it when we return.
 */
static void
udp6_abort(netmsg_t msg)
{
	struct socket *so = msg->abort.base.nm_so;
	struct inpcb *inp;
	int error;

	inp = so->so_pcb;
	if (inp) {
		soisdisconnected(so);

		in6_pcbdetach(inp);
		error = 0;
	} else {
		error = EINVAL;
	}
	lwkt_replymsg(&msg->abort.base.lmsg, error);
}
Пример #7
0
void
in6_pcbdisconnect(
	struct inpcb *inp)
{
	if (!lck_rw_try_lock_exclusive(inp->inp_pcbinfo->mtx)) {
		/*lock inversion issue, mostly with udp multicast packets */
		socket_unlock(inp->inp_socket, 0);
		lck_rw_lock_exclusive(inp->inp_pcbinfo->mtx);
		socket_lock(inp->inp_socket, 0);
	}
	bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr));
	inp->inp_fport = 0;
	/* clear flowinfo - draft-itojun-ipv6-flowlabel-api-00 */
	inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
	in_pcbrehash(inp);
	lck_rw_done(inp->inp_pcbinfo->mtx);
	if (inp->inp_socket->so_state & SS_NOFDREF)
		in6_pcbdetach(inp);
}
/*
 * 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;
#ifdef INET6
	int isipv6 = INP_CHECK_SOCKAF(so, AF_INET6) != 0;
#endif

	INP_INFO_WLOCK_ASSERT(&tcbinfo);
	INP_LOCK_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_vflag & 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_vflag & INP_DROPPED) {
			KASSERT(tp == NULL, ("tcp_detach: INP_TIMEWAIT && "
			    "INP_DROPPED && tp != NULL"));
#ifdef INET6
			if (isipv6) {
				in6_pcbdetach(inp);
				in6_pcbfree(inp);
			} else {
#endif
				in_pcbdetach(inp);
				in_pcbfree(inp);
#ifdef INET6
			}
#endif
		} else {
#ifdef INET6
			if (isipv6)
				in6_pcbdetach(inp);
			else
#endif
				in_pcbdetach(inp);
			INP_UNLOCK(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_vflag & INP_DROPPED ||
		    tp->t_state < TCPS_SYN_SENT) {
			tcp_discardcb(tp);
#ifdef INET6
			if (isipv6) {
				in6_pcbdetach(inp);
				in6_pcbfree(inp);
			} else {
#endif
				in_pcbdetach(inp);
				in_pcbfree(inp);
#ifdef INET6
			}
#endif
		} else {
#ifdef INET6
			if (isipv6)
				in6_pcbdetach(inp);
			else
#endif
				in_pcbdetach(inp);
		}
	}
}