tcp updates to support IPv6.

also a small patch to sys/nfs/nfs_socket.c, as max_hdr size change.

Reviewed by: freebsd-arch, cvs-committers
Obtained from: KAME project
This commit is contained in:
Yoshinobu Inoue 2000-01-09 19:17:30 +00:00
parent 549f978ab6
commit fb59c426ff
21 changed files with 3006 additions and 755 deletions

View File

@ -977,13 +977,14 @@ non_ip: ip = NULL ;
NTOHL(tip->ti_ack);
tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2);
if (tcp->th_flags & TH_ACK) {
tcp_respond(NULL, tip, *m,
tcp_respond(NULL, (void *)ip, tcp, *m,
(tcp_seq)0, ntohl(tcp->th_ack), TH_RST);
} else {
if (tcp->th_flags & TH_SYN)
tip->ti_len++;
tcp_respond(NULL, tip, *m, tip->ti_seq
+ tip->ti_len, (tcp_seq)0, TH_RST|TH_ACK);
tcp_respond(NULL, (void *)ip, tcp, *m,
tip->ti_seq + tip->ti_len,
(tcp_seq)0, TH_RST|TH_ACK);
}
*m = NULL;
break;

View File

@ -40,6 +40,9 @@
typedef u_int32_t tcp_seq;
typedef u_int32_t tcp_cc; /* connection count per rfc1644 */
#define tcp6_seq tcp_seq /* for KAME src sync over BSD*'s */
#define tcp6hdr tcphdr /* for KAME src sync over BSD*'s */
/*
* TCP header.
* Per RFC 793, September, 1981.

View File

@ -35,6 +35,7 @@
*/
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_tcpdebug.h"
#ifndef INET
@ -55,6 +56,10 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#ifdef INET6
#include <netinet6/ip6.h>
#endif
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
@ -74,16 +79,23 @@ static int tcp_debx;
* Tcp debug routines
*/
void
tcp_trace(act, ostate, tp, ti, req)
tcp_trace(act, ostate, tp, ipgen, th, req)
short act, ostate;
struct tcpcb *tp;
struct tcpiphdr *ti;
void *ipgen;
struct tcphdr *th;
int req;
{
#ifdef INET6
int isipv6;
#endif /* INET6 */
tcp_seq seq, ack;
int len, flags;
struct tcp_debug *td = &tcp_debug[tcp_debx++];
#ifdef INET6
isipv6 = (ipgen != NULL && ((struct ip *)ipgen)->ip_v == 6) ? 1 : 0;
#endif /* INET6 */
if (tcp_debx == TCP_NDEBUG)
tcp_debx = 0;
td->td_time = iptime();
@ -94,10 +106,18 @@ tcp_trace(act, ostate, tp, ti, req)
td->td_cb = *tp;
else
bzero((caddr_t)&td->td_cb, sizeof (*tp));
if (ti)
td->td_ti = *ti;
if (ipgen)
bcopy((caddr_t)ipgen, td->td_ipgen,
#ifdef INET6
isipv6 ? sizeof(struct ip6_hdr) :
#endif
sizeof(struct ip));
else
bzero((caddr_t)&td->td_ti, sizeof (*ti));
bzero((caddr_t)td->td_ipgen, sizeof (td->td_ipgen));
if (th)
td->td_th = *th;
else
bzero((caddr_t)&td->td_th, sizeof (td->td_th));
td->td_req = req;
#ifdef TCPDEBUG
if (tcpconsdebug == 0)
@ -112,11 +132,15 @@ tcp_trace(act, ostate, tp, ti, req)
case TA_INPUT:
case TA_OUTPUT:
case TA_DROP:
if (ti == 0)
if (ipgen == NULL || th == NULL)
break;
seq = ti->ti_seq;
ack = ti->ti_ack;
len = ti->ti_len;
seq = th->th_seq;
ack = th->th_ack;
len =
#ifdef INET6
isipv6 ? ((struct ip6_hdr *)ipgen)->ip6_plen :
#endif
((struct ip *)ipgen)->ip_len;
if (act == TA_OUTPUT) {
seq = ntohl(seq);
ack = ntohl(ack);
@ -128,12 +152,12 @@ tcp_trace(act, ostate, tp, ti, req)
printf("[%x..%x)", seq, seq+len);
else
printf("%x", seq);
printf("@%x, urp=%x", ack, ti->ti_urp);
flags = ti->ti_flags;
printf("@%x, urp=%x", ack, th->th_urp);
flags = th->th_flags;
if (flags) {
char *cp = "<";
#define pf(f) { \
if (ti->ti_flags & TH_##f) { \
if (th->th_flags & TH_##f) { \
printf("%s%s", cp, #f); \
cp = ","; \
} \

View File

@ -42,7 +42,8 @@ struct tcp_debug {
short td_act;
short td_ostate;
caddr_t td_tcb;
struct tcpiphdr td_ti;
u_char td_ipgen[40]; /* the size must be of max ip header, now IPv6 */
struct tcphdr td_th;
short td_req;
struct tcpcb td_cb;
};

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@
* $FreeBSD$
*/
#include "opt_inet6.h"
#include "opt_tcpdebug.h"
#include <stddef.h>
@ -52,8 +53,17 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#ifdef INET6
#include <netinet/ip6.h>
#endif
#include <netinet/in_pcb.h>
#ifdef INET6
#include <netinet6/in6_pcb.h>
#endif
#include <netinet/ip_var.h>
#ifdef INET6
#include <netinet6/ip6_var.h>
#endif
#include <netinet/tcp.h>
#define TCPOUTFLAGS
#include <netinet/tcp_fsm.h>
@ -92,12 +102,24 @@ tcp_output(tp)
register long len, win;
int off, flags, error;
register struct mbuf *m;
register struct tcpiphdr *ti;
struct ip *ip = NULL;
register struct ipovly *ipov = NULL;
#ifdef INET6
struct ip6_hdr *ip6 = NULL;
#endif /* INET6 */
register struct tcphdr *th;
u_char opt[TCP_MAXOLEN];
unsigned ipoptlen, optlen, hdrlen;
int idle, sendalot;
struct rmxp_tao *taop;
struct rmxp_tao tao_noncached;
#ifdef INET6
int isipv6;
#endif
#ifdef INET6
isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0;
#endif
/*
* Determine length of data that should be transmitted,
@ -115,7 +137,16 @@ tcp_output(tp)
* Set the slow-start flight size depending on whether
* this is a local network or not.
*/
if (in_localaddr(tp->t_inpcb->inp_faddr))
if (
#ifdef INET6
(isipv6 && in6_localaddr(&tp->t_inpcb->in6p_faddr)) ||
(!isipv6 &&
#endif
in_localaddr(tp->t_inpcb->inp_faddr)
#ifdef INET6
)
#endif
)
tp->snd_cwnd = tp->t_maxseg * ss_fltsz_local;
else
tp->snd_cwnd = tp->t_maxseg * ss_fltsz;
@ -340,6 +371,11 @@ tcp_output(tp)
* max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN
*/
optlen = 0;
#ifdef INET6
if (isipv6)
hdrlen = sizeof (struct ip6_hdr) + sizeof (struct tcphdr);
else
#endif
hdrlen = sizeof (struct tcpiphdr);
if (flags & TH_SYN) {
tp->snd_nxt = tp->iss;
@ -456,12 +492,22 @@ tcp_output(tp)
hdrlen += optlen;
#ifdef INET6
if (isipv6)
ipoptlen = ip6_optlen(tp->t_inpcb);
else
#endif
{
if (tp->t_inpcb->inp_options) {
ipoptlen = tp->t_inpcb->inp_options->m_len -
offsetof(struct ipoption, ipopt_list);
} else {
ipoptlen = 0;
}
}
#ifdef IPSEC
ipoptlen += ipsec_hdrsiz_tcp(tp);
#endif
/*
* Adjust data length if insertion of options will
@ -515,6 +561,12 @@ tcp_output(tp)
error = ENOBUFS;
goto out;
}
#ifdef INET6
if (isipv6 && (MHLEN < hdrlen + max_linkhdr) &&
MHLEN >= hdrlen) {
MH_ALIGN(m, hdrlen);
} else
#endif
m->m_data += max_linkhdr;
m->m_len = hdrlen;
if (len <= MHLEN - hdrlen - max_linkhdr) {
@ -553,14 +605,37 @@ tcp_output(tp)
error = ENOBUFS;
goto out;
}
#ifdef INET6
if (isipv6 && (MHLEN < hdrlen + max_linkhdr) &&
MHLEN >= hdrlen) {
MH_ALIGN(m, hdrlen);
} else
#endif
m->m_data += max_linkhdr;
m->m_len = hdrlen;
}
m->m_pkthdr.rcvif = (struct ifnet *)0;
ti = mtod(m, struct tcpiphdr *);
if (tp->t_template == 0)
panic("tcp_output");
(void)memcpy(ti, tp->t_template, sizeof (struct tcpiphdr));
#ifdef INET6
if (isipv6) {
ip6 = mtod(m, struct ip6_hdr *);
th = (struct tcphdr *)(ip6 + 1);
bcopy((caddr_t)tp->t_template->tt_ipgen, (caddr_t)ip6,
sizeof(struct ip6_hdr));
bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th,
sizeof(struct tcphdr));
} else
#endif /* INET6 */
{
ip = mtod(m, struct ip *);
ipov = (struct ipovly *)ip;
th = (struct tcphdr *)(ip + 1);
bcopy((caddr_t)tp->t_template->tt_ipgen, (caddr_t)ip,
sizeof(struct ip));
bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th,
sizeof(struct tcphdr));
}
/*
* Fill in fields, remembering maximum advertised
@ -585,15 +660,15 @@ tcp_output(tp)
*/
if (len || (flags & (TH_SYN|TH_FIN))
|| callout_active(tp->tt_persist))
ti->ti_seq = htonl(tp->snd_nxt);
th->th_seq = htonl(tp->snd_nxt);
else
ti->ti_seq = htonl(tp->snd_max);
ti->ti_ack = htonl(tp->rcv_nxt);
th->th_seq = htonl(tp->snd_max);
th->th_ack = htonl(tp->rcv_nxt);
if (optlen) {
bcopy(opt, ti + 1, optlen);
ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2;
bcopy(opt, th + 1, optlen);
th->th_off = (sizeof (struct tcphdr) + optlen) >> 2;
}
ti->ti_flags = flags;
th->th_flags = flags;
/*
* Calculate receive window. Don't shrink window,
* but avoid silly window syndrome.
@ -604,10 +679,10 @@ tcp_output(tp)
win = (long)(tp->rcv_adv - tp->rcv_nxt);
if (win > (long)TCP_MAXWIN << tp->rcv_scale)
win = (long)TCP_MAXWIN << tp->rcv_scale;
ti->ti_win = htons((u_short) (win>>tp->rcv_scale));
th->th_win = htons((u_short) (win>>tp->rcv_scale));
if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
ti->ti_urp = htons((u_short)(tp->snd_up - tp->snd_nxt));
ti->ti_flags |= TH_URG;
th->th_urp = htons((u_short)(tp->snd_up - tp->snd_nxt));
th->th_flags |= TH_URG;
} else
/*
* If no urgent pointer to send, then we pull
@ -621,10 +696,28 @@ tcp_output(tp)
* Put TCP length in extended header, and then
* checksum extended header and data.
*/
m->m_pkthdr.len = hdrlen + len; /* in6_cksum() need this */
#ifdef INET6
if (isipv6)
/*
* ip6_plen is not need to be filled now, and will be filled
* in ip6_output.
*/
th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr),
sizeof(struct tcphdr) + optlen + len);
else
#endif /* INET6 */
{
if (len + optlen)
ti->ti_len = htons((u_short)(sizeof (struct tcphdr) +
ipov->ih_len = htons((u_short)(sizeof (struct tcphdr) +
optlen + len));
ti->ti_sum = in_cksum(m, (int)(hdrlen + len));
th->th_sum = in_cksum(m, (int)(hdrlen + len));
#ifdef INET6
/* Re-initialization for later version check */
ip->ip_v = IPVERSION;
#endif /* INET6 */
}
/*
* In transmit state, time the transmission and arrange for
@ -684,7 +777,7 @@ tcp_output(tp)
* Trace.
*/
if (so->so_options & SO_DEBUG)
tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0);
tcp_trace(TA_OUTPUT, tp->t_state, tp, mtod(m, void *), th, 0);
#endif
/*
@ -693,12 +786,39 @@ tcp_output(tp)
* to handle ttl and tos; we could keep them in
* the template, but need a way to checksum without them.
*/
m->m_pkthdr.len = hdrlen + len;
/*
* m->m_pkthdr.len should have been set before cksum calcuration,
* because in6_cksum() need it.
*/
#ifdef INET6
if (isipv6) {
/*
* we separately set hoplimit for every segment, since the
* user might want to change the value via setsockopt.
* Also, desired default hop limit might be changed via
* Neighbor Discovery.
*/
ip6->ip6_hlim = in6_selecthlim(tp->t_inpcb,
tp->t_inpcb->in6p_route.ro_rt ?
tp->t_inpcb->in6p_route.ro_rt->rt_ifp
: NULL);
/* TODO: IPv6 IP6TOS_ECT bit on */
#ifdef IPSEC
m->m_pkthdr.rcvif = (struct ifnet *)so;
#endif /*IPSEC*/
error = ip6_output(m,
tp->t_inpcb->in6p_outputopts,
&tp->t_inpcb->in6p_route,
(so->so_options & SO_DONTROUTE)|IPV6_SOCKINMRCVIF,
NULL, NULL);
} else
#endif /* INET6 */
{
struct rtentry *rt;
((struct ip *)ti)->ip_len = m->m_pkthdr.len;
((struct ip *)ti)->ip_ttl = tp->t_inpcb->inp_ip_ttl; /* XXX */
((struct ip *)ti)->ip_tos = tp->t_inpcb->inp_ip_tos; /* XXX */
ip->ip_len = m->m_pkthdr.len;
ip->ip_ttl = tp->t_inpcb->inp_ip_ttl; /* XXX */
ip->ip_tos = tp->t_inpcb->inp_ip_tos; /* XXX */
/*
* See if we should do MTU discovery. We do it only if the following
* are true:
@ -710,10 +830,10 @@ tcp_output(tp)
&& (rt = tp->t_inpcb->inp_route.ro_rt)
&& rt->rt_flags & RTF_UP
&& !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
((struct ip *)ti)->ip_off |= IP_DF;
ip->ip_off |= IP_DF;
}
error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
so->so_options & SO_DONTROUTE, 0);
(so->so_options & SO_DONTROUTE)|IP_SOCKINMRCVIF, 0);
}
if (error) {
out:

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,9 @@
#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#ifdef INET6
#include <sys/domain.h>
#endif
#include <sys/proc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
@ -59,18 +62,35 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#ifdef INET6
#include <netinet/ip6.h>
#endif
#include <netinet/in_pcb.h>
#ifdef INET6
#include <netinet6/in6_pcb.h>
#endif
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
#ifdef INET6
#include <netinet6/ip6_var.h>
#endif
#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#ifdef INET6
#include <netinet6/tcp6_var.h>
#endif
#include <netinet/tcpip.h>
#ifdef TCPDEBUG
#include <netinet/tcp_debug.h>
#endif
#include <netinet6/ip6protosw.h>
#ifdef IPSEC
#include <netinet6/ipsec.h>
#endif /*IPSEC*/
int tcp_mssdflt = TCP_MSS;
SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, CTLFLAG_RW,
@ -79,7 +99,8 @@ SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, CTLFLAG_RW,
#ifdef INET6
int tcp_v6mssdflt = TCP6_MSS;
SYSCTL_INT(_net_inet_tcp, TCPCTL_V6MSSDFLT, v6mssdflt,
CTLFLAG_RW, &tcp_v6mssdflt , 0, "");
CTLFLAG_RW, &tcp_v6mssdflt , 0,
"Default TCP Maximum Segment Size for IPv6");
#endif
#if 0
@ -174,11 +195,16 @@ tcp_init()
&tcbinfo.porthashmask);
tcbinfo.ipi_zone = zinit("tcpcb", sizeof(struct inp_tp), maxsockets,
ZONE_INTERRUPT, 0);
if (max_protohdr < sizeof(struct tcpiphdr))
max_protohdr = sizeof(struct tcpiphdr);
if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN)
#ifdef INET6
#define TCP_MINPROTOHDR (sizeof(struct ip6_hdr) + sizeof(struct tcphdr))
#else /* INET6 */
#define TCP_MINPROTOHDR (sizeof(struct tcpiphdr))
#endif /* INET6 */
if (max_protohdr < TCP_MINPROTOHDR)
max_protohdr = TCP_MINPROTOHDR;
if (max_linkhdr + TCP_MINPROTOHDR > MHLEN)
panic("tcp_init");
#undef TCP_MINPROTOHDR
}
/*
@ -187,36 +213,56 @@ tcp_init()
* in a skeletal tcp/ip header, minimizing the amount of work
* necessary when the connection is used.
*/
struct tcpiphdr *
struct tcptemp *
tcp_template(tp)
struct tcpcb *tp;
{
register struct inpcb *inp = tp->t_inpcb;
register struct mbuf *m;
register struct tcpiphdr *n;
register struct tcptemp *n;
if ((n = tp->t_template) == 0) {
m = m_get(M_DONTWAIT, MT_HEADER);
if (m == NULL)
return (0);
m->m_len = sizeof (struct tcpiphdr);
n = mtod(m, struct tcpiphdr *);
m->m_len = sizeof (struct tcptemp);
n = mtod(m, struct tcptemp *);
}
bzero(n->ti_x1, sizeof(n->ti_x1));
n->ti_pr = IPPROTO_TCP;
n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
n->ti_src = inp->inp_laddr;
n->ti_dst = inp->inp_faddr;
n->ti_sport = inp->inp_lport;
n->ti_dport = inp->inp_fport;
n->ti_seq = 0;
n->ti_ack = 0;
n->ti_x2 = 0;
n->ti_off = 5;
n->ti_flags = 0;
n->ti_win = 0;
n->ti_sum = 0;
n->ti_urp = 0;
#ifdef INET6
if ((inp->inp_vflag & INP_IPV6) != 0) {
register struct ip6_hdr *ip6;
ip6 = (struct ip6_hdr *)n->tt_ipgen;
ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
(inp->in6p_flowinfo & IPV6_FLOWINFO_MASK);
ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
(IPV6_VERSION & IPV6_VERSION_MASK);
ip6->ip6_nxt = IPPROTO_TCP;
ip6->ip6_plen = sizeof(struct tcphdr);
ip6->ip6_src = inp->in6p_laddr;
ip6->ip6_dst = inp->in6p_faddr;
} else
#endif
{
register struct ipovly *ipov;
ipov = (struct ipovly *)n->tt_ipgen;
bzero(ipov->ih_x1, sizeof(ipov->ih_x1));
ipov->ih_pr = IPPROTO_TCP;
ipov->ih_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
ipov->ih_src = inp->inp_laddr;
ipov->ih_dst = inp->inp_faddr;
}
n->tt_t.th_sport = inp->inp_lport;
n->tt_t.th_dport = inp->inp_fport;
n->tt_t.th_seq = 0;
n->tt_t.th_ack = 0;
n->tt_t.th_x2 = 0;
n->tt_t.th_off = 5;
n->tt_t.th_flags = 0;
n->tt_t.th_win = 0;
n->tt_t.th_sum = 0;
n->tt_t.th_urp = 0;
return (n);
}
@ -236,9 +282,10 @@ tcp_template(tp)
* NOTE: If m != NULL, then ti must point to *inside* the mbuf.
*/
void
tcp_respond(tp, ti, m, ack, seq, flags)
tcp_respond(tp, ipgen, th, m, ack, seq, flags)
struct tcpcb *tp;
register struct tcpiphdr *ti;
void *ipgen;
register struct tcphdr *th;
register struct mbuf *m;
tcp_seq ack, seq;
int flags;
@ -247,14 +294,44 @@ tcp_respond(tp, ti, m, ack, seq, flags)
int win = 0;
struct route *ro = 0;
struct route sro;
struct ip *ip;
struct ipovly *ipov;
struct tcphdr *nth;
#ifdef INET6
struct route_in6 *ro6 = 0;
struct route_in6 sro6;
struct ip6_hdr *ip6;
int isipv6;
#endif /* INET6 */
int ipflags = 0;
#ifdef INET6
isipv6 = IP_VHL_V(((struct ip *)ipgen)->ip_vhl) == 6;
ip6 = ipgen;
#endif /* INET6 */
ip = ipgen;
ipov = ipgen;
if (tp) {
if (!(flags & TH_RST))
win = sbspace(&tp->t_inpcb->inp_socket->so_rcv);
#ifdef INET6
if (isipv6)
ro6 = &tp->t_inpcb->in6p_route;
else
#endif /* INET6 */
ro = &tp->t_inpcb->inp_route;
} else {
#ifdef INET6
if (isipv6) {
ro6 = &sro6;
bzero(ro6, sizeof *ro6);
} else
#endif /* INET6 */
{
ro = &sro;
bzero(ro, sizeof *ro);
}
}
if (m == 0) {
m = m_gethdr(M_DONTWAIT, MT_HEADER);
@ -266,48 +343,125 @@ tcp_respond(tp, ti, m, ack, seq, flags)
tlen = 0;
#endif
m->m_data += max_linkhdr;
*mtod(m, struct tcpiphdr *) = *ti;
ti = mtod(m, struct tcpiphdr *);
#ifdef INET6
if (isipv6) {
bcopy((caddr_t)ip6, mtod(m, caddr_t),
sizeof(struct ip6_hdr));
ip6 = mtod(m, struct ip6_hdr *);
nth = (struct tcphdr *)(ip6 + 1);
} else
#endif /* INET6 */
{
bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
ip = mtod(m, struct ip *);
ipov = mtod(m, struct ipovly *);
nth = (struct tcphdr *)(ip + 1);
}
bcopy((caddr_t)th, (caddr_t)nth, sizeof(struct tcphdr));
flags = TH_ACK;
} else {
m_freem(m->m_next);
m->m_next = 0;
m->m_data = (caddr_t)ti;
m->m_len = sizeof (struct tcpiphdr);
m->m_data = (caddr_t)ipgen;
/* m_len is set later */
tlen = 0;
#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, n_long);
xchg(ti->ti_dport, ti->ti_sport, n_short);
#ifdef INET6
if (isipv6) {
xchg(ip6->ip6_dst, ip6->ip6_src, struct in6_addr);
nth = (struct tcphdr *)(ip6 + 1);
} else
#endif /* INET6 */
{
xchg(ip->ip_dst.s_addr, ip->ip_src.s_addr, n_long);
nth = (struct tcphdr *)(ip + 1);
}
if (th != nth) {
/*
* this is usually a case when an extension header
* exists between the IPv6 header and the
* TCP header.
*/
nth->th_sport = th->th_sport;
nth->th_dport = th->th_dport;
}
xchg(nth->th_dport, nth->th_sport, n_short);
#undef xchg
}
ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
#ifdef INET6
if (isipv6) {
ip6->ip6_plen = htons((u_short)(sizeof (struct tcphdr) +
tlen));
tlen += sizeof (struct ip6_hdr) + sizeof (struct tcphdr);
}
#endif
{
ipov->ih_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
tlen += sizeof (struct tcpiphdr);
}
m->m_len = tlen;
m->m_pkthdr.len = tlen;
m->m_pkthdr.rcvif = (struct ifnet *) 0;
bzero(ti->ti_x1, sizeof(ti->ti_x1));
ti->ti_seq = htonl(seq);
ti->ti_ack = htonl(ack);
ti->ti_x2 = 0;
ti->ti_off = sizeof (struct tcphdr) >> 2;
ti->ti_flags = flags;
nth->th_seq = htonl(seq);
nth->th_ack = htonl(ack);
nth->th_x2 = 0;
nth->th_off = sizeof (struct tcphdr) >> 2;
nth->th_flags = flags;
if (tp)
ti->ti_win = htons((u_short) (win >> tp->rcv_scale));
nth->th_win = htons((u_short) (win >> tp->rcv_scale));
else
ti->ti_win = htons((u_short)win);
ti->ti_urp = 0;
ti->ti_sum = 0;
ti->ti_sum = in_cksum(m, tlen);
((struct ip *)ti)->ip_len = tlen;
((struct ip *)ti)->ip_ttl = ip_defttl;
nth->th_win = htons((u_short)win);
nth->th_urp = 0;
nth->th_sum = 0;
#ifdef INET6
if (isipv6) {
nth->th_sum = in6_cksum(m, IPPROTO_TCP,
sizeof(struct ip6_hdr),
tlen - sizeof(struct ip6_hdr));
ip6->ip6_plen = htons((u_short)tlen);
ip6->ip6_hlim = in6_selecthlim(tp ? tp->t_inpcb : NULL,
ro6 && ro6->ro_rt ?
ro6->ro_rt->rt_ifp :
NULL);
} else
#endif /* INET6 */
{
bzero(ipov->ih_x1, sizeof(ipov->ih_x1));
nth->th_sum = in_cksum(m, tlen);
#ifdef INET6
/* Re-initialization for later version check */
ip->ip_vhl = IP_MAKE_VHL(IPVERSION, 0);
#endif /* INET6 */
ip->ip_len = tlen;
ip->ip_ttl = ip_defttl;
}
#ifdef TCPDEBUG
if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
tcp_trace(TA_OUTPUT, 0, tp, ti, 0);
tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0);
#endif
(void) ip_output(m, NULL, ro, 0, NULL);
#ifdef IPSEC
if (tp != NULL) {
m->m_pkthdr.rcvif = (struct ifnet *)tp->t_inpcb->inp_socket;
ipflags |=
#ifdef INET6
isipv6 ? IPV6_SOCKINMRCVIF :
#endif
IP_SOCKINMRCVIF;
}
#endif
#ifdef INET6
if (isipv6) {
(void)ip6_output(m, NULL, ro6, ipflags, NULL, NULL);
if (ro6 == &sro6 && ro6->ro_rt)
RTFREE(ro6->ro_rt);
} else
#endif /* INET6 */
{
(void) ip_output(m, NULL, ro, ipflags, NULL);
if (ro == &sro && ro->ro_rt) {
RTFREE(ro->ro_rt);
}
}
}
/*
@ -322,12 +476,19 @@ tcp_newtcpcb(inp)
{
struct inp_tp *it;
register struct tcpcb *tp;
#ifdef INET6
int isipv6 = (inp->inp_vflag & INP_IPV6) != 0;
#endif /* INET6 */
it = (struct inp_tp *)inp;
tp = &it->tcb;
bzero((char *) tp, sizeof(struct tcpcb));
tp->t_segq = NULL;
tp->t_maxseg = tp->t_maxopd = tcp_mssdflt;
LIST_INIT(&tp->t_segq);
tp->t_maxseg = tp->t_maxopd =
#ifdef INET6
isipv6 ? tcp_v6mssdflt :
#endif /* INET6 */
tcp_mssdflt;
/* Set up our timeouts. */
callout_init(tp->tt_rexmt = &it->inp_tp_rexmt);
@ -353,6 +514,14 @@ tcp_newtcpcb(inp)
tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
tp->t_rcvtime = ticks;
#ifdef INET6
if (isipv6 != 0)
inp->in6p_ip6_hlim = in6_selecthlim(inp,
inp->in6p_route.ro_rt ?
inp->in6p_route.ro_rt->rt_ifp :
NULL);
else
#endif
inp->inp_ip_ttl = ip_defttl;
inp->inp_ppcb = (caddr_t)tp;
return (tp); /* XXX */
@ -392,10 +561,12 @@ struct tcpcb *
tcp_close(tp)
register struct tcpcb *tp;
{
register struct mbuf *q;
register struct mbuf *nq;
register struct tseg_qent *q;
struct inpcb *inp = tp->t_inpcb;
struct socket *so = inp->inp_socket;
#ifdef INET6
int isipv6 = (inp->inp_vflag & INP_IPV6) != 0;
#endif /* INET6 */
register struct rtentry *rt;
int dosavessthresh;
@ -420,10 +591,24 @@ tcp_close(tp)
* Don't update the default route's characteristics and don't
* update anything that the user "locked".
*/
if (tp->t_rttupdated >= 16 &&
(rt = inp->inp_route.ro_rt) &&
((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) {
if (tp->t_rttupdated >= 16) {
register u_long i = 0;
#ifdef INET6
if (isipv6) {
struct sockaddr_in6 *sin6;
if ((rt = inp->in6p_route.ro_rt) == NULL)
goto no_valid_rt;
sin6 = (struct sockaddr_in6 *)rt_key(rt);
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
goto no_valid_rt;
}
else
#endif /* INET6 */
if ((rt = inp->inp_route.ro_rt) == NULL ||
((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr
== INADDR_ANY)
goto no_valid_rt;
if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) {
i = tp->t_srtt *
@ -480,7 +665,16 @@ tcp_close(tp)
i = (i + tp->t_maxseg / 2) / tp->t_maxseg;
if (i < 2)
i = 2;
i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr));
i *= (u_long)(tp->t_maxseg +
#ifdef INET6
(isipv6 ? sizeof (struct ip6_hdr) +
sizeof (struct tcphdr) :
#endif
sizeof (struct tcpiphdr)
#ifdef INET6
)
#endif
);
if (rt->rt_rmx.rmx_ssthresh)
rt->rt_rmx.rmx_ssthresh =
(rt->rt_rmx.rmx_ssthresh + i) / 2;
@ -489,16 +683,22 @@ tcp_close(tp)
tcpstat.tcps_cachedssthresh++;
}
}
no_valid_rt:
/* free the reassembly queue, if any */
for (q = tp->t_segq; q; q = nq) {
nq = q->m_nextpkt;
tp->t_segq = nq;
m_freem(q);
while((q = LIST_FIRST(&tp->t_segq)) != NULL) {
LIST_REMOVE(q, tqe_q);
m_freem(q->tqe_m);
FREE(q, M_TSEGQ);
}
if (tp->t_template)
(void) m_free(dtom(tp->t_template));
inp->inp_ppcb = NULL;
soisdisconnected(so);
#ifdef INET6
if (INP_CHECK_SOCKAF(so, AF_INET6))
in6_pcbdetach(inp);
else
#endif /* INET6 */
in_pcbdetach(inp);
tcpstat.tcps_closed++;
return ((struct tcpcb *)0);
@ -511,7 +711,7 @@ tcp_drain()
{
struct inpcb *inpb;
struct tcpcb *tcpb;
struct mbuf *m, *mq;
struct tseg_qent *te;
/*
* Walk the tcpbs, if existing, and flush the reassembly queue,
@ -524,10 +724,11 @@ tcp_drain()
for (inpb = tcbinfo.listhead->lh_first; inpb;
inpb = inpb->inp_list.le_next) {
if ((tcpb = intotcpcb(inpb))) {
for (mq = tcpb->t_segq; mq; mq = m) {
m = mq->m_nextpkt;
tcpb->t_segq = m;
m_freem(mq);
while ((te = LIST_FIRST(&tcpb->t_segq))
!= NULL) {
LIST_REMOVE(te, tqe_q);
m_freem(te->tqe_m);
FREE(te, M_TSEGQ);
}
}
}
@ -690,6 +891,56 @@ tcp_getcred SYSCTL_HANDLER_ARGS
SYSCTL_PROC(_net_inet_tcp, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
0, 0, tcp_getcred, "S,ucred", "Get the ucred of a TCP connection");
#ifdef INET6
static int
tcp6_getcred SYSCTL_HANDLER_ARGS
{
struct sockaddr_in6 addrs[2];
struct inpcb *inp;
int error, s, mapped = 0;
error = suser(req->p);
if (error)
return (error);
error = SYSCTL_IN(req, addrs, sizeof(addrs));
if (error)
return (error);
if (IN6_IS_ADDR_V4MAPPED(&addrs[0].sin6_addr)) {
if (IN6_IS_ADDR_V4MAPPED(&addrs[1].sin6_addr))
mapped = 1;
else
return (EINVAL);
}
s = splnet();
if (mapped == 1)
inp = in_pcblookup_hash(&tcbinfo,
*(struct in_addr *)&addrs[1].sin6_addr.s6_addr[12],
addrs[1].sin6_port,
*(struct in_addr *)&addrs[0].sin6_addr.s6_addr[12],
addrs[0].sin6_port,
0, NULL);
else
inp = in6_pcblookup_hash(&tcbinfo, &addrs[1].sin6_addr,
addrs[1].sin6_port,
&addrs[0].sin6_addr, addrs[0].sin6_port,
0, NULL);
if (inp == NULL || inp->inp_socket == NULL) {
error = ENOENT;
goto out;
}
error = SYSCTL_OUT(req, inp->inp_socket->so_cred,
sizeof(struct ucred));
out:
splx(s);
return (error);
}
SYSCTL_PROC(_net_inet6_tcp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
0, 0,
tcp6_getcred, "S,ucred", "Get the ucred of a TCP6 connection");
#endif
void
tcp_ctlinput(cmd, sa, vip)
int cmd;
@ -716,6 +967,84 @@ tcp_ctlinput(cmd, sa, vip)
in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify);
}
#ifdef INET6
void
tcp6_ctlinput(cmd, sa, d)
int cmd;
struct sockaddr *sa;
void *d;
{
register struct tcphdr *thp;
struct tcphdr th;
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
struct sockaddr_in6 sa6;
struct ip6_hdr *ip6;
struct mbuf *m;
int off;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
return;
if (cmd == PRC_QUENCH)
notify = tcp_quench;
else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
else if (!PRC_IS_REDIRECT(cmd) &&
((unsigned)cmd > PRC_NCMDS || inet6ctlerrmap[cmd] == 0))
return;
/* if the parameter is from icmp6, decode it. */
if (d != NULL) {
struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
m = ip6cp->ip6c_m;
ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
} else {
m = NULL;
ip6 = NULL;
}
/*
* Translate addresses into internal form.
* Sa check if it is AF_INET6 is done at the top of this funciton.
*/
sa6 = *(struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) != 0 && m != NULL &&
m->m_pkthdr.rcvif != NULL)
sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
if (ip6) {
/*
* XXX: We assume that when IPV6 is non NULL,
* M and OFF are valid.
*/
struct in6_addr s;
/* translate addresses into internal form */
memcpy(&s, &ip6->ip6_src, sizeof(s));
if (IN6_IS_ADDR_LINKLOCAL(&s) != 0 && m != NULL &&
m->m_pkthdr.rcvif != NULL)
s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
if (m->m_len < off + sizeof(*thp)) {
/*
* this should be rare case
* because now MINCLSIZE is "(MHLEN + 1)",
* so we compromise on this copy...
*/
m_copydata(m, off, sizeof(th), (caddr_t)&th);
thp = &th;
} else
thp = (struct tcphdr *)(mtod(m, caddr_t) + off);
in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, thp->th_dport,
&s, thp->th_sport, cmd, notify);
} else
in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, 0, &zeroin6_addr,
0, cmd, notify);
}
#endif /* INET6 */
/*
* When a source quench is received, close congestion window
* to one segment. We will gradually open it again as we proceed.
@ -748,16 +1077,38 @@ tcp_mtudisc(inp, errno)
struct socket *so = inp->inp_socket;
int offered;
int mss;
#ifdef INET6
int isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0;
#endif /* INET6 */
if (tp) {
#ifdef INET6
if (isipv6)
rt = tcp_rtlookup6(inp);
else
#endif /* INET6 */
rt = tcp_rtlookup(inp);
if (!rt || !rt->rt_rmx.rmx_mtu) {
tp->t_maxopd = tp->t_maxseg = tcp_mssdflt;
tp->t_maxopd = tp->t_maxseg =
#ifdef INET6
isipv6 ? tcp_v6mssdflt :
#endif /* INET6 */
tcp_mssdflt;
return;
}
taop = rmx_taop(rt->rt_rmx);
offered = taop->tao_mssopt;
mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr);
mss = rt->rt_rmx.rmx_mtu -
#ifdef INET6
(isipv6 ?
sizeof(struct ip6_hdr) + sizeof(struct tcphdr) :
#endif /* INET6 */
sizeof(struct tcpiphdr)
#ifdef INET6
)
#endif /* INET6 */
;
if (offered)
mss = min(mss, offered);
/*
@ -835,6 +1186,80 @@ tcp_rtlookup(inp)
return rt;
}
#ifdef INET6
struct rtentry *
tcp_rtlookup6(inp)
struct inpcb *inp;
{
struct route_in6 *ro6;
struct rtentry *rt;
ro6 = &inp->in6p_route;
rt = ro6->ro_rt;
if (rt == NULL || !(rt->rt_flags & RTF_UP)) {
/* No route yet, so try to acquire one */
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
ro6->ro_dst.sin6_family = AF_INET6;
ro6->ro_dst.sin6_len = sizeof(ro6->ro_dst);
ro6->ro_dst.sin6_addr = inp->in6p_faddr;
rtalloc((struct route *)ro6);
rt = ro6->ro_rt;
}
}
return rt;
}
#endif /* INET6 */
#ifdef IPSEC
/* compute ESP/AH header size for TCP, including outer IP header. */
size_t
ipsec_hdrsiz_tcp(tp)
struct tcpcb *tp;
{
struct inpcb *inp;
struct mbuf *m;
size_t hdrsiz;
struct ip *ip;
#ifdef INET6
struct ip6_hdr *ip6;
#endif /* INET6 */
struct tcphdr *th;
if (!tp || !tp->t_template || !(inp = tp->t_inpcb))
return 0;
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (!m)
return 0;
#ifdef INET6
if ((inp->inp_vflag & INP_IPV6) != 0) {
ip6 = mtod(m, struct ip6_hdr *);
th = (struct tcphdr *)(ip6 + 1);
m->m_pkthdr.len = m->m_len =
sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
bcopy((caddr_t)&tp->t_template->tt_ipgen, (caddr_t)ip6,
sizeof(struct ip6_hdr));
bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th,
sizeof(struct tcphdr));
hdrsiz = ipsec6_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp);
} else
#endif /* INET6 */
{
ip = mtod(m, struct ip *);
th = (struct tcphdr *)(ip + 1);
m->m_pkthdr.len = m->m_len = sizeof(struct tcpiphdr);
bcopy((caddr_t)&tp->t_template->tt_ipgen, (caddr_t)ip,
sizeof(struct ip));
bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th,
sizeof(struct tcphdr));
hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp);
}
m_free(m);
return hdrsiz;
}
#endif /*IPSEC*/
/*
* Return a pointer to the cached information about the remote host.
* The cached information is stored in the protocol specific part of
@ -844,7 +1269,14 @@ struct rmxp_tao *
tcp_gettaocache(inp)
struct inpcb *inp;
{
struct rtentry *rt = tcp_rtlookup(inp);
struct rtentry *rt;
#ifdef INET6
if ((inp->inp_vflag & INP_IPV6) != 0)
rt = tcp_rtlookup6(inp);
else
#endif /* INET6 */
rt = tcp_rtlookup(inp);
/* Make sure this is a host route and is up. */
if (rt == NULL ||

View File

@ -35,6 +35,7 @@
*/
#include "opt_compat.h"
#include "opt_inet6.h"
#include "opt_tcpdebug.h"
#include <sys/param.h>
@ -52,6 +53,9 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_pcb.h>
#ifdef INET6
#include <netinet6/in6_pcb.h>
#endif
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
@ -209,7 +213,7 @@ tcp_timer_2msl(xtp)
#ifdef TCPDEBUG
if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0,
tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
PRU_SLOWTIMO);
#endif
splx(s);
@ -262,10 +266,12 @@ tcp_timer_keep(xtp)
* The keepalive packet must have nonzero length
* to get a 4.2 host to respond.
*/
tcp_respond(tp, tp->t_template, (struct mbuf *)NULL,
tcp_respond(tp, tp->t_template->tt_ipgen,
&tp->t_template->tt_t, (struct mbuf *)NULL,
tp->rcv_nxt - 1, tp->snd_una - 1, 0);
#else
tcp_respond(tp, tp->t_template, (struct mbuf *)NULL,
tcp_respond(tp, tp->t_template->tt_ipgen,
&tp->t_template->tt_t, (struct mbuf *)NULL,
tp->rcv_nxt, tp->snd_una - 1, 0);
#endif
callout_reset(tp->tt_keep, tcp_keepintvl, tcp_timer_keep, tp);
@ -274,7 +280,7 @@ tcp_timer_keep(xtp)
#ifdef TCPDEBUG
if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)
tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0,
tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
PRU_SLOWTIMO);
#endif
splx(s);
@ -286,7 +292,7 @@ tcp_timer_keep(xtp)
#ifdef TCPDEBUG
if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0,
tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
PRU_SLOWTIMO);
#endif
splx(s);
@ -336,7 +342,7 @@ tcp_timer_persist(xtp)
out:
#ifdef TCPDEBUG
if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)
tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0,
tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
PRU_SLOWTIMO);
#endif
splx(s);
@ -399,6 +405,11 @@ tcp_timer_rexmt(xtp)
* retransmit times until then.
*/
if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
#ifdef INET6
if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0)
in6_losing(tp->t_inpcb);
else
#endif
in_losing(tp->t_inpcb);
tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
tp->t_srtt = 0;
@ -449,7 +460,7 @@ tcp_timer_rexmt(xtp)
out:
#ifdef TCPDEBUG
if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0,
tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
PRU_SLOWTIMO);
#endif
splx(s);

