summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1999-01-11 02:01:37 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1999-01-11 02:01:37 +0000
commit54ec4ac803b4008b00c68e4bd4a4fc1ec3f5e097 (patch)
treec20c66c2ad89268a8deb2019ddd5ee306d652421 /sys/netinet
parent2f10b00f0ab323af0befe8b6887b503520414090 (diff)
netinet merge of NRL stuff. some indent and shrinkage needed; NRL/cmetz
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/in_pcb.c8
-rw-r--r--sys/netinet/in_pcb.h6
-rw-r--r--sys/netinet/ip_var.h5
-rw-r--r--sys/netinet/raw_ip.c25
-rw-r--r--sys/netinet/tcp.h10
-rw-r--r--sys/netinet/tcp_debug.c61
-rw-r--r--sys/netinet/tcp_debug.h5
-rw-r--r--sys/netinet/tcp_input.c761
-rw-r--r--sys/netinet/tcp_output.c129
-rw-r--r--sys/netinet/tcp_subr.c329
-rw-r--r--sys/netinet/tcp_usrreq.c116
-rw-r--r--sys/netinet/tcp_var.h18
-rw-r--r--sys/netinet/udp_usrreq.c407
13 files changed, 1519 insertions, 361 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 5428694fed0..b36fe6b55d3 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.c,v 1.28 1999/01/08 07:47:22 deraadt Exp $ */
+/* $OpenBSD: in_pcb.c,v 1.29 1999/01/11 02:01:34 deraadt Exp $ */
/* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
/*
@@ -59,9 +59,7 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/proc.h>
-#ifdef INET6
#include <sys/domain.h>
-#endif /* INET6 */
#include <net/if.h>
#include <net/route.h>
@@ -74,6 +72,10 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#include <netinet/ip_var.h>
#include <dev/rndvar.h>
+#ifdef INET6
+#include <netinet6/ipv6_var.h>
+#endif /* INET6 */
+
#ifdef IPSEC
#include <net/encap.h>
#include <netinet/ip_ipsp.h>
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 9253b903021..bd13b189a3e 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.h,v 1.14 1999/01/08 07:47:54 deraadt Exp $ */
+/* $OpenBSD: in_pcb.h,v 1.15 1999/01/11 02:01:34 deraadt Exp $ */
/* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */
/*
@@ -181,6 +181,10 @@ struct inpcb *
struct inpcb *
in6_pcbhashlookup __P((struct inpcbtable *, struct in6_addr *,
u_int, struct in6_addr *, u_int));
+int in6_pcbbind __P((struct inpcb *, struct mbuf *));
+int in6_pcbconnect __P((struct inpcb *, struct mbuf *));
+int in6_setsockaddr __P((struct inpcb *, struct mbuf *));
+int in6_setpeeraddr __P((struct inpcb *, struct mbuf *));
#endif /* INET6 */
void in_pcbinit __P((struct inpcbtable *, int));
struct inpcb *
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index d249293406a..1583d199f98 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_var.h,v 1.9 1998/12/26 12:35:12 provos Exp $ */
+/* $OpenBSD: ip_var.h,v 1.10 1999/01/11 02:01:34 deraadt Exp $ */
/* $NetBSD: ip_var.h,v 1.16 1996/02/13 23:43:20 christos Exp $ */
/*
@@ -65,7 +65,7 @@ struct ipqent {
LIST_ENTRY(ipqent) ipqe_q;
union {
struct ip *_ip;
- struct tcpiphdr *_tcp;
+ struct tcphdr *_tcp;
} _ipqe_u1;
union {
u_int8_t _mff; /* for IP fragmentation */
@@ -189,6 +189,7 @@ struct mbuf *
void ip_stripoptions __P((struct mbuf *, struct mbuf *));
int ip_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
void ipintr __P((void));
+void ipv4_input __P((struct mbuf *, ...));
int rip_ctloutput __P((int, struct socket *, int, int, struct mbuf **));
void rip_init __P((void));
void rip_input __P((struct mbuf *, ...));
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 344dc62fb23..75eb85dc4ed 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: raw_ip.c,v 1.14 1999/01/08 21:51:23 provos Exp $ */
+/* $OpenBSD: raw_ip.c,v 1.15 1999/01/11 02:01:34 deraadt Exp $ */
/* $NetBSD: raw_ip.c,v 1.25 1996/02/18 18:58:33 christos Exp $ */
/*
@@ -36,6 +36,18 @@
* @(#)raw_ip.c 8.2 (Berkeley) 1/4/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>.
+*/
+
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
@@ -84,7 +96,8 @@ rip_init()
in_pcbinit(&rawcbtable, 1);
}
-struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
+struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
+
/*
* Setup generic address and protocol structures
* for raw_input routine, then pass them along with
@@ -137,6 +150,7 @@ rip_input(m, va_alist)
sorwakeup(last);
} else {
m_freem(m);
+ /* Perhaps should send an ICMP protocol unreachable here. */
ipstat.ips_noproto++;
ipstat.ips_delivered--;
}
@@ -214,6 +228,13 @@ rip_output(m, va_alist)
flags |= IP_RAWOUTPUT;
ipstat.ips_rawout++;
}
+#ifdef INET6
+ /*
+ * A thought: Even though raw IP shouldn't be able to set IPv6
+ * multicast options, if it does, the last parameter to
+ * ip_output should be guarded against v6/v4 problems.
+ */
+#endif
return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
inp->inp_moptions, inp));
}
diff --git a/sys/netinet/tcp.h b/sys/netinet/tcp.h
index d259fede69b..e2140aec80d 100644
--- a/sys/netinet/tcp.h
+++ b/sys/netinet/tcp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp.h,v 1.5 1999/01/07 09:14:54 deraadt Exp $ */
+/* $OpenBSD: tcp.h,v 1.6 1999/01/11 02:01:35 deraadt Exp $ */
/* $NetBSD: tcp.h,v 1.8 1995/04/17 05:32:58 cgd Exp $ */
/*
@@ -36,7 +36,11 @@
* @(#)tcp.h 8.1 (Berkeley) 6/10/93
*/
+#ifndef _NETINET_TCP_H_
+#define _NETINET_TCP_H_
+
typedef u_int32_t tcp_seq;
+
/*
* TCP header.
* Per RFC 793, September, 1981.
@@ -65,6 +69,8 @@ struct tcphdr {
u_int16_t th_sum; /* checksum */
u_int16_t th_urp; /* urgent pointer */
};
+#define th_reseqlen th_urp /* TCP data length for
+ resequencing/reassembly */
#define TCPOPT_EOL 0
#define TCPOPT_NOP 1
@@ -111,3 +117,5 @@ struct tcphdr {
#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
#define TCP_MAXSEG 0x02 /* set maximum segment size */
#define TCP_SACK_DISABLE 0x300 /* disable SACKs(if enabled by deflt.)*/
+
+#endif /* !_NETINET_TCP_H_ */
diff --git a/sys/netinet/tcp_debug.c b/sys/netinet/tcp_debug.c
index 6adc013193e..a728744b64f 100644
--- a/sys/netinet/tcp_debug.c
+++ b/sys/netinet/tcp_debug.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_debug.c,v 1.3 1998/11/17 19:23:01 provos Exp $ */
+/* $OpenBSD: tcp_debug.c,v 1.4 1999/01/11 02:01:35 deraadt Exp $ */
/* $NetBSD: tcp_debug.c,v 1.10 1996/02/13 23:43:36 christos Exp $ */
/*
@@ -36,6 +36,18 @@
* @(#)tcp_debug.c 8.1 (Berkeley) 6/10/93
*/
+/*
+%%% 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>.
+*/
+
#ifdef TCPDEBUG
/* load symbolic names */
#define PRUREQUESTS
@@ -68,6 +80,11 @@
#include <netinet/tcpip.h>
#include <netinet/tcp_debug.h>
+#ifdef INET6
+#include <netinet6/ipv6.h>
+#include <netinet6/in6.h>
+#endif /* INET6 */
+
#ifdef TCPDEBUG
int tcpconsdebug = 0;
#endif
@@ -75,17 +92,22 @@ int tcpconsdebug = 0;
* Tcp debug routines
*/
void
-tcp_trace(act, ostate, tp, ti, req)
+tcp_trace(act, ostate, tp, ti, req, len)
short act, ostate;
struct tcpcb *tp;
struct tcpiphdr *ti;
int req;
+ int len;
{
#ifdef TCPDEBUG
tcp_seq seq, ack;
- int len, flags;
+ int flags;
#endif
struct tcp_debug *td = &tcp_debug[tcp_debx++];
+#ifdef INET6
+ struct tcphdr *th;
+ struct tcpipv6hdr *ti6 = (struct tcpipv6hdr *)ti;
+#endif
if (tcp_debx == TCP_NDEBUG)
tcp_debx = 0;
@@ -97,10 +119,29 @@ tcp_trace(act, ostate, tp, ti, req)
td->td_cb = *tp;
else
bzero((caddr_t)&td->td_cb, sizeof (*tp));
+#ifdef INET6
+ if (tp->pf == PF_INET6) {
+ if (ti) {
+ th = &ti6->ti6_t;
+ td->td_ti6 = *ti6;
+ } else {
+ bzero(&td->td_ti6, sizeof(struct tcpipv6hdr));
+ }
+ } else {
+ if (ti) {
+ th = &ti->ti_t;
+ td->td_ti = *ti;
+ } else {
+ bzero(&td->td_ti, sizeof(struct tcpiphdr));
+ }
+ }
+#else /* INET6 */
if (ti)
td->td_ti = *ti;
else
bzero((caddr_t)&td->td_ti, sizeof (*ti));
+#endif /* INET6 */
+
td->td_req = req;
#ifdef TCPDEBUG
if (tcpconsdebug == 0)
@@ -117,26 +158,22 @@ tcp_trace(act, ostate, tp, ti, req)
case TA_DROP:
if (ti == 0)
break;
- seq = ti->ti_seq;
- ack = ti->ti_ack;
- len = ti->ti_len;
+ seq = th->th_seq;
+ ack = th->th_ack;
if (act == TA_OUTPUT) {
seq = ntohl(seq);
ack = ntohl(ack);
- len = ntohs((u_int16_t)len);
}
- if (act == TA_OUTPUT)
- len -= sizeof (struct tcphdr);
if (len)
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) {
#ifndef lint
char *cp = "<";
-#define pf(f) { if (ti->ti_flags&TH_/**/f) { printf("%s%s", cp, "f"); cp = ","; } }
+#define pf(f) { if (th->th_flags&TH_/**/f) { printf("%s%s", cp, "f"); cp = ","; } }
pf(SYN); pf(ACK); pf(FIN); pf(RST); pf(PUSH); pf(URG);
#endif
printf(">");
diff --git a/sys/netinet/tcp_debug.h b/sys/netinet/tcp_debug.h
index be53b602410..0504f95df92 100644
--- a/sys/netinet/tcp_debug.h
+++ b/sys/netinet/tcp_debug.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_debug.h,v 1.3 1997/08/26 20:02:31 deraadt Exp $ */
+/* $OpenBSD: tcp_debug.h,v 1.4 1999/01/11 02:01:35 deraadt Exp $ */
/* $NetBSD: tcp_debug.h,v 1.5 1994/06/29 06:38:38 cgd Exp $ */
/*
@@ -36,12 +36,15 @@
* @(#)tcp_debug.h 8.1 (Berkeley) 6/10/93
*/
+#include <netinet6/tcpipv6.h>
+
struct tcp_debug {
n_time td_time;
short td_act;
short td_ostate;
caddr_t td_tcb;
struct tcpiphdr td_ti;
+ struct tcpipv6hdr td_ti6;
short td_req;
struct tcpcb td_cb;
};
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;
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 6e88e2dbc9b..8b3c5c57683 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_output.c,v 1.15 1998/11/25 05:44:37 millert Exp $ */
+/* $OpenBSD: tcp_output.c,v 1.16 1999/01/11 02:01:36 deraadt Exp $ */
/* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */
/*
@@ -36,6 +36,18 @@
* @(#)tcp_output.c 8.3 (Berkeley) 12/30/93
*/
+/*
+%%% 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>.
+*/
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -44,6 +56,7 @@
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/errno.h>
+#include <sys/domain.h>
#include <net/route.h>
@@ -66,6 +79,10 @@
#include <netiso/tuba_table.h>
#endif
+#ifdef INET6
+#include <netinet6/tcpipv6.h>
+#endif /* INET6 */
+
#ifdef notyet
extern struct mbuf *m_copypack();
#endif
@@ -165,6 +182,10 @@ tcp_output(tp)
int off, flags, error;
register struct mbuf *m;
register struct tcpiphdr *ti;
+ register struct tcphdr *th;
+#ifdef INET6
+ register struct tcpipv6hdr *ti6 = NULL;
+#endif /* INET6 */
u_char opt[MAX_TCPOPTLEN];
unsigned int optlen, hdrlen;
int idle, sendalot;
@@ -419,7 +440,20 @@ send:
* link header, i.e.
* max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN
*/
+#ifdef INET6
+ /*
+ * For IPv6, this has changed to be:
+ * max_linkhdr + sizeof(struct tcphdr) + optlen +
+ * sizeof(struct ipv6) <= MHLEN
+ * This MIGHT be harder...
+ */
+#endif /* INET6 */
optlen = 0;
+#ifdef INET6
+ if (tp->pf == PF_INET6) /* if tp->pf is 0, then assume IPv4. */
+ hdrlen = sizeof(struct tcphdr) + sizeof(struct ipv6);
+ else
+#endif /* INET6 */
hdrlen = sizeof (struct tcpiphdr);
if (flags & TH_SYN) {
tp->snd_nxt = tp->iss;
@@ -596,10 +630,31 @@ send:
m->m_len = hdrlen;
}
m->m_pkthdr.rcvif = (struct ifnet *)0;
- ti = mtod(m, struct tcpiphdr *);
- if (tp->t_template == 0)
- panic("tcp_output");
- bcopy((caddr_t)tp->t_template, (caddr_t)ti, sizeof (struct tcpiphdr));
+#ifdef INET6
+ if (tp->pf == PF_INET6) {
+ ti6 = mtod(m, struct tcpipv6hdr *);
+ ti = NULL;
+
+ if (!tp->t_template)
+ panic("tcp_output");
+
+ bcopy((caddr_t)tp->t_template, (caddr_t)ti6,
+ sizeof (struct tcpipv6hdr));
+
+ th = &ti6->ti6_t;
+ } else
+#endif /* INET6 */
+ {
+ ti = mtod(m, struct tcpiphdr *);
+
+ if (tp->t_template == 0)
+ panic("tcp_output");
+
+ bcopy((caddr_t)tp->t_template, (caddr_t)ti,
+ sizeof (struct tcpiphdr));
+
+ th = &ti->ti_t;
+ };
/*
* Fill in fields, remembering maximum advertised
@@ -623,9 +678,10 @@ send:
* (retransmit and persist are mutually exclusive...)
*/
if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST])
- ti->ti_seq = htonl(tp->snd_nxt);
+ th->th_seq = htonl(tp->snd_nxt);
else
- ti->ti_seq = htonl(tp->snd_max);
+ th->th_seq = htonl(tp->snd_max);
+
#ifdef TCP_SACK
if (sack_rxmit) {
/*
@@ -635,7 +691,7 @@ send:
*/
if (sendalot)
sendalot = 0;
- ti->ti_seq = htonl(p->rxmit);
+ th->th_seq = htonl(p->rxmit);
p->rxmit += len;
#if defined(TCP_SACK) && defined(TCP_FACK)
tp->retran_data += len;
@@ -643,12 +699,13 @@ send:
}
#endif /* TCP_SACK */
- ti->ti_ack = htonl(tp->rcv_nxt);
+ th->th_ack = htonl(tp->rcv_nxt);
if (optlen) {
- bcopy((caddr_t)opt, (caddr_t)(ti + 1), optlen);
- ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2;
+ bcopy((caddr_t)opt, (caddr_t)(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.
@@ -661,13 +718,13 @@ send:
win = (long)(tp->rcv_adv - tp->rcv_nxt);
if (flags & TH_RST)
win = 0;
- ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale));
+ th->th_win = htons((u_int16_t) (win>>tp->rcv_scale));
if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
u_int32_t urp = tp->snd_up - tp->snd_nxt;
if (urp > IP_MAXPACKET)
urp = IP_MAXPACKET;
- ti->ti_urp = htons((u_int16_t)urp);
- ti->ti_flags |= TH_URG;
+ th->th_urp = htons((u_int16_t)urp);
+ th->th_flags |= TH_URG;
} else
/*
* If no urgent pointer to send, then we pull
@@ -681,10 +738,19 @@ send:
* Put TCP length in extended header, and then
* checksum extended header and data.
*/
- if (len + optlen)
- ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) +
- optlen + len));
- ti->ti_sum = in_cksum(m, (int)(hdrlen + len));
+#ifdef INET6
+ if (tp->pf == PF_INET6) {
+ th->th_sum = in6_cksum(m, IPPROTO_TCP,
+ sizeof(struct tcphdr) + optlen + len,
+ sizeof(struct ipv6));
+ } else
+#endif /* INET6 */
+ {
+ if (len + optlen)
+ ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) +
+ optlen + len));
+ ti->ti_sum = in_cksum(m, (int)(hdrlen + len));
+ }
/*
* In transmit state, time the transmission and arrange for
@@ -762,7 +828,12 @@ send:
* Trace.
*/
if (so->so_options & SO_DEBUG)
- tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0);
+#if INET6
+ tcp_trace(TA_OUTPUT, tp->t_state, tp,
+ (tp->pf == AF_INET6) ? (struct tcpiphdr *)ti6 : ti, 0, len);
+#else
+ tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0, len);
+#endif
/*
* Fill in IP length and desired time to live and
@@ -776,17 +847,25 @@ send:
error = tuba_output(m, tp);
else
#endif
+#ifdef INET6
+ if (tp->pf == PF_INET6) {
+ ((struct ipv6 *)ti6)->ipv6_length = m->m_pkthdr.len - sizeof(struct ipv6);
+
+ /* Following fields are already grabbed from the tcp_template. */
+ /* ((struct ipv6 *)ti6)->ipv6_versfl = ntohl(0x60000000);
+ ((struct ipv6 *)ti6)->ipv6_nexthdr = IPPROTO_TCP;
+ ((struct ipv6 *)ti6)->ipv6_hoplimit =
+ tp->t_inpcb->inp_ipv6.ipv6_hoplimit;*/
+
+ error = ipv6_output(m, &tp->t_inpcb->inp_route6, (so->so_options & SO_DONTROUTE), NULL, NULL, tp->t_inpcb->inp_socket);
+ } else
+#endif /* INET6 */
{
((struct ip *)ti)->ip_len = m->m_pkthdr.len;
((struct ip *)ti)->ip_ttl = tp->t_inpcb->inp_ip.ip_ttl; /* XXX */
((struct ip *)ti)->ip_tos = tp->t_inpcb->inp_ip.ip_tos; /* XXX */
-#if BSD >= 43
error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
so->so_options & SO_DONTROUTE, 0, tp->t_inpcb);
-#else
- error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route,
- so->so_options & SO_DONTROUTE);
-#endif
#if defined(TCP_SACK) && defined(TCP_FACK)
/* Update snd_awnd to reflect the new data that was sent. */
tp->snd_awnd = tcp_seq_subtract(tp->snd_max, tp->snd_fack) +
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 255f94e8519..bd08bc4550b 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_subr.c,v 1.12 1998/11/17 19:23:02 provos Exp $ */
+/* $OpenBSD: tcp_subr.c,v 1.13 1999/01/11 02:01:36 deraadt Exp $ */
/* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */
/*
@@ -36,6 +36,18 @@
* @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93
*/
+/*
+%%% 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>.
+*/
+
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
@@ -63,6 +75,12 @@
#include <netinet/tcpip.h>
#include <dev/rndvar.h>
+#ifdef INET6
+#include <netinet6/ipv6_var.h>
+#include <netinet6/tcpipv6.h>
+#include <sys/domain.h>
+#endif /* INET6 */
+
/* patchable/settable parameters for tcp */
int tcp_mssdflt = TCP_MSS;
int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
@@ -95,6 +113,10 @@ int tcp_do_sack = TCP_DO_SACK; /* RFC 2018 selective ACKs */
#endif
int tcbhashsize = TCBHASHSIZE;
+#ifdef INET6
+extern int ipv6_defhoplmt;
+#endif /* INET6 */
+
/*
* Tcp initialization
*/
@@ -107,10 +129,18 @@ tcp_init()
tcp_iss = arc4random() + 1;
#endif /* !TCP_COMPAT_42 */
in_pcbinit(&tcbtable, tcbhashsize);
- if (max_protohdr < sizeof(struct tcpiphdr))
- max_protohdr = sizeof(struct tcpiphdr);
- if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN)
+
+#ifdef INET6
+ /*
+ * Since sizeof(struct ipv6) > sizeof(struct ip), we
+ * do max length checks/computations only on the former.
+ */
+ if (max_protohdr < (sizeof(struct ipv6) + sizeof(struct tcphdr)))
+ max_protohdr = (sizeof(struct ipv6) + sizeof(struct tcphdr));
+ if ((max_linkhdr + sizeof(struct ipv6) + sizeof(struct tcphdr)) >
+ MHLEN)
panic("tcp_init");
+#endif /* INET6 */
}
/*
@@ -119,6 +149,14 @@ tcp_init()
* in a skeletal tcp/ip header, minimizing the amount of work
* necessary when the connection is used.
*/
+#ifdef INET6
+/*
+ * To support IPv6 in addition to IPv4 and considering that the sizes of
+ * the IPv4 and IPv6 headers are not the same, we now use a separate pointer
+ * for the TCP header. Also, we made the former tcpiphdr header pointer
+ * into just an IP overlay pointer, with casting as appropriate for v6. rja
+ */
+#endif /* INET6 */
struct tcpiphdr *
tcp_template(tp)
struct tcpcb *tp;
@@ -126,29 +164,60 @@ tcp_template(tp)
register struct inpcb *inp = tp->t_inpcb;
register struct mbuf *m;
register struct tcpiphdr *n;
+ register struct tcphdr *th;
+#ifdef INET6
+ register struct tcpipv6hdr *ti6;
+ register struct ipv6 *ipv6;
+#endif /* INET6 */
if ((n = tp->t_template) == 0) {
m = m_get(M_DONTWAIT, MT_HEADER);
if (m == NULL)
return (0);
- m->m_len = sizeof (struct tcpiphdr);
+#ifdef INET6
+ if (tp->pf == PF_INET6)
+ m->m_len = sizeof (struct tcphdr) + sizeof(struct ipv6);
+ else
+#endif /* INET6 */
+ m->m_len = sizeof (struct tcpiphdr);
n = mtod(m, struct tcpiphdr *);
}
- 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 (tp->pf == PF_INET6) {
+
+ ti6 = (struct tcpipv6hdr *)n;
+ ipv6 = (struct ipv6 *)n;
+ th = &ti6->ti6_t;
+
+ ipv6->ipv6_src = inp->inp_laddr6;
+ ipv6->ipv6_dst = inp->inp_faddr6;
+ ipv6->ipv6_versfl = htonl(0x60000000) |
+ (inp->inp_ipv6.ipv6_versfl & htonl(0x0fffffff));
+
+ ipv6->ipv6_nexthdr = IPPROTO_TCP;
+ ipv6->ipv6_length = htons(sizeof(struct tcphdr)); /*XXX*/
+ ipv6->ipv6_hoplimit = inp->inp_ipv6.ipv6_hoplimit;
+ } else
+#endif /* INET6 */
+ {
+ th = &n->ti_t;
+ 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;
+ }
+
+ th->th_sport = inp->inp_lport;
+ th->th_dport = inp->inp_fport;
+ th->th_seq = 0;
+ th->th_ack = 0;
+ th->th_x2 = 0;
+ th->th_off = 5;
+ th->th_flags = 0;
+ th->th_win = 0;
+ th->th_sum = 0;
+ th->th_urp = 0;
return (n);
}
@@ -165,6 +234,9 @@ tcp_template(tp)
* In any case the ack and sequence number of the transmitted
* segment are as specified by the parameters.
*/
+#ifdef INET6
+/* This function looks hairy, because it was so IPv4-dependent. */
+#endif /* INET6 */
void
tcp_respond(tp, ti, m, ack, seq, flags)
struct tcpcb *tp;
@@ -176,11 +248,31 @@ tcp_respond(tp, ti, m, ack, seq, flags)
register int tlen;
int win = 0;
struct route *ro = 0;
+ register struct tcphdr *th;
+#ifdef INET6
+ int is_ipv6 = 0; /* true iff IPv6 */
+#endif /* INET6 */
if (tp) {
win = sbspace(&tp->t_inpcb->inp_socket->so_rcv);
+#ifdef INET6
+ /*
+ * If this is called with an unconnected
+ * socket/tp/pcb (tp->pf is 0), we lose.
+ */
+ is_ipv6 = (tp->pf == PF_INET6);
+
+ /*
+ * The route/route6 distinction is meaningless
+ * unless you're allocating space or passing parameters.
+ */
+#endif /* INET6 */
ro = &tp->t_inpcb->inp_route;
}
+#ifdef INET6
+ else
+ is_ipv6 = (((struct ip *)ti)->ip_v == 6);
+#endif /* INET6 */
if (m == 0) {
m = m_gethdr(M_DONTWAIT, MT_HEADER);
if (m == NULL)
@@ -191,41 +283,87 @@ tcp_respond(tp, ti, m, ack, seq, flags)
tlen = 0;
#endif
m->m_data += max_linkhdr;
- *mtod(m, struct tcpiphdr *) = *ti;
+#ifdef INET6
+ if (is_ipv6)
+ bcopy(ti, mtod(m, caddr_t), sizeof(struct tcphdr) +
+ sizeof(struct ipv6));
+ else
+#endif /* INET6 */
+ bcopy(ti, mtod(m, caddr_t), sizeof(struct tcphdr) +
+ sizeof(struct ip));
+
ti = mtod(m, struct tcpiphdr *);
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);
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, u_int32_t);
- xchg(ti->ti_dport, ti->ti_sport, u_int16_t);
+#ifdef INET6
+ if (is_ipv6) {
+ m->m_len = sizeof(struct tcphdr) + sizeof(struct ipv6);
+ xchg(((struct ipv6 *)ti)->ipv6_dst,\
+ ((struct ipv6 *)ti)->ipv6_src,\
+ struct in6_addr);
+ th = (void *)ti + sizeof(struct ipv6);
+ } else
+#endif /* INET6 */
+ {
+ m->m_len = sizeof (struct tcpiphdr);
+ xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t);
+ th = (void *)ti + sizeof(struct ip);
+ }
+ xchg(th->th_dport, th->th_sport, u_int16_t);
#undef xchg
}
- ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + tlen));
- tlen += sizeof (struct tcpiphdr);
+#ifdef INET6
+ if (is_ipv6) {
+ tlen += sizeof(struct tcphdr) + sizeof(struct ipv6);
+ th = (struct tcphdr *)((caddr_t)ti + sizeof(struct ipv6));
+ } else
+#endif /* INET6 */
+ {
+ ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + tlen));
+ tlen += sizeof (struct tcpiphdr);
+ th = (struct tcphdr *)((caddr_t)ti + sizeof(struct ip));
+ }
+
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;
+ th->th_seq = htonl(seq);
+ th->th_ack = htonl(ack);
+ th->th_x2 = 0;
+ th->th_off = sizeof (struct tcphdr) >> 2;
+ th->th_flags = flags;
if (tp)
- ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale));
+ th->th_win = htons((u_int16_t) (win >> tp->rcv_scale));
else
- ti->ti_win = htons((u_int16_t)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;
- (void) ip_output(m, NULL, ro, 0, NULL, tp ? tp->t_inpcb : NULL);
+ th->th_win = htons((u_int16_t)win);
+ th->th_urp = 0;
+
+#ifdef INET6
+ if (is_ipv6) {
+ ((struct ipv6 *)ti)->ipv6_versfl = htonl(0x60000000);
+ ((struct ipv6 *)ti)->ipv6_nexthdr = IPPROTO_TCP;
+ ((struct ipv6 *)ti)->ipv6_hoplimit = MAXHOPLIMIT;
+ ((struct ipv6 *)ti)->ipv6_length = tlen - sizeof(struct ipv6);
+ th->th_sum = 0;
+ th->th_sum = in6_cksum(m, IPPROTO_TCP,
+ ((struct ipv6 *)ti)->ipv6_length, sizeof(struct ipv6));
+ HTONS(((struct ipv6 *)ti)->ipv6_length);
+ ipv6_output(m, (struct route6 *)ro, 0, NULL, NULL, NULL);
+ } else
+#endif /* INET6 */
+ {
+ bzero(ti->ti_x1, sizeof ti->ti_x1);
+ ti->ti_len = htons((u_short)tlen - sizeof(struct ip));
+ th->th_sum = in_cksum(m, tlen);
+ ((struct ip *)ti)->ip_len = tlen;
+ ((struct ip *)ti)->ip_ttl = ip_defttl;
+ ip_output(m, NULL, ro, 0, NULL, tp ? tp->t_inpcb : NULL);
+ }
}
/*
@@ -263,7 +401,23 @@ tcp_newtcpcb(inp)
TCPTV_MIN, TCPTV_REXMTMAX);
tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
- inp->inp_ip.ip_ttl = ip_defttl;
+#ifdef INET6
+ /*
+ * If we want to use tp->pf for a quick-n-easy way to determine
+ * the outbound dgram type, we cannot make this decision
+ * until a connection is established! Bzero() sets pf to zero, and
+ * that's the way we want it, unless, of course, it's an AF_INET
+ * socket...
+ */
+ if ((inp->inp_flags & INP_IPV6) == 0)
+ tp->pf = PF_INET; /* If AF_INET socket, we can't do v6 from it. */
+
+ if (inp->inp_flags & INP_IPV6)
+ inp->inp_ipv6.ipv6_hoplimit = ipv6_defhoplmt;
+ else
+#endif /* INET6 */
+ inp->inp_ip.ip_ttl = ip_defttl;
+
inp->inp_ppcb = (caddr_t)tp;
return (tp);
}
@@ -310,6 +464,30 @@ tcp_close(tp)
#endif
#ifdef RTV_RTT
register struct rtentry *rt;
+#ifdef INET6
+ register int bound_to_specific = 0; /* I.e. non-default */
+
+ /*
+ * This code checks the nature of the route for this connection.
+ * Normally this is done by two simple checks in the next
+ * INET/INET6 ifdef block, but because of two possible lower layers,
+ * that check is done here.
+ *
+ * Perhaps should be doing this only for a RTF_HOST route.
+ */
+ rt = inp->inp_route.ro_rt; /* Same for route or route6. */
+ if (tp->pf == PF_INET6) {
+ if (rt)
+ bound_to_specific =
+ !(IN6_IS_ADDR_UNSPECIFIED(&
+ ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr));
+ } else {
+ if (rt)
+ bound_to_specific =
+ (((struct sockaddr_in *)rt_key(rt))->
+ sin_addr.s_addr != INADDR_ANY);
+ }
+#endif /* INET6 */
/*
* If we sent enough data to get some meaningful characteristics,
@@ -323,9 +501,17 @@ tcp_close(tp)
* Don't update the default route's characteristics and don't
* update anything that the user "locked".
*/
+#ifdef INET6
+ /*
+ * Note that rt and bound_to_specific are set above.
+ */
+ if (SEQ_LT(tp->iss + so->so_snd.sb_hiwat * 16, tp->snd_max) &&
+ rt && bound_to_specific) {
+#else /* INET6 */
if (SEQ_LT(tp->iss + so->so_snd.sb_hiwat * 16, tp->snd_max) &&
(rt = inp->inp_route.ro_rt) &&
satosin(rt_key(rt))->sin_addr.s_addr != INADDR_ANY) {
+#endif /* INET6 */
register u_long i = 0;
if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) {
@@ -369,7 +555,15 @@ 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));
+#ifdef INET6
+ if (tp->pf == PF_INET6)
+ i *= (u_long)(tp->t_maxseg + sizeof (struct tcphdr)
+ + sizeof(struct ipv6));
+ else
+#endif /* INET6 */
+ i *= (u_long)(tp->t_maxseg +
+ sizeof (struct tcpiphdr));
+
if (rt->rt_rmx.rmx_ssthresh)
rt->rt_rmx.rmx_ssthresh =
(rt->rt_rmx.rmx_ssthresh + i) / 2;
@@ -378,12 +572,27 @@ tcp_close(tp)
}
}
#endif /* RTV_RTT */
+
/* free the reassembly queue, if any */
- while ((qe = tp->segq.lh_first) != NULL) {
- LIST_REMOVE(qe, ipqe_q);
- m_freem(qe->ipqe_m);
- FREE(qe, M_IPQ);
- }
+#ifdef INET6
+ /* Reassembling TCP segments in v6 might be sufficiently different
+ * to merit two codepaths to free the reasssembly queue.
+ * If an undecided TCP socket, then the IPv4 codepath will be used
+ * because it won't matter much anyway.
+ */
+ if (tp->pf == AF_INET6) {
+ while ((qe = tp->segq.lh_first) != NULL) {
+ LIST_REMOVE(qe, ipqe_q);
+ m_freem(qe->ipqe_m);
+ FREE(qe, M_IPQ);
+ }
+ } else
+#endif /* INET6 */
+ while ((qe = tp->segq.lh_first) != NULL) {
+ LIST_REMOVE(qe, ipqe_q);
+ m_freem(qe->ipqe_m);
+ FREE(qe, M_IPQ);
+ }
#ifdef TCP_SACK
/* Free SACK holes. */
q = p = tp->snd_holes;
@@ -466,12 +675,28 @@ tcp_ctlinput(cmd, sa, v)
ip = 0;
else if (errno == 0)
return NULL;
- if (ip) {
- th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
- in_pcbnotify(&tcbtable, sa, th->th_dport, ip->ip_src,
- th->th_sport, errno, notify);
+
+#ifdef INET6
+ if (sa->sa_family == AF_INET6) {
+ if (ip) {
+ struct ipv6 *ipv6 = (struct ipv6 *)ip;
+
+ th = (struct tcphdr *)(ipv6 + 1);
+ in6_pcbnotify(&tcbtable, sa, th->th_dport,
+ &ipv6->ipv6_src, th->th_sport, cmd, notify);
+ } else
+ in6_pcbnotify(&tcbtable, sa, 0,
+ (struct in6_addr *)&in6addr_any, 0, cmd, notify);
} else
- in_pcbnotifyall(&tcbtable, sa, errno, notify);
+#endif /* INET6 */
+ {
+ if (ip) {
+ th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
+ in_pcbnotify(&tcbtable, sa, th->th_dport, ip->ip_src,
+ th->th_sport, errno, notify);
+ } else
+ in_pcbnotifyall(&tcbtable, sa, errno, notify);
+ }
return NULL;
}
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 02cb808c772..953ebef8e9d 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_usrreq.c,v 1.31 1999/01/07 06:05:05 deraadt Exp $ */
+/* $OpenBSD: tcp_usrreq.c,v 1.32 1999/01/11 02:01:36 deraadt Exp $ */
/* $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */
/*
@@ -36,6 +36,18 @@
* @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/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>.
+*/
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -73,6 +85,10 @@
extern int check_ipsec_policy __P((struct inpcb *, u_int32_t));
#endif
+#ifdef INET6
+#include <sys/domain.h>
+#endif /* INET6 */
+
/*
* TCP protocol interface to socket abstraction.
*/
@@ -103,9 +119,16 @@ tcp_usrreq(so, req, m, nam, control)
int error = 0;
int ostate;
- if (req == PRU_CONTROL)
- return (in_control(so, (u_long)m, (caddr_t)nam,
- (struct ifnet *)control));
+ if (req == PRU_CONTROL) {
+#ifdef INET6
+ if (sotopf(so) == PF_INET6)
+ return in6_control(so, (u_long)m, (caddr_t)nam,
+ (struct ifnet *)control, 0);
+ else
+#endif /* INET6 */
+ return (in_control(so, (u_long)m, (caddr_t)nam,
+ (struct ifnet *)control));
+ }
if (control && control->m_len) {
m_freem(control);
if (m)
@@ -176,6 +199,20 @@ tcp_usrreq(so, req, m, nam, control)
error = in_pcbbind(inp, nam);
if (error)
break;
+#ifdef INET6
+ /*
+ * If we bind to an address, set up the tp->pf accordingly!
+ */
+ if (inp->inp_flags & INP_IPV6) {
+ /* If a PF_INET6 socket... */
+ if (inp->inp_flags & INP_IPV6_MAPPED)
+ tp->pf = AF_INET;
+ else if ((inp->inp_flags & INP_IPV6_UNDEC) == 0)
+ tp->pf = AF_INET6;
+ /* else tp->pf is still 0. */
+ }
+ /* else socket is PF_INET, and tp->pf is PF_INET. */
+#endif /* INET6 */
break;
/*
@@ -184,6 +221,8 @@ tcp_usrreq(so, req, m, nam, control)
case PRU_LISTEN:
if (inp->inp_lport == 0)
error = in_pcbbind(inp, NULL);
+ /* If the in_pcbbind() above is called, the tp->pf
+ should still be whatever it was before. */
if (error == 0)
tp->t_state = TCPS_LISTEN;
break;
@@ -198,11 +237,28 @@ tcp_usrreq(so, req, m, nam, control)
case PRU_CONNECT:
sin = mtod(nam, struct sockaddr_in *);
- /* Disallow connects to a multicast address */
- if (IN_MULTICAST(sin->sin_addr.s_addr)) {
- error = EINVAL;
- break;
- }
+#ifdef INET6
+ if (sin->sin_family == AF_INET6) {
+ struct in6_addr *in6_addr = &mtod(nam,
+ struct sockaddr_in6 *)->sin6_addr;
+
+ if (IN6_IS_ADDR_UNSPECIFIED(in6_addr) ||
+ IN6_IS_ADDR_MULTICAST(in6_addr) ||
+ (IN6_IS_ADDR_V4MAPPED(in6_addr) &&
+ ((in6_addr->in6a_words[3] == INADDR_ANY) ||
+ IN_MULTICAST(in6_addr->in6a_words[3]) ||
+ in_broadcast(sin->sin_addr, NULL)))) {
+ error = EINVAL;
+ break;
+ }
+ } else if (sin->sin_family == AF_INET)
+#endif /* INET6 */
+ if ((sin->sin_addr.s_addr == INADDR_ANY) ||
+ IN_MULTICAST(sin->sin_addr.s_addr) ||
+ in_broadcast(sin->sin_addr, NULL)) {
+ error = EINVAL;
+ break;
+ }
/* Trying to connect to some broadcast address */
if (in_broadcast(sin->sin_addr, NULL)) {
@@ -219,12 +275,34 @@ tcp_usrreq(so, req, m, nam, control)
if (error)
break;
+#ifdef INET6
+ /*
+ * With a connection, I now know the version of IP
+ * is in use and hence can set tp->pf with authority.
+ */
+ if (inp->inp_flags & INP_IPV6) {
+ if (inp->inp_flags & INP_IPV6_MAPPED)
+ tp->pf = PF_INET;
+ else
+ tp->pf = PF_INET6;
+ }
+ /* else I'm a PF_INET socket, and hence tp->pf is PF_INET. */
+#endif /* INET6 */
+
tp->t_template = tcp_template(tp);
if (tp->t_template == 0) {
in_pcbdisconnect(inp);
error = ENOBUFS;
break;
}
+
+#ifdef INET6
+ if ((inp->inp_flags & INP_IPV6) && (tp->pf == PF_INET)) {
+ inp->inp_ip.ip_ttl = ip_defttl;
+ inp->inp_ip.ip_tos = 0;
+ }
+#endif /* INET6 */
+
so->so_state |= SS_CONNECTOUT;
/* Compute window scaling to request. */
while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
@@ -388,7 +466,7 @@ tcp_usrreq(so, req, m, nam, control)
panic("tcp_usrreq");
}
if (tp && (so->so_options & SO_DEBUG))
- tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
+ tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req, 0);
splx(s);
return (error);
}
@@ -414,12 +492,28 @@ tcp_ctloutput(op, so, level, optname, mp)
(void) m_free(*mp);
return (ECONNRESET);
}
+#ifdef INET6
+ tp = intotcpcb(inp);
+#endif /* INET6 */
if (level != IPPROTO_TCP) {
- error = ip_ctloutput(op, so, level, optname, mp);
+#ifdef INET6
+ /*
+ * Not sure if this is the best approach.
+ * It seems to be, but we don't set tp->pf until the connection
+ * is established, which may lead to confusion in the case of
+ * AF_INET6 sockets which get SET/GET options for IPv4.
+ */
+ if (tp->pf == PF_INET6)
+ error = ipv6_ctloutput(op, so, level, optname, mp);
+ else
+#endif /* INET6 */
+ error = ip_ctloutput(op, so, level, optname, mp);
splx(s);
return (error);
}
+#ifndef INET6
tp = intotcpcb(inp);
+#endif /* !INET6 */
switch (op) {
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index e7949e60a84..9d136abf83f 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_var.h,v 1.14 1998/11/18 17:42:22 deraadt Exp $ */
+/* $OpenBSD: tcp_var.h,v 1.15 1999/01/11 02:01:36 deraadt Exp $ */
/* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */
/*
@@ -77,7 +77,8 @@ struct tcpcb {
#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */
#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */
- struct tcpiphdr *t_template; /* skeletal packet for transmit */
+ struct tcpiphdr *t_template; /* skeletal packet for transmit, will
+ * be either tcpiphdr or tcpipv6hdr */
struct inpcb *t_inpcb; /* back pointer to internet pcb */
/*
* The following fields are used as in the protocol specification.
@@ -165,6 +166,8 @@ struct tcpcb {
/* TUBA stuff */
caddr_t t_tuba_pcb; /* next level down pcb for TCP over z */
+
+ int pf;
};
#define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb)
@@ -324,7 +327,7 @@ struct tcpcb *
struct tcpcb *
tcp_drop __P((struct tcpcb *, int));
void tcp_dooptions __P((struct tcpcb *,
- u_char *, int, struct tcpiphdr *, int *, u_int32_t *, u_int32_t *));
+ u_char *, int, struct tcphdr *, int *, u_int32_t *, u_int32_t *));
void tcp_drain __P((void));
void tcp_fasttimo __P((void));
void tcp_init __P((void));
@@ -334,10 +337,9 @@ struct tcpcb *
tcp_newtcpcb __P((struct inpcb *));
void tcp_notify __P((struct inpcb *, int));
int tcp_output __P((struct tcpcb *));
-void tcp_pulloutofband __P((struct socket *,
- struct tcpiphdr *, struct mbuf *));
+void tcp_pulloutofband __P((struct socket *, u_int, struct mbuf *));
void tcp_quench __P((struct inpcb *, int));
-int tcp_reass __P((struct tcpcb *, struct tcpiphdr *, struct mbuf *));
+int tcp_reass __P((struct tcpcb *, struct tcphdr *, struct mbuf *, int *));
void tcp_respond __P((struct tcpcb *,
struct tcpiphdr *, struct mbuf *, tcp_seq, tcp_seq, int));
void tcp_setpersist __P((struct tcpcb *));
@@ -346,7 +348,7 @@ struct tcpiphdr *
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 *, struct tcpiphdr *, int, int));
struct tcpcb *
tcp_usrclosed __P((struct tcpcb *));
int tcp_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
@@ -371,4 +373,4 @@ int tcp_newreno __P((struct tcpcb *, struct tcpiphdr *));
u_long tcp_seq_subtract __P((u_long, u_long ));
#endif /* TCP_NEWRENO || TCP_SACK */
-#endif /* KERNEL */
+#endif /* _KERNEL */
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index e3f173c79e3..89bf839fdec 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: udp_usrreq.c,v 1.18 1999/01/07 06:05:05 deraadt Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.19 1999/01/11 02:01:36 deraadt Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
@@ -36,6 +36,18 @@
* @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/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>.
+*/
+
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
@@ -69,13 +81,23 @@ extern int check_ipsec_policy __P((struct inpcb *, u_int32_t));
#include <machine/stdarg.h>
+#ifdef INET6
+#include <netinet6/in6.h>
+#include <netinet6/ipv6.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/ipv6_var.h>
+#include <netinet6/ipv6_icmp.h>
+
+extern int ipv6_defhoplmt;
+
+#endif /* INET6 */
+
/*
* UDP protocol implementation.
* Per RFC 768, August, 1980.
*/
int udpcksum = 1;
-struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
static void udp_detach __P((struct inpcb *));
static void udp_notify __P((struct inpcb *, int));
@@ -114,6 +136,17 @@ udp_input(m, va_alist)
int iphlen;
va_list ap;
u_int16_t savesum;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+#endif /* INET6 */
+ } srcsa, dstsa;
+#ifdef INET6
+ struct ipv6 *ipv6;
+ struct sockaddr_in6 src_v4mapped;
+#endif /* INET6 */
va_start(ap, m);
iphlen = va_arg(ap, int);
@@ -121,12 +154,39 @@ udp_input(m, va_alist)
udpstat.udps_ipackets++;
+ switch (mtod(m, struct ip *)->ip_v) {
+ case 4:
+ ip = mtod(m, struct ip *);
+#ifdef INET6
+ ipv6 = NULL;
+#endif /* INET6 */
+ srcsa.sa.sa_family = AF_INET;
+ break;
+#ifdef INET6
+ case 6:
+ ip = NULL;
+ ipv6 = mtod(m, struct ipv6 *);
+ srcsa.sa.sa_family = AF_INET6;
+ break;
+#endif /* INET6 */
+ default:
+ printf("udp_input: received unknown IP version %d", mtod(m, struct ip *)->ip_v);
+ goto bad;
+ }
+
/*
* Strip IP options, if any; should skip this,
* make available to user, and use on returned packets,
* but we don't yet have a way to check the checksum
* with options still present.
*/
+ /*
+ * (contd. from above...) Furthermore, we may want to strip options
+ * for such things as ICMP errors, where options just get in the way.
+ */
+#ifdef INET6
+ if (ip)
+#endif /* INET6 */
if (iphlen > sizeof (struct ip)) {
ip_stripoptions(m, (struct mbuf *)0);
iphlen = sizeof(struct ip);
@@ -135,34 +195,39 @@ udp_input(m, va_alist)
/*
* Get IP and UDP header together in first mbuf.
*/
- ip = mtod(m, struct ip *);
if (m->m_len < iphlen + sizeof(struct udphdr)) {
- if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
+ if ((m = m_pullup2(m, iphlen + sizeof(struct udphdr))) == 0) {
udpstat.udps_hdrops++;
return;
}
- ip = mtod(m, struct ip *);
+#ifdef INET6
+ if (ipv6)
+ ipv6 = mtod(m, struct ipv6 *);
+ else
+#endif /* INET6 */
+ ip = mtod(m, struct ip *);
}
- uh = (struct udphdr *)((caddr_t)ip + iphlen);
+ uh = (struct udphdr *)(mtod(m, caddr_t) + iphlen);
/*
* Make mbuf data length reflect UDP length.
* If not enough data to reflect UDP length, drop.
*/
len = ntohs((u_int16_t)uh->uh_ulen);
- if (ip->ip_len != len) {
- if (len > ip->ip_len || len < sizeof(struct udphdr)) {
+ if (m->m_pkthdr.len - iphlen != len) {
+ if (len > (m->m_pkthdr.len - iphlen) ||
+ len < sizeof(struct udphdr)) {
udpstat.udps_badlen++;
goto bad;
}
- m_adj(m, len - ip->ip_len);
- /* ip->ip_len = len; */
+ m_adj(m, len - (m->m_pkthdr.len - iphlen));
}
/*
* Save a copy of the IP header in case we want restore it
* for sending an ICMP error message in response.
*/
- save_ip = *ip;
+ if (ip)
+ save_ip = *ip;
/*
* Checksum extended UDP header and data.
@@ -170,6 +235,17 @@ udp_input(m, va_alist)
* udpcksum is not set.
*/
savesum = uh->uh_sum;
+#ifdef INET6
+ if (ipv6) {
+ /*
+ * In IPv6, the UDP checksum is ALWAYS used.
+ */
+ if ((uh->uh_sum = in6_cksum(m, IPPROTO_UDP, len, iphlen))) {
+ udpstat.udps_badsum++;
+ goto bad;
+ }
+ } else
+#endif /* INET6 */
if (uh->uh_sum) {
bzero(((struct ipovly *)ip)->ih_x1,
sizeof ((struct ipovly *)ip)->ih_x1);
@@ -181,8 +257,54 @@ udp_input(m, va_alist)
}
}
+ switch (srcsa.sa.sa_family) {
+ case AF_INET:
+ memset(&srcsa, 0, sizeof(struct sockaddr_in));
+ srcsa.sin.sin_len = sizeof(struct sockaddr_in);
+ srcsa.sin.sin_family = AF_INET;
+ srcsa.sin.sin_port = uh->uh_sport;
+ srcsa.sin.sin_addr = ip->ip_src;
+
+#ifdef INET6
+ memset(&src_v4mapped, 0, sizeof(struct sockaddr_in6));
+ src_v4mapped.sin6_len = sizeof(struct sockaddr_in6);
+ src_v4mapped.sin6_family = AF_INET6;
+ src_v4mapped.sin6_port = uh->uh_sport;
+ CREATE_IPV6_MAPPED(src_v4mapped.sin6_addr, ip->ip_src.s_addr);
+#endif /* INET6 */
+
+ memset(&dstsa, 0, sizeof(struct sockaddr_in));
+ dstsa.sin.sin_len = sizeof(struct sockaddr_in);
+ dstsa.sin.sin_family = AF_INET;
+ dstsa.sin.sin_port = uh->uh_dport;
+ dstsa.sin.sin_addr = ip->ip_dst;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ memset(&srcsa, 0, sizeof(struct sockaddr_in6));
+ srcsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
+ srcsa.sin6.sin6_family = AF_INET6;
+ srcsa.sin6.sin6_port = uh->uh_sport;
+ srcsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ipv6->ipv6_versfl;
+ srcsa.sin6.sin6_addr = ipv6->ipv6_src;
+
+ memset(&dstsa, 0, sizeof(struct sockaddr_in6));
+ dstsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
+ dstsa.sin6.sin6_family = AF_INET6;
+ dstsa.sin6.sin6_port = uh->uh_dport;
+ dstsa.sin6.sin6_addr = ipv6->ipv6_dst;
+ break;
+#endif /* INET6 */
+ }
+
+#ifdef INET6
+ if ((ipv6 && IN6_IS_ADDR_MULTICAST(&ipv6->ipv6_dst)) ||
+ (ip && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) ||
+ (ip && in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))) {
+#else /* INET6 */
if (IN_MULTICAST(ip->ip_dst.s_addr) ||
in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
+#endif /* INET6 */
struct socket *last;
/*
* Deliver a multicast or broadcast datagram to *all* sockets
@@ -200,11 +322,6 @@ udp_input(m, va_alist)
* fixing the interface. Maybe 4.5BSD will remedy this?)
*/
- /*
- * Construct sockaddr format source address.
- */
- udp_in.sin_port = uh->uh_sport;
- udp_in.sin_addr = ip->ip_src;
iphlen += sizeof(struct udphdr);
m->m_len -= iphlen;
m->m_pkthdr.len -= iphlen;
@@ -219,11 +336,27 @@ udp_input(m, va_alist)
inp = inp->inp_queue.cqe_next) {
if (inp->inp_lport != uh->uh_dport)
continue;
+#ifdef INET6
+ if (ipv6) {
+ if (!(inp->inp_flags & INP_IPV6))
+ continue;
+ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
+ if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &ipv6->ipv6_dst))
+ continue;
+ } else
+#endif /* INET6 */
if (inp->inp_laddr.s_addr != INADDR_ANY) {
if (inp->inp_laddr.s_addr !=
ip->ip_dst.s_addr)
continue;
}
+#ifdef INET6
+ if (ipv6) {
+ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
+ if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, &ipv6->ipv6_src) || inp->inp_fport != uh->uh_sport)
+ continue;
+ } else
+#endif /* INET6 */
if (inp->inp_faddr.s_addr != INADDR_ANY) {
if (inp->inp_faddr.s_addr !=
ip->ip_src.s_addr ||
@@ -235,9 +368,18 @@ udp_input(m, va_alist)
struct mbuf *n;
if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
+#ifdef INET6
+ if (ipv6)
+ opts = ipv6_headertocontrol(m, iphlen, ((struct inpcb *)last->so_pcb)->inp_flags);
+#endif /* INET6 */
if (sbappendaddr(&last->so_rcv,
- sintosa(&udp_in), n,
- (struct mbuf *)0) == 0) {
+#ifdef INET6
+ /* This cruft is needed in (the rare) case I deliver a {multi,broad}cast
+ IPv4 packet to an AF_INET6 socket. */
+ ((((struct inpcb *)last->so_pcb)->inp_flags & INP_IPV6) && ip) ?
+ (struct sockaddr *)&src_v4mapped :
+#endif /* INET6 */
+ &srcsa.sa, n, (struct mbuf *)0) == 0) {
m_freem(n);
udpstat.udps_fullsock++;
} else
@@ -266,8 +408,19 @@ udp_input(m, va_alist)
udpstat.udps_noportbcast++;
goto bad;
}
- if (sbappendaddr(&last->so_rcv, sintosa(&udp_in), m,
- (struct mbuf *)0) == 0) {
+
+#ifdef INET6
+ if (ipv6)
+ opts = ipv6_headertocontrol(m, iphlen, ((struct inpcb *)last->so_pcb)->inp_flags);
+#endif /* INET6 */
+ if (sbappendaddr(&last->so_rcv,
+#ifdef INET6
+ /* This cruft is needed in (the rare) case I deliver a
+ {multi,broad}cast IPv4 packet to an AF_INET6 socket. */
+ ((((struct inpcb *)last->so_pcb)->inp_flags & INP_IPV6) && ip) ?
+ (struct sockaddr *)&src_v4mapped :
+#endif /* INET6 */
+ &srcsa.sa, m, (struct mbuf *)0) == 0) {
udpstat.udps_fullsock++;
goto bad;
}
@@ -277,10 +430,23 @@ udp_input(m, va_alist)
/*
* Locate pcb for datagram.
*/
+#ifdef INET6
+ if (ipv6)
+ inp = in6_pcbhashlookup(&udbtable, &ipv6->ipv6_src, uh->uh_sport,
+ &ipv6->ipv6_dst, uh->uh_dport);
+ else
+#endif /* INET6 */
inp = in_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport,
ip->ip_dst, uh->uh_dport);
if (inp == 0) {
++udpstat.udps_pcbhashmiss;
+#ifdef INET6
+ if (ipv6) {
+ inp = in_pcblookup(&udbtable, (struct in_addr *)&(ipv6->ipv6_src),
+ uh->uh_sport, (struct in_addr *)&(ipv6->ipv6_dst),
+ uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
+ } else
+#endif /* INET6 */
inp = in_pcblookup(&udbtable, &ip->ip_src, uh->uh_sport,
&ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
if (inp == 0) {
@@ -294,20 +460,26 @@ udp_input(m, va_alist)
HTONS(ip->ip_id);
HTONS(ip->ip_off);
uh->uh_sum = savesum;
+#ifdef INET6
+ if (ipv6)
+ ipv6_icmp_error(m, ICMPV6_UNREACH,ICMPV6_UNREACH_PORT,0);
+ else
+#endif /* INET6 */
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
return;
}
}
- /*
- * Construct sockaddr format source address.
- * Stuff source address and datagram in user buffer.
- */
- udp_in.sin_port = uh->uh_sport;
- udp_in.sin_addr = ip->ip_src;
if (inp->inp_flags & INP_CONTROLOPTS) {
struct mbuf **mp = &opts;
+#ifdef INET6
+ if (ipv6) {
+ if (inp->inp_flags & INP_IPV6)
+ opts = ipv6_headertocontrol(m, iphlen, inp->inp_flags);
+ } else
+ if (ip)
+#endif /* INET6 */
if (inp->inp_flags & INP_RECVDSTADDR) {
*mp = udp_saveopt((caddr_t) &ip->ip_dst,
sizeof(struct in_addr), IP_RECVDSTADDR);
@@ -335,8 +507,14 @@ udp_input(m, va_alist)
m->m_len -= iphlen;
m->m_pkthdr.len -= iphlen;
m->m_data += iphlen;
- if (sbappendaddr(&inp->inp_socket->so_rcv, sintosa(&udp_in), m,
- opts) == 0) {
+
+ if (sbappendaddr(&inp->inp_socket->so_rcv,
+#ifdef INET6
+ /* This cruft is needed to deliver a IPv4 packet to an AF_INET6 socket. */
+ ((((struct inpcb *)inp->inp_socket->so_pcb)->inp_flags & INP_IPV6) && ip) ?
+ (struct sockaddr *)&src_v4mapped :
+#endif /* INET6 */
+ &srcsa.sa, m, opts) == 0) {
udpstat.udps_fullsock++;
goto bad;
}
@@ -408,6 +586,17 @@ udp_ctlinput(cmd, sa, v)
ip = 0;
else if (errno == 0)
return NULL;
+#ifdef INET6
+ if (sa->sa_family == AF_INET6) {
+ if (ip) {
+ struct ipv6 *ipv6 = (struct ipv6 *)ip;
+
+ uh = (struct udphdr *)((caddr_t)ipv6 + sizeof(struct ipv6));
+ in6_pcbnotify(&udbtable, sa, uh->uh_dport, &(ipv6->ipv6_src), uh->uh_sport, cmd, udp_notify);
+ } else
+ in6_pcbnotify(&udbtable, sa, 0, (struct in6_addr *)&in6addr_any, 0, cmd, udp_notify);
+ } else
+#endif /* INET6 */
if (ip) {
uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
in_pcbnotify(&udbtable, sa, uh->uh_dport, ip->ip_src,
@@ -433,6 +622,12 @@ udp_output(m, va_alist)
struct in_addr laddr;
int s = 0, error = 0;
va_list ap;
+#ifdef INET6
+ register struct in6_addr laddr6;
+ int v6packet = 0;
+ struct ifnet *forceif = NULL;
+#endif /* INET6 */
+ int pcbflags = 0;
va_start(ap, m);
inp = va_arg(ap, struct inpcb *);
@@ -440,12 +635,32 @@ udp_output(m, va_alist)
control = va_arg(ap, struct mbuf *);
va_end(ap);
+#ifndef INET6
if (control)
m_freem(control); /* XXX */
+#endif /* INET6 */
if (addr) {
+ /*
+ * Save current PCB flags because they may change during
+ * temporary connection, particularly the INP_IPV6_UNDEC
+ * flag.
+ */
+ pcbflags = inp->inp_flags;
+
+#ifdef INET6
+ if (inp->inp_flags & INP_IPV6)
+ laddr6 = inp->inp_laddr6;
+ else
+#endif /* INET6 */
laddr = inp->inp_laddr;
+#ifdef INET6
+ if (((inp->inp_flags & INP_IPV6) &&
+ !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
+ || (inp->inp_faddr.s_addr != INADDR_ANY)) {
+#else /* INET6 */
if (inp->inp_faddr.s_addr != INADDR_ANY) {
+#endif /* INET6 */
error = EISCONN;
goto release;
}
@@ -459,7 +674,13 @@ udp_output(m, va_alist)
goto release;
}
} else {
+#ifdef INET6
+ if (((inp->inp_flags & INP_IPV6) &&
+ IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
+ || (inp->inp_faddr.s_addr == INADDR_ANY)) {
+#else /* INET6 */
if (inp->inp_faddr.s_addr == INADDR_ANY) {
+#endif /* INET6 */
error = ENOTCONN;
goto release;
}
@@ -468,7 +689,21 @@ udp_output(m, va_alist)
* Calculate data length and get a mbuf
* for UDP and IP headers.
*/
+#ifdef INET6
+ /*
+ * Handles IPv4-mapped IPv6 address because temporary connect sets
+ * the right flag.
+ */
+ v6packet = ((inp->inp_flags & INP_IPV6) &&
+ !(inp->inp_flags & INP_IPV6_MAPPED));
+
+ if (!v6packet && control)
+ m_freem(control);
+
+ M_PREPEND(m, v6packet ? (sizeof(struct udphdr) + sizeof(struct ipv6)) : sizeof(struct udpiphdr), M_DONTWAIT);
+#else /* INET6 */
M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
+#endif /* INET6 */
if (m == 0) {
error = ENOBUFS;
goto bail;
@@ -487,6 +722,36 @@ udp_output(m, va_alist)
* Fill in mbuf with extended UDP header
* and addresses and length put into network format.
*/
+#ifdef INET6
+ if (v6packet) {
+ struct ipv6 *ipv6 = mtod(m, struct ipv6 *);
+ struct udphdr *uh = (struct udphdr *)(mtod(m, caddr_t) + sizeof(struct ipv6));
+ int payload = sizeof(struct ipv6);
+
+ ipv6->ipv6_versfl = htonl(0x60000000) | (inp->inp_ipv6.ipv6_versfl & htonl(0x0fffffff));
+
+ ipv6->ipv6_hoplimit = inp->inp_ipv6.ipv6_hoplimit;
+ ipv6->ipv6_nexthdr = IPPROTO_UDP;
+ ipv6->ipv6_src = inp->inp_laddr6;
+ ipv6->ipv6_dst = inp->inp_faddr6;
+ ipv6->ipv6_length = (u_short)len + sizeof(struct udphdr);
+
+ uh->uh_sport = inp->inp_lport;
+ uh->uh_dport = inp->inp_fport;
+ uh->uh_ulen = htons(ipv6->ipv6_length);
+ uh->uh_sum = 0;
+
+ if (control)
+ if ((error = ipv6_controltoheader(&m, control, &forceif, &payload)))
+ goto release;
+
+ /*
+ * Always calculate udp checksum for IPv6 datagrams
+ */
+ if (!(uh->uh_sum = in6_cksum(m, IPPROTO_UDP, len + sizeof(struct udphdr), payload)))
+ uh->uh_sum = 0xffff;
+ } else {
+#endif /* INET6 */
ui = mtod(m, struct udpiphdr *);
bzero(ui->ui_x1, sizeof ui->ui_x1);
ui->ui_pr = IPPROTO_UDP;
@@ -496,19 +761,59 @@ udp_output(m, va_alist)
ui->ui_sport = inp->inp_lport;
ui->ui_dport = inp->inp_fport;
ui->ui_ulen = ui->ui_len;
+#ifdef INET6
+ }
+#endif /* INET6 */
/*
* Stuff checksum and output datagram.
*/
+#ifdef INET6
+ if (!v6packet) {
+#endif /* INET6 */
ui->ui_sum = 0;
if (udpcksum) {
if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
ui->ui_sum = 0xffff;
}
((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
+#ifdef INET6
+ /*
+ * For now, we use the default values for ttl and tos for
+ * v4 packets sent using a v6 pcb. We probably want to
+ * later allow v4 setsockopt operations on a v6 socket to
+ * modify the ttl and tos for v4 packets sent using
+ * the mapped address format. We really ought to
+ * save the v4 ttl and v6 hoplimit in separate places
+ * instead of craming both in the inp_hu union.
+ */
+ if (inp->inp_flags & INP_IPV6) {
+ ((struct ip *)ui)->ip_ttl = ip_defttl;
+ ((struct ip *)ui)->ip_tos = 0;
+ } else {
+#endif /* INET6 */
+ ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
+ ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
+#ifdef INET6
+ };
+ };
+#endif /* INET6 */
((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
udpstat.udps_opackets++;
+#ifdef INET6
+ if (v6packet)
+ error = ipv6_output(m, &inp->inp_route6,
+ inp->inp_socket->so_options & SO_DONTROUTE,
+ (inp->inp_flags & INP_IPV6_MCAST)?inp->inp_moptions6:NULL,
+ forceif, inp->inp_socket);
+ else
+ if (inp->inp_flags & INP_IPV6_MCAST)
+ error = ip_output(m, inp->inp_options, &inp->inp_route,
+ inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
+ NULL, NULL, inp->inp_socket);
+ else
+#endif /* INET6 */
error = ip_output(m, inp->inp_options, &inp->inp_route,
inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
inp->inp_moptions, inp);
@@ -516,6 +821,12 @@ udp_output(m, va_alist)
bail:
if (addr) {
in_pcbdisconnect(inp);
+ inp->inp_flags = pcbflags;
+#ifdef INET6
+ if (inp->inp_flags & INP_IPV6)
+ inp->inp_laddr6 = laddr6;
+ else
+#endif /* INET6 */
inp->inp_laddr = laddr;
splx(s);
}
@@ -541,9 +852,16 @@ udp_usrreq(so, req, m, addr, control)
int error = 0;
int s;
- if (req == PRU_CONTROL)
+ if (req == PRU_CONTROL) {
+#ifdef INET6
+ if (inp->inp_flags & INP_IPV6)
+ return (in6_control(so, (u_long)m, (caddr_t)addr,
+ (struct ifnet *)control, 0));
+ else
+#endif /* INET6 */
return (in_control(so, (u_long)m, (caddr_t)addr,
(struct ifnet *)control));
+ }
if (inp == NULL && req != PRU_ATTACH) {
error = EINVAL;
goto release;
@@ -567,6 +885,12 @@ udp_usrreq(so, req, m, addr, control)
error = soreserve(so, udp_sendspace, udp_recvspace);
if (error)
break;
+#ifdef INET6
+ if (((struct inpcb *)so->so_pcb)->inp_flags & INP_IPV6)
+ ((struct inpcb *) so->so_pcb)->inp_ipv6.ipv6_hoplimit =
+ ipv6_defhoplmt;
+ else
+#endif /* INET6 */
((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl;
break;
@@ -585,6 +909,14 @@ udp_usrreq(so, req, m, addr, control)
break;
case PRU_CONNECT:
+#ifdef INET6
+ if (inp->inp_flags & INP_IPV6) {
+ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
+ error = EISCONN;
+ break;
+ }
+ } else
+#endif /* INET6 */
if (inp->inp_faddr.s_addr != INADDR_ANY) {
error = EISCONN;
break;
@@ -605,12 +937,25 @@ udp_usrreq(so, req, m, addr, control)
break;
case PRU_DISCONNECT:
+#ifdef INET6
+ if (inp->inp_flags & INP_IPV6) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
+ error = ENOTCONN;
+ break;
+ }
+ } else
+#endif /* INET6 */
if (inp->inp_faddr.s_addr == INADDR_ANY) {
error = ENOTCONN;
break;
}
s = splsoftnet();
in_pcbdisconnect(inp);
+#ifdef INET6
+ if (inp->inp_flags & INP_IPV6)
+ inp->inp_laddr6 = in6addr_any;
+ else
+#endif /* INET6 */
inp->inp_laddr.s_addr = INADDR_ANY;
splx(s);
so->so_state &= ~SS_ISCONNECTED; /* XXX */
@@ -645,6 +990,10 @@ udp_usrreq(so, req, m, addr, control)
/*
* stat: don't bother with a blocksize.
*/
+ /*
+ * Perhaps Path MTU might be returned for a connected
+ * UDP socket in this case.
+ */
return (0);
case PRU_SENDOOB: