/* * 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 */ }
static void tcp6_connect(netmsg_t msg) { struct tcpcb *tp; struct socket *so = msg->connect.base.nm_so; struct sockaddr *nam = msg->connect.nm_nam; struct thread *td = msg->connect.nm_td; struct inpcb *inp; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; struct in6_addr *addr6; #ifdef SMP lwkt_port_t port; #endif int error; 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) { error = in6_pcbbind(inp, NULL, td); if (error) goto out; } /* * 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. */ error = in6_pcbladdr(inp, nam, &addr6, td); if (error) goto out; #ifdef SMP port = tcp6_addrport(); /* XXX hack for now, always cpu0 */ 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)); in_pcbunlink(so->so_pcb, &tcbinfo[mycpu->gd_cpuid]); sosetport(so, port); msg->connect.nm_reconnect |= NMSG_RECONNECT_RECONNECT; msg->connect.base.nm_dispatch = tcp6_connect; lwkt_forwardmsg(port, &msg->connect.base.lmsg); /* msg invalid now */ return; } #endif error = tcp6_connect_oncpu(tp, msg->connect.nm_flags, &msg->connect.nm_m, sin6, addr6); /* nm_m may still be intact */ out: if (error && (msg->connect.nm_reconnect & NMSG_RECONNECT_FALLBACK)) { tcp_connect(msg); /* msg invalid now */ } else { 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 */ } }
static void tcp_sosetport(struct lwkt_msg *msg, lwkt_port_t port) { sosetport(((struct netmsg_base *)msg)->nm_so, port); }