View File

@ -45,6 +45,9 @@
#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#ifdef INET6
#include <sys/domain.h>
#endif
#include <sys/proc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
@ -59,18 +62,35 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#ifdef INET6
#include <netinet/ip6.h>
#endif
#include <netinet/in_pcb.h>
#ifdef INET6
#include <netinet6/in6_pcb.h>
#endif
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
#ifdef INET6
#include <netinet6/ip6_var.h>
#endif
#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#ifdef INET6
#include <netinet6/tcp6_var.h>
#endif
#include <netinet/tcpip.h>
#ifdef TCPDEBUG
#include <netinet/tcp_debug.h>
#endif
#include <netinet6/ip6protosw.h>
#ifdef IPSEC
#include <netinet6/ipsec.h>
#endif /*IPSEC*/
int tcp_mssdflt = TCP_MSS;
SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, CTLFLAG_RW,
@ -79,7 +99,8 @@ SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, CTLFLAG_RW,
#ifdef INET6
int tcp_v6mssdflt = TCP6_MSS;
SYSCTL_INT(_net_inet_tcp, TCPCTL_V6MSSDFLT, v6mssdflt,
CTLFLAG_RW, &tcp_v6mssdflt , 0, "");
CTLFLAG_RW, &tcp_v6mssdflt , 0,
"Default TCP Maximum Segment Size for IPv6");
#endif
#if 0
@ -174,11 +195,16 @@ tcp_init()
&tcbinfo.porthashmask);
tcbinfo.ipi_zone = zinit("tcpcb", sizeof(struct inp_tp), maxsockets,
ZONE_INTERRUPT, 0);
if (max_protohdr < sizeof(struct tcpiphdr))
max_protohdr = sizeof(struct tcpiphdr);
if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN)
#ifdef INET6
#define TCP_MINPROTOHDR (sizeof(struct ip6_hdr) + sizeof(struct tcphdr))
#else /* INET6 */
#define TCP_MINPROTOHDR (sizeof(struct tcpiphdr))
#endif /* INET6 */
if (max_protohdr < TCP_MINPROTOHDR)
max_protohdr = TCP_MINPROTOHDR;
if (max_linkhdr + TCP_MINPROTOHDR > MHLEN)
panic("tcp_init");
#undef TCP_MINPROTOHDR
}
/*
@ -187,36 +213,56 @@ tcp_init()
* in a skeletal tcp/ip header, minimizing the amount of work
* necessary when the connection is used.
*/
struct tcpiphdr *
struct tcptemp *
tcp_template(tp)
struct tcpcb *tp;
{
register struct inpcb *inp = tp->t_inpcb;
register struct mbuf *m;
register struct tcpiphdr *n;
register struct tcptemp *n;
if ((n = tp->t_template) == 0) {
m = m_get(M_DONTWAIT, MT_HEADER);
if (m == NULL)
return (0);
m->m_len = sizeof (struct tcpiphdr);
n = mtod(m, struct tcpiphdr *);
m->m_len = sizeof (struct tcptemp);
n = mtod(m, struct tcptemp *);
}
bzero(n->ti_x1, sizeof(n->ti_x1));
n->ti_pr = IPPROTO_TCP;
n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
n->ti_src = inp->inp_laddr;
n->ti_dst = inp->inp_faddr;
n->ti_sport = inp->inp_lport;
n->ti_dport = inp->inp_fport;
n->ti_seq = 0;
n->ti_ack = 0;
n->ti_x2 = 0;
n->ti_off = 5;
n->ti_flags = 0;
n->ti_win = 0;
n->ti_sum = 0;
n->ti_urp = 0;
#ifdef INET6
if ((inp->inp_vflag & INP_IPV6) != 0) {
register struct ip6_hdr *ip6;
ip6 = (struct ip6_hdr *)n->tt_ipgen;
ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
(inp->in6p_flowinfo & IPV6_FLOWINFO_MASK);
ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
(IPV6_VERSION & IPV6_VERSION_MASK);
ip6->ip6_nxt = IPPROTO_TCP;
ip6->ip6_plen = sizeof(struct tcphdr);
ip6->ip6_src = inp->in6p_laddr;
ip6->ip6_dst = inp->in6p_faddr;
} else
#endif
{
register struct ipovly *ipov;
ipov = (struct ipovly *)n->tt_ipgen;
bzero(ipov->ih_x1, sizeof(ipov->ih_x1));
ipov->ih_pr = IPPROTO_TCP;
ipov->ih_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
ipov->ih_src = inp->inp_laddr;
ipov->ih_dst = inp->inp_faddr;
}
n->tt_t.th_sport = inp->inp_lport;
n->tt_t.th_dport = inp->inp_fport;
n->tt_t.th_seq = 0;
n->tt_t.th_ack = 0;
n->tt_t.th_x2 = 0;
n->tt_t.th_off = 5;
n->tt_t.th_flags = 0;
n->tt_t.th_win = 0;
n->tt_t.th_sum = 0;
n->tt_t.th_urp = 0;
return (n);
}
@ -236,9 +282,10 @@ tcp_template(tp)
* NOTE: If m != NULL, then ti must point to *inside* the mbuf.
*/
void
tcp_respond(tp, ti, m, ack, seq, flags)
tcp_respond(tp, ipgen, th, m, ack, seq, flags)
struct tcpcb *tp;
register struct tcpiphdr *ti;
void *ipgen;
register struct tcphdr *th;
register struct mbuf *m;
tcp_seq ack, seq;
int flags;
@ -247,14 +294,44 @@ tcp_respond(tp, ti, m, ack, seq, flags)
int win = 0;
struct route *ro = 0;
struct route sro;
struct ip *ip;
struct ipovly *ipov;
struct tcphdr *nth;
#ifdef INET6
struct route_in6 *ro6 = 0;
struct route_in6 sro6;
struct ip6_hdr *ip6;
int isipv6;
#endif /* INET6 */
int ipflags = 0;
#ifdef INET6
isipv6 = IP_VHL_V(((struct ip *)ipgen)->ip_vhl) == 6;
ip6 = ipgen;
#endif /* INET6 */
ip = ipgen;
ipov = ipgen;
if (tp) {
if (!(flags & TH_RST))
win = sbspace(&tp->t_inpcb->inp_socket->so_rcv);
#ifdef INET6
if (isipv6)
ro6 = &tp->t_inpcb->in6p_route;
else
#endif /* INET6 */
ro = &tp->t_inpcb->inp_route;
} else {
#ifdef INET6
if (isipv6) {
ro6 = &sro6;
bzero(ro6, sizeof *ro6);
} else
#endif /* INET6 */
{
ro = &sro;
bzero(ro, sizeof *ro);
}
}
if (m == 0) {
m = m_gethdr(M_DONTWAIT, MT_HEADER);
@ -266,48 +343,125 @@ tcp_respond(tp, ti, m, ack, seq, flags)
tlen = 0;
#endif
m->m_data += max_linkhdr;
*mtod(m, struct tcpiphdr *) = *ti;
ti = mtod(m, struct tcpiphdr *);
#ifdef INET6
if (isipv6) {
bcopy((caddr_t)ip6, mtod(m, caddr_t),
sizeof(struct ip6_hdr));
ip6 = mtod(m, struct ip6_hdr *);
nth = (struct tcphdr *)(ip6 + 1);
} else
#endif /* INET6 */
{
bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
ip = mtod(m, struct ip *);
ipov = mtod(m, struct ipovly *);
nth = (struct tcphdr *)(ip + 1);
}
bcopy((caddr_t)th, (caddr_t)nth, sizeof(struct tcphdr));
flags = TH_ACK;
} else {
m_freem(m->m_next);
m->m_next = 0;
m->m_data = (caddr_t)ti;
m->m_len = sizeof (struct tcpiphdr);
m->m_data = (caddr_t)ipgen;
/* m_len is set later */
tlen = 0;
#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, n_long);
xchg(ti->ti_dport, ti->ti_sport, n_short);
#ifdef INET6
if (isipv6) {
xchg(ip6->ip6_dst, ip6->ip6_src, struct in6_addr);
nth = (struct tcphdr *)(ip6 + 1);
} else
#endif /* INET6 */
{
xchg(ip->ip_dst.s_addr, ip->ip_src.s_addr, n_long);
nth = (struct tcphdr *)(ip + 1);
}
if (th != nth) {
/*
* this is usually a case when an extension header
* exists between the IPv6 header and the
* TCP header.
*/
nth->th_sport = th->th_sport;
nth->th_dport = th->th_dport;
}
xchg(nth->th_dport, nth->th_sport, n_short);
#undef xchg
}
ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
#ifdef INET6
if (isipv6) {
ip6->ip6_plen = htons((u_short)(sizeof (struct tcphdr) +
tlen));
tlen += sizeof (struct ip6_hdr) + sizeof (struct tcphdr);
}
#endif
{
ipov->ih_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
tlen += sizeof (struct tcpiphdr);
}
m->m_len = tlen;
m->m_pkthdr.len = tlen;
m->m_pkthdr.rcvif = (struct ifnet *) 0;
bzero(ti->ti_x1, sizeof(ti->ti_x1));
ti->ti_seq = htonl(seq);
ti->ti_ack = htonl(ack);
ti->ti_x2 = 0;
ti->ti_off = sizeof (struct tcphdr) >> 2;
ti->ti_flags = flags;
nth->th_seq = htonl(seq);
nth->th_ack = htonl(ack);
nth->th_x2 = 0;
nth->th_off = sizeof (struct tcphdr) >> 2;
nth->th_flags = flags;
if (tp)
ti->ti_win = htons((u_short) (win >> tp->rcv_scale));
nth->th_win = htons((u_short) (win >> tp->rcv_scale));
else
ti->ti_win = htons((u_short)win);
ti->ti_urp = 0;
ti->ti_sum = 0;
ti->ti_sum = in_cksum(m, tlen);
((struct ip *)ti)->ip_len = tlen;
((struct ip *)ti)->ip_ttl = ip_defttl;
nth->th_win = htons((u_short)win);
nth->th_urp = 0;
nth->th_sum = 0;
#ifdef INET6
if (isipv6) {
nth->th_sum = in6_cksum(m, IPPROTO_TCP,
sizeof(struct ip6_hdr),
tlen - sizeof(struct ip6_hdr));
ip6->ip6_plen = htons((u_short)tlen);
ip6->ip6_hlim = in6_selecthlim(tp ? tp->t_inpcb : NULL,
ro6 && ro6->ro_rt ?
ro6->ro_rt->rt_ifp :
NULL);
} else
#endif /* INET6 */
{
bzero(ipov->ih_x1, sizeof(ipov->ih_x1));
nth->th_sum = in_cksum(m, tlen);
#ifdef INET6
/* Re-initialization for later version check */
ip->ip_vhl = IP_MAKE_VHL(IPVERSION, 0);
#endif /* INET6 */
ip->ip_len = tlen;
ip->ip_ttl = ip_defttl;
}
#ifdef TCPDEBUG
if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
tcp_trace(TA_OUTPUT, 0, tp, ti, 0);
tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0);
#endif
(void) ip_output(m, NULL, ro, 0, NULL);
#ifdef IPSEC
if (tp != NULL) {
m->m_pkthdr.rcvif = (struct ifnet *)tp->t_inpcb->inp_socket;
ipflags |=
#ifdef INET6
isipv6 ? IPV6_SOCKINMRCVIF :
#endif
IP_SOCKINMRCVIF;
}
#endif
#ifdef INET6
if (isipv6) {
(void)ip6_output(m, NULL, ro6, ipflags, NULL, NULL);
if (ro6 == &sro6 && ro6->ro_rt)
RTFREE(ro6->ro_rt);
} else
#endif /* INET6 */
{
(void) ip_output(m, NULL, ro, ipflags, NULL);
if (ro == &sro && ro->ro_rt) {
RTFREE(ro->ro_rt);
}
}
}
/*
@ -322,12 +476,19 @@ tcp_newtcpcb(inp)
{
struct inp_tp *it;
register struct tcpcb *tp;
#ifdef INET6
int isipv6 = (inp->inp_vflag & INP_IPV6) != 0;
#endif /* INET6 */
it = (struct inp_tp *)inp;
tp = &it->tcb;
bzero((char *) tp, sizeof(struct tcpcb));
tp->t_segq = NULL;
tp->t_maxseg = tp->t_maxopd = tcp_mssdflt;
LIST_INIT(&tp->t_segq);
tp->t_maxseg = tp->t_maxopd =
#ifdef INET6
isipv6 ? tcp_v6mssdflt :
#endif /* INET6 */
tcp_mssdflt;
/* Set up our timeouts. */
callout_init(tp->tt_rexmt = &it->inp_tp_rexmt);
@ -353,6 +514,14 @@ tcp_newtcpcb(inp)
tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
tp->t_rcvtime = ticks;
#ifdef INET6
if (isipv6 != 0)
inp->in6p_ip6_hlim = in6_selecthlim(inp,
inp->in6p_route.ro_rt ?
inp->in6p_route.ro_rt->rt_ifp :
NULL);
else
#endif
inp->inp_ip_ttl = ip_defttl;
inp->inp_ppcb = (caddr_t)tp;
return (tp); /* XXX */
@ -392,10 +561,12 @@ struct tcpcb *
tcp_close(tp)
register struct tcpcb *tp;
{
register struct mbuf *q;
register struct mbuf *nq;
register struct tseg_qent *q;
struct inpcb *inp = tp->t_inpcb;
struct socket *so = inp->inp_socket;
#ifdef INET6
int isipv6 = (inp->inp_vflag & INP_IPV6) != 0;
#endif /* INET6 */
register struct rtentry *rt;
int dosavessthresh;
@ -420,10 +591,24 @@ tcp_close(tp)
* Don't update the default route's characteristics and don't
* update anything that the user "locked".
*/
if (tp->t_rttupdated >= 16 &&
(rt = inp->inp_route.ro_rt) &&
((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) {
if (tp->t_rttupdated >= 16) {
register u_long i = 0;
#ifdef INET6
if (isipv6) {
struct sockaddr_in6 *sin6;
if ((rt = inp->in6p_route.ro_rt) == NULL)
goto no_valid_rt;
sin6 = (struct sockaddr_in6 *)rt_key(rt);
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
goto no_valid_rt;
}
else
#endif /* INET6 */
if ((rt = inp->inp_route.ro_rt) == NULL ||
((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr
== INADDR_ANY)
goto no_valid_rt;
if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) {
i = tp->t_srtt *
@ -480,7 +665,16 @@ tcp_close(tp)
i = (i + tp->t_maxseg / 2) / tp->t_maxseg;
if (i < 2)
i = 2;
i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr));
i *= (u_long)(tp->t_maxseg +
#ifdef INET6
(isipv6 ? sizeof (struct ip6_hdr) +
sizeof (struct tcphdr) :
#endif
sizeof (struct tcpiphdr)
#ifdef INET6
)
#endif
);
if (rt->rt_rmx.rmx_ssthresh)
rt->rt_rmx.rmx_ssthresh =
(rt->rt_rmx.rmx_ssthresh + i) / 2;
@ -489,16 +683,22 @@ tcp_close(tp)
tcpstat.tcps_cachedssthresh++;
}
}
no_valid_rt:
/* free the reassembly queue, if any */
for (q = tp->t_segq; q; q = nq) {
nq = q->m_nextpkt;
tp->t_segq = nq;
m_freem(q);
while((q = LIST_FIRST(&tp->t_segq)) != NULL) {
LIST_REMOVE(q, tqe_q);
m_freem(q->tqe_m);
FREE(q, M_TSEGQ);
}
if (tp->t_template)
(void) m_free(dtom(tp->t_template));
inp->inp_ppcb = NULL;
soisdisconnected(so);
#ifdef INET6
if (INP_CHECK_SOCKAF(so, AF_INET6))
in6_pcbdetach(inp);
else
#endif /* INET6 */
in_pcbdetach(inp);
tcpstat.tcps_closed++;
return ((struct tcpcb *)0);
@ -511,7 +711,7 @@ tcp_drain()
{
struct inpcb *inpb;
struct tcpcb *tcpb;
struct mbuf *m, *mq;
struct tseg_qent *te;
/*
* Walk the tcpbs, if existing, and flush the reassembly queue,
@ -524,10 +724,11 @@ tcp_drain()
for (inpb = tcbinfo.listhead->lh_first; inpb;
inpb = inpb->inp_list.le_next) {
if ((tcpb = intotcpcb(inpb))) {
for (mq = tcpb->t_segq; mq; mq = m) {
m = mq->m_nextpkt;
tcpb->t_segq = m;
m_freem(mq);
while ((te = LIST_FIRST(&tcpb->t_segq))
!= NULL) {
LIST_REMOVE(te, tqe_q);
m_freem(te->tqe_m);
FREE(te, M_TSEGQ);
}
}
}
@ -690,6 +891,56 @@ tcp_getcred SYSCTL_HANDLER_ARGS
SYSCTL_PROC(_net_inet_tcp, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
0, 0, tcp_getcred, "S,ucred", "Get the ucred of a TCP connection");
#ifdef INET6
static int
tcp6_getcred SYSCTL_HANDLER_ARGS
{
struct sockaddr_in6 addrs[2];
struct inpcb *inp;
int error, s, mapped = 0;
error = suser(req->p);
if (error)
return (error);
error = SYSCTL_IN(req, addrs, sizeof(addrs));
if (error)
return (error);
if (IN6_IS_ADDR_V4MAPPED(&addrs[0].sin6_addr)) {
if (IN6_IS_ADDR_V4MAPPED(&addrs[1].sin6_addr))
mapped = 1;
else
return (EINVAL);
}
s = splnet();
if (mapped == 1)
inp = in_pcblookup_hash(&tcbinfo,
*(struct in_addr *)&addrs[1].sin6_addr.s6_addr[12],
addrs[1].sin6_port,
*(struct in_addr *)&addrs[0].sin6_addr.s6_addr[12],
addrs[0].sin6_port,
0, NULL);
else
inp = in6_pcblookup_hash(&tcbinfo, &addrs[1].sin6_addr,
addrs[1].sin6_port,
&addrs[0].sin6_addr, addrs[0].sin6_port,
0, NULL);
if (inp == NULL || inp->inp_socket == NULL) {
error = ENOENT;
goto out;
}
error = SYSCTL_OUT(req, inp->inp_socket->so_cred,
sizeof(struct ucred));
out:
splx(s);
return (error);
}
SYSCTL_PROC(_net_inet6_tcp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
0, 0,
tcp6_getcred, "S,ucred", "Get the ucred of a TCP6 connection");
#endif
void
tcp_ctlinput(cmd, sa, vip)
int cmd;
@ -716,6 +967,84 @@ tcp_ctlinput(cmd, sa, vip)
in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify);
}
#ifdef INET6
void
tcp6_ctlinput(cmd, sa, d)
int cmd;
struct sockaddr *sa;
void *d;
{
register struct tcphdr *thp;
struct tcphdr th;
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
struct sockaddr_in6 sa6;
struct ip6_hdr *ip6;
struct mbuf *m;
int off;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
return;
if (cmd == PRC_QUENCH)
notify = tcp_quench;
else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
else if (!PRC_IS_REDIRECT(cmd) &&
((unsigned)cmd > PRC_NCMDS || inet6ctlerrmap[cmd] == 0))
return;
/* if the parameter is from icmp6, decode it. */
if (d != NULL) {
struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
m = ip6cp->ip6c_m;
ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
} else {
m = NULL;
ip6 = NULL;
}
/*
* Translate addresses into internal form.
* Sa check if it is AF_INET6 is done at the top of this funciton.
*/
sa6 = *(struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) != 0 && m != NULL &&
m->m_pkthdr.rcvif != NULL)
sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
if (ip6) {
/*
* XXX: We assume that when IPV6 is non NULL,
* M and OFF are valid.
*/
struct in6_addr s;
/* translate addresses into internal form */
memcpy(&s, &ip6->ip6_src, sizeof(s));
if (IN6_IS_ADDR_LINKLOCAL(&s) != 0 && m != NULL &&
m->m_pkthdr.rcvif != NULL)
s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
if (m->m_len < off + sizeof(*thp)) {
/*
* this should be rare case
* because now MINCLSIZE is "(MHLEN + 1)",
* so we compromise on this copy...
*/
m_copydata(m, off, sizeof(th), (caddr_t)&th);
thp = &th;
} else
thp = (struct tcphdr *)(mtod(m, caddr_t) + off);
in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, thp->th_dport,
&s, thp->th_sport, cmd, notify);
} else
in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, 0, &zeroin6_addr,
0, cmd, notify);
}
#endif /* INET6 */
/*
* When a source quench is received, close congestion window
* to one segment. We will gradually open it again as we proceed.
@ -748,16 +1077,38 @@ tcp_mtudisc(inp, errno)
struct socket *so = inp->inp_socket;
int offered;
int mss;
#ifdef INET6
int isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0;
#endif /* INET6 */
if (tp) {
#ifdef INET6
if (isipv6)
rt = tcp_rtlookup6(inp);
else
#endif /* INET6 */
rt = tcp_rtlookup(inp);
if (!rt || !rt->rt_rmx.rmx_mtu) {
tp->t_maxopd = tp->t_maxseg = tcp_mssdflt;
tp->t_maxopd = tp->t_maxseg =
#ifdef INET6
isipv6 ? tcp_v6mssdflt :
#endif /* INET6 */
tcp_mssdflt;
return;
}
taop = rmx_taop(rt->rt_rmx);
offered = taop->tao_mssopt;
mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr);
mss = rt->rt_rmx.rmx_mtu -
#ifdef INET6
(isipv6 ?
sizeof(struct ip6_hdr) + sizeof(struct tcphdr) :
#endif /* INET6 */
sizeof(struct tcpiphdr)
#ifdef INET6
)
#endif /* INET6 */
;
if (offered)
mss = min(mss, offered);
/*
@ -835,6 +1186,80 @@ tcp_rtlookup(inp)
return rt;
}
#ifdef INET6
struct rtentry *
tcp_rtlookup6(inp)
struct inpcb *inp;
{
struct route_in6 *ro6;
struct rtentry *rt;
ro6 = &inp->in6p_route;
rt = ro6->ro_rt;
if (rt == NULL || !(rt->rt_flags & RTF_UP)) {
/* No route yet, so try to acquire one */
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
ro6->ro_dst.sin6_family = AF_INET6;
ro6->ro_dst.sin6_len = sizeof(ro6->ro_dst);
ro6->ro_dst.sin6_addr = inp->in6p_faddr;
rtalloc((struct route *)ro6);
rt = ro6->ro_rt;
}
}
return rt;
}
#endif /* INET6 */
#ifdef IPSEC
/* compute ESP/AH header size for TCP, including outer IP header. */
size_t
ipsec_hdrsiz_tcp(tp)
struct tcpcb *tp;
{
struct inpcb *inp;
struct mbuf *m;
size_t hdrsiz;
struct ip *ip;
#ifdef INET6
struct ip6_hdr *ip6;
#endif /* INET6 */
struct tcphdr *th;
if (!tp || !tp->t_template || !(inp = tp->t_inpcb))
return 0;
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (!m)
return 0;
#ifdef INET6
if ((inp->inp_vflag & INP_IPV6) != 0) {
ip6 = mtod(m, struct ip6_hdr *);
th = (struct tcphdr *)(ip6 + 1);
m->m_pkthdr.len = m->m_len =
sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
bcopy((caddr_t)&tp->t_template->tt_ipgen, (caddr_t)ip6,
sizeof(struct ip6_hdr));
bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th,
sizeof(struct tcphdr));
hdrsiz = ipsec6_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp);
} else
#endif /* INET6 */
{
ip = mtod(m, struct ip *);
th = (struct tcphdr *)(ip + 1);
m->m_pkthdr.len = m->m_len = sizeof(struct tcpiphdr);
bcopy((caddr_t)&tp->t_template->tt_ipgen, (caddr_t)ip,
sizeof(struct ip));
bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th,
sizeof(struct tcphdr));
hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp);
}
m_free(m);
return hdrsiz;
}
#endif /*IPSEC*/
/*
* Return a pointer to the cached information about the remote host.
* The cached information is stored in the protocol specific part of
@ -844,7 +1269,14 @@ struct rmxp_tao *
tcp_gettaocache(inp)
struct inpcb *inp;
{
struct rtentry *rt = tcp_rtlookup(inp);
struct rtentry *rt;
#ifdef INET6
if ((inp->inp_vflag & INP_IPV6) != 0)
rt = tcp_rtlookup6(inp);
else
#endif /* INET6 */
rt = tcp_rtlookup(inp);
/* Make sure this is a host route and is up. */
if (rt == NULL ||

View File

@ -35,6 +35,7 @@
*/
#include "opt_ipsec.h"
#include "opt_inet6.h"
#include "opt_tcpdebug.h"
#include <sys/param.h>
@ -42,6 +43,9 @@
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/mbuf.h>
#ifdef INET6
#include <sys/domain.h>
#endif /* INET6 */
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/protosw.h>
@ -51,9 +55,18 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#ifdef INET6
#include <netinet/ip6.h>
#endif
#include <netinet/in_pcb.h>
#ifdef INET6
#include <netinet6/in6_pcb.h>
#endif
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
#ifdef INET6
#include <netinet6/ip6_var.h>
#endif
#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
@ -76,6 +89,10 @@ extern char *tcpstates[]; /* XXX ??? */
static int tcp_attach __P((struct socket *, struct proc *));
static int tcp_connect __P((struct tcpcb *, struct sockaddr *,
struct proc *));
#ifdef INET6
static int tcp6_connect __P((struct tcpcb *, struct sockaddr *,
struct proc *));
#endif /* INET6 */
static struct tcpcb *
tcp_disconnect __P((struct tcpcb *));
static struct tcpcb *
@ -85,7 +102,7 @@ static struct tcpcb *
#define TCPDEBUG0 int ostate
#define TCPDEBUG1() ostate = tp ? tp->t_state : 0
#define TCPDEBUG2(req) if (tp && (so->so_options & SO_DEBUG)) \
tcp_trace(TA_USER, ostate, tp, 0, req)
tcp_trace(TA_USER, ostate, tp, 0, 0, req)
#else
#define TCPDEBUG0
#define TCPDEBUG1()
@ -197,6 +214,51 @@ tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
}
#ifdef INET6
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_BINDV6ONLY) == NULL) {
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);
}
#endif /* INET6 */
/*
* Prepare to accept connections.
*/
@ -216,6 +278,29 @@ tcp_usr_listen(struct socket *so, struct proc *p)
COMMON_END(PRU_LISTEN);
}
#ifdef INET6
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_BINDV6ONLY) == NULL)
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);
}
#endif /* INET6 */
/*
* Initiate connection to peer.
* Create a template for use in transmissions on this connection.
@ -252,6 +337,49 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
COMMON_END(PRU_CONNECT);
}
#ifdef INET6
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 (ip6_mapped_addr_on &&
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;
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);
}
#endif /* INET6 */
/*
* Initiate disconnect from peer.
* If connection never passed embryonic stage, just drop;
@ -294,6 +422,20 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam)
COMMON_END(PRU_ACCEPT);
}
#ifdef INET6
static int
tcp6_usr_accept(struct socket *so, struct sockaddr **nam)
{
int s = splnet();
int error = 0;
struct inpcb *inp = sotoinpcb(so);
struct tcpcb *tp;
COMMON_START();
in6_mapped_peeraddr(so, nam);
COMMON_END(PRU_ACCEPT);
}
#endif /* INET6 */
/*
* Mark the connection as being incapable of further output.
*/
@ -344,6 +486,9 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
int error = 0;
struct inpcb *inp = sotoinpcb(so);
struct tcpcb *tp;
#ifdef INET6
int isipv6;
#endif
TCPDEBUG0;
if (inp == NULL) {
@ -361,6 +506,9 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
TCPDEBUG1();
goto out;
}
#ifdef INET6
isipv6 = nam && nam->sa_family == AF_INET6;
#endif /* INET6 */
tp = intotcpcb(inp);
TCPDEBUG1();
if (control) {
@ -383,6 +531,11 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
* initialize maxseg/maxopd using peer's cached
* MSS.
*/
#ifdef INET6
if (isipv6)
error = tcp6_connect(tp, nam, p);
else
#endif /* INET6 */
error = tcp_connect(tp, nam, p);
if (error)
goto out;
@ -427,6 +580,11 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
* initialize maxseg/maxopd using peer's cached
* MSS.
*/
#ifdef INET6
if (isipv6)
error = tcp6_connect(tp, nam, p);
else
#endif /* INET6 */
error = tcp_connect(tp, nam, p);
if (error)
goto out;
@ -497,6 +655,16 @@ struct pr_usrreqs tcp_usrreqs = {
in_setsockaddr, sosend, soreceive, sopoll
};
#ifdef INET6
struct pr_usrreqs tcp6_usrreqs = {
tcp_usr_abort, tcp6_usr_accept, tcp_usr_attach, tcp6_usr_bind,
tcp6_usr_connect, pru_connect2_notsupp, in6_control, tcp_usr_detach,
tcp_usr_disconnect, tcp6_usr_listen, in6_mapped_peeraddr, tcp_usr_rcvd,
tcp_usr_rcvoob, tcp_usr_send, pru_sense_null, tcp_usr_shutdown,
in6_mapped_sockaddr, sosend, soreceive, sopoll
};
#endif /* INET6 */
/*
* 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
@ -595,6 +763,99 @@ tcp_connect(tp, nam, p)
return 0;
}
#ifdef INET6
static int
tcp6_connect(tp, nam, p)
register struct tcpcb *tp;
struct sockaddr *nam;
struct proc *p;
{
struct inpcb *inp = tp->t_inpcb, *oinp;
struct socket *so = inp->inp_socket;
struct tcpcb *otp;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
struct in6_addr *addr6;
struct rmxp_tao *taop;
struct rmxp_tao tao_noncached;
int error;
if (inp->inp_lport == 0) {
error = in6_pcbbind(inp, (struct sockaddr *)0, p);
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.
*/
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) {
if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
otp->t_state == TCPS_TIME_WAIT &&
(ticks - otp->t_starttime) < tcp_msl &&
(otp->t_flags & TF_RCVD_CC))
otp = tcp_close(otp);
else
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) != NULL)
inp->in6p_flowinfo = sin6->sin6_flowinfo;
in_pcbrehash(inp);
tp->t_template = tcp_template(tp);
if (tp->t_template == 0) {
in6_pcbdisconnect(inp);
return ENOBUFS;
}
/* Compute window scaling to request. */
while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
(TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
tp->request_r_scale++;
soisconnecting(so);
tcpstat.tcps_connattempt++;
tp->t_state = TCPS_SYN_SENT;
callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp);
tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
tcp_sendseqinit(tp);
/*
* Generate a CC value for this connection and
* check whether CC or CCnew should be used.
*/
if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {
taop = &tao_noncached;
bzero(taop, sizeof(*taop));
}
tp->cc_send = CC_INC(tcp_ccgen);
if (taop->tao_ccsent != 0 &&
CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
taop->tao_ccsent = tp->cc_send;
} else {
taop->tao_ccsent = 0;
tp->t_flags |= TF_SENDCCNEW;
}
return 0;
}
#endif /* INET6 */
/*
* The new sockopt interface makes it possible for us to block in the
* copyin/out step (if we take a page fault). Taking a page fault at
@ -619,6 +880,11 @@ tcp_ctloutput(so, sopt)
return (ECONNRESET);
}
if (sopt->sopt_level != IPPROTO_TCP) {
#ifdef INET6
if (INP_CHECK_SOCKAF(so, AF_INET6))
error = ip6_ctloutput(so, sopt);
else
#endif /* INET6 */
error = ip_ctloutput(so, sopt);
splx(s);
return (error);
@ -726,6 +992,9 @@ tcp_attach(so, p)
register struct tcpcb *tp;
struct inpcb *inp;
int error;
#ifdef INET6
int isipv6 = INP_CHECK_SOCKAF(so, AF_INET6) != NULL;
#endif
if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
error = soreserve(so, tcp_sendspace, tcp_recvspace);
@ -739,16 +1008,33 @@ tcp_attach(so, p)
#ifdef IPSEC
error = ipsec_init_policy(so, &inp->inp_sp);
if (error) {
#ifdef INET6
if (isipv6)
in6_pcbdetach(inp);
else
#endif
in_pcbdetach(inp);
return (error);
}
#endif /*IPSEC*/
#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 == 0) {
int nofd = so->so_state & SS_NOFDREF; /* XXX */
so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */
#ifdef INET6
if (isipv6)
in6_pcbdetach(inp);
else
#endif
in_pcbdetach(inp);
so->so_state |= nofd;
return (ENOBUFS);

