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:
parent
549f978ab6
commit
fb59c426ff
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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 = ","; \
|
||||
} \
|
||||
|
@ -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
@ -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
@ -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 ||
|
||||
|
@ -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);
|
||||
|
@ -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 ||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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 = ","; \
|
||||
} \
|
||||
|
Loading…
Reference in New Issue
Block a user