/* 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); }
/* * 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 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); }
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); }
/* * 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); }
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); } } }