示例#1
0
static void
tcp6_usr_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;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
	struct sockaddr_in6 *sin6p;

	COMMON_START(so, inp, 0);

	/*
	 * Must disallow TCP ``connections'' to multicast addresses.
	 */
	sin6p = (struct sockaddr_in6 *)nam;
	if (sin6p->sin6_family == AF_INET6
	    && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
		error = EAFNOSUPPORT;
		goto out;
	}

	if (!prison_remote_ip(td, nam)) {
		error = EAFNOSUPPORT; /* IPv4 only jail */
		goto out;
	}

	if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
		struct sockaddr_in *sinp;

		if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) {
			error = EINVAL;
			goto out;
		}
		sinp = kmalloc(sizeof(*sinp), M_LWKTMSG, M_INTWAIT);
		in6_sin6_2_sin(sinp, sin6p);
		inp->inp_vflag |= INP_IPV4;
		inp->inp_vflag &= ~INP_IPV6;
		msg->connect.nm_nam = (struct sockaddr *)sinp;
		msg->connect.nm_reconnect |= NMSG_RECONNECT_NAMALLOC;
		tcp_connect(msg);
		/* msg is invalid now */
		return;
	}
	inp->inp_vflag &= ~INP_IPV4;
	inp->inp_vflag |= INP_IPV6;
	inp->inp_inc.inc_isipv6 = 1;

	msg->connect.nm_reconnect |= NMSG_RECONNECT_FALLBACK;
	tcp6_connect(msg);
	/* msg is invalid now */
	return;
out:
	if (msg->connect.nm_m) {
		m_freem(msg->connect.nm_m);
		msg->connect.nm_m = NULL;
	}
	lwkt_replymsg(&msg->lmsg, error);
}
示例#2
0
/*
 * Receive out-of-band data.
 */
static void
tcp_usr_rcvoob(netmsg_t msg)
{
	struct socket *so = msg->rcvoob.base.nm_so;
	struct mbuf *m = msg->rcvoob.nm_m;
	int flags = msg->rcvoob.nm_flags;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;

	COMMON_START(so, inp, 0);
	if ((so->so_oobmark == 0 &&
	     (so->so_state & SS_RCVATMARK) == 0) ||
	    so->so_options & SO_OOBINLINE ||
	    tp->t_oobflags & TCPOOB_HADDATA) {
		error = EINVAL;
		goto out;
	}
	if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
		error = EWOULDBLOCK;
		goto out;
	}
	m->m_len = 1;
	*mtod(m, caddr_t) = tp->t_iobc;
	if ((flags & MSG_PEEK) == 0)
		tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
	COMMON_END(PRU_RCVOOB);
}
示例#3
0
/*
 * Give the socket an address.
 */
static int
tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;
	struct sockaddr_in *sinp;

	COMMON_START();

	/*
	 * Must check for multicast addresses and disallow binding
	 * to them.
	 */
	sinp = (struct sockaddr_in *)nam;
	if (sinp->sin_family == AF_INET &&
	    IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
		error = EAFNOSUPPORT;
		goto out;
	}
	error = in_pcbbind(inp, nam, p);
	if (error)
		goto out;
	COMMON_END(PRU_BIND);

}
示例#4
0
/*
 * Initiate connection to peer.
 * Create a template for use in transmissions on this connection.
 * Enter SYN_SENT state, and mark socket as connecting.
 * Start keep-alive timer, and seed output sequence space.
 * Send initial segment on connection.
 */
static int
tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;
	struct sockaddr_in *sinp;

	COMMON_START();

	/*
	 * Must disallow TCP ``connections'' to multicast addresses.
	 */
	sinp = (struct sockaddr_in *)nam;
	if (sinp->sin_family == AF_INET
	    && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
		error = EAFNOSUPPORT;
		goto out;
	}


	if ((error = tcp_connect(tp, nam, p)) != 0)
		goto out;
	error = tcp_output(tp);
	COMMON_END(PRU_CONNECT);
}
示例#5
0
/*
 * Give the socket an address.
 */