View File

@ -40,14 +40,33 @@
* Kernel variables for tcp.
*/
/* TCP segment queue entry */
struct tseg_qent {
LIST_ENTRY(tseg_qent) tqe_q;
int tqe_len; /* TCP segment data length */
struct tcphdr *tqe_th; /* a pointer to tcp header */
struct mbuf *tqe_m; /* mbuf contains packet */
};
LIST_HEAD(tsegqe_head, tseg_qent);
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_TSEGQ);
#endif
struct tcptemp {
u_char tt_ipgen[40]; /* the size must be of max ip header, now IPv6 */
struct tcphdr tt_t;
};
#define tcp6cb tcpcb /* for KAME src sync over BSD*'s */
/*
* Tcp control block, one per tcp; fields:
* Organized for 16 byte cacheline efficiency.
*/
struct tcpcb {
struct mbuf *t_segq;
struct tsegqe_head t_segq;
int t_dupacks; /* consecutive dup acks recd */
struct tcpiphdr *t_template; /* skeletal packet for transmit */
struct tcptemp *t_template; /* skeletal packet for transmit */
struct callout *tt_rexmt; /* retransmit timer */
struct callout *tt_persist; /* retransmit persistence */
@ -369,17 +388,18 @@ struct tcpcb *
tcp_newtcpcb __P((struct inpcb *));
int tcp_output __P((struct tcpcb *));
void tcp_quench __P((struct inpcb *, int));
void tcp_respond __P((struct tcpcb *,
struct tcpiphdr *, struct mbuf *, tcp_seq, tcp_seq, int));
void tcp_respond __P((struct tcpcb *, void *,
struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int));
struct rtentry *
tcp_rtlookup __P((struct inpcb *));
void tcp_setpersist __P((struct tcpcb *));
void tcp_slowtimo __P((void));
struct tcpiphdr *
struct tcptemp *
tcp_template __P((struct tcpcb *));
struct tcpcb *
tcp_timers __P((struct tcpcb *, int));
void tcp_trace __P((int, int, struct tcpcb *, struct tcpiphdr *, int));
void tcp_trace __P((int, int, struct tcpcb *, void *, struct tcphdr *,
int));
extern struct pr_usrreqs tcp_usrreqs;
extern u_long tcp_sendspace;

View File

@ -71,6 +71,7 @@
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
@ -90,6 +91,7 @@
#include <netinet/in_var.h>
#include <netinet/in_systm.h>
#include <netinet6/ip6.h>
#include <netinet/ip_var.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
#include <netinet/in_pcb.h>
@ -211,7 +213,7 @@ in6_pcbbind(inp, nam, p)
return(EACCES);
if (so->so_cred->cr_uid != 0 &&
!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
t = in6_pcblookup_local(inp->inp_pcbinfo,
t = in6_pcblookup_local(pcbinfo,
&sin6->sin6_addr, lport,
INPLOOKUP_WILDCARD);
if (t &&
@ -222,11 +224,44 @@ in6_pcbbind(inp, nam, p)
(so->so_cred->cr_uid !=
t->inp_socket->so_cred->cr_uid))
return (EADDRINUSE);
if (ip6_mapped_addr_on != 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
in6_sin6_2_sin(&sin, sin6);
t = in_pcblookup_local(pcbinfo,
sin.sin_addr, lport,
INPLOOKUP_WILDCARD);
if (t &&
(so->so_cred->cr_uid !=
t->inp_socket->so_cred->cr_uid) &&
(ntohl(t->inp_laddr.s_addr) !=
INADDR_ANY ||
INP_SOCKAF(so) ==
INP_SOCKAF(t->inp_socket)))
return (EADDRINUSE);
}
}
t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr,
lport, wild);
if (t && (reuseport & t->inp_socket->so_options) == 0)
return(EADDRINUSE);
if (ip6_mapped_addr_on != 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
in6_sin6_2_sin(&sin, sin6);
t = in_pcblookup_local(pcbinfo, sin.sin_addr,
lport, wild);
if (t &&
(reuseport & t->inp_socket->so_options)
== 0 &&
(ntohl(t->inp_laddr.s_addr)
!= INADDR_ANY ||
INP_SOCKAF(so) ==
INP_SOCKAF(t->inp_socket)))
return (EADDRINUSE);
}
}
inp->in6p_laddr = sin6->sin6_addr;
}
@ -455,6 +490,12 @@ in6_pcbconnect(inp, nam, p)
* but if this line is missing, the garbage value remains.
*/
inp->in6p_flowinfo = sin6->sin6_flowinfo;
#ifdef INET6
if ((inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) == 0 &&
ip6_auto_flowlable != 0)
inp->in6p_flowinfo |=
(htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
#endif
in_pcbrehash(inp);
return (0);
@ -701,6 +742,14 @@ in6_pcbdetach(inp)
if (inp->in6p_route.ro_rt)
rtfree(inp->in6p_route.ro_rt);
ip6_freemoptions(inp->in6p_moptions);
/* Check and free IPv4 related resources in case of mapped addr */
if (inp->inp_options)
(void)m_free(inp->inp_options);
if (inp->inp_route.ro_rt)
rtfree(inp->inp_route.ro_rt);
ip_freemoptions(inp->inp_moptions);
inp->inp_vflag = 0;
zfreei(ipi->ipi_zone, inp);
}

View File

@ -64,6 +64,7 @@
* @(#)in_proto.c 8.1 (Berkeley) 6/10/93
*/
#include "opt_inet.h"
#include "opt_ipsec.h"
#include <sys/param.h>
@ -144,6 +145,16 @@ struct ip6protosw inet6sw[] = {
0, 0, 0, 0,
&udp6_usrreqs,
},
{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED | PR_WANTRCVD,
tcp6_input, 0, tcp6_ctlinput, tcp_ctloutput,
0,
#ifdef INET /* don't call timeout routines twice */
tcp_init, 0, 0, tcp_drain,
#else
tcp_init, 0, tcp_slowtimo, tcp_drain,
#endif
&tcp6_usrreqs,
},
{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC | PR_ADDR,
rip6_input, rip6_output, 0, rip6_ctloutput,
0,

View File

@ -69,6 +69,11 @@
#define _NETINET_TCP6_VAR_H_
#ifdef _KERNEL
#ifdef SYSCTL_DECL
SYSCTL_DECL(_net_inet6_tcp6);
#endif
extern int tcp_v6mssdflt; /* XXX */
struct ip6_hdr;
void tcp6_ctlinput __P((int, struct sockaddr *, void *));
@ -78,6 +83,6 @@ struct rtentry *tcp_rtlookup6 __P((struct inpcb *));
extern struct pr_usrreqs tcp6_usrreqs;
#endif
#endif /* _KERNEL */
#endif /* _NETINET_TCP6_VAR_H_ */

View File

@ -705,7 +705,6 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
inp = sotoinpcb(so);
if (inp == 0)
return EINVAL;
if (ip6_mapped_addr_on) {
struct sockaddr_in6 *sin6_p;
@ -727,22 +726,14 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
return error;
}
}
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
return EISCONN;
s = splnet();
error = in6_pcbconnect(inp, nam, p);
if (ip6_auto_flowlabel) {
inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
inp->in6p_flowinfo |=
(htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
}
splx(s);
if (error == 0) {
if (ip6_mapped_addr_on) { /* should be non mapped addr */
inp->inp_vflag &= ~INP_IPV4;
inp->inp_vflag |= INP_IPV6;
}
inp->inp_vflag &= ~INP_IPV4;
inp->inp_vflag |= INP_IPV6;
soisconnected(so);
}
return error;

View File

@ -1231,7 +1231,7 @@ nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp)
* try and leave leading space for the lower level headers.
*/
siz += RPC_REPLYSIZ;
if (siz >= MINCLSIZE) {
if ((max_hdr + siz) >= MINCLSIZE) {
MCLGET(mreq, M_WAIT);
} else
mreq->m_data += max_hdr;

View File

@ -1231,7 +1231,7 @@ nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp)
* try and leave leading space for the lower level headers.
*/
siz += RPC_REPLYSIZ;
if (siz >= MINCLSIZE) {
if ((max_hdr + siz) >= MINCLSIZE) {
MCLGET(mreq, M_WAIT);
} else
mreq->m_data += max_hdr;

View File

@ -1231,7 +1231,7 @@ nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp)
* try and leave leading space for the lower level headers.
*/
siz += RPC_REPLYSIZ;
if (siz >= MINCLSIZE) {
if ((max_hdr + siz) >= MINCLSIZE) {
MCLGET(mreq, M_WAIT);
} else
mreq->m_data += max_hdr;

View File

@ -1,8 +1,10 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# $FreeBSD$
PROG= trpt
MAN8= trpt.8
BINGRP= kmem
BINMODE=2555
CFLAGS+=-DINET6
.include <bsd.prog.mk>

View File

@ -60,6 +60,9 @@ static const char rcsid[] =
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#ifdef INET6
#include <netinet/ip6.h>
#endif
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#define TCPSTATES
@ -97,7 +100,7 @@ void dotrace __P((caddr_t));
void klseek __P((int, off_t, int));
int numeric __P((caddr_t *, caddr_t *));
void tcp_trace __P((short, short, struct tcpcb *, struct tcpcb *,
struct tcpiphdr *, int));
void *, struct tcphdr *, int));
static void usage __P((void));
int
@ -234,7 +237,7 @@ again: if (--tcp_debx < 0)
continue;
ntime = ntohl(td->td_time);
tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb,
&td->td_ti, td->td_req);
td->td_ipgen, &td->td_th, td->td_req);
if (i == tcp_debx)
goto done;
}
@ -244,7 +247,7 @@ again: if (--tcp_debx < 0)
continue;
ntime = ntohl(td->td_time);
tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb,
&td->td_ti, td->td_req);
td->td_ipgen, &td->td_th, td->td_req);
}
done: if (follow) {
prev_debx = tcp_debx + 1;
@ -270,31 +273,77 @@ done: if (follow) {
*/
/*ARGSUSED*/
void
tcp_trace(act, ostate, atp, tp, ti, req)
tcp_trace(act, ostate, atp, tp, ip, th, req)
short act, ostate;
struct tcpcb *atp, *tp;
struct tcpiphdr *ti;
void *ip;
struct tcphdr *th;
int req;
{
tcp_seq seq, ack;
int flags, len, win, timer;
struct ip *ip4;
#ifdef INET6
int isipv6, nopkt = 1;
struct ip6_hdr *ip6;
char ntop_buf[INET6_ADDRSTRLEN];
#endif
#ifdef INET6
switch (((struct ip *)ip)->ip_v) {
case 4:
nopkt = 0;
ip4 = (struct ip *)ip;
break;
case 6:
nopkt = 0;
isipv6 = 1;
ip6 = (struct ip6_hdr *)ip;
case 0:
default:
break;
}
#else
ip4 = (struct ip *)ip;
#endif
printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate],
tanames[act]);
switch (act) {
case TA_INPUT:
case TA_OUTPUT:
case TA_DROP:
#ifdef INET6
if (nopkt != 0)
break;
#endif
if (aflag) {
printf("(src=%s,%u, ",
inet_ntoa(ti->ti_src), ntohs(ti->ti_sport));
#ifdef INET6
isipv6
? inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf,
sizeof(ntop_buf)) :
#endif
inet_ntoa(ip4->ip_src),
ntohs(th->th_sport));
printf("dst=%s,%u)",
inet_ntoa(ti->ti_dst), ntohs(ti->ti_dport));
#ifdef INET6
isipv6
? inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf,
sizeof(ntop_buf)) :
#endif
inet_ntoa(ip4->ip_dst),
ntohs(th->th_dport));
}
seq = ti->ti_seq;
ack = ti->ti_ack;
len = ti->ti_len;
win = ti->ti_win;
seq = th->th_seq;
ack = th->th_ack;
len =
#ifdef INET6
isipv6 ? ip6->ip6_plen :
#endif
ip4->ip_len;
win = th->th_win;
if (act == TA_OUTPUT) {
seq = ntohl(seq);
ack = ntohl(ack);
@ -310,11 +359,11 @@ tcp_trace(act, ostate, atp, tp, ti, req)
printf("@%lx", ack);
if (win)
printf("(win=%x)", win);
flags = ti->ti_flags;
flags = th->th_flags;
if (flags) {
register char *cp = "<";
#define pf(flag, string) { \
if (ti->ti_flags&flag) { \
if (th->th_flags&flag) { \
(void)printf("%s%s", cp, string); \
cp = ","; \
} \