summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r--sys/netinet/tcp_input.c173
1 files changed, 133 insertions, 40 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index e2a6b6136d3..f080fb3c386 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.51 1999/11/15 05:50:59 hugh Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.52 1999/12/08 06:50:20 itojun Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -82,18 +82,32 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#endif /* IPSEC */
#ifdef INET6
+#ifndef INET
+#include <netinet/in.h>
+#endif
#include <sys/domain.h>
#include <netinet6/in6_var.h>
-#include <netinet6/ipv6.h>
-#include <netinet6/ipv6_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
#include <netinet6/tcpipv6.h>
+#include <netinet/icmp6.h>
+#include <netinet6/nd6.h>
+
+#ifndef CREATE_IPV6_MAPPED
+#define CREATE_IPV6_MAPPED(a6, a4) \
+do { \
+ bzero(&(a6), sizeof(a6)); \
+ (a6).s6_addr[10] = (a6).s6_addr[11] = 0xff; \
+ *(u_int32_t *)&(a6).s6_addr[12] = (a4); \
+} while (0)
+#endif
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_V6_LEN(m) (M_PH_LEN(m) - sizeof(struct ip6_hdr))
#define M_V4_LEN(m) (M_PH_LEN(m) - sizeof(struct ip))
#endif /* INET6 */
@@ -111,6 +125,22 @@ extern u_long sb_max;
#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0)
/*
+ * Neighbor Discovery, Neighbor Unreachability Detection Upper layer hint.
+ */
+#ifdef INET6
+#define ND6_HINT(tp) \
+do { \
+ if (tp && tp->t_inpcb && (tp->t_inpcb->inp_flags & INP_IPV6) \
+ && !(tp->t_inpcb->inp_flags & INP_IPV6_MAPPED) \
+ && tp->t_inpcb->inp_route6.ro_rt) { \
+ nd6_nud_hint(tp->t_inpcb->inp_route6.ro_rt, NULL); \
+ } \
+} while (0)
+#else
+#define ND6_HINT(tp)
+#endif
+
+/*
* Insert segment ti into reassembly queue of tcp with
* control block tp. Return TH_FIN if reassembly now includes
* a segment with FIN. The macro form does the common case inline
@@ -237,6 +267,7 @@ present:
nq = q->ipqe_q.le_next;
LIST_REMOVE(q, ipqe_q);
+ ND6_HINT(tp);
if (so->so_state & SS_CANTRCVMORE)
m_freem(q->ipqe_m);
else
@@ -295,6 +326,44 @@ done:
splx(s);
}
+#if defined(INET6) && !defined(TCP6)
+int
+tcp6_input(mp, offp, proto)
+ struct mbuf **mp;
+ int *offp, proto;
+{
+ struct mbuf *m = *mp;
+
+#if defined(NFAITH) && 0 < NFAITH
+ if (m->m_pkthdr.rcvif) {
+ if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
+ /* XXX send icmp6 host/port unreach? */
+ m_freem(m);
+ return IPPROTO_DONE;
+ }
+ }
+#endif
+
+ /*
+ * draft-itojun-ipv6-tcp-to-anycast
+ * better place to put this in?
+ */
+ if (m->m_flags & M_ANYCAST6) {
+ if (m->m_len >= sizeof(struct ip6_hdr)) {
+ struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+ icmp6_error(m, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_ADDR,
+ (caddr_t)&ip6->ip6_dst - (caddr_t)ip6);
+ } else
+ m_freem(m);
+ return IPPROTO_DONE;
+ }
+
+ tcp_input(m, *offp, proto);
+ return IPPROTO_DONE;
+}
+#endif
+
/*
* TCP input routine, follows pages 65-76 of the
* protocol specification dated September, 1981 very closely.
@@ -316,6 +385,7 @@ tcp_input(m, va_alist)
register int tiflags;
struct socket *so = NULL;
int todrop, acked, ourfinisacked, needoutput = 0;
+ int hdroptlen = 0;
short ostate = 0;
struct in_addr laddr;
int dropsocket = 0;
@@ -332,7 +402,7 @@ tcp_input(m, va_alist)
#ifdef INET6
struct in6_addr laddr6;
unsigned short is_ipv6; /* Type of incoming datagram. */
- struct ipv6 *ipv6 = NULL;
+ struct ip6_hdr *ipv6 = NULL;
#endif /* INET6 */
va_start(ap, m);
@@ -369,8 +439,15 @@ tcp_input(m, va_alist)
#else /* INET6 */
if (!is_ipv6)
#endif /* INET6 */
- if (iphlen > sizeof (struct ip))
+ if (iphlen > sizeof (struct ip)) {
+#if 0 /*XXX*/
ip_stripoptions(m, (struct mbuf *)0);
+#else
+ printf("extension headers are not allowed\n");
+ m_freem(m);
+ return;
+#endif
+ }
if (m->m_len < iphlen + sizeof(struct tcphdr)) {
if ((m = m_pullup2(m, iphlen + sizeof(struct tcphdr))) == 0) {
tcpstat.tcps_rcvshort++;
@@ -391,22 +468,28 @@ tcp_input(m, va_alist)
if (is_ipv6) {
#ifdef DIAGNOSTIC
- if (iphlen < sizeof(struct ipv6)) {
+ if (iphlen < sizeof(struct ip6_hdr)) {
m_freem(m);
return;
}
#endif /* DIAGNOSTIC */
/* strip off any options */
- if (iphlen > sizeof(struct ipv6)) {
+ if (iphlen > sizeof(struct ip6_hdr)) {
+#if 0 /*XXX*/
ipv6_stripoptions(m, iphlen);
- iphlen = sizeof(struct ipv6);
+#else
+ printf("extension headers are not allowed\n");
+ m_freem(m);
+ return;
+#endif
+ iphlen = sizeof(struct ip6_hdr);
}
ti = NULL;
- ipv6 = mtod(m, struct ipv6 *);
+ ipv6 = mtod(m, struct ip6_hdr *);
- if (in6_cksum(m, IPPROTO_TCP, tlen, sizeof(struct ipv6))) {
+ if (in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr), tlen)) {
tcpstat.tcps_rcvbadsum++;
goto drop;
} /* endif in6_cksum */
@@ -453,7 +536,7 @@ tcp_input(m, va_alist)
}
#ifdef INET6
if (is_ipv6)
- ipv6 = mtod(m, struct ipv6 *);
+ ipv6 = mtod(m, struct ip6_hdr *);
else
#endif /* INET6 */
ti = mtod(m, struct tcpiphdr *);
@@ -495,8 +578,8 @@ tcp_input(m, va_alist)
findpcb:
#ifdef INET6
if (is_ipv6) {
- inp = in6_pcbhashlookup(&tcbtable, &ipv6->ipv6_src, th->th_sport,
- &ipv6->ipv6_dst, th->th_dport);
+ inp = in6_pcbhashlookup(&tcbtable, &ipv6->ip6_src, th->th_sport,
+ &ipv6->ip6_dst, th->th_dport);
} else
#endif /* INET6 */
inp = in_pcbhashlookup(&tcbtable, ti->ti_src, ti->ti_sport,
@@ -505,8 +588,8 @@ findpcb:
++tcpstat.tcps_pcbhashmiss;
#ifdef INET6
if (is_ipv6)
- inp = in_pcblookup(&tcbtable, &ipv6->ipv6_src,
- th->th_sport, &ipv6->ipv6_dst, th->th_dport,
+ inp = in_pcblookup(&tcbtable, &ipv6->ip6_src,
+ th->th_sport, &ipv6->ip6_dst, th->th_dport,
INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
else
#endif /* INET6 */
@@ -601,10 +684,10 @@ findpcb:
| 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;
+ inp->inp_ipv6.ip6_hlim =
+ oldinpcb->inp_ipv6.ip6_hlim;
+ inp->inp_ipv6.ip6_flow =
+ oldinpcb->inp_ipv6.ip6_flow;
}
}
#else /* INET6 */
@@ -613,11 +696,11 @@ findpcb:
inp->inp_lport = th->th_dport;
#ifdef INET6
if (is_ipv6) {
- inp->inp_laddr6 = ipv6->ipv6_dst;
+ inp->inp_laddr6 = ipv6->ip6_dst;
inp->inp_fflowinfo = htonl(0x0fffffff) &
- ipv6->ipv6_versfl;
+ ipv6->ip6_flow;
- /*inp->inp_options = ipv6_srcroute();*/ /* soon. */
+ /*inp->inp_options = ip6_srcroute();*/ /* soon. */
/* still need to tweak outbound options
processing to include this mbuf in
the right place and put the correct
@@ -656,7 +739,7 @@ findpcb:
#ifdef notyet
#ifdef INET6
if (is_ipv6)
- ipv6_icmp_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0);
+ icmp6_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0);
else
#endif /* INET6 */
icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0);
@@ -744,6 +827,7 @@ findpcb:
acked = th->th_ack - tp->snd_una;
tcpstat.tcps_rcvackpack++;
tcpstat.tcps_rcvackbyte += acked;
+ ND6_HINT(tp);
sbdrop(&so->so_snd, acked);
tp->snd_una = th->th_ack;
#if defined(TCP_SACK) || defined(TCP_NEWRENO)
@@ -797,12 +881,12 @@ findpcb:
tp->rcv_nxt += tlen;
tcpstat.tcps_rcvpack++;
tcpstat.tcps_rcvbyte += tlen;
+ ND6_HINT(tp);
/*
* Drop TCP, IP headers and TCP options then add data
* to socket buffer.
*/
- m->m_data += iphlen + off;
- m->m_len -= iphlen + off;
+ m_adj(m, iphlen + off);
sbappend(&so->so_rcv, m);
sorwakeup(so);
if (th->th_flags & TH_PUSH)
@@ -814,10 +898,9 @@ findpcb:
}
/*
- * Drop TCP, IP headers and TCP options.
+ * Compute mbuf offset to TCP data segment.
*/
- m->m_data += iphlen + off;
- m->m_len -= iphlen + off;
+ hdroptlen = iphlen + off;
/*
* Calculate amount of space in receive window,
@@ -865,7 +948,7 @@ findpcb:
if (th->th_dport == th->th_sport) {
#ifdef INET6
if (is_ipv6) {
- if (IN6_ARE_ADDR_EQUAL(&ipv6->ipv6_src, &ipv6->ipv6_dst))
+ if (IN6_ARE_ADDR_EQUAL(&ipv6->ip6_src, &ipv6->ip6_dst))
goto drop;
} else {
#endif /* INET6 */
@@ -886,7 +969,7 @@ findpcb:
#ifdef INET6
if (is_ipv6) {
/* XXX What about IPv6 Anycasting ?? :-( rja */
- if (IN6_IS_ADDR_MULTICAST(&ipv6->ipv6_dst))
+ if (IN6_IS_ADDR_MULTICAST(&ipv6->ip6_dst))
goto drop;
} else
#endif /* INET6 */
@@ -912,13 +995,13 @@ findpcb:
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_addr = ipv6->ip6_src;
sin6->sin6_port = th->th_sport;
sin6->sin6_flowinfo = htonl(0x0fffffff) &
- inp->inp_ipv6.ipv6_versfl;
+ inp->inp_ipv6.ip6_flow;
laddr6 = inp->inp_laddr6;
if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
- inp->inp_laddr6 = ipv6->ipv6_dst;
+ inp->inp_laddr6 = ipv6->ip6_dst;
/* This is a good optimization. */
if (in6_pcbconnect(inp, am)) {
inp->inp_laddr6 = laddr6;
@@ -982,6 +1065,7 @@ findpcb:
goto drop;
}
(void) m_free(am);
+ tp->pf = PF_INET;
#ifdef INET6
} /* if (inp->inp_flags & INP_IPV6) */
} /* if (is_ipv6) */
@@ -1210,7 +1294,7 @@ trimthenstep6:
tcpstat.tcps_rcvpartduppack++;
tcpstat.tcps_rcvpartdupbyte += todrop;
}
- m_adj(m, todrop);
+ hdroptlen += todrop; /* drop from head afterwards */
th->th_seq += todrop;
tlen -= todrop;
if (th->th_urp > todrop)
@@ -1295,7 +1379,11 @@ trimthenstep6:
* Close the tcb.
*/
if (tiflags & TH_RST) {
+#ifndef INET6
if (ti->ti_seq != tp->last_ack_sent)
+#else
+ if (th->th_seq != tp->last_ack_sent)
+#endif
goto drop;
switch (tp->t_state) {
@@ -1662,6 +1750,7 @@ trimthenstep6:
#endif
tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);
}
+ ND6_HINT(tp);
if (acked > so->so_snd.sb_cc) {
tp->snd_wnd -= so->so_snd.sb_cc;
sbdrop(&so->so_snd, (int)so->so_snd.sb_cc);
@@ -1814,7 +1903,7 @@ step6:
&& (so->so_options & SO_OOBINLINE) == 0
#endif
)
- tcp_pulloutofband(so, th->th_urp, m); /* XXX? */
+ tcp_pulloutofband(so, th->th_urp, m, hdroptlen);
} else
/*
* If no out of band data is expected,
@@ -1845,9 +1934,12 @@ dodata: /* XXX */
tiflags = th->th_flags & TH_FIN;
tcpstat.tcps_rcvpack++;
tcpstat.tcps_rcvbyte += tlen;
+ ND6_HINT(tp);
+ m_adj(m, hdroptlen);
sbappend(&so->so_rcv, m);
sorwakeup(so);
} else {
+ m_adj(m, hdroptlen);
tiflags = tcp_reass(tp, th, m, &tlen);
tp->t_flags |= TF_ACKNOW;
}
@@ -1973,7 +2065,7 @@ dropwithreset:
if (is_ipv6) {
/* For following calls to tcp_respond */
ti = mtod(m, struct tcpiphdr *);
- if (IN6_IS_ADDR_MULTICAST(&ipv6->ipv6_dst))
+ if (IN6_IS_ADDR_MULTICAST(&ipv6->ip6_dst))
goto drop;
} else {
#endif /* INET6 */
@@ -2515,12 +2607,13 @@ tcp_sack_partialack(tp, th)
* sequencing purposes.
*/
void
-tcp_pulloutofband(so, urgent, m)
+tcp_pulloutofband(so, urgent, m, off)
struct socket *so;
u_int urgent;
register struct mbuf *m;
+ int off;
{
- int cnt = urgent - 1;
+ int cnt = off + urgent - 1;
while (cnt >= 0) {
if (m->m_len > cnt) {
@@ -2665,7 +2758,7 @@ tcp_mss(tp, offer)
* 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));
+ bzero(ro,sizeof(struct route_in6));
if (sotopf(so) == AF_INET6) {
if (IN6_IS_ADDR_V4MAPPED(&inp->inp_faddr6)) {
/* Get an IPv4 route. */