summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_input.c
diff options
context:
space:
mode:
authorderaadt <deraadt@openbsd.org>1999-01-11 02:01:34 +0000
committerderaadt <deraadt@openbsd.org>1999-01-11 02:01:34 +0000
commit8c2ac9d7537dc4e22408c4bd43910e65c031161e (patch)
tree0c7176ce45a39d81b60b95860a971a7c4ec3afb2 /sys/netinet/tcp_input.c
parentpanic prints a newline for you, don't do it in the panic string (diff)
downloadwireguard-openbsd-8c2ac9d7537dc4e22408c4bd43910e65c031161e.tar.xz
wireguard-openbsd-8c2ac9d7537dc4e22408c4bd43910e65c031161e.zip
netinet merge of NRL stuff. some indent and shrinkage needed; NRL/cmetz
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r--sys/netinet/tcp_input.c761
1 files changed, 547 insertions, 214 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index e08dd29ed12..2b368b72ebd 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.23 1999/01/07 06:05:04 deraadt Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.24 1999/01/11 02:01:35 deraadt Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -36,6 +36,18 @@
* @(#)tcp_input.c 8.5 (Berkeley) 4/10/94
*/
+/*
+%%% portions-copyright-nrl-95
+Portions of this software are Copyright 1995-1998 by Randall Atkinson,
+Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights
+Reserved. All rights under this copyright have been assigned to the US
+Naval Research Laboratory (NRL). The NRL Copyright Notice and License
+Agreement Version 1.1 (January 17, 1995) applies to these portions of the
+software.
+You should have received a copy of the license with this software. If you
+didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
+*/
+
#ifndef TUBA_INCLUDE
#include <sys/param.h>
#include <sys/systm.h>
@@ -65,6 +77,22 @@
#include <machine/stdarg.h>
#include <sys/md5k.h>
+#ifdef INET6
+#include <sys/domain.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/ipv6.h>
+#include <netinet6/ipv6_var.h>
+#include <netinet6/tcpipv6.h>
+
+struct tcpiphdr tcp_saveti;
+struct tcpipv6hdr tcp_saveti6;
+
+/* for the packet header length in the mbuf */
+#define M_PH_LEN(m) (((struct mbuf *)(m))->m_pkthdr.len)
+#define M_V6_LEN(m) (M_PH_LEN(m) - sizeof(struct ipv6))
+#define M_V4_LEN(m) (M_PH_LEN(m) - sizeof(struct ip))
+#endif /* INET6 */
+
int tcprexmtthresh = 3;
struct tcpiphdr tcp_saveti;
int tcptv_keep_init = TCPTV_KEEP_INIT;
@@ -203,42 +231,25 @@ tck_chkcookie(ti)
* Set DELACK for segments received in order, but ack immediately
* when segments are out of order (so fast retransmit can work).
*/
-#define TCP_REASS(tp, ti, m, so, flags) { \
- if ((ti)->ti_seq == (tp)->rcv_nxt && \
- (tp)->segq.lh_first == NULL && \
- (tp)->t_state == TCPS_ESTABLISHED) { \
- if ((ti)->ti_flags & TH_PUSH) \
- tp->t_flags |= TF_ACKNOW; \
- else \
- tp->t_flags |= TF_DELACK; \
- (tp)->rcv_nxt += (ti)->ti_len; \
- flags = (ti)->ti_flags & TH_FIN; \
- tcpstat.tcps_rcvpack++;\
- tcpstat.tcps_rcvbyte += (ti)->ti_len;\
- sbappend(&(so)->so_rcv, (m)); \
- sorwakeup(so); \
- } else { \
- (flags) = tcp_reass((tp), (ti), (m)); \
- tp->t_flags |= TF_ACKNOW; \
- } \
-}
+
#ifndef TUBA_INCLUDE
int
-tcp_reass(tp, ti, m)
+tcp_reass(tp, th, m, tlen)
register struct tcpcb *tp;
- register struct tcpiphdr *ti;
+ register struct tcphdr *th;
struct mbuf *m;
+ int *tlen;
{
register struct ipqent *p, *q, *nq, *tiqe;
struct socket *so = tp->t_inpcb->inp_socket;
int flags;
/*
- * Call with ti==0 after become established to
+ * Call with th==0 after become established to
* force pre-ESTABLISHED data up to user socket.
*/
- if (ti == 0)
+ if (th == 0)
goto present;
/*
@@ -257,7 +268,7 @@ tcp_reass(tp, ti, m)
*/
for (p = NULL, q = tp->segq.lh_first; q != NULL;
p = q, q = q->ipqe_q.le_next)
- if (SEQ_GT(q->ipqe_tcp->ti_seq, ti->ti_seq))
+ if (SEQ_GT(q->ipqe_tcp->th_seq, th->th_seq))
break;
/*
@@ -266,40 +277,40 @@ tcp_reass(tp, ti, m)
* segment. If it provides all of our data, drop us.
*/
if (p != NULL) {
- register struct tcpiphdr *phdr = p->ipqe_tcp;
+ register struct tcphdr *phdr = p->ipqe_tcp;
register int i;
/* conversion to int (in i) handles seq wraparound */
- i = phdr->ti_seq + phdr->ti_len - ti->ti_seq;
+ i = phdr->th_seq + phdr->th_reseqlen - th->th_seq;
if (i > 0) {
- if (i >= ti->ti_len) {
+ if (i >= *tlen) {
tcpstat.tcps_rcvduppack++;
- tcpstat.tcps_rcvdupbyte += ti->ti_len;
+ tcpstat.tcps_rcvdupbyte += *tlen;
m_freem(m);
FREE(tiqe, M_IPQ);
return (0);
}
m_adj(m, i);
- ti->ti_len -= i;
- ti->ti_seq += i;
+ *tlen -= i;
+ th->th_seq += i;
}
}
tcpstat.tcps_rcvoopack++;
- tcpstat.tcps_rcvoobyte += ti->ti_len;
+ tcpstat.tcps_rcvoobyte += *tlen;
/*
* While we overlap succeeding segments trim them or,
* if they are completely covered, dequeue them.
*/
for (; q != NULL; q = nq) {
- register struct tcpiphdr *qhdr = q->ipqe_tcp;
- register int i = (ti->ti_seq + ti->ti_len) - qhdr->ti_seq;
+ register struct tcphdr *qhdr = q->ipqe_tcp;
+ register int i = (th->th_seq + *tlen) - qhdr->th_seq;
if (i <= 0)
break;
- if (i < qhdr->ti_len) {
- qhdr->ti_seq += i;
- qhdr->ti_len -= i;
+ if (i < qhdr->th_reseqlen) {
+ qhdr->th_seq += i;
+ qhdr->th_reseqlen -= i;
m_adj(q->ipqe_m, i);
break;
}
@@ -311,7 +322,8 @@ tcp_reass(tp, ti, m)
/* Insert the new fragment queue entry into place. */
tiqe->ipqe_m = m;
- tiqe->ipqe_tcp = ti;
+ th->th_reseqlen = *tlen;
+ tiqe->ipqe_tcp = th;
if (p == NULL) {
LIST_INSERT_HEAD(&tp->segq, tiqe, ipqe_q);
} else {
@@ -326,13 +338,13 @@ present:
if (TCPS_HAVEESTABLISHED(tp->t_state) == 0)
return (0);
q = tp->segq.lh_first;
- if (q == NULL || q->ipqe_tcp->ti_seq != tp->rcv_nxt)
+ if (q == NULL || q->ipqe_tcp->th_seq != tp->rcv_nxt)
return (0);
- if (tp->t_state == TCPS_SYN_RECEIVED && q->ipqe_tcp->ti_len)
+ if (tp->t_state == TCPS_SYN_RECEIVED && q->ipqe_tcp->th_reseqlen)
return (0);
do {
- tp->rcv_nxt += q->ipqe_tcp->ti_len;
- flags = q->ipqe_tcp->ti_flags & TH_FIN;
+ tp->rcv_nxt += q->ipqe_tcp->th_reseqlen;
+ flags = q->ipqe_tcp->th_flags & TH_FIN;
nq = q->ipqe_q.le_next;
LIST_REMOVE(q, ipqe_q);
@@ -342,7 +354,7 @@ present:
sbappend(&so->so_rcv, q->ipqe_m);
FREE(q, M_IPQ);
q = nq;
- } while (q != NULL && q->ipqe_tcp->ti_seq == tp->rcv_nxt);
+ } while (q != NULL && q->ipqe_tcp->th_seq == tp->rcv_nxt);
sorwakeup(so);
return (flags);
}
@@ -424,31 +436,87 @@ tcp_input(m, va_alist)
int ts_present = 0;
int iphlen;
va_list ap;
+ register struct tcphdr *th;
+#ifdef INET6
+ struct in6_addr laddr6;
+ unsigned short is_ipv6; /* Type of incoming datagram. */
+ struct ipv6 *ipv6 = NULL;
+#endif /* INET6 */
va_start(ap, m);
iphlen = va_arg(ap, int);
va_end(ap);
tcpstat.tcps_rcvtotal++;
+
+#ifdef INET6
+ /*
+ * Before we do ANYTHING, we have to figure out if it's TCP/IPv6 or
+ * TCP/IPv4.
+ */
+ is_ipv6 = mtod(m, struct ip *)->ip_v == 6;
+#endif /* INET6 */
+
/*
* Get IP and TCP header together in first mbuf.
* Note: IP leaves IP header in first mbuf.
*/
+#ifndef INET6
ti = mtod(m, struct tcpiphdr *);
+#else /* INET6 */
+ if (!is_ipv6)
+#endif /* INET6 */
if (iphlen > sizeof (struct ip))
ip_stripoptions(m, (struct mbuf *)0);
- if (m->m_len < sizeof (struct tcpiphdr)) {
- if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) {
+ if (m->m_len < iphlen + sizeof(struct tcphdr)) {
+ if ((m = m_pullup2(m, iphlen + sizeof(struct tcphdr))) == 0) {
tcpstat.tcps_rcvshort++;
return;
}
+#ifndef INET6
ti = mtod(m, struct tcpiphdr *);
+#endif /* INET6 */
}
+ tlen = m->m_pkthdr.len - iphlen;
+
+#ifdef INET6
+ /*
+ * After that, do initial segment processing which is still very
+ * dependent on what IP version you're using.
+ */
+
+ if (is_ipv6) {
+#ifdef DIAGNOSTIC
+ if (iphlen < sizeof(struct ipv6)) {
+ m_freem(m);
+ return;
+ }
+#endif /* DIAGNOSTIC */
+
+ /* strip off any options */
+ if (iphlen > sizeof(struct ipv6)) {
+ ipv6_stripoptions(m, iphlen);
+ iphlen = sizeof(struct ipv6);
+ }
+
+ ti = NULL;
+ ipv6 = mtod(m, struct ipv6 *);
+
+ if (in6_cksum(m, IPPROTO_TCP, tlen, sizeof(struct ipv6))) {
+ tcpstat.tcps_rcvbadsum++;
+ goto drop;
+ } /* endif in6_cksum */
+ } else {
+ ti = mtod(m, struct tcpiphdr *);
+#endif /* INET6 */
+
/*
* Checksum extended TCP header and data.
*/
+#ifndef INET6
tlen = ((struct ip *)ti)->ip_len;
+#endif /* INET6 */
len = sizeof (struct ip) + tlen;
bzero(ti->ti_x1, sizeof ti->ti_x1);
ti->ti_len = (u_int16_t)tlen;
@@ -457,29 +525,39 @@ tcp_input(m, va_alist)
tcpstat.tcps_rcvbadsum++;
goto drop;
}
+#ifdef INET6
+ }
+#endif /* INET6 */
#endif /* TUBA_INCLUDE */
+ th = (struct tcphdr *)(mtod(m, caddr_t) + iphlen);
+
/*
* Check that TCP offset makes sense,
* pull out TCP options and adjust length. XXX
*/
- off = ti->ti_off << 2;
+ off = th->th_off << 2;
if (off < sizeof (struct tcphdr) || off > tlen) {
tcpstat.tcps_rcvbadoff++;
goto drop;
}
tlen -= off;
- ti->ti_len = tlen;
if (off > sizeof (struct tcphdr)) {
- if (m->m_len < sizeof(struct ip) + off) {
- if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) {
+ if (m->m_len < iphlen + off) {
+ if ((m = m_pullup2(m, iphlen + off)) == 0) {
tcpstat.tcps_rcvshort++;
return;
}
+#ifdef INET6
+ if (is_ipv6)
+ ipv6 = mtod(m, struct ipv6 *);
+ else
+#endif /* INET6 */
ti = mtod(m, struct tcpiphdr *);
+ th = (struct tcphdr *)(mtod(m, caddr_t) + iphlen);
}
optlen = off - sizeof (struct tcphdr);
- optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
+ optp = mtod(m, caddr_t) + iphlen + sizeof(struct tcphdr);
/*
* Do quick retrieval of timestamp options ("options
* prediction?"). If timestamp is the only option and it's
@@ -491,22 +569,22 @@ tcp_input(m, va_alist)
(optlen > TCPOLEN_TSTAMP_APPA &&
optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) &&
*(u_int32_t *)optp == htonl(TCPOPT_TSTAMP_HDR) &&
- (ti->ti_flags & TH_SYN) == 0) {
+ (th->th_flags & TH_SYN) == 0) {
ts_present = 1;
ts_val = ntohl(*(u_int32_t *)(optp + 4));
ts_ecr = ntohl(*(u_int32_t *)(optp + 8));
optp = NULL; /* we've parsed the options */
}
}
- tiflags = ti->ti_flags;
+ tiflags = th->th_flags;
/*
* Convert TCP protocol specific fields to host format.
*/
- NTOHL(ti->ti_seq);
- NTOHL(ti->ti_ack);
- NTOHS(ti->ti_win);
- NTOHS(ti->ti_urp);
+ NTOHL(th->th_seq);
+ NTOHL(th->th_ack);
+ NTOHS(th->th_win);
+ NTOHS(th->th_urp);
#ifdef TCPCOOKIE
/*
@@ -515,7 +593,11 @@ tcp_input(m, va_alist)
* of the packet to the friends list.
*/
+#ifdef INET6
+ if (!is_ipv6 && (tiflags & TH_RST) && (ntohs(th->th_dport) == TCK_PORT))
+#else /* INET6 */
if ((tiflags & TH_RST) && (ntohs(ti->ti_dport) == TCK_PORT))
+#endif /* INET6 */
if (tck_chkcookie(ti))
goto drop; /* RST is no longer needed */
#endif /* TCPCOOKIE */
@@ -524,10 +606,23 @@ tcp_input(m, va_alist)
* Locate pcb for segment.
*/
findpcb:
+#ifdef INET6
+ if (is_ipv6) {
+ inp = in6_pcbhashlookup(&tcbtable, &ipv6->ipv6_src, th->th_sport,
+ &ipv6->ipv6_dst, th->th_dport);
+ } else
+#endif /* INET6 */
inp = in_pcbhashlookup(&tcbtable, ti->ti_src, ti->ti_sport,
ti->ti_dst, ti->ti_dport);
if (inp == 0) {
++tcpstat.tcps_pcbhashmiss;
+#ifdef INET6
+ if (is_ipv6)
+ inp = in_pcblookup(&tcbtable, &ipv6->ipv6_src,
+ th->th_sport, &ipv6->ipv6_dst, th->th_dport,
+ INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
+ else
+#endif /* INET6 */
inp = in_pcblookup(&tcbtable, &ti->ti_src, ti->ti_sport,
&ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD);
/*
@@ -550,14 +645,19 @@ findpcb:
/* Unscale the window into a 32-bit value. */
if ((tiflags & TH_SYN) == 0)
- tiwin = ti->ti_win << tp->snd_scale;
+ tiwin = th->th_win << tp->snd_scale;
else
- tiwin = ti->ti_win;
+ tiwin = th->th_win;
so = inp->inp_socket;
if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {
if (so->so_options & SO_DEBUG) {
ostate = tp->t_state;
+#ifdef INET6
+ if (is_ipv6)
+ tcp_saveti6 = *(mtod(m, struct tcpipv6hdr *));
+ else
+#endif /* INET6 */
tcp_saveti = *ti;
}
if (so->so_options & SO_ACCEPTCONN) {
@@ -565,7 +665,7 @@ findpcb:
so1 = sonewconn(so, 0);
if (so1 == NULL) {
- tcpdropoldhalfopen(tp, ti->ti_dport);
+ tcpdropoldhalfopen(tp, th->th_dport);
so1 = sonewconn(so, 0);
if (so1 == NULL)
goto drop;
@@ -583,13 +683,60 @@ findpcb:
* we're committed to it below in TCPS_LISTEN.
*/
dropsocket++;
+#ifdef INET6
+ /*
+ * inp still has the OLD in_pcb stuff, set the
+ * v6-related flags on the new guy, too. This is
+ * done particularly for the case where an AF_INET6
+ * socket is bound only to a port, and a v4 connection
+ * comes in on that port.
+ * we also copy the flowinfo from the original pcb
+ * to the new one.
+ */
+ {
+ int flags = inp->inp_flags;
+ struct inpcb *oldinpcb = inp;
+
+ inp = (struct inpcb *)so->so_pcb;
+ inp->inp_flags |= (flags & (INP_IPV6 | INP_IPV6_UNDEC
+ | INP_IPV6_MAPPED));
+ if ((inp->inp_flags & INP_IPV6) &&
+ !(inp->inp_flags & INP_IPV6_MAPPED)) {
+ inp->inp_ipv6.ipv6_hoplimit =
+ oldinpcb->inp_ipv6.ipv6_hoplimit;
+ inp->inp_ipv6.ipv6_versfl =
+ oldinpcb->inp_ipv6.ipv6_versfl;
+ }
+ }
+#else /* INET6 */
inp = (struct inpcb *)so->so_pcb;
- inp->inp_laddr = ti->ti_dst;
- inp->inp_lport = ti->ti_dport;
+#endif /* INET6 */
+ inp->inp_lport = th->th_dport;
+#ifdef INET6
+ if (is_ipv6) {
+ inp->inp_laddr6 = ipv6->ipv6_dst;
+ inp->inp_fflowinfo = htonl(0x0fffffff) &
+ ipv6->ipv6_versfl;
+
+ /*inp->inp_options = ipv6_srcroute();*/ /* soon. */
+ /* still need to tweak outbound options
+ processing to include this mbuf in
+ the right place and put the correct
+ NextHdr values in the right places.
+ XXX rja */
+ } else {
+ if (inp->inp_flags & INP_IPV6) {/* v4 to v6 socket */
+ CREATE_IPV6_MAPPED(inp->inp_laddr6,
+ ti->ti_dst.s_addr);
+ } else {
+#endif /* INET6 */
+ inp->inp_laddr = ti->ti_dst;
+ inp->inp_options = ip_srcroute();
+#if INET6
+ }
+ };
+#endif /* INET6 */
in_pcbrehash(inp);
-#if BSD>=43
- inp->inp_options = ip_srcroute();
-#endif
tp = intotcpcb(inp);
tp->t_state = TCPS_LISTEN;
@@ -611,7 +758,7 @@ findpcb:
#ifdef TCP_SACK
if (!tp->sack_disable)
- tcp_del_sackholes(tp, ti); /* Delete stale SACK holes */
+ tcp_del_sackholes(tp, th); /* Delete stale SACK holes */
#endif /* TCP_SACK */
/*
@@ -619,13 +766,13 @@ findpcb:
* else do it below (after getting remote address).
*/
if (optp && tp->t_state != TCPS_LISTEN)
- tcp_dooptions(tp, optp, optlen, ti,
+ tcp_dooptions(tp, optp, optlen, th,
&ts_present, &ts_val, &ts_ecr);
#ifdef TCP_SACK
if (!tp->sack_disable) {
- tp->rcv_laststart = ti->ti_seq; /* last rec'vd segment*/
- tp->rcv_lastend = ti->ti_seq + ti->ti_len;
+ tp->rcv_laststart = th->th_seq; /* last rec'vd segment*/
+ tp->rcv_lastend = th->th_seq + tlen;
}
#endif /* TCP_SACK */
/*
@@ -645,7 +792,7 @@ findpcb:
if (tp->t_state == TCPS_ESTABLISHED &&
(tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
(!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) &&
- ti->ti_seq == tp->rcv_nxt &&
+ th->th_seq == tp->rcv_nxt &&
tiwin && tiwin == tp->snd_wnd &&
tp->snd_nxt == tp->snd_max) {
@@ -654,14 +801,14 @@ findpcb:
* record the timestamp.
* Fix from Braden, see Stevens p. 870
*/
- if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent)) {
+ if (ts_present && SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
tp->ts_recent_age = tcp_now;
tp->ts_recent = ts_val;
}
- if (ti->ti_len == 0) {
- if (SEQ_GT(ti->ti_ack, tp->snd_una) &&
- SEQ_LEQ(ti->ti_ack, tp->snd_max) &&
+ if (tlen == 0) {
+ if (SEQ_GT(th->th_ack, tp->snd_una) &&
+ SEQ_LEQ(th->th_ack, tp->snd_max) &&
tp->snd_cwnd >= tp->snd_wnd &&
tp->t_dupacks == 0) {
/*
@@ -671,13 +818,13 @@ findpcb:
if (ts_present)
tcp_xmit_timer(tp, tcp_now-ts_ecr+1);
else if (tp->t_rtt &&
- SEQ_GT(ti->ti_ack, tp->t_rtseq))
+ SEQ_GT(th->th_ack, tp->t_rtseq))
tcp_xmit_timer(tp, tp->t_rtt);
- acked = ti->ti_ack - tp->snd_una;
+ acked = th->th_ack - tp->snd_una;
tcpstat.tcps_rcvackpack++;
tcpstat.tcps_rcvackbyte += acked;
sbdrop(&so->so_snd, acked);
- tp->snd_una = ti->ti_ack;
+ tp->snd_una = th->th_ack;
#if defined(TCP_SACK) && defined(TCP_FACK)
tp->snd_fack = tp->snd_una;
tp->retran_data = 0;
@@ -704,11 +851,11 @@ findpcb:
(void) tcp_output(tp);
return;
}
- } else if (ti->ti_ack == tp->snd_una &&
+ } else if (th->th_ack == tp->snd_una &&
tp->segq.lh_first == NULL &&
- ti->ti_len <= sbspace(&so->so_rcv)) {
+ tlen <= sbspace(&so->so_rcv)) {
/*
- * this is a pure, in-sequence data packet
+ * This is a pure, in-sequence data packet
* with nothing on the reassembly queue and
* we have enough buffer space to take it.
*/
@@ -718,18 +865,18 @@ findpcb:
tcp_clean_sackreport(tp);
#endif /* TCP_SACK */
++tcpstat.tcps_preddat;
- tp->rcv_nxt += ti->ti_len;
+ tp->rcv_nxt += tlen;
tcpstat.tcps_rcvpack++;
- tcpstat.tcps_rcvbyte += ti->ti_len;
+ tcpstat.tcps_rcvbyte += tlen;
/*
* Drop TCP, IP headers and TCP options then add data
* to socket buffer.
*/
- m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
- m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+ m->m_data += iphlen + off;
+ m->m_len -= iphlen + off;
sbappend(&so->so_rcv, m);
sorwakeup(so);
- if (ti->ti_flags & TH_PUSH)
+ if (th->th_flags & TH_PUSH)
tp->t_flags |= TF_ACKNOW;
else
tp->t_flags |= TF_DELACK;
@@ -740,8 +887,8 @@ findpcb:
/*
* Drop TCP, IP headers and TCP options.
*/
- m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
- m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+ m->m_data += iphlen + off;
+ m->m_len -= iphlen + off;
/*
* Calculate amount of space in receive window,
@@ -776,6 +923,9 @@ findpcb:
case TCPS_LISTEN: {
struct mbuf *am;
register struct sockaddr_in *sin;
+#ifdef INET6
+ register struct sockaddr_in6 *sin6;
+#endif /* INET6 */
if (tiflags & TH_RST)
goto drop;
@@ -783,9 +933,19 @@ findpcb:
goto dropwithreset;
if ((tiflags & TH_SYN) == 0)
goto drop;
- if ((ti->ti_dport == ti->ti_sport) &&
- (ti->ti_dst.s_addr == ti->ti_src.s_addr))
- goto drop;
+ if (th->th_dport == th->th_sport) {
+#ifdef INET6
+ if (is_ipv6) {
+ if (IN6_ARE_ADDR_EQUAL(&ipv6->ipv6_src, &ipv6->ipv6_dst))
+ goto drop;
+ } else {
+#endif /* INET6 */
+ if (ti->ti_dst.s_addr == ti->ti_src.s_addr)
+ goto drop;
+#ifdef INET6
+ }
+#endif /* INET6 */
+ }
#ifdef TCPCOOKIE
/*
@@ -811,12 +971,91 @@ findpcb:
* in_broadcast() should never return true on a received
* packet with M_BCAST not set.
*/
- if (m->m_flags & (M_BCAST|M_MCAST) ||
- IN_MULTICAST(ti->ti_dst.s_addr))
+ if (m->m_flags & (M_BCAST|M_MCAST))
+ goto drop;
+#ifdef INET6
+ if (is_ipv6) {
+ /* XXX What about IPv6 Anycasting ?? :-( rja */
+ if (IN6_IS_ADDR_MULTICAST(&ipv6->ipv6_dst))
+ goto drop;
+ } else
+#endif /* INET6 */
+ if (IN_MULTICAST(ntohl(ti->ti_dst.s_addr)))
goto drop;
am = m_get(M_DONTWAIT, MT_SONAME); /* XXX */
if (am == NULL)
goto drop;
+#ifdef INET6
+ if (is_ipv6) {
+ /*
+ * This is probably the place to set the tp->pf value.
+ * (Don't forget to do it in the v4 code as well!)
+ *
+ * Also, remember to blank out things like flowlabel, or
+ * set flowlabel for accepted sockets in v6.
+ *
+ * FURTHERMORE, this is PROBABLY the place where the whole
+ * business of key munging is set up for passive
+ * connections.
+ */
+ am->m_len = sizeof(struct sockaddr_in6);
+ sin6 = mtod(am, struct sockaddr_in6 *);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
+ sin6->sin6_addr = ipv6->ipv6_src;
+ sin6->sin6_port = th->th_sport;
+ sin6->sin6_flowinfo = htonl(0x0fffffff) &
+ inp->inp_ipv6.ipv6_versfl;
+ laddr6 = inp->inp_laddr6;
+ if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
+ inp->inp_laddr6 = ipv6->ipv6_dst;
+ /* This is a good optimization. */
+ if (in6_pcbconnect(inp, am)) {
+ inp->inp_laddr6 = laddr6;
+ (void) m_free(am);
+ goto drop;
+ } /* endif in6_pcbconnect() */
+ tp->pf = PF_INET6;
+ } else {
+ /*
+ * Letting v4 incoming datagrams to reach valid
+ * PF_INET6 sockets causes some overhead here.
+ */
+ if (inp->inp_flags & INP_IPV6) {
+ if (!(inp->inp_flags & (INP_IPV6_UNDEC|INP_IPV6_MAPPED))) {
+ (void) m_free(am);
+ goto drop;
+ }
+
+ am->m_len = sizeof(struct sockaddr_in6);
+
+ sin6 = mtod(am, struct sockaddr_in6 *);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(*sin6);
+ CREATE_IPV6_MAPPED(sin6->sin6_addr, ti->ti_src.s_addr);
+ sin6->sin6_port = th->th_sport;
+ sin6->sin6_flowinfo = 0;
+
+ laddr6 = inp->inp_laddr6;
+ if (inp->inp_laddr.s_addr == INADDR_ANY)
+ CREATE_IPV6_MAPPED(inp->inp_laddr6, ti->ti_dst.s_addr);
+
+ /*
+ * The pcb initially has the v6 default hoplimit
+ * set. We're sending v4 packets so we need to set
+ * the v4 ttl and tos.
+ */
+ inp->inp_ip.ip_ttl = ip_defttl;
+ inp->inp_ip.ip_tos = 0;
+
+ if (in6_pcbconnect(inp, am)) {
+ inp->inp_laddr6 = laddr6;
+ (void) m_freem(am);
+ goto drop;
+ }
+ tp->pf = PF_INET;
+ } else {
+#endif /* INET6 */
am->m_len = sizeof (struct sockaddr_in);
sin = mtod(am, struct sockaddr_in *);
sin->sin_family = AF_INET;
@@ -833,6 +1072,10 @@ findpcb:
goto drop;
}
(void) m_free(am);
+#ifdef INET6
+ } /* if (inp->inp_flags & INP_IPV6) */
+ } /* if (is_ipv6) */
+#endif /* INET6 */
tp->t_template = tcp_template(tp);
if (tp->t_template == 0) {
tp = tcp_drop(tp, ENOBUFS);
@@ -840,7 +1083,7 @@ findpcb:
goto drop;
}
if (optp)
- tcp_dooptions(tp, optp, optlen, ti,
+ tcp_dooptions(tp, optp, optlen, th,
&ts_present, &ts_val, &ts_ecr);
#ifdef TCP_SACK
/*
@@ -862,7 +1105,7 @@ findpcb:
#else /* TCP_COMPAT_42 */
tcp_iss += arc4random() % (TCP_ISSINCR / 2) + 1;
#endif /* !TCP_COMPAT_42 */
- tp->irs = ti->ti_seq;
+ tp->irs = th->th_seq;
tcp_sendseqinit(tp);
#if defined (TCP_SACK) || defined (TCP_NEWRENO)
tp->snd_last = tp->snd_una;
@@ -893,8 +1136,8 @@ findpcb:
tcpstat.tcps_badsyn++;
goto dropwithreset;
}
- if (SEQ_LEQ(ti->ti_ack, tp->snd_una) ||
- SEQ_GT(ti->ti_ack, tp->snd_max))
+ if (SEQ_LEQ(th->th_ack, tp->snd_una) ||
+ SEQ_GT(th->th_ack, tp->snd_max))
goto dropwithreset;
}
break;
@@ -913,8 +1156,8 @@ findpcb:
*/
case TCPS_SYN_SENT:
if ((tiflags & TH_ACK) &&
- (SEQ_LEQ(ti->ti_ack, tp->iss) ||
- SEQ_GT(ti->ti_ack, tp->snd_max)))
+ (SEQ_LEQ(th->th_ack, tp->iss) ||
+ SEQ_GT(th->th_ack, tp->snd_max)))
goto dropwithreset;
if (tiflags & TH_RST) {
if (tiflags & TH_ACK)
@@ -924,12 +1167,12 @@ findpcb:
if ((tiflags & TH_SYN) == 0)
goto drop;
if (tiflags & TH_ACK) {
- tp->snd_una = ti->ti_ack;
+ tp->snd_una = th->th_ack;
if (SEQ_LT(tp->snd_nxt, tp->snd_una))
tp->snd_nxt = tp->snd_una;
}
tp->t_timer[TCPT_REXMT] = 0;
- tp->irs = ti->ti_seq;
+ tp->irs = th->th_seq;
tcp_rcvseqinit(tp);
tp->t_flags |= TF_ACKNOW;
#ifdef TCP_SACK
@@ -952,8 +1195,8 @@ findpcb:
tp->snd_scale = tp->requested_s_scale;
tp->rcv_scale = tp->request_r_scale;
}
- (void) tcp_reass(tp, (struct tcpiphdr *)0,
- (struct mbuf *)0);
+ (void) tcp_reass(tp, (struct tcphdr *)0,
+ (struct mbuf *)0, &tlen);
/*
* if we didn't have to retransmit the SYN,
* use its rtt as our initial srtt & rtt var.
@@ -978,17 +1221,17 @@ trimthenstep6:
* If data, trim to stay within window,
* dropping FIN if necessary.
*/
- ti->ti_seq++;
- if (ti->ti_len > tp->rcv_wnd) {
- todrop = ti->ti_len - tp->rcv_wnd;
+ th->th_seq++;
+ if (tlen > tp->rcv_wnd) {
+ todrop = tlen - tp->rcv_wnd;
m_adj(m, -todrop);
- ti->ti_len = tp->rcv_wnd;
+ tlen = tp->rcv_wnd;
tiflags &= ~TH_FIN;
tcpstat.tcps_rcvpackafterwin++;
tcpstat.tcps_rcvbyteafterwin += todrop;
}
- tp->snd_wl1 = ti->ti_seq - 1;
- tp->rcv_up = ti->ti_seq;
+ tp->snd_wl1 = th->th_seq - 1;
+ tp->rcv_up = th->th_seq;
goto step6;
}
@@ -1021,25 +1264,25 @@ trimthenstep6:
tp->ts_recent = 0;
} else {
tcpstat.tcps_rcvduppack++;
- tcpstat.tcps_rcvdupbyte += ti->ti_len;
+ tcpstat.tcps_rcvdupbyte += tlen;
tcpstat.tcps_pawsdrop++;
goto dropafterack;
}
}
- todrop = tp->rcv_nxt - ti->ti_seq;
+ todrop = tp->rcv_nxt - th->th_seq;
if (todrop > 0) {
if (tiflags & TH_SYN) {
tiflags &= ~TH_SYN;
- ti->ti_seq++;
- if (ti->ti_urp > 1)
- ti->ti_urp--;
+ th->th_seq++;
+ if (th->th_urp > 1)
+ th->th_urp--;
else
tiflags &= ~TH_URG;
todrop--;
}
- if (todrop >= ti->ti_len ||
- (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) {
+ if (todrop >= tlen ||
+ (todrop == tlen && (tiflags & TH_FIN) == 0)) {
/*
* Any valid FIN must be to the left of the
* window. At this point, FIN must be a
@@ -1051,20 +1294,20 @@ trimthenstep6:
* but keep on processing for RST or ACK.
*/
tp->t_flags |= TF_ACKNOW;
- tcpstat.tcps_rcvdupbyte += todrop = ti->ti_len;
+ tcpstat.tcps_rcvdupbyte += todrop = tlen;
tcpstat.tcps_rcvduppack++;
} else {
tcpstat.tcps_rcvpartduppack++;
tcpstat.tcps_rcvpartdupbyte += todrop;
}
m_adj(m, todrop);
- ti->ti_seq += todrop;
- ti->ti_len -= todrop;
- if (ti->ti_urp > todrop)
- ti->ti_urp -= todrop;
+ th->th_seq += todrop;
+ tlen -= todrop;
+ if (th->th_urp > todrop)
+ th->th_urp -= todrop;
else {
tiflags &= ~TH_URG;
- ti->ti_urp = 0;
+ th->th_urp = 0;
}
}
@@ -1073,7 +1316,7 @@ trimthenstep6:
* user processes are gone, then RST the other end.
*/
if ((so->so_state & SS_NOFDREF) &&
- tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {
+ tp->t_state > TCPS_CLOSE_WAIT && tlen) {
tp = tcp_close(tp);
tcpstat.tcps_rcvafterclose++;
goto dropwithreset;
@@ -1083,11 +1326,11 @@ trimthenstep6:
* If segment ends after window, drop trailing data
* (and PUSH and FIN); if nothing left, just ACK.
*/
- todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
+ todrop = (th->th_seq + tlen) - (tp->rcv_nxt+tp->rcv_wnd);
if (todrop > 0) {
tcpstat.tcps_rcvpackafterwin++;
- if (todrop >= ti->ti_len) {
- tcpstat.tcps_rcvbyteafterwin += ti->ti_len;
+ if (todrop >= tlen) {
+ tcpstat.tcps_rcvbyteafterwin += tlen;
/*
* If a new connection request is received
* while in TIME_WAIT, drop the old connection
@@ -1096,7 +1339,7 @@ trimthenstep6:
*/
if (tiflags & TH_SYN &&
tp->t_state == TCPS_TIME_WAIT &&
- SEQ_GT(ti->ti_seq, tp->rcv_nxt)) {
+ SEQ_GT(th->th_seq, tp->rcv_nxt)) {
iss = tp->rcv_nxt + TCP_ISSINCR;
tp = tcp_close(tp);
goto findpcb;
@@ -1108,7 +1351,7 @@ trimthenstep6:
* remember to ack. Otherwise, drop segment
* and ack.
*/
- if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
+ if (tp->rcv_wnd == 0 && th->th_seq == tp->rcv_nxt) {
tp->t_flags |= TF_ACKNOW;
tcpstat.tcps_rcvwinprobe++;
} else
@@ -1116,7 +1359,7 @@ trimthenstep6:
} else
tcpstat.tcps_rcvbyteafterwin += todrop;
m_adj(m, -todrop);
- ti->ti_len -= todrop;
+ tlen -= todrop;
tiflags &= ~(TH_PUSH|TH_FIN);
}
@@ -1126,7 +1369,7 @@ trimthenstep6:
* Fix from Braden, see Stevens p. 870
*/
if (ts_present && TSTMP_GEQ(ts_val, tp->ts_recent) &&
- SEQ_LEQ(ti->ti_seq, tp->last_ack_sent)) {
+ SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
tp->ts_recent_age = tcp_now;
tp->ts_recent = ts_val;
}
@@ -1142,10 +1385,9 @@ trimthenstep6:
* Close the tcb.
*/
if (tiflags & TH_RST) {
-
- if ((ti->ti_seq != tp->rcv_nxt) &&
- (ti->ti_ack && ((SEQ_GT(ti->ti_ack, tp->snd_nxt) ||
- SEQ_LT(ti->ti_ack, (tp->snd_nxt - tp->snd_wnd))))))
+ if ((th->th_seq != tp->rcv_nxt) &&
+ (th->th_ack && ((SEQ_GT(th->th_ack, tp->snd_nxt) ||
+ SEQ_LT(th->th_ack, (tp->snd_nxt - tp->snd_wnd))))))
goto drop;
switch (tp->t_state) {
@@ -1206,8 +1448,9 @@ trimthenstep6:
tp->snd_scale = tp->requested_s_scale;
tp->rcv_scale = tp->request_r_scale;
}
- (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
- tp->snd_wl1 = ti->ti_seq - 1;
+ (void) tcp_reass(tp, (struct tcphdr *)0, (struct mbuf *)0,
+ &tlen);
+ tp->snd_wl1 = th->th_seq - 1;
/* fall into ... */
/*
@@ -1225,8 +1468,7 @@ trimthenstep6:
case TCPS_CLOSING:
case TCPS_LAST_ACK:
case TCPS_TIME_WAIT:
-
- if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
+ if (SEQ_LEQ(th->th_ack, tp->snd_una)) {
/*
* Duplicate/old ACK processing.
* Increments t_dupacks:
@@ -1239,7 +1481,7 @@ trimthenstep6:
* Window shrinks
* Old ACK
*/
- if (ti->ti_len)
+ if (tlen)
break;
/*
* If we get an old ACK, there is probably packet
@@ -1247,7 +1489,7 @@ trimthenstep6:
* t_dupacks so that we are less agressive in
* doing a fast retransmit.
*/
- if (ti->ti_ack != tp->snd_una) {
+ if (th->th_ack != tp->snd_una) {
tp->t_dupacks = 0;
break;
}
@@ -1297,7 +1539,7 @@ trimthenstep6:
2 / tp->t_maxseg;
#if defined(TCP_SACK) || defined(TCP_NEWRENO)
- if (SEQ_LT(ti->ti_ack, tp->snd_last)){
+ if (SEQ_LT(th->th_ack, tp->snd_last)){
/*
* False fast retx after
* timeout. Do not cut window.
@@ -1353,7 +1595,7 @@ trimthenstep6:
#endif /* TCP_SACK */
tp->t_timer[TCPT_REXMT] = 0;
tp->t_rtt = 0;
- tp->snd_nxt = ti->ti_ack;
+ tp->snd_nxt = th->th_ack;
tp->snd_cwnd = tp->t_maxseg;
tcpstat.tcps_sndrexmitfast++;
(void) tcp_output(tp);
@@ -1395,7 +1637,7 @@ trimthenstep6:
* for the other side's cached packets, retract it.
*/
#ifdef TCP_NEWRENO
- if (tp->t_dupacks >= tcprexmtthresh && !tcp_newreno(tp, ti)) {
+ if (tp->t_dupacks >= tcprexmtthresh && !tcp_newreno(tp, th)) {
/* Out of fast recovery */
tp->snd_cwnd = tp->snd_ssthresh;
/*
@@ -1404,17 +1646,17 @@ trimthenstep6:
* would be inclined to send a burst, better to do
* it via the slow start mechanism.
*/
- if (tcp_seq_subtract(tp->snd_max, ti->ti_ack) <
+ if (tcp_seq_subtract(tp->snd_max, th->th_ack) <
tp->snd_ssthresh)
tp->snd_cwnd = tcp_seq_subtract(tp->snd_max,
- ti->ti_ack) + tp->t_maxseg;
+ th->th_ack) + tp->t_maxseg;
tp->t_dupacks = 0;
}
#elif defined(TCP_SACK)
if (!tp->sack_disable) {
if (tp->t_dupacks >= tcprexmtthresh) {
/* Check for a partial ACK */
- if (tcp_sack_partialack(tp, ti)) {
+ if (tcp_sack_partialack(tp, th)) {
#if defined(TCP_SACK) && defined(TCP_FACK)
/* Force call to tcp_output */
if (tp->snd_awnd < tp->snd_cwnd)
@@ -1427,27 +1669,27 @@ trimthenstep6:
/* Out of fast recovery */
tp->snd_cwnd = tp->snd_ssthresh;
if (tcp_seq_subtract(tp->snd_max,
- ti->ti_ack) < tp->snd_ssthresh)
+ th->th_ack) < tp->snd_ssthresh)
tp->snd_cwnd =
tcp_seq_subtract(tp->snd_max,
- ti->ti_ack) + tp->t_maxseg;
+ th->th_ack) + tp->t_maxseg;
tp->t_dupacks = 0;
#if defined(TCP_SACK) && defined(TCP_FACK)
- if (SEQ_GT(ti->ti_ack, tp->snd_fack))
- tp->snd_fack = ti->ti_ack;
+ if (SEQ_GT(th->th_ack, tp->snd_fack))
+ tp->snd_fack = th->th_ack;
#endif /* TCP_FACK */
}
}
} else {
if (tp->t_dupacks >= tcprexmtthresh &&
- !tcp_newreno(tp, ti)) {
+ !tcp_newreno(tp, th)) {
/* Out of fast recovery */
tp->snd_cwnd = tp->snd_ssthresh;
- if (tcp_seq_subtract(tp->snd_max, ti->ti_ack) <
+ if (tcp_seq_subtract(tp->snd_max, th->th_ack) <
tp->snd_ssthresh)
tp->snd_cwnd =
tcp_seq_subtract(tp->snd_max,
- ti->ti_ack) + tp->t_maxseg;
+ th->th_ack) + tp->t_maxseg;
tp->t_dupacks = 0;
}
}
@@ -1457,11 +1699,11 @@ trimthenstep6:
tp->snd_cwnd = tp->snd_ssthresh;
tp->t_dupacks = 0;
#endif
- if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
+ if (SEQ_GT(th->th_ack, tp->snd_max)) {
tcpstat.tcps_rcvacktoomuch++;
goto dropafterack;
}
- acked = ti->ti_ack - tp->snd_una;
+ acked = th->th_ack - tp->snd_una;
tcpstat.tcps_rcvackpack++;
tcpstat.tcps_rcvackbyte += acked;
@@ -1476,7 +1718,7 @@ trimthenstep6:
*/
if (ts_present)
tcp_xmit_timer(tp, tcp_now-ts_ecr+1);
- else if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
+ else if (tp->t_rtt && SEQ_GT(th->th_ack, tp->t_rtseq))
tcp_xmit_timer(tp,tp->t_rtt);
/*
@@ -1485,7 +1727,7 @@ trimthenstep6:
* If there is more data to be acked, restart retransmit
* timer, using current (possibly backed-off) value.
*/
- if (ti->ti_ack == tp->snd_max) {
+ if (th->th_ack == tp->snd_max) {
tp->t_timer[TCPT_REXMT] = 0;
needoutput = 1;
} else if (tp->t_timer[TCPT_PERSIST] == 0)
@@ -1504,7 +1746,7 @@ trimthenstep6:
if (cw > tp->snd_ssthresh)
incr = incr * incr / cw;
#if defined (TCP_NEWRENO) || defined (TCP_SACK)
- if (SEQ_GEQ(ti->ti_ack, tp->snd_last))
+ if (SEQ_GEQ(th->th_ack, tp->snd_last))
#endif
tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);
}
@@ -1519,7 +1761,7 @@ trimthenstep6:
}
if (sb_notify(&so->so_snd))
sowwakeup(so);
- tp->snd_una = ti->ti_ack;
+ tp->snd_una = th->th_ack;
if (SEQ_LT(tp->snd_nxt, tp->snd_una))
tp->snd_nxt = tp->snd_una;
#if defined (TCP_SACK) && defined (TCP_FACK)
@@ -1595,16 +1837,16 @@ step6:
* Update window information.
* Don't look at window if no ACK: TAC's send garbage on first SYN.
*/
- if (((tiflags & TH_ACK) && SEQ_LT(tp->snd_wl1, ti->ti_seq)) ||
- (tp->snd_wl1 == ti->ti_seq && SEQ_LT(tp->snd_wl2, ti->ti_ack)) ||
- (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd)) {
+ if (((tiflags & TH_ACK) && SEQ_LT(tp->snd_wl1, th->th_seq)) ||
+ (tp->snd_wl1 == th->th_seq && SEQ_LT(tp->snd_wl2, th->th_ack)) ||
+ (tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)) {
/* keep track of pure window updates */
- if (ti->ti_len == 0 &&
- tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd)
+ if (tlen == 0 &&
+ tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
tcpstat.tcps_rcvwinupd++;
tp->snd_wnd = tiwin;
- tp->snd_wl1 = ti->ti_seq;
- tp->snd_wl2 = ti->ti_ack;
+ tp->snd_wl1 = th->th_seq;
+ tp->snd_wl2 = th->th_ack;
if (tp->snd_wnd > tp->max_sndwnd)
tp->max_sndwnd = tp->snd_wnd;
needoutput = 1;
@@ -1613,7 +1855,7 @@ step6:
/*
* Process segments with URG.
*/
- if ((tiflags & TH_URG) && ti->ti_urp &&
+ if ((tiflags & TH_URG) && th->th_urp &&
TCPS_HAVERCVDFIN(tp->t_state) == 0) {
/*
* This is a kludge, but if we receive and accept
@@ -1621,8 +1863,8 @@ step6:
* soreceive. It's hard to imagine someone
* actually wanting to send this much urgent data.
*/
- if (ti->ti_urp + so->so_rcv.sb_cc > sb_max) {
- ti->ti_urp = 0; /* XXX */
+ if (th->th_urp + so->so_rcv.sb_cc > sb_max) {
+ th->th_urp = 0; /* XXX */
tiflags &= ~TH_URG; /* XXX */
goto dodata; /* XXX */
}
@@ -1640,8 +1882,8 @@ step6:
* of data past the urgent section as the original
* spec states (in one of two places).
*/
- if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {
- tp->rcv_up = ti->ti_seq + ti->ti_urp;
+ if (SEQ_GT(th->th_seq+th->th_urp, tp->rcv_up)) {
+ tp->rcv_up = th->th_seq + th->th_urp;
so->so_oobmark = so->so_rcv.sb_cc +
(tp->rcv_up - tp->rcv_nxt) - 1;
if (so->so_oobmark == 0)
@@ -1655,12 +1897,12 @@ step6:
* but if two URG's are pending at once, some out-of-band
* data may creep in... ick.
*/
- if (ti->ti_urp <= (u_int16_t) ti->ti_len
+ if (th->th_urp <= (u_int16_t) tlen
#ifdef SO_OOBINLINE
&& (so->so_options & SO_OOBINLINE) == 0
#endif
)
- tcp_pulloutofband(so, ti, m);
+ tcp_pulloutofband(so, th->th_urp, m); /* XXX? */
} else
/*
* If no out of band data is expected,
@@ -1679,19 +1921,41 @@ dodata: /* XXX */
* case PRU_RCVD). If a FIN has already been received on this
* connection then we just ignore the text.
*/
- if ((ti->ti_len || (tiflags & TH_FIN)) &&
+ if ((tlen || (tiflags & TH_FIN)) &&
TCPS_HAVERCVDFIN(tp->t_state) == 0) {
- TCP_REASS(tp, ti, m, so, tiflags);
+ if (th->th_seq == tp->rcv_nxt && tp->segq.lh_first == NULL &&
+ tp->t_state == TCPS_ESTABLISHED) {
+ if (th->th_flags & TH_PUSH)
+ tp->t_flags |= TF_ACKNOW;
+ else
+ tp->t_flags |= TF_DELACK;
+ (tp)->rcv_nxt += tlen;
+ tiflags = th->th_flags & TH_FIN;
+ tcpstat.tcps_rcvpack++;
+ tcpstat.tcps_rcvbyte += tlen;
+ sbappend(&so->so_rcv, m);
+ sorwakeup(so);
+ } else {
+ tcp_reass(tp, th, m, &tlen);
+ tp->t_flags |= TF_ACKNOW;
+ }
#ifdef TCP_SACK
if (!tp->sack_disable)
tcp_update_sack_list(tp);
#endif
+
+ /*
+ * variable len never referenced again in modern BSD,
+ * so why bother computing it ??
+ */
+#if 0
/*
* Note the amount of data that peer has sent into
* our window, in order to estimate the sender's
* buffer size.
*/
len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt);
+#endif /* 0 */
} else {
m_freem(m);
tiflags &= ~TH_FIN;
@@ -1745,8 +2009,14 @@ dodata: /* XXX */
break;
}
}
- if (so->so_options & SO_DEBUG)
- tcp_trace(TA_INPUT, ostate, tp, &tcp_saveti, 0);
+ if (so->so_options & SO_DEBUG) {
+#ifdef INET6
+ if (tp->pf == PF_INET6)
+ tcp_trace(TA_INPUT, ostate, tp, (struct tcpiphdr *) &tcp_saveti6, 0, tlen);
+ else
+#endif /* INET6 */
+ tcp_trace(TA_INPUT, ostate, tp, &tcp_saveti, 0, tlen);
+ }
/*
* Return any desired output.
@@ -1785,15 +2055,27 @@ dropwithreset:
* Make ACK acceptable to originator of segment.
* Don't bother to respond if destination was broadcast/multicast.
*/
- if ((tiflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST) ||
- IN_MULTICAST(ti->ti_dst.s_addr))
- goto drop;
+ if ((tiflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST))
+ goto drop;
+#ifdef INET6
+ if (is_ipv6) {
+ /* For following calls to tcp_respond */
+ ti = mtod(m, struct tcpiphdr *);
+ if (IN6_IS_ADDR_MULTICAST(&ipv6->ipv6_dst))
+ goto drop;
+ } else {
+#endif /* INET6 */
+ if (IN_MULTICAST(ntohl(ti->ti_dst.s_addr)))
+ goto drop;
+#ifdef INET6
+ }
+#endif /* INET6 */
if (tiflags & TH_ACK)
- tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
+ tcp_respond(tp, ti, m, (tcp_seq)0, th->th_ack, TH_RST);
else {
if (tiflags & TH_SYN)
- ti->ti_len++;
- tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0,
+ tlen++;
+ tcp_respond(tp, ti, m, th->th_seq+tlen, (tcp_seq)0,
TH_RST|TH_ACK);
}
/* destroy temporarily created socket */
@@ -1805,8 +2087,15 @@ drop:
/*
* Drop space held by incoming segment and return.
*/
- if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
- tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0);
+ if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) {
+#ifdef INET6
+ if (tp->pf == PF_INET6)
+ tcp_trace(TA_DROP, ostate, tp, (struct tcpiphdr *)&tcp_saveti6, 0, tlen);
+ else
+#endif /* INET6 */
+ tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0, tlen);
+ }
+
m_freem(m);
/* destroy temporarily created socket */
if (dropsocket)
@@ -1816,11 +2105,11 @@ drop:
}
void
-tcp_dooptions(tp, cp, cnt, ti, ts_present, ts_val, ts_ecr)
+tcp_dooptions(tp, cp, cnt, th, ts_present, ts_val, ts_ecr)
struct tcpcb *tp;
u_char *cp;
int cnt;
- struct tcpiphdr *ti;
+ struct tcphdr *th;
int *ts_present;
u_int32_t *ts_val, *ts_ecr;
{
@@ -1846,7 +2135,7 @@ tcp_dooptions(tp, cp, cnt, ti, ts_present, ts_val, ts_ecr)
case TCPOPT_MAXSEG:
if (optlen != TCPOLEN_MAXSEG)
continue;
- if (!(ti->ti_flags & TH_SYN))
+ if (!(th->th_flags & TH_SYN))
continue;
bcopy((char *) cp + 2, (char *) &mss, sizeof(mss));
NTOHS(mss);
@@ -1855,7 +2144,7 @@ tcp_dooptions(tp, cp, cnt, ti, ts_present, ts_val, ts_ecr)
case TCPOPT_WINDOW:
if (optlen != TCPOLEN_WINDOW)
continue;
- if (!(ti->ti_flags & TH_SYN))
+ if (!(th->th_flags & TH_SYN))
continue;
tp->t_flags |= TF_RCVD_SCALE;
tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT);
@@ -1874,7 +2163,7 @@ tcp_dooptions(tp, cp, cnt, ti, ts_present, ts_val, ts_ecr)
* A timestamp received in a SYN makes
* it ok to send timestamp requests and replies.
*/
- if (ti->ti_flags & TH_SYN) {
+ if (th->th_flags & TH_SYN) {
tp->t_flags |= TF_RCVD_TSTMP;
tp->ts_recent = *ts_val;
tp->ts_recent_age = tcp_now;
@@ -1884,20 +2173,20 @@ tcp_dooptions(tp, cp, cnt, ti, ts_present, ts_val, ts_ecr)
#ifdef TCP_SACK
case TCPOPT_SACK_PERMITTED:
if (tp->sack_disable || optlen!=TCPOLEN_SACK_PERMITTED)
- continue;
- if (ti->ti_flags & TH_SYN)
+ continue;
+ if (th->th_flags & TH_SYN)
/* MUST only be set on SYN */
tp->t_flags |= TF_SACK_PERMIT;
break;
case TCPOPT_SACK:
- if (tcp_sack_option(tp, ti, cp, optlen))
+ if (tcp_sack_option(tp, th, cp, optlen))
continue;
break;
#endif
}
}
/* Update t_maxopd and t_maxseg after all options are processed */
- if (ti->ti_flags & TH_SYN)
+ if (th->th_flags & TH_SYN)
(void) tcp_mss(tp, mss); /* sets t_maxseg */
}
@@ -2012,10 +2301,10 @@ tcp_update_sack_list(tp)
* and 0 otherwise, if the option was fine. tp->snd_holes is an ordered list
* of holes (oldest to newest, in terms of the sequence space).
*/
-int
-tcp_sack_option(tp, ti, cp, optlen)
+int
+tcp_sack_option(tp, th, cp, optlen)
struct tcpcb *tp;
- struct tcpiphdr *ti;
+ struct tcphdr *th;
u_char *cp;
int optlen;
{
@@ -2058,7 +2347,7 @@ tcp_sack_option(tp, ti, cp, optlen)
tp->snd_holes = (struct sackhole *)
malloc(sizeof(struct sackhole), M_PCB, M_NOWAIT);
cur = tp->snd_holes;
- cur->start = ti->ti_ack;
+ cur->start = th->th_ack;
cur->end = sack.start;
cur->rxmit = cur->start;
cur->next = 0;
@@ -2223,13 +2512,13 @@ tcp_sack_option(tp, ti, cp, optlen)
* tcp_dooptions(), will fix up the hole.
*/
void
-tcp_del_sackholes(tp, ti)
+tcp_del_sackholes(tp, th)
struct tcpcb *tp;
- struct tcpiphdr *ti;
+ struct tcpiphdr *th;
{
if (!tp->sack_disable && tp->t_state != TCPS_LISTEN) {
/* max because this could be an older ack just arrived */
- tcp_seq lastack = max(ti->ti_ack, tp->snd_una);
+ tcp_seq lastack = max(th->th_ack, tp->snd_una);
struct sackhole *cur = tp->snd_holes;
struct sackhole *prev = cur;
while (cur)
@@ -2268,11 +2557,11 @@ tcp_clean_sackreport(tp)
* If the ack advances at least to tp->snd_last, return 0.
*/
int
-tcp_sack_partialack(tp, ti)
+tcp_sack_partialack(tp, th)
struct tcpcb *tp;
- struct tcpiphdr *ti;
+ struct tcpiphdr *th;
{
- if (SEQ_LT(ti->ti_ack, tp->snd_last)) {
+ if (SEQ_LT(th->ti_ack, tp->snd_last)) {
/* Turn off retx. timer (will start again next segment) */
tp->t_timer[TCPT_REXMT] = 0;
tp->t_rtt = 0;
@@ -2282,7 +2571,7 @@ tcp_sack_partialack(tp, ti)
* fact that tp->snd_una has not been updated yet. In FACK
* hold snd_cwnd constant during fast recovery.
*/
- tp->snd_cwnd -= (ti->ti_ack - tp->snd_una - tp->t_maxseg);
+ tp->snd_cwnd -= (th->th_ack - tp->snd_una - tp->t_maxseg);
#endif
return 1;
}
@@ -2297,12 +2586,12 @@ tcp_sack_partialack(tp, ti)
* sequencing purposes.
*/
void
-tcp_pulloutofband(so, ti, m)
+tcp_pulloutofband(so, urgent, m)
struct socket *so;
- struct tcpiphdr *ti;
+ u_int urgent;
register struct mbuf *m;
{
- int cnt = ti->ti_urp - 1;
+ int cnt = urgent - 1;
while (cnt >= 0) {
if (m->m_len > cnt) {
@@ -2434,9 +2723,33 @@ tcp_mss(tp, offer)
inp = tp->t_inpcb;
ro = &inp->inp_route;
+ so = inp->inp_socket;
if ((rt = ro->ro_rt) == (struct rtentry *)0) {
/* No route yet, so try to acquire one */
+#ifdef INET6
+ /*
+ * Get a new IPv6 route if an IPv6 destination, otherwise, get
+ * and IPv4 route (including those pesky IPv4-mapped addresses).
+ */
+ bzero(ro,sizeof(struct route6));
+ if (sotopf(so) == AF_INET6) {
+ if (IN6_IS_ADDR_V4MAPPED(&inp->inp_faddr6)) {
+ /* Get an IPv4 route. */
+ ro->ro_dst.sa_family = AF_INET;
+ ro->ro_dst.sa_len = sizeof(ro->ro_dst);
+ ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
+ inp->inp_faddr;
+ rtalloc(ro);
+ } else {
+ ro->ro_dst.sa_family = AF_INET6;
+ ro->ro_dst.sa_len = sizeof(struct sockaddr_in6);
+ ((struct sockaddr_in6 *) &ro->ro_dst)->sin6_addr =
+ inp->inp_faddr6;
+ rtalloc(ro);
+ }
+ } else
+#endif /* INET6 */
if (inp->inp_faddr.s_addr != INADDR_ANY) {
ro->ro_dst.sa_family = AF_INET;
ro->ro_dst.sa_len = sizeof(ro->ro_dst);
@@ -2449,7 +2762,6 @@ tcp_mss(tp, offer)
}
}
ifp = rt->rt_ifp;
- so = inp->inp_socket;
#ifdef RTV_MTU /* if route characteristics exist ... */
/*
@@ -2480,11 +2792,32 @@ tcp_mss(tp, offer)
* if there's an mtu associated with the route, use it
*/
if (rt->rt_rmx.rmx_mtu)
+#ifdef INET6
+ {
+ /*
+ * One may wish to lower MSS to take into account options,
+ * especially security-related options.
+ */
+ if (tp->pf == AF_INET6)
+ mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpipv6hdr);
+ else
+#endif /* INET6 */
mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr);
+#ifdef INET6
+ }
+#endif /* INET6 */
else
#endif /* RTV_MTU */
{
- mss = ifp->if_mtu - sizeof(struct tcpiphdr);
+ /*
+ * ifp may be null and rmx_mtu may be zero in certain
+ * v6 cases (e.g., if ND wasn't able to resolve the
+ * destination host.
+ */
+ mss = ifp ? ifp->if_mtu - sizeof(struct tcpiphdr) : 0;
+#ifdef INET6
+ if (tp->pf == AF_INET)
+#endif /* INET6 */
if (!in_localaddr(inp->inp_faddr))
mss = min(mss, tcp_mssdflt);
}
@@ -2574,19 +2907,19 @@ tcp_mss(tp, offer)
* be started again. If the ack advances at least to tp->snd_last, return 0.
*/
int
-tcp_newreno(tp, ti)
+tcp_newreno(tp, th)
struct tcpcb *tp;
-struct tcpiphdr *ti;
+struct tcphdr *th;
{
- if (SEQ_LT(ti->ti_ack, tp->snd_last)) {
+ if (SEQ_LT(th->th_ack, tp->snd_last)) {
tcp_seq onxt = tp->snd_nxt;
tcp_seq ouna = tp->snd_una; /* snd_una not yet updated */
u_long ocwnd = tp->snd_cwnd;
tp->t_timer[TCPT_REXMT] = 0;
tp->t_rtt = 0;
- tp->snd_nxt = ti->ti_ack;
+ tp->snd_nxt = th->th_ack;
tp->snd_cwnd = tp->t_maxseg;
- tp->snd_una = ti->ti_ack;
+ tp->snd_una = th->th_ack;
(void) tcp_output(tp);
tp->snd_cwnd = ocwnd;
tp->snd_una = ouna;
@@ -2596,7 +2929,7 @@ struct tcpiphdr *ti;
* Partial window deflation. Relies on fact that tp->snd_una
* not updated yet.
*/
- tp->snd_cwnd -= (ti->ti_ack - tp->snd_una - tp->t_maxseg);
+ tp->snd_cwnd -= (th->th_ack - tp->snd_una - tp->t_maxseg);
return 1;
}
return 0;