static void
tcp_usr_bind(netmsg_t msg)
{
	struct socket *so = msg->bind.base.nm_so;
	struct sockaddr *nam = msg->bind.nm_nam;
	struct thread *td = msg->bind.nm_td;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
	struct sockaddr_in *sinp;

	COMMON_START(so, inp, 0);

	/*
	 * Must check for multicast addresses and disallow binding
	 * to them.
	 */
	sinp = (struct sockaddr_in *)nam;
	if (sinp->sin_family == AF_INET &&
	    IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
		error = EAFNOSUPPORT;
		goto out;
	}
	error = in_pcbbind(inp, nam, td);
	if (error)
		goto out;
	COMMON_END(PRU_BIND);

}
示例#6
0
/*
 * Receive out-of-band data.
 */
static int
tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;

	COMMON_START();
	if ((so->so_oobmark == 0 &&
	     (so->so_state & SS_RCVATMARK) == 0) ||
	    so->so_options & SO_OOBINLINE ||
	    tp->t_oobflags & TCPOOB_HADDATA) {
		error = EINVAL;
		goto out;
	}
	if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
		error = EWOULDBLOCK;
		goto out;
	}
	m->m_len = 1;
	*mtod(m, caddr_t) = tp->t_iobc;
	if ((flags & MSG_PEEK) == 0)
		tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
	COMMON_END(PRU_RCVOOB);
}
示例#7
0
static void
tcp6_usr_listen(netmsg_t msg)
{
	struct socket *so = msg->listen.base.nm_so;
	struct thread *td = msg->listen.nm_td;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
#ifdef SMP
	struct netmsg_inswildcard nm;
#endif

	COMMON_START(so, inp, 0);

	if (tp->t_flags & TF_LISTEN)
		goto out;

	if (inp->inp_lport == 0) {
		if (!(inp->inp_flags & IN6P_IPV6_V6ONLY))
			inp->inp_vflag |= INP_IPV4;
		else
			inp->inp_vflag &= ~INP_IPV4;
		error = in6_pcbbind(inp, NULL, td);
		if (error)
			goto out;
	}

	tp->t_state = TCPS_LISTEN;
	tp->t_flags |= TF_LISTEN;
	tp->tt_msg = NULL; /* Catch any invalid timer usage */

#ifdef SMP
	if (ncpus > 1) {
		/*
		 * We have to set the flag because we can't have other cpus
		 * messing with our inp's flags.
		 */
		KASSERT(!(inp->inp_flags & INP_CONNECTED),
			("already on connhash\n"));
		KASSERT(!(inp->inp_flags & INP_WILDCARD),
			("already on wildcardhash\n"));
		KASSERT(!(inp->inp_flags & INP_WILDCARD_MP),
			("already on MP wildcardhash\n"));
		inp->inp_flags |= INP_WILDCARD_MP;

		KKASSERT(so->so_port == cpu_portfn(0));
		KKASSERT(&curthread->td_msgport == cpu_portfn(0));
		KKASSERT(inp->inp_pcbinfo == &tcbinfo[0]);

		netmsg_init(&nm.base, NULL, &curthread->td_msgport,
			    MSGF_PRIORITY, in_pcbinswildcardhash_handler);
		nm.nm_inp = inp;
		lwkt_domsg(cpu_portfn(1), &nm.base.lmsg, 0);
	}
#endif
	in_pcbinswildcardhash(inp);
	COMMON_END(PRU_LISTEN);
}
示例#8
0
/*
 * After a receive, possibly send window update to peer.
 */
static void
tcp_usr_rcvd(netmsg_t msg)
{
	struct socket *so = msg->rcvd.base.nm_so;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;

	COMMON_START(so, inp, 0);
	tcp_output(tp);
	COMMON_END(PRU_RCVD);
}
示例#9
0
/*
 * After a receive, possibly send window update to peer.
 */
static int
tcp_usr_rcvd(struct socket *so, int flags)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;

	COMMON_START();
	tcp_output(tp);
	COMMON_END(PRU_RCVD);
}
示例#10
0
/*
 * Initiate disconnect from peer.
 * If connection never passed embryonic stage, just drop;
 * else if don't need to let data drain, then can just drop anyways,
 * else have to begin TCP shutdown process: mark socket disconnecting,
 * drain unread data, state switch to reflect user close, and
 * send segment (e.g. FIN) to peer.  Socket will be really disconnected
 * when peer sends FIN and acks ours.
 *
 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
 */
static int
tcp_usr_disconnect(struct socket *so)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;

	COMMON_START();
	tp = tcp_disconnect(tp);
	COMMON_END(PRU_DISCONNECT);
}
示例#11
0
/*
 * Initiate disconnect from peer.
 * If connection never passed embryonic stage, just drop;
 * else if don't need to let data drain, then can just drop anyways,
 * else have to begin TCP shutdown process: mark socket disconnecting,
 * drain unread data, state switch to reflect user close, and
 * send segment (e.g. FIN) to peer.  Socket will be really disconnected
 * when peer sends FIN and acks ours.
 *
 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
 */
static void
tcp_usr_disconnect(netmsg_t msg)
{
	struct socket *so = msg->disconnect.base.nm_so;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;

	COMMON_START(so, inp, 1);
	tp = tcp_disconnect(tp);
	COMMON_END(PRU_DISCONNECT);
}
示例#12
0
/*
 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
 *	 will sofree() it when we return.
 */
static void
tcp_usr_abort(netmsg_t msg)
{
	struct socket *so = msg->abort.base.nm_so;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;

	COMMON_START(so, inp, 1);
	tp = tcp_drop(tp, ECONNABORTED);
	COMMON_END(PRU_ABORT);
}
示例#13
0
/*
 * Abort the TCP.
 */
static int
tcp_usr_abort(struct socket *so)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;

	COMMON_START();
	tp = tcp_drop(tp, ECONNABORTED);
	COMMON_END(PRU_ABORT);
}
示例#14
0
/*
 * Prepare to accept connections.
 */
static int
tcp_usr_listen(struct socket *so, struct proc *p)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;

	COMMON_START();
	if (inp->inp_lport == 0)
		error = in_pcbbind(inp, (struct sockaddr *)0, p);
	if (error == 0)
		tp->t_state = TCPS_LISTEN;
	COMMON_END(PRU_LISTEN);
}
示例#15
0
/*
 * Mark the connection as being incapable of further output.
 */
static void
tcp_usr_shutdown(netmsg_t msg)
{
	struct socket *so = msg->shutdown.base.nm_so;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;

	COMMON_START(so, inp, 0);
	socantsendmore(so);
	tp = tcp_usrclosed(tp);
	if (tp)
		error = tcp_output(tp);
	COMMON_END(PRU_SHUTDOWN);
}
示例#16
0
/*
 * Mark the connection as being incapable of further output.
 */
static int
tcp_usr_shutdown(struct socket *so)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;

	COMMON_START();
	socantsendmore(so);
	tp = tcp_usrclosed(tp);
	if (tp)
		error = tcp_output(tp);
	COMMON_END(PRU_SHUTDOWN);
}
示例#17
0
static void
tcp6_usr_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;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
	struct sockaddr_in6 *sin6p;

	COMMON_START(so, inp, 0);

	/*
	 * Must disallow TCP ``connections'' to multicast addresses.
	 */
	sin6p = (struct sockaddr_in6 *)nam;
	if (sin6p->sin6_family == AF_INET6
	    && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
		error = EAFNOSUPPORT;
		goto out;
	}

	if (!prison_remote_ip(td, nam)) {
		error = EAFNOSUPPORT; /* IPv4 only jail */
		goto out;
	}

	/* Reject v4-mapped address */
	if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
		error = EADDRNOTAVAIL;
		goto out;
	}

	inp->inp_inc.inc_isipv6 = 1;
	tcp6_connect(msg);
	/* msg is invalid now */
	return;
out:
	if (msg->connect.nm_m) {
		m_freem(msg->connect.nm_m);
		msg->connect.nm_m = NULL;
	}
	lwkt_replymsg(&msg->lmsg, error);
}
示例#18
0
/*
 * After a receive, possibly send window update to peer.
 */
static void
tcp_usr_rcvd(netmsg_t msg)
{
	struct socket *so = msg->rcvd.base.nm_so;
	int error = 0, noreply = 0;
	struct inpcb *inp;
	struct tcpcb *tp;

	COMMON_START(so, inp, 0);

	if (msg->rcvd.nm_pru_flags & PRUR_ASYNC) {
		noreply = 1;
		so_async_rcvd_reply(so);
	}
	tcp_output(tp);

	COMMON_END1(PRU_RCVD, noreply);
}
示例#19
0
/*
 * Initiate connection to peer.
 * Create a template for use in transmissions on this connection.
 * Enter SYN_SENT state, and mark socket as connecting.
 * Start keep-alive timer, and seed output sequence space.
 * Send initial segment on connection.
 */
static void
tcp_usr_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;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
	struct sockaddr_in *sinp;

	COMMON_START(so, inp, 0);

	/*
	 * Must disallow TCP ``connections'' to multicast addresses.
	 */
	sinp = (struct sockaddr_in *)nam;
	if (sinp->sin_family == AF_INET
	    && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
		error = EAFNOSUPPORT;
		goto out;
	}

	if (!prison_remote_ip(td, (struct sockaddr*)sinp)) {
		error = EAFNOSUPPORT; /* IPv6 only jail */
		goto out;
	}

	tcp_connect(msg);
	/* msg is invalid now */
	return;
out:
	if (msg->connect.nm_m) {
		m_freem(msg->connect.nm_m);
		msg->connect.nm_m = NULL;
	}
	if (msg->connect.nm_flags & PRUC_HELDTD)
		lwkt_rele(td);
	if (error && (msg->connect.nm_flags & PRUC_ASYNC)) {
		so->so_error = error;
		soisdisconnected(so);
	}
	lwkt_replymsg(&msg->lmsg, error);
}
示例#20
0
static int
tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;
	struct sockaddr_in6 *sin6p;

	COMMON_START();

	/*
	 * Must disallow TCP ``connections'' to multicast addresses.
	 */
	sin6p = (struct sockaddr_in6 *)nam;
	if (sin6p->sin6_family == AF_INET6
	    && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
		error = EAFNOSUPPORT;
		goto out;
	}

	if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
		struct sockaddr_in sin;

		if (!ip6_mapped_addr_on ||
		    (inp->inp_flags & IN6P_IPV6_V6ONLY))
			return(EINVAL);

		in6_sin6_2_sin(&sin, sin6p);
		inp->inp_vflag |= INP_IPV4;
		inp->inp_vflag &= ~INP_IPV6;
		if ((error = tcp_connect(tp, (struct sockaddr *)&sin, p)) != 0)
			goto out;
		error = tcp_output(tp);
		goto out;
	}
	inp->inp_vflag &= ~INP_IPV4;
	inp->inp_vflag |= INP_IPV6;
	if ((error = tcp6_connect(tp, nam, p)) != 0)
		goto out;
	error = tcp_output(tp);
	COMMON_END(PRU_CONNECT);
}
示例#21
0
static void
tcp6_usr_bind(netmsg_t msg)
{
	struct socket *so = msg->bind.base.nm_so;
	struct sockaddr *nam = msg->bind.nm_nam;
	struct thread *td = msg->bind.nm_td;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
	struct sockaddr_in6 *sin6p;

	COMMON_START(so, inp, 0);

	/*
	 * Must check for multicast addresses and disallow binding
	 * to them.
	 */
	sin6p = (struct sockaddr_in6 *)nam;
	if (sin6p->sin6_family == AF_INET6 &&
	    IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
		error = EAFNOSUPPORT;
		goto out;
	}
	inp->inp_vflag &= ~INP_IPV4;
	inp->inp_vflag |= INP_IPV6;
	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
		if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr))
			inp->inp_vflag |= INP_IPV4;
		else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
			struct sockaddr_in sin;

			in6_sin6_2_sin(&sin, sin6p);
			inp->inp_vflag |= INP_IPV4;
			inp->inp_vflag &= ~INP_IPV6;
			error = in_pcbbind(inp, (struct sockaddr *)&sin, td);
			goto out;
		}
	}
	error = in6_pcbbind(inp, nam, td);
	if (error)
		goto out;
	COMMON_END(PRU_BIND);
}
示例#22
0
static void
tcp6_usr_listen(netmsg_t msg)
{
	struct socket *so = msg->listen.base.nm_so;
	struct thread *td = msg->listen.nm_td;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
	struct netmsg_inswildcard nm;

	COMMON_START(so, inp, 0);

	if (tp->t_flags & TF_LISTEN)
		goto out;

	if (inp->inp_lport == 0) {
		error = in6_pcbbind(inp, NULL, td);
		if (error)
			goto out;
	}

	tp->t_state = TCPS_LISTEN;
	tp->t_flags |= TF_LISTEN;
	tp->tt_msg = NULL; /* Catch any invalid timer usage */

	if (ncpus2 > 1) {
		/*
		 * Put this inpcb into wildcard hash on other cpus.
		 */
		KKASSERT(so->so_port == netisr_cpuport(0));
		ASSERT_IN_NETISR(0);
		KKASSERT(inp->inp_pcbinfo == &tcbinfo[0]);
		ASSERT_INP_NOTINHASH(inp);

		netmsg_init(&nm.base, NULL, &curthread->td_msgport,
			    MSGF_PRIORITY, in_pcbinswildcardhash_handler);
		nm.nm_inp = inp;
		lwkt_domsg(netisr_cpuport(1), &nm.base.lmsg, 0);
	}
	in_pcbinswildcardhash(inp);
	COMMON_END(PRU_LISTEN);
}
示例#23
0
static int
tcp6_usr_listen(struct socket *so, struct proc *p)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;

	COMMON_START();
	if (inp->inp_lport == 0) {
		inp->inp_vflag &= ~INP_IPV4;
		if (ip6_mapped_addr_on &&
		    (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
			inp->inp_vflag |= INP_IPV4;
		error = in6_pcbbind(inp, (struct sockaddr *)0, p);
	}
	if (error == 0)
		tp->t_state = TCPS_LISTEN;
	COMMON_END(PRU_LISTEN);
}
示例#24
0
static int
tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;
	struct sockaddr_in6 *sin6p;

	COMMON_START();

	/*
	 * Must check for multicast addresses and disallow binding
	 * to them.
	 */
	sin6p = (struct sockaddr_in6 *)nam;
	if (sin6p->sin6_family == AF_INET6 &&
	    IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
		error = EAFNOSUPPORT;
		goto out;
	}
	inp->inp_vflag &= ~INP_IPV4;
	inp->inp_vflag |= INP_IPV6;
	if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
		if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr))
			inp->inp_vflag |= INP_IPV4;
		else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
			struct sockaddr_in sin;

			in6_sin6_2_sin(&sin, sin6p);
			inp->inp_vflag |= INP_IPV4;
			inp->inp_vflag &= ~INP_IPV6;
			error = in_pcbbind(inp, (struct sockaddr *)&sin, p);
			goto out;
		}
	}
	error = in6_pcbbind(inp, nam, p);
	if (error)
		goto out;
	COMMON_END(PRU_BIND);
}
示例#25
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 */
}
示例#26
0
/*
 * Prepare to accept connections.
 */
static void
tcp_usr_listen(netmsg_t msg)
{
	struct socket *so = msg->listen.base.nm_so;
	struct thread *td = msg->listen.nm_td;
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp;
	struct netmsg_inswildcard nm;
	lwkt_port_t port0 = netisr_cpuport(0);

	COMMON_START(so, inp, 0);

	if (&curthread->td_msgport != port0) {
		lwkt_msg_t lmsg = &msg->listen.base.lmsg;

		KASSERT((msg->listen.nm_flags & PRUL_RELINK) == 0,
		    ("already asked to relink"));

		in_pcbunlink(so->so_pcb, &tcbinfo[mycpuid]);
		msg->listen.nm_flags |= PRUL_RELINK;

		/* See the related comment in tcp_connect() */
		lwkt_setmsg_receipt(lmsg, tcp_sosetport);
		lwkt_forwardmsg(port0, lmsg);
		/* msg invalid now */
		return;
	}
	KASSERT(so->so_port == port0, ("so_port is not netisr0"));

	if (msg->listen.nm_flags & PRUL_RELINK) {
		msg->listen.nm_flags &= ~PRUL_RELINK;
		in_pcblink(so->so_pcb, &tcbinfo[mycpuid]);
	}
	KASSERT(inp->inp_pcbinfo == &tcbinfo[0], ("pcbinfo is not tcbinfo0"));

	if (tp->t_flags & TF_LISTEN)
		goto out;

	if (inp->inp_lport == 0) {
		error = in_pcbbind(inp, NULL, td);
		if (error)
			goto out;
	}

	tp->t_state = TCPS_LISTEN;
	tp->t_flags |= TF_LISTEN;
	tp->tt_msg = NULL; /* Catch any invalid timer usage */

	if (ncpus2 > 1) {
		/*
		 * Put this inpcb into wildcard hash on other cpus.
		 */
		ASSERT_INP_NOTINHASH(inp);
		netmsg_init(&nm.base, NULL, &curthread->td_msgport,
			    MSGF_PRIORITY, in_pcbinswildcardhash_handler);
		nm.nm_inp = inp;
		lwkt_domsg(netisr_cpuport(1), &nm.base.lmsg, 0);
	}
	in_pcbinswildcardhash(inp);
	COMMON_END(PRU_LISTEN);
}
示例#27
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 */
	}
}