コード例 #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_pcbconnect_setup to do the routing and
 * to choose a local host address (interface).  If there is an existing
 * incarnation of the same connection in TIME-WAIT state and if the remote
 * host was sending CC options and if the connection duration was < MSL, then
 * truncate the previous TIME-WAIT state and proceed.
 * Initialize connection parameters and enter SYN-SENT state.
 */
static int
tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
{
	struct inpcb *inp = tp->t_inpcb, *oinp;
	struct socket *so = inp->inp_socket;
	struct in_addr laddr;
	u_short lport;
	int error;

	INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
	INP_WLOCK_ASSERT(inp);

	if (inp->inp_lport == 0) {
		error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
		if (error)
			return error;
	}

	/*
	 * 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.
	 */
	laddr = inp->inp_laddr;
	lport = inp->inp_lport;
	error = in_pcbconnect_setup(inp, nam, &laddr.s_addr, &lport,
	    &inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, td->td_ucred);
	if (error && oinp == NULL)
		return error;
	if (oinp)
		return EADDRINUSE;
	inp->inp_laddr = laddr;
	in_pcbrehash(inp);

	/*
	 * Compute window scaling to request:
	 * Scale to fit into sweet spot.  See tcp_syncache.c.
	 * XXX: This should move to tcp_output().
	 */
	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
	    (TCP_MAXWIN << tp->request_r_scale) < sb_max)
		tp->request_r_scale++;

	soisconnecting(so);
	TCPSTAT_INC(tcps_connattempt);
	tp->t_state = TCPS_SYN_SENT;
	tcp_timer_activate(tp, TT_KEEP, tcp_keepinit);
	tp->iss = tcp_new_isn(tp);
	tp->t_bw_rtseq = tp->iss;
	tcp_sendseqinit(tp);

	return 0;
}
コード例 #2
0
static int
tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
{
	struct inpcb *inp = tp->t_inpcb, *oinp;
	struct socket *so = inp->inp_socket;
	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
	struct in6_addr addr6;
	int error;

	INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
	INP_WLOCK_ASSERT(inp);

	if (inp->inp_lport == 0) {
		error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
		if (error)
			return error;
	}

	/*
	 * 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.
	 * in6_pcbladdr() also handles scope zone IDs.
	 */
	error = in6_pcbladdr(inp, nam, &addr6);
	if (error)
		return error;
	oinp = in6_pcblookup_hash(inp->inp_pcbinfo,
				  &sin6->sin6_addr, sin6->sin6_port,
				  IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
				  ? &addr6
				  : &inp->in6p_laddr,
				  inp->inp_lport,  0, NULL);
	if (oinp)
		return EADDRINUSE;
	if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
		inp->in6p_laddr = addr6;
	inp->in6p_faddr = sin6->sin6_addr;
	inp->inp_fport = sin6->sin6_port;
	/* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */
	inp->inp_flow &= ~IPV6_FLOWLABEL_MASK;
	if (inp->inp_flags & IN6P_AUTOFLOWLABEL)
		inp->inp_flow |=
		    (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
	in_pcbrehash(inp);

	/* Compute window scaling to request.  */
	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
	    (TCP_MAXWIN << tp->request_r_scale) < sb_max)
		tp->request_r_scale++;

	soisconnecting(so);
	TCPSTAT_INC(tcps_connattempt);
	tp->t_state = TCPS_SYN_SENT;
	tcp_timer_activate(tp, TT_KEEP, tcp_keepinit);
	tp->iss = tcp_new_isn(tp);
	tp->t_bw_rtseq = tp->iss;
	tcp_sendseqinit(tp);

	return 0;
}
コード例 #3
0
static int
tcp_connect_oncpu(struct tcpcb *tp, int flags, struct mbuf *m,
		  struct sockaddr_in *sin, struct sockaddr_in *if_sin)
{
	struct inpcb *inp = tp->t_inpcb, *oinp;
	struct socket *so = inp->inp_socket;
	struct route *ro = &inp->inp_route;

	oinp = in_pcblookup_hash(&tcbinfo[mycpu->gd_cpuid],
				 sin->sin_addr, sin->sin_port,
				 (inp->inp_laddr.s_addr != INADDR_ANY ?
				  inp->inp_laddr : if_sin->sin_addr),
				inp->inp_lport, 0, NULL);
	if (oinp != NULL) {
		m_freem(m);
		return (EADDRINUSE);
	}
	if (inp->inp_laddr.s_addr == INADDR_ANY)
		inp->inp_laddr = if_sin->sin_addr;
	inp->inp_faddr = sin->sin_addr;
	inp->inp_fport = sin->sin_port;
	inp->inp_cpcbinfo = &tcbinfo[mycpu->gd_cpuid];
	in_pcbinsconnhash(inp);

	/*
	 * We are now on the inpcb's owner CPU, if the cached route was
	 * freed because the rtentry's owner CPU is not the current CPU
	 * (e.g. in tcp_connect()), then we try to reallocate it here with
	 * the hope that a rtentry may be cloned from a RTF_PRCLONING
	 * rtentry.
	 */
	if (!(inp->inp_socket->so_options & SO_DONTROUTE) && /*XXX*/
	    ro->ro_rt == NULL) {
		bzero(&ro->ro_dst, sizeof(struct sockaddr_in));
		ro->ro_dst.sa_family = AF_INET;
		ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
		((struct sockaddr_in *)&ro->ro_dst)->sin_addr =
			sin->sin_addr;
		rtalloc(ro);
	}

	/*
	 * Now that no more errors can occur, change the protocol processing
	 * port to the current thread (which is the correct thread).
	 *
	 * Create TCP timer message now; we are on the tcpcb's owner
	 * CPU/thread.
	 */
	tcp_create_timermsg(tp, &curthread->td_msgport);

	/*
	 * Compute window scaling to request.  Use a larger scaling then
	 * needed for the initial receive buffer in case the receive buffer
	 * gets expanded.
	 */
	if (tp->request_r_scale < TCP_MIN_WINSHIFT)
		tp->request_r_scale = TCP_MIN_WINSHIFT;
	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
	       (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.ssb_hiwat
	) {
		tp->request_r_scale++;
	}

	soisconnecting(so);
	tcpstat.tcps_connattempt++;
	tp->t_state = TCPS_SYN_SENT;
	tcp_callout_reset(tp, tp->tt_keep, tcp_keepinit, tcp_timer_keep);
	tp->iss = tcp_new_isn(tp);
	tcp_sendseqinit(tp);
	if (m) {
		ssb_appendstream(&so->so_snd, m);
		m = NULL;
		if (flags & PRUS_OOB)
			tp->snd_up = tp->snd_una + so->so_snd.ssb_cc;
	}

	/*
	 * Close the send side of the connection after
	 * the data is sent if flagged.
	 */
	if ((flags & (PRUS_OOB|PRUS_EOF)) == PRUS_EOF) {
		socantsendmore(so);
		tp = tcp_usrclosed(tp);
	}
	return (tcp_output(tp));
}
コード例 #4
0
static int
tcp6_connect_oncpu(struct tcpcb *tp, int flags, struct mbuf **mp,
		   struct sockaddr_in6 *sin6, struct in6_addr *addr6)
{
	struct mbuf *m = *mp;
	struct inpcb *inp = tp->t_inpcb;
	struct socket *so = inp->inp_socket;
	struct inpcb *oinp;

	/*
	 * 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.
	 */
	oinp = in6_pcblookup_hash(inp->inp_cpcbinfo,
				  &sin6->sin6_addr, sin6->sin6_port,
				  (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) ?
				      addr6 : &inp->in6p_laddr),
				  inp->inp_lport,  0, NULL);
	if (oinp)
		return (EADDRINUSE);

	if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
		inp->in6p_laddr = *addr6;
	inp->in6p_faddr = sin6->sin6_addr;
	inp->inp_fport = sin6->sin6_port;
	if ((sin6->sin6_flowinfo & IPV6_FLOWINFO_MASK) != 0)
		inp->in6p_flowinfo = sin6->sin6_flowinfo;
	in_pcbinsconnhash(inp);

	/*
	 * Now that no more errors can occur, change the protocol processing
	 * port to the current thread (which is the correct thread).
	 *
	 * Create TCP timer message now; we are on the tcpcb's owner
	 * CPU/thread.
	 */
	tcp_create_timermsg(tp, &curthread->td_msgport);

	/* Compute window scaling to request.  */
	if (tp->request_r_scale < TCP_MIN_WINSHIFT)
		tp->request_r_scale = TCP_MIN_WINSHIFT;
	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
	    (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.ssb_hiwat) {
		tp->request_r_scale++;
	}

	soisconnecting(so);
	tcpstat.tcps_connattempt++;
	tp->t_state = TCPS_SYN_SENT;
	tcp_callout_reset(tp, tp->tt_keep, tcp_keepinit, tcp_timer_keep);
	tp->iss = tcp_new_isn(tp);
	tcp_sendseqinit(tp);
	if (m) {
		ssb_appendstream(&so->so_snd, m);
		*mp = NULL;
		if (flags & PRUS_OOB)
			tp->snd_up = tp->snd_una + so->so_snd.ssb_cc;
	}

	/*
	 * Close the send side of the connection after
	 * the data is sent if flagged.
	 */
	if ((flags & (PRUS_OOB|PRUS_EOF)) == PRUS_EOF) {
		socantsendmore(so);
		tp = tcp_usrclosed(tp);
	}
	return (tcp_output(tp));
}