예제 #1
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 */
}
예제 #2
0
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 */
	}
}
예제 #3
0
static void
tcp_sosetport(struct lwkt_msg *msg, lwkt_port_t port)
{
	sosetport(((struct netmsg_base *)msg)->nm_so, port);
}