mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 15:47:46 +00:00
[tcp] add TCPlp's FreeBSD-derived protocol code, with explanatory comments (#7074)
This commit adds TCPlp's TCP protocol logic, which is derived from the TCP protocol logic in the FreeBSD Operating System. The FreeBSD code had to be refactored to work for TCPlp, and I have added extensive comments explaining the code that was deleted and changed. The changes are primarily modifications to work with TCPlp's data buffering (see #6926), removal of features that depend on dynamic memory allocation to save memory (SYN cache, compressed TIME-WAIT state) and removal of features that aren't relevant in this setting (e.g., TCP Segmentation Offloading, IPv4 support).
This commit is contained in:
Vendored
+17
@@ -29,6 +29,15 @@
|
||||
project("TCPlp" C)
|
||||
|
||||
set(src_tcplp
|
||||
bsdtcp/cc/cc_newreno.c
|
||||
bsdtcp/tcp_input.c
|
||||
bsdtcp/tcp_output.c
|
||||
bsdtcp/tcp_reass.c
|
||||
bsdtcp/tcp_sack.c
|
||||
bsdtcp/tcp_subr.c
|
||||
bsdtcp/tcp_timer.c
|
||||
bsdtcp/tcp_timewait.c
|
||||
bsdtcp/tcp_usrreq.c
|
||||
lib/bitmap.c
|
||||
lib/cbuf.c
|
||||
lib/lbuf.c
|
||||
@@ -36,6 +45,14 @@ set(src_tcplp
|
||||
|
||||
set(tcplp_static_target "tcplp")
|
||||
|
||||
string(REPLACE "-Wsign-compare" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-compare")
|
||||
|
||||
string(REPLACE "-Wconversion" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
|
||||
string(REPLACE "-Wunused-parameter" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-parameter")
|
||||
|
||||
add_library(${tcplp_static_target} STATIC ${src_tcplp})
|
||||
set_target_properties(${tcplp_static_target} PROPERTIES OUTPUT_NAME tcplp)
|
||||
target_include_directories(${tcplp_static_target}
|
||||
|
||||
Vendored
+29
@@ -29,6 +29,19 @@
|
||||
include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
|
||||
|
||||
EXTRA_DIST = \
|
||||
bsdtcp/cc/cc_module.h \
|
||||
bsdtcp/sys/queue.h \
|
||||
bsdtcp/cc.h \
|
||||
bsdtcp/icmp_var.h \
|
||||
bsdtcp/ip6.h \
|
||||
bsdtcp/ip.h \
|
||||
bsdtcp/tcp_const.h \
|
||||
bsdtcp/tcp_fsm.h \
|
||||
bsdtcp/tcp.h \
|
||||
bsdtcp/tcp_seq.h \
|
||||
bsdtcp/tcp_timer.h \
|
||||
bsdtcp/tcp_var.h \
|
||||
bsdtcp/types.h \
|
||||
lib/bitmap.h \
|
||||
lib/cbuf.h \
|
||||
lib/lbuf.h \
|
||||
@@ -43,6 +56,13 @@ lib_LIBRARIES = \
|
||||
override CFLAGS := $(filter-out -Wsign-compare,$(CFLAGS))
|
||||
override CFLAGS := $(CFLAGS) -Wno-sign-compare
|
||||
|
||||
# Do not enable -Wconversion for TCPlp
|
||||
override CFLAGS := $(filter-out -Wconversion,$(CFLAGS))
|
||||
|
||||
# Do not enable -Wcast-align for TCPlp
|
||||
override CFLAGS := $(filter-out -Wcast-align,$(CFLAGS))
|
||||
override CFLAGS := $(CFLAGS) -Wno-cast-align
|
||||
|
||||
# Do not enable -Wunused-parameter for TCPlp
|
||||
override CFLAGS := $(filter-out -Wunused-parameter,$(CFLAGS))
|
||||
override CFLAGS := $(CFLAGS) -Wno-unused-parameter
|
||||
@@ -65,6 +85,15 @@ libtcplp_a_CPPFLAGS = \
|
||||
$(NULL)
|
||||
|
||||
libtcplp_a_SOURCES = \
|
||||
bsdtcp/cc/cc_newreno.c \
|
||||
bsdtcp/tcp_input.c \
|
||||
bsdtcp/tcp_output.c \
|
||||
bsdtcp/tcp_reass.c \
|
||||
bsdtcp/tcp_sack.c \
|
||||
bsdtcp/tcp_subr.c \
|
||||
bsdtcp/tcp_timer.c \
|
||||
bsdtcp/tcp_timewait.c \
|
||||
bsdtcp/tcp_usrreq.c \
|
||||
lib/bitmap.c \
|
||||
lib/cbuf.c \
|
||||
lib/lbuf.c \
|
||||
|
||||
Vendored
+163
@@ -0,0 +1,163 @@
|
||||
/*-
|
||||
* Copyright (c) 2007-2008
|
||||
* Swinburne University of Technology, Melbourne, Australia.
|
||||
* Copyright (c) 2009-2010 Lawrence Stewart <[email protected]>
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed at the Centre for Advanced Internet
|
||||
* Architectures, Swinburne University of Technology, by Lawrence Stewart and
|
||||
* James Healy, made possible in part by a grant from the Cisco University
|
||||
* Research Program Fund at Community Foundation Silicon Valley.
|
||||
*
|
||||
* Portions of this software were developed at the Centre for Advanced
|
||||
* Internet Architectures, Swinburne University of Technology, Melbourne,
|
||||
* Australia by David Hayes under sponsorship from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* This software was first released in 2007 by James Healy and Lawrence Stewart
|
||||
* whilst working on the NewTCP research project at Swinburne University of
|
||||
* Technology's Centre for Advanced Internet Architectures, Melbourne,
|
||||
* Australia, which was made possible in part by a grant from the Cisco
|
||||
* University Research Program Fund at Community Foundation Silicon Valley.
|
||||
* More details are available at:
|
||||
* http://caia.swin.edu.au/urp/newtcp/
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar: The FreeBSD implementation supports many congestion control
|
||||
* algorithms, each represented by a struct. Each tcpcb has a pointer to the
|
||||
* relevant congestion control struct, and the congestion control structs are
|
||||
* themselves part of an intrusive linked list. TCPlp hardcodes the congestion
|
||||
* control algorithm to New Reno, so the fields corresponding to maintaining
|
||||
* the global linked list are removed.
|
||||
*/
|
||||
|
||||
#ifndef _NETINET_CC_H_
|
||||
#define _NETINET_CC_H_
|
||||
|
||||
/* XXX: TCP_CA_NAME_MAX define lives in tcp.h for compat reasons. */
|
||||
#include "tcp.h"
|
||||
|
||||
extern const struct cc_algo newreno_cc_algo;
|
||||
|
||||
/*
|
||||
* Wrapper around transport structs that contain same-named congestion
|
||||
* control variables. Allows algos to be shared amongst multiple CC aware
|
||||
* transprots.
|
||||
*/
|
||||
struct cc_var {
|
||||
void *cc_data; /* Per-connection private CC algorithm data. */
|
||||
int bytes_this_ack; /* # bytes acked by the current ACK. */
|
||||
tcp_seq curack; /* Most recent ACK. */
|
||||
uint32_t flags; /* Flags for cc_var (see below) */
|
||||
/* samkumar: removing type, since TCPlp uses TCP congestion control. */
|
||||
//int type; /* Indicates which ptr is valid in ccvc. */
|
||||
union ccv_container {
|
||||
struct tcpcb *tcp;
|
||||
struct sctp_nets *sctp;
|
||||
} ccvc;
|
||||
};
|
||||
|
||||
/* cc_var flags. */
|
||||
#define CCF_ABC_SENTAWND 0x0001 /* ABC counted cwnd worth of bytes? */
|
||||
#define CCF_CWND_LIMITED 0x0002 /* Are we currently cwnd limited? */
|
||||
#define CCF_DELACK 0x0004 /* Is this ack delayed? */
|
||||
#define CCF_ACKNOW 0x0008 /* Will this ack be sent now? */
|
||||
#define CCF_IPHDR_CE 0x0010 /* Does this packet set CE bit? */
|
||||
#define CCF_TCPHDR_CWR 0x0020 /* Does this packet set CWR bit? */
|
||||
|
||||
/* ACK types passed to the ack_received() hook. */
|
||||
#define CC_ACK 0x0001 /* Regular in sequence ACK. */
|
||||
#define CC_DUPACK 0x0002 /* Duplicate ACK. */
|
||||
#define CC_PARTIALACK 0x0004 /* Not yet. */
|
||||
#define CC_SACK 0x0008 /* Not yet. */
|
||||
|
||||
/*
|
||||
* Congestion signal types passed to the cong_signal() hook. The highest order 8
|
||||
* bits (0x01000000 - 0x80000000) are reserved for CC algos to declare their own
|
||||
* congestion signal types.
|
||||
*/
|
||||
#define CC_ECN 0x00000001 /* ECN marked packet received. */
|
||||
#define CC_RTO 0x00000002 /* RTO fired. */
|
||||
#define CC_RTO_ERR 0x00000004 /* RTO fired in error. */
|
||||
#define CC_NDUPACK 0x00000008 /* Threshold of dupack's reached. */
|
||||
|
||||
#define CC_SIGPRIVMASK 0xFF000000 /* Mask to check if sig is private. */
|
||||
|
||||
/*
|
||||
* Structure to hold data and function pointers that together represent a
|
||||
* congestion control algorithm.
|
||||
*/
|
||||
struct cc_algo {
|
||||
char name[TCP_CA_NAME_MAX];
|
||||
|
||||
/* Init global module state on kldload. */
|
||||
int (*mod_init)(void);
|
||||
|
||||
/* Cleanup global module state on kldunload. */
|
||||
int (*mod_destroy)(void);
|
||||
|
||||
/* Init CC state for a new control block. */
|
||||
int (*cb_init)(struct cc_var *ccv);
|
||||
|
||||
/* Cleanup CC state for a terminating control block. */
|
||||
void (*cb_destroy)(struct cc_var *ccv);
|
||||
|
||||
/* Init variables for a newly established connection. */
|
||||
void (*conn_init)(struct cc_var *ccv);
|
||||
|
||||
/* Called on receipt of an ack. */
|
||||
void (*ack_received)(struct cc_var *ccv, uint16_t type);
|
||||
|
||||
/* Called on detection of a congestion signal. */
|
||||
void (*cong_signal)(struct cc_var *ccv, uint32_t type);
|
||||
|
||||
/* Called after exiting congestion recovery. */
|
||||
void (*post_recovery)(struct cc_var *ccv);
|
||||
|
||||
/* Called when data transfer resumes after an idle period. */
|
||||
void (*after_idle)(struct cc_var *ccv);
|
||||
|
||||
/* Called for an additional ECN processing apart from RFC3168. */
|
||||
void (*ecnpkt_handler)(struct cc_var *ccv);
|
||||
|
||||
/*
|
||||
* samkumar: This field is removed since we no longer use the intrusive
|
||||
* linked list.
|
||||
*/
|
||||
//STAILQ_ENTRY (cc_algo) entries;
|
||||
};
|
||||
|
||||
/* Macro to obtain the CC algo's struct ptr. */
|
||||
//#define CC_ALGO(tp) ((tp)->cc_algo)
|
||||
#define CC_ALGO(tp) (&newreno_cc_algo) // samkumar: This allows the #defines in cc_newreno.c to work as intended
|
||||
|
||||
/* Macro to obtain the CC algo's data ptr. */
|
||||
#define CC_DATA(tp) ((tp)->ccv->cc_data)
|
||||
|
||||
#endif /* _NETINET_CC_H_ */
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*-
|
||||
* Copyright (c) 2009-2010 Lawrence Stewart <[email protected]>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Lawrence Stewart while studying at the Centre
|
||||
* for Advanced Internet Architectures, Swinburne University of Technology, made
|
||||
* possible in part by a grant from the Cisco University Research Program Fund
|
||||
* at Community Foundation Silicon Valley.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* This software was first released in 2009 by Lawrence Stewart as part of the
|
||||
* NewTCP research project at Swinburne University of Technology's Centre for
|
||||
* Advanced Internet Architectures, Melbourne, Australia, which was made
|
||||
* possible in part by a grant from the Cisco University Research Program Fund
|
||||
* at Community Foundation Silicon Valley. More details are available at:
|
||||
* http://caia.swin.edu.au/urp/newtcp/
|
||||
*/
|
||||
|
||||
#ifndef _NETINET_CC_MODULE_H_
|
||||
#define _NETINET_CC_MODULE_H_
|
||||
|
||||
/* samkumar: This was already commented out in FreeBSD (I didn't do it). */
|
||||
/*
|
||||
* Allows a CC algorithm to manipulate a commonly named CC variable regardless
|
||||
* of the transport protocol and associated C struct.
|
||||
* XXXLAS: Out of action until the work to support SCTP is done.
|
||||
*
|
||||
#define CCV(ccv, what) \
|
||||
(*( \
|
||||
(ccv)->type == IPPROTO_TCP ? &(ccv)->ccvc.tcp->what : \
|
||||
&(ccv)->ccvc.sctp->what \
|
||||
))
|
||||
*/
|
||||
#define CCV(ccv, what) (ccv)->ccvc.tcp->what
|
||||
|
||||
/*
|
||||
* samkumar: I've commented this out (using #if 0) because our current TCPlp
|
||||
* implementation hardcodes New Reno. Thus, we don't need FreeBSD's "module"
|
||||
* mechanism to choose a congestion control algorithm.
|
||||
*/
|
||||
#if 0
|
||||
#define DECLARE_CC_MODULE(ccname, ccalgo) \
|
||||
static moduledata_t cc_##ccname = { \
|
||||
.name = #ccname, \
|
||||
.evhand = cc_modevent, \
|
||||
.priv = ccalgo \
|
||||
}; \
|
||||
DECLARE_MODULE(ccname, cc_##ccname, \
|
||||
SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY)
|
||||
|
||||
int cc_modevent(module_t mod, int type, void *data);
|
||||
#endif
|
||||
|
||||
#endif /* _NETINET_CC_MODULE_H_ */
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
|
||||
* The Regents of the University of California.
|
||||
* Copyright (c) 2007-2008,2010
|
||||
* Swinburne University of Technology, Melbourne, Australia.
|
||||
* Copyright (c) 2009-2010 Lawrence Stewart <[email protected]>
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed at the Centre for Advanced Internet
|
||||
* Architectures, Swinburne University of Technology, by Lawrence Stewart, James
|
||||
* Healy and David Hayes, made possible in part by a grant from the Cisco
|
||||
* University Research Program Fund at Community Foundation Silicon Valley.
|
||||
*
|
||||
* Portions of this software were developed at the Centre for Advanced
|
||||
* Internet Architectures, Swinburne University of Technology, Melbourne,
|
||||
* Australia by David Hayes under sponsorship from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This software was first released in 2007 by James Healy and Lawrence Stewart
|
||||
* whilst working on the NewTCP research project at Swinburne University of
|
||||
* Technology's Centre for Advanced Internet Architectures, Melbourne,
|
||||
* Australia, which was made possible in part by a grant from the Cisco
|
||||
* University Research Program Fund at Community Foundation Silicon Valley.
|
||||
* More details are available at:
|
||||
* http://caia.swin.edu.au/urp/newtcp/
|
||||
*/
|
||||
|
||||
/* samkumar: Removed/replaced a bunch of #include's. */
|
||||
|
||||
#include "../cc.h"
|
||||
#include "../tcp.h"
|
||||
#include "../tcp_seq.h"
|
||||
#include "../tcp_var.h"
|
||||
#include "cc_module.h"
|
||||
|
||||
#include "../tcp_const.h"
|
||||
|
||||
static int min(int a, int b) { return (a < b) ? a : b; }
|
||||
|
||||
static void newreno_ack_received(struct cc_var *ccv, uint16_t type);
|
||||
static void newreno_after_idle(struct cc_var *ccv);
|
||||
static void newreno_cong_signal(struct cc_var *ccv, uint32_t type);
|
||||
static void newreno_post_recovery(struct cc_var *ccv);
|
||||
|
||||
const struct cc_algo newreno_cc_algo = {
|
||||
.name = "newreno",
|
||||
.ack_received = newreno_ack_received,
|
||||
.after_idle = newreno_after_idle,
|
||||
.cong_signal = newreno_cong_signal,
|
||||
.post_recovery = newreno_post_recovery,
|
||||
};
|
||||
|
||||
/*
|
||||
* samkumar: Normally, this is done in cc.c. It's commented out since we
|
||||
* just hardcode using New Reno in TCPlp (for now). We don't use FreeBSD's
|
||||
* mechanism to have multiple congestion control modules and choose among
|
||||
* them.
|
||||
*/
|
||||
//struct cc_algo* V_default_cc_ptr = &newreno_cc_algo;
|
||||
|
||||
/* samkumar: Constant that is referenced (may want to change this later) */
|
||||
enum {
|
||||
V_tcp_do_rfc3465 = 1
|
||||
};
|
||||
|
||||
static void
|
||||
newreno_ack_received(struct cc_var *ccv, uint16_t type)
|
||||
{
|
||||
if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) &&
|
||||
(ccv->flags & CCF_CWND_LIMITED)) {
|
||||
uint32_t cw = CCV(ccv, snd_cwnd);
|
||||
uint32_t incr = CCV(ccv, t_maxseg);
|
||||
|
||||
/*
|
||||
* Regular in-order ACK, open the congestion window.
|
||||
* Method depends on which congestion control state we're
|
||||
* in (slow start or cong avoid) and if ABC (RFC 3465) is
|
||||
* enabled.
|
||||
*
|
||||
* slow start: cwnd <= ssthresh
|
||||
* cong avoid: cwnd > ssthresh
|
||||
*
|
||||
* slow start and ABC (RFC 3465):
|
||||
* Grow cwnd exponentially by the amount of data
|
||||
* ACKed capping the max increment per ACK to
|
||||
* (abc_l_var * maxseg) bytes.
|
||||
*
|
||||
* slow start without ABC (RFC 5681):
|
||||
* Grow cwnd exponentially by maxseg per ACK.
|
||||
*
|
||||
* cong avoid and ABC (RFC 3465):
|
||||
* Grow cwnd linearly by maxseg per RTT for each
|
||||
* cwnd worth of ACKed data.
|
||||
*
|
||||
* cong avoid without ABC (RFC 5681):
|
||||
* Grow cwnd linearly by approximately maxseg per RTT using
|
||||
* maxseg^2 / cwnd per ACK as the increment.
|
||||
* If cwnd > maxseg^2, fix the cwnd increment at 1 byte to
|
||||
* avoid capping cwnd.
|
||||
*/
|
||||
if (cw > CCV(ccv, snd_ssthresh)) {
|
||||
if (V_tcp_do_rfc3465) {
|
||||
if (ccv->flags & CCF_ABC_SENTAWND)
|
||||
ccv->flags &= ~CCF_ABC_SENTAWND;
|
||||
else
|
||||
incr = 0;
|
||||
} else
|
||||
incr = max((incr * incr / cw), 1);
|
||||
} else if (V_tcp_do_rfc3465) {
|
||||
/*
|
||||
* In slow-start with ABC enabled and no RTO in sight?
|
||||
* (Must not use abc_l_var > 1 if slow starting after
|
||||
* an RTO. On RTO, snd_nxt = snd_una, so the
|
||||
* snd_nxt == snd_max check is sufficient to
|
||||
* handle this).
|
||||
*
|
||||
* XXXLAS: Find a way to signal SS after RTO that
|
||||
* doesn't rely on tcpcb vars.
|
||||
*/
|
||||
if (CCV(ccv, snd_nxt) == CCV(ccv, snd_max))
|
||||
incr = min(ccv->bytes_this_ack,
|
||||
V_tcp_abc_l_var * CCV(ccv, t_maxseg));
|
||||
else
|
||||
incr = min(ccv->bytes_this_ack, CCV(ccv, t_maxseg));
|
||||
}
|
||||
/* ABC is on by default, so incr equals 0 frequently. */
|
||||
if (incr > 0)
|
||||
CCV(ccv, snd_cwnd) = min(cw + incr,
|
||||
TCP_MAXWIN << CCV(ccv, snd_scale));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
newreno_after_idle(struct cc_var *ccv)
|
||||
{
|
||||
int rw;
|
||||
|
||||
/*
|
||||
* If we've been idle for more than one retransmit timeout the old
|
||||
* congestion window is no longer current and we have to reduce it to
|
||||
* the restart window before we can transmit again.
|
||||
*
|
||||
* The restart window is the initial window or the last CWND, whichever
|
||||
* is smaller.
|
||||
*
|
||||
* This is done to prevent us from flooding the path with a full CWND at
|
||||
* wirespeed, overloading router and switch buffers along the way.
|
||||
*
|
||||
* See RFC5681 Section 4.1. "Restarting Idle Connections".
|
||||
*/
|
||||
if (V_tcp_do_rfc3390)
|
||||
rw = min(4 * CCV(ccv, t_maxseg),
|
||||
max(2 * CCV(ccv, t_maxseg), 4380));
|
||||
else
|
||||
rw = CCV(ccv, t_maxseg) * 2;
|
||||
|
||||
CCV(ccv, snd_cwnd) = min(rw, CCV(ccv, snd_cwnd));
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform any necessary tasks before we enter congestion recovery.
|
||||
*/
|
||||
static void
|
||||
newreno_cong_signal(struct cc_var *ccv, uint32_t type)
|
||||
{
|
||||
uint32_t win;
|
||||
|
||||
/* Catch algos which mistakenly leak private signal types. */
|
||||
KASSERT((type & CC_SIGPRIVMASK) == 0,
|
||||
("%s: congestion signal type 0x%08x is private\n", __func__, (unsigned int) type));
|
||||
|
||||
win = max(CCV(ccv, snd_cwnd) / 2 / CCV(ccv, t_maxseg), 2) *
|
||||
CCV(ccv, t_maxseg);
|
||||
|
||||
switch (type) {
|
||||
case CC_NDUPACK:
|
||||
if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) {
|
||||
if (!IN_CONGRECOVERY(CCV(ccv, t_flags)))
|
||||
CCV(ccv, snd_ssthresh) = win;
|
||||
ENTER_RECOVERY(CCV(ccv, t_flags));
|
||||
}
|
||||
break;
|
||||
case CC_ECN:
|
||||
if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) {
|
||||
CCV(ccv, snd_ssthresh) = win;
|
||||
CCV(ccv, snd_cwnd) = win;
|
||||
ENTER_CONGRECOVERY(CCV(ccv, t_flags));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform any necessary tasks before we exit congestion recovery.
|
||||
*/
|
||||
static void
|
||||
newreno_post_recovery(struct cc_var *ccv)
|
||||
{
|
||||
if (IN_FASTRECOVERY(CCV(ccv, t_flags))) {
|
||||
/*
|
||||
* Fast recovery will conclude after returning from this
|
||||
* function. Window inflation should have left us with
|
||||
* approximately snd_ssthresh outstanding data. But in case we
|
||||
* would be inclined to send a burst, better to do it via the
|
||||
* slow start mechanism.
|
||||
*
|
||||
* XXXLAS: Find a way to do this without needing curack
|
||||
*/
|
||||
if (SEQ_GT(ccv->curack + CCV(ccv, snd_ssthresh),
|
||||
CCV(ccv, snd_max)))
|
||||
CCV(ccv, snd_cwnd) = CCV(ccv, snd_max) -
|
||||
ccv->curack + CCV(ccv, t_maxseg);
|
||||
else
|
||||
CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: I commented this out because it's not necessary for TCPlp. See the
|
||||
* comment above about not using FreeBSD's mechanism for having multiple
|
||||
* congestion control modules.
|
||||
*/
|
||||
//DECLARE_CC_MODULE(newreno, &newreno_cc_algo);
|
||||
Vendored
+57
@@ -0,0 +1,57 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)icmp_var.h 8.1 (Berkeley) 6/10/93
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar: Removed some #if guards and several definitions/declarations that
|
||||
* weren't necessary (and often introduced additional dependencies).
|
||||
*/
|
||||
|
||||
#ifndef _NETINET_ICMP_VAR_H_
|
||||
#define _NETINET_ICMP_VAR_H_
|
||||
/*
|
||||
* Identifiers for ICMP sysctl nodes
|
||||
*/
|
||||
#define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */
|
||||
#define ICMPCTL_STATS 2 /* statistics (read-only) */
|
||||
#define ICMPCTL_ICMPLIM 3
|
||||
|
||||
#define BANDLIM_UNLIMITED -1
|
||||
#define BANDLIM_ICMP_UNREACH 0
|
||||
#define BANDLIM_ICMP_ECHO 1
|
||||
#define BANDLIM_ICMP_TSTAMP 2
|
||||
#define BANDLIM_RST_CLOSEDPORT 3 /* No connection, and no listeners */
|
||||
#define BANDLIM_RST_OPENPORT 4 /* No connection, listener */
|
||||
#define BANDLIM_ICMP6_UNREACH 5
|
||||
#define BANDLIM_SCTP_OOTB 6
|
||||
#define BANDLIM_MAX 6
|
||||
|
||||
#endif
|
||||
Vendored
+151
@@ -0,0 +1,151 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)ip.h 8.2 (Berkeley) 6/1/94
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _NETINET_IP_H_
|
||||
#define _NETINET_IP_H_
|
||||
|
||||
#define IP_MAXPACKET 65535 /* maximum packet size */
|
||||
|
||||
/*
|
||||
* Definitions for IP type of service (ip_tos).
|
||||
*/
|
||||
#define IPTOS_LOWDELAY 0x10
|
||||
#define IPTOS_THROUGHPUT 0x08
|
||||
#define IPTOS_RELIABILITY 0x04
|
||||
#define IPTOS_MINCOST 0x02
|
||||
|
||||
/*
|
||||
* Definitions for IP precedence (also in ip_tos) (deprecated).
|
||||
*/
|
||||
#define IPTOS_PREC_NETCONTROL IPTOS_DSCP_CS7
|
||||
#define IPTOS_PREC_INTERNETCONTROL IPTOS_DSCP_CS6
|
||||
#define IPTOS_PREC_CRITIC_ECP IPTOS_DSCP_CS5
|
||||
#define IPTOS_PREC_FLASHOVERRIDE IPTOS_DSCP_CS4
|
||||
#define IPTOS_PREC_FLASH IPTOS_DSCP_CS3
|
||||
#define IPTOS_PREC_IMMEDIATE IPTOS_DSCP_CS2
|
||||
#define IPTOS_PREC_PRIORITY IPTOS_DSCP_CS1
|
||||
#define IPTOS_PREC_ROUTINE IPTOS_DSCP_CS0
|
||||
|
||||
/*
|
||||
* Definitions for DiffServ Codepoints as per RFC2474 and RFC5865.
|
||||
*/
|
||||
#define IPTOS_DSCP_CS0 0x00
|
||||
#define IPTOS_DSCP_CS1 0x20
|
||||
#define IPTOS_DSCP_AF11 0x28
|
||||
#define IPTOS_DSCP_AF12 0x30
|
||||
#define IPTOS_DSCP_AF13 0x38
|
||||
#define IPTOS_DSCP_CS2 0x40
|
||||
#define IPTOS_DSCP_AF21 0x48
|
||||
#define IPTOS_DSCP_AF22 0x50
|
||||
#define IPTOS_DSCP_AF23 0x58
|
||||
#define IPTOS_DSCP_CS3 0x60
|
||||
#define IPTOS_DSCP_AF31 0x68
|
||||
#define IPTOS_DSCP_AF32 0x70
|
||||
#define IPTOS_DSCP_AF33 0x78
|
||||
#define IPTOS_DSCP_CS4 0x80
|
||||
#define IPTOS_DSCP_AF41 0x88
|
||||
#define IPTOS_DSCP_AF42 0x90
|
||||
#define IPTOS_DSCP_AF43 0x98
|
||||
#define IPTOS_DSCP_CS5 0xa0
|
||||
#define IPTOS_DSCP_VA 0xb0
|
||||
#define IPTOS_DSCP_EF 0xb8
|
||||
#define IPTOS_DSCP_CS6 0xc0
|
||||
#define IPTOS_DSCP_CS7 0xe0
|
||||
|
||||
/*
|
||||
* ECN (Explicit Congestion Notification) codepoints in RFC3168 mapped to the
|
||||
* lower 2 bits of the TOS field.
|
||||
*/
|
||||
#define IPTOS_ECN_NOTECT 0x00 /* not-ECT */
|
||||
#define IPTOS_ECN_ECT1 0x01 /* ECN-capable transport (1) */
|
||||
#define IPTOS_ECN_ECT0 0x02 /* ECN-capable transport (0) */
|
||||
#define IPTOS_ECN_CE 0x03 /* congestion experienced */
|
||||
#define IPTOS_ECN_MASK 0x03 /* ECN field mask */
|
||||
|
||||
/*
|
||||
* Definitions for options.
|
||||
*/
|
||||
#define IPOPT_COPIED(o) ((o)&0x80)
|
||||
#define IPOPT_CLASS(o) ((o)&0x60)
|
||||
#define IPOPT_NUMBER(o) ((o)&0x1f)
|
||||
|
||||
#define IPOPT_CONTROL 0x00
|
||||
#define IPOPT_RESERVED1 0x20
|
||||
#define IPOPT_DEBMEAS 0x40
|
||||
#define IPOPT_RESERVED2 0x60
|
||||
|
||||
#define IPOPT_EOL 0 /* end of option list */
|
||||
#define IPOPT_NOP 1 /* no operation */
|
||||
|
||||
#define IPOPT_RR 7 /* record packet route */
|
||||
#define IPOPT_TS 68 /* timestamp */
|
||||
#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */
|
||||
#define IPOPT_LSRR 131 /* loose source route */
|
||||
#define IPOPT_ESO 133 /* extended security */
|
||||
#define IPOPT_CIPSO 134 /* commerical security */
|
||||
#define IPOPT_SATID 136 /* satnet id */
|
||||
#define IPOPT_SSRR 137 /* strict source route */
|
||||
#define IPOPT_RA 148 /* router alert */
|
||||
|
||||
/*
|
||||
* Offsets to fields in options other than EOL and NOP.
|
||||
*/
|
||||
#define IPOPT_OPTVAL 0 /* option ID */
|
||||
#define IPOPT_OLEN 1 /* option length */
|
||||
#define IPOPT_OFFSET 2 /* offset within option */
|
||||
#define IPOPT_MINOFF 4 /* min value of above */
|
||||
|
||||
/* Flag bits for ipt_flg. */
|
||||
#define IPOPT_TS_TSONLY 0 /* timestamps only */
|
||||
#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
|
||||
#define IPOPT_TS_PRESPEC 3 /* specified modules only */
|
||||
|
||||
/* Bits for security (not byte swapped). */
|
||||
#define IPOPT_SECUR_UNCLASS 0x0000
|
||||
#define IPOPT_SECUR_CONFID 0xf135
|
||||
#define IPOPT_SECUR_EFTO 0x789a
|
||||
#define IPOPT_SECUR_MMMM 0xbc4d
|
||||
#define IPOPT_SECUR_RESTR 0xaf13
|
||||
#define IPOPT_SECUR_SECRET 0xd788
|
||||
#define IPOPT_SECUR_TOPSECRET 0x6bc5
|
||||
|
||||
/*
|
||||
* Internet implementation parameters.
|
||||
*/
|
||||
#define MAXTTL 255 /* maximum time to live (seconds) */
|
||||
#define IPDEFTTL 64 /* default ttl, from RFC 1340 */
|
||||
#define IPFRAGTTL 60 /* time to live for frags, slowhz */
|
||||
#define IPTTLDEC 1 /* subtracted when forwarding */
|
||||
#define IP_MSS 576 /* default maximum segment size */
|
||||
|
||||
#endif
|
||||
Vendored
+164
@@ -0,0 +1,164 @@
|
||||
/* $FreeBSD$ */
|
||||
/* $KAME: ip6.h,v 1.18 2001/03/29 05:34:30 itojun Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)ip.h 8.1 (Berkeley) 6/10/93
|
||||
*/
|
||||
|
||||
#ifndef _NETINET_IP6_H_
|
||||
#define _NETINET_IP6_H_
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/* samkumar: Copied from netinet/in6.h */
|
||||
struct in6_addr {
|
||||
union {
|
||||
uint8_t __u6_addr8[16];
|
||||
uint16_t __u6_addr16[8];
|
||||
uint32_t __u6_addr32[4];
|
||||
} __u6_addr; /* 128-bit IP6 address */
|
||||
} __attribute__((packed)); // added this to allow unaligned access
|
||||
#define s6_addr __u6_addr.__u6_addr8
|
||||
|
||||
struct sockaddr_in6 {
|
||||
uint8_t sin6_len; /* length of this struct */
|
||||
int sin6_family; /* AF_INET6 */
|
||||
uint16_t sin6_port; /* Transport layer port # */
|
||||
uint32_t sin6_flowinfo; /* IP6 flow information */
|
||||
struct in6_addr sin6_addr; /* IP6 address */
|
||||
uint32_t sin6_scope_id; /* scope zone index */
|
||||
};
|
||||
|
||||
/*
|
||||
* Definition for internet protocol version 6.
|
||||
* RFC 2460
|
||||
*/
|
||||
struct ip6_hdr {
|
||||
union {
|
||||
struct ip6_hdrctl {
|
||||
u_int32_t ip6_un1_flow; /* 20 bits of flow-ID */
|
||||
u_int16_t ip6_un1_plen; /* payload length */
|
||||
u_int8_t ip6_un1_nxt; /* next header */
|
||||
u_int8_t ip6_un1_hlim; /* hop limit */
|
||||
} ip6_un1;
|
||||
u_int8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */
|
||||
} ip6_ctlun;
|
||||
struct in6_addr ip6_src; /* source address */
|
||||
struct in6_addr ip6_dst; /* destination address */
|
||||
} __attribute__((packed));
|
||||
|
||||
#define ip6_vfc ip6_ctlun.ip6_un2_vfc
|
||||
#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
|
||||
#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
|
||||
#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
|
||||
#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
|
||||
#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
|
||||
|
||||
#define IPV6_VERSION 0x60
|
||||
#define IPV6_VERSION_MASK 0xf0
|
||||
|
||||
/* samkumar: Removed #if guard since ECN is enabled in TCPlp. */
|
||||
/* ECN bits proposed by Sally Floyd */
|
||||
#define IP6TOS_CE 0x01 /* congestion experienced */
|
||||
#define IP6TOS_ECT 0x02 /* ECN-capable transport */
|
||||
|
||||
// samkumar: Copied from in6.h
|
||||
#define IN6_ARE_ADDR_EQUAL(a, b) \
|
||||
(memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0)
|
||||
|
||||
/* Multicast */
|
||||
#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff)
|
||||
|
||||
/*
|
||||
* Unspecified
|
||||
*/
|
||||
#define IN6_IS_ADDR_UNSPECIFIED(a) \
|
||||
((a)->__u6_addr.__u6_addr32[0] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[1] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[2] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[3] == 0)
|
||||
|
||||
/*
|
||||
* Loopback
|
||||
*/
|
||||
#define IN6_IS_ADDR_LOOPBACK(a) \
|
||||
((a)->__u6_addr.__u6_addr32[0] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[1] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[2] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[3] == ntohl(1))
|
||||
|
||||
/*
|
||||
* Unicast Scope
|
||||
* Note that we must check topmost 10 bits only, not 16 bits (see RFC2373).
|
||||
*/
|
||||
#define IN6_IS_ADDR_LINKLOCAL(a) \
|
||||
(((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
|
||||
#define IN6_IS_ADDR_SITELOCAL(a) \
|
||||
(((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
|
||||
|
||||
/*
|
||||
* Mapped
|
||||
*/
|
||||
|
||||
#define IN6_IS_ADDR_V4MAPPED(a) \
|
||||
((a)->__u6_addr.__u6_addr32[0] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[1] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[2] == ntohl(0x0000ffff))
|
||||
|
||||
#endif /* not _NETINET_IP6_H_ */
|
||||
Vendored
+754
@@ -0,0 +1,754 @@
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SYS_QUEUE_H_
|
||||
#define _SYS_QUEUE_H_
|
||||
|
||||
/* samkumar: Removing this, as it adds yet another dependency. */
|
||||
//#include <sys/cdefs.h>
|
||||
|
||||
/*
|
||||
* This file defines four types of data structures: singly-linked lists,
|
||||
* singly-linked tail queues, lists and tail queues.
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The elements
|
||||
* are singly linked for minimum space and pointer manipulation overhead at
|
||||
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||
* added to the list after an existing element or at the head of the list.
|
||||
* Elements being removed from the head of the list should use the explicit
|
||||
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||
* for applications with large datasets and few or no removals or for
|
||||
* implementing a LIFO queue.
|
||||
*
|
||||
* A singly-linked tail queue is headed by a pair of pointers, one to the
|
||||
* head of the list and the other to the tail of the list. The elements are
|
||||
* singly linked for minimum space and pointer manipulation overhead at the
|
||||
* expense of O(n) removal for arbitrary elements. New elements can be added
|
||||
* to the list after an existing element, at the head of the list, or at the
|
||||
* end of the list. Elements being removed from the head of the tail queue
|
||||
* should use the explicit macro for this purpose for optimum efficiency.
|
||||
* A singly-linked tail queue may only be traversed in the forward direction.
|
||||
* Singly-linked tail queues are ideal for applications with large datasets
|
||||
* and few or no removals or for implementing a FIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may be traversed in either direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*
|
||||
*
|
||||
* SLIST LIST STAILQ TAILQ
|
||||
* _HEAD + + + +
|
||||
* _CLASS_HEAD + + + +
|
||||
* _HEAD_INITIALIZER + + + +
|
||||
* _ENTRY + + + +
|
||||
* _CLASS_ENTRY + + + +
|
||||
* _INIT + + + +
|
||||
* _EMPTY + + + +
|
||||
* _FIRST + + + +
|
||||
* _NEXT + + + +
|
||||
* _PREV - + - +
|
||||
* _LAST - - + +
|
||||
* _FOREACH + + + +
|
||||
* _FOREACH_FROM + + + +
|
||||
* _FOREACH_SAFE + + + +
|
||||
* _FOREACH_FROM_SAFE + + + +
|
||||
* _FOREACH_REVERSE - - - +
|
||||
* _FOREACH_REVERSE_FROM - - - +
|
||||
* _FOREACH_REVERSE_SAFE - - - +
|
||||
* _FOREACH_REVERSE_FROM_SAFE - - - +
|
||||
* _INSERT_HEAD + + + +
|
||||
* _INSERT_BEFORE - + - +
|
||||
* _INSERT_AFTER + + + +
|
||||
* _INSERT_TAIL - - + +
|
||||
* _CONCAT - - + +
|
||||
* _REMOVE_AFTER + - + -
|
||||
* _REMOVE_HEAD + - + -
|
||||
* _REMOVE + + + +
|
||||
* _SWAP + + + +
|
||||
*
|
||||
*/
|
||||
#ifdef QUEUE_MACRO_DEBUG
|
||||
/* Store the last 2 places the queue element or head was altered */
|
||||
struct qm_trace {
|
||||
unsigned long lastline;
|
||||
unsigned long prevline;
|
||||
const char *lastfile;
|
||||
const char *prevfile;
|
||||
};
|
||||
|
||||
#define TRACEBUF struct qm_trace trace;
|
||||
#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } ,
|
||||
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
|
||||
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
|
||||
|
||||
#define QMD_TRACE_HEAD(head) do { \
|
||||
(head)->trace.prevline = (head)->trace.lastline; \
|
||||
(head)->trace.prevfile = (head)->trace.lastfile; \
|
||||
(head)->trace.lastline = __LINE__; \
|
||||
(head)->trace.lastfile = __FILE__; \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TRACE_ELEM(elem) do { \
|
||||
(elem)->trace.prevline = (elem)->trace.lastline; \
|
||||
(elem)->trace.prevfile = (elem)->trace.lastfile; \
|
||||
(elem)->trace.lastline = __LINE__; \
|
||||
(elem)->trace.lastfile = __FILE__; \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#define QMD_TRACE_ELEM(elem)
|
||||
#define QMD_TRACE_HEAD(head)
|
||||
#define QMD_SAVELINK(name, link)
|
||||
#define TRACEBUF
|
||||
#define TRACEBUF_INITIALIZER
|
||||
#define TRASHIT(x)
|
||||
#endif /* QUEUE_MACRO_DEBUG */
|
||||
|
||||
#ifdef __cplusplus
|
||||
/*
|
||||
* In C++ there can be structure lists and class lists:
|
||||
*/
|
||||
#define QUEUE_TYPEOF(type) type
|
||||
#else
|
||||
#define QUEUE_TYPEOF(type) struct type
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Singly-linked List declarations.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_CLASS_HEAD(name, type) \
|
||||
struct name { \
|
||||
class type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
#define SLIST_CLASS_ENTRY(type) \
|
||||
struct { \
|
||||
class type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
|
||||
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for ((var) = SLIST_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = SLIST_NEXT((var), field))
|
||||
|
||||
#define SLIST_FOREACH_FROM(var, head, field) \
|
||||
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
|
||||
(var); \
|
||||
(var) = SLIST_NEXT((var), field))
|
||||
|
||||
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = SLIST_FIRST((head)); \
|
||||
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
|
||||
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
|
||||
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
|
||||
for ((varp) = &SLIST_FIRST((head)); \
|
||||
((var) = *(varp)) != NULL; \
|
||||
(varp) = &SLIST_NEXT((var), field))
|
||||
|
||||
#define SLIST_INIT(head) do { \
|
||||
SLIST_FIRST((head)) = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
|
||||
SLIST_NEXT((slistelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
|
||||
SLIST_FIRST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||
QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
|
||||
if (SLIST_FIRST((head)) == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \
|
||||
while (SLIST_NEXT(curelm, field) != (elm)) \
|
||||
curelm = SLIST_NEXT(curelm, field); \
|
||||
SLIST_REMOVE_AFTER(curelm, field); \
|
||||
} \
|
||||
TRASHIT(*oldnext); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_AFTER(elm, field) do { \
|
||||
SLIST_NEXT(elm, field) = \
|
||||
SLIST_NEXT(SLIST_NEXT(elm, field), field); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_SWAP(head1, head2, type) do { \
|
||||
QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \
|
||||
SLIST_FIRST(head1) = SLIST_FIRST(head2); \
|
||||
SLIST_FIRST(head2) = swap_first; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue declarations.
|
||||
*/
|
||||
#define STAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *stqh_first;/* first element */ \
|
||||
struct type **stqh_last;/* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define STAILQ_CLASS_HEAD(name, type) \
|
||||
struct name { \
|
||||
class type *stqh_first; /* first element */ \
|
||||
class type **stqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define STAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).stqh_first }
|
||||
|
||||
#define STAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *stqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
#define STAILQ_CLASS_ENTRY(type) \
|
||||
struct { \
|
||||
class type *stqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue functions.
|
||||
*/
|
||||
#define STAILQ_CONCAT(head1, head2) do { \
|
||||
if (!STAILQ_EMPTY((head2))) { \
|
||||
*(head1)->stqh_last = (head2)->stqh_first; \
|
||||
(head1)->stqh_last = (head2)->stqh_last; \
|
||||
STAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
|
||||
|
||||
#define STAILQ_FIRST(head) ((head)->stqh_first)
|
||||
|
||||
#define STAILQ_FOREACH(var, head, field) \
|
||||
for((var) = STAILQ_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = STAILQ_NEXT((var), field))
|
||||
|
||||
#define STAILQ_FOREACH_FROM(var, head, field) \
|
||||
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
|
||||
(var); \
|
||||
(var) = STAILQ_NEXT((var), field))
|
||||
|
||||
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = STAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
|
||||
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
|
||||
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define STAILQ_INIT(head) do { \
|
||||
STAILQ_FIRST((head)) = NULL; \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
|
||||
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
STAILQ_NEXT((tqelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
STAILQ_FIRST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
STAILQ_NEXT((elm), field) = NULL; \
|
||||
*(head)->stqh_last = (elm); \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_LAST(head, type, field) \
|
||||
(STAILQ_EMPTY((head)) ? NULL : \
|
||||
__containerof((head)->stqh_last, \
|
||||
QUEUE_TYPEOF(type), field.stqe_next))
|
||||
|
||||
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
|
||||
|
||||
#define STAILQ_REMOVE(head, elm, type, field) do { \
|
||||
QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
|
||||
if (STAILQ_FIRST((head)) == (elm)) { \
|
||||
STAILQ_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \
|
||||
while (STAILQ_NEXT(curelm, field) != (elm)) \
|
||||
curelm = STAILQ_NEXT(curelm, field); \
|
||||
STAILQ_REMOVE_AFTER(head, curelm, field); \
|
||||
} \
|
||||
TRASHIT(*oldnext); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
|
||||
if ((STAILQ_NEXT(elm, field) = \
|
||||
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE_HEAD(head, field) do { \
|
||||
if ((STAILQ_FIRST((head)) = \
|
||||
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_SWAP(head1, head2, type) do { \
|
||||
QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \
|
||||
QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \
|
||||
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
|
||||
(head1)->stqh_last = (head2)->stqh_last; \
|
||||
STAILQ_FIRST(head2) = swap_first; \
|
||||
(head2)->stqh_last = swap_last; \
|
||||
if (STAILQ_EMPTY(head1)) \
|
||||
(head1)->stqh_last = &STAILQ_FIRST(head1); \
|
||||
if (STAILQ_EMPTY(head2)) \
|
||||
(head2)->stqh_last = &STAILQ_FIRST(head2); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* List declarations.
|
||||
*/
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_CLASS_HEAD(name, type) \
|
||||
struct name { \
|
||||
class type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
#define LIST_CLASS_ENTRY(type) \
|
||||
struct { \
|
||||
class type *le_next; /* next element */ \
|
||||
class type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
|
||||
#if (defined(_KERNEL) && defined(INVARIANTS))
|
||||
#define QMD_LIST_CHECK_HEAD(head, field) do { \
|
||||
if (LIST_FIRST((head)) != NULL && \
|
||||
LIST_FIRST((head))->field.le_prev != \
|
||||
&LIST_FIRST((head))) \
|
||||
panic("Bad list head %p first->prev != head", (head)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_LIST_CHECK_NEXT(elm, field) do { \
|
||||
if (LIST_NEXT((elm), field) != NULL && \
|
||||
LIST_NEXT((elm), field)->field.le_prev != \
|
||||
&((elm)->field.le_next)) \
|
||||
panic("Bad link elm %p next->prev != elm", (elm)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_LIST_CHECK_PREV(elm, field) do { \
|
||||
if (*(elm)->field.le_prev != (elm)) \
|
||||
panic("Bad link elm %p prev->next != elm", (elm)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define QMD_LIST_CHECK_HEAD(head, field)
|
||||
#define QMD_LIST_CHECK_NEXT(elm, field)
|
||||
#define QMD_LIST_CHECK_PREV(elm, field)
|
||||
#endif /* (_KERNEL && INVARIANTS) */
|
||||
|
||||
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
|
||||
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for ((var) = LIST_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = LIST_NEXT((var), field))
|
||||
|
||||
#define LIST_FOREACH_FROM(var, head, field) \
|
||||
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
|
||||
(var); \
|
||||
(var) = LIST_NEXT((var), field))
|
||||
|
||||
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = LIST_FIRST((head)); \
|
||||
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
|
||||
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
|
||||
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define LIST_INIT(head) do { \
|
||||
LIST_FIRST((head)) = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
QMD_LIST_CHECK_NEXT(listelm, field); \
|
||||
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
|
||||
LIST_NEXT((listelm), field)->field.le_prev = \
|
||||
&LIST_NEXT((elm), field); \
|
||||
LIST_NEXT((listelm), field) = (elm); \
|
||||
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
QMD_LIST_CHECK_PREV(listelm, field); \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
LIST_NEXT((elm), field) = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||
QMD_LIST_CHECK_HEAD((head), field); \
|
||||
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
|
||||
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
|
||||
LIST_FIRST((head)) = (elm); \
|
||||
(elm)->field.le_prev = &LIST_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
#define LIST_PREV(elm, head, type, field) \
|
||||
((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
|
||||
__containerof((elm)->field.le_prev, \
|
||||
QUEUE_TYPEOF(type), field.le_next))
|
||||
|
||||
#define LIST_REMOVE(elm, field) do { \
|
||||
QMD_SAVELINK(oldnext, (elm)->field.le_next); \
|
||||
QMD_SAVELINK(oldprev, (elm)->field.le_prev); \
|
||||
QMD_LIST_CHECK_NEXT(elm, field); \
|
||||
QMD_LIST_CHECK_PREV(elm, field); \
|
||||
if (LIST_NEXT((elm), field) != NULL) \
|
||||
LIST_NEXT((elm), field)->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
|
||||
TRASHIT(*oldnext); \
|
||||
TRASHIT(*oldprev); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_SWAP(head1, head2, type, field) do { \
|
||||
QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \
|
||||
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
|
||||
LIST_FIRST((head2)) = swap_tmp; \
|
||||
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
|
||||
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
|
||||
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
|
||||
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Tail queue declarations.
|
||||
*/
|
||||
#define TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
TRACEBUF \
|
||||
}
|
||||
|
||||
#define TAILQ_CLASS_HEAD(name, type) \
|
||||
struct name { \
|
||||
class type *tqh_first; /* first element */ \
|
||||
class type **tqh_last; /* addr of last next element */ \
|
||||
TRACEBUF \
|
||||
}
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first, TRACEBUF_INITIALIZER }
|
||||
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
TRACEBUF \
|
||||
}
|
||||
|
||||
#define TAILQ_CLASS_ENTRY(type) \
|
||||
struct { \
|
||||
class type *tqe_next; /* next element */ \
|
||||
class type **tqe_prev; /* address of previous next element */ \
|
||||
TRACEBUF \
|
||||
}
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#if (defined(_KERNEL) && defined(INVARIANTS))
|
||||
#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
|
||||
if (!TAILQ_EMPTY(head) && \
|
||||
TAILQ_FIRST((head))->field.tqe_prev != \
|
||||
&TAILQ_FIRST((head))) \
|
||||
panic("Bad tailq head %p first->prev != head", (head)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
|
||||
if (*(head)->tqh_last != NULL) \
|
||||
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
|
||||
if (TAILQ_NEXT((elm), field) != NULL && \
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev != \
|
||||
&((elm)->field.tqe_next)) \
|
||||
panic("Bad link elm %p next->prev != elm", (elm)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
|
||||
if (*(elm)->field.tqe_prev != (elm)) \
|
||||
panic("Bad link elm %p prev->next != elm", (elm)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define QMD_TAILQ_CHECK_HEAD(head, field)
|
||||
#define QMD_TAILQ_CHECK_TAIL(head, headname)
|
||||
#define QMD_TAILQ_CHECK_NEXT(elm, field)
|
||||
#define QMD_TAILQ_CHECK_PREV(elm, field)
|
||||
#endif /* (_KERNEL && INVARIANTS) */
|
||||
|
||||
#define TAILQ_CONCAT(head1, head2, field) do { \
|
||||
if (!TAILQ_EMPTY(head2)) { \
|
||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
TAILQ_INIT((head2)); \
|
||||
QMD_TRACE_HEAD(head1); \
|
||||
QMD_TRACE_HEAD(head2); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = TAILQ_NEXT((var), field))
|
||||
|
||||
#define TAILQ_FOREACH_FROM(var, head, field) \
|
||||
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
|
||||
(var); \
|
||||
(var) = TAILQ_NEXT((var), field))
|
||||
|
||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
|
||||
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
|
||||
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = TAILQ_LAST((head), headname); \
|
||||
(var); \
|
||||
(var) = TAILQ_PREV((var), headname, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \
|
||||
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
|
||||
(var); \
|
||||
(var) = TAILQ_PREV((var), headname, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
|
||||
for ((var) = TAILQ_LAST((head), headname); \
|
||||
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
|
||||
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
|
||||
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_INIT(head) do { \
|
||||
TAILQ_FIRST((head)) = NULL; \
|
||||
(head)->tqh_last = &TAILQ_FIRST((head)); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
QMD_TAILQ_CHECK_NEXT(listelm, field); \
|
||||
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev = \
|
||||
&TAILQ_NEXT((elm), field); \
|
||||
else { \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
} \
|
||||
TAILQ_NEXT((listelm), field) = (elm); \
|
||||
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
QMD_TRACE_ELEM(&(listelm)->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
QMD_TAILQ_CHECK_PREV(listelm, field); \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
TAILQ_NEXT((elm), field) = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
QMD_TRACE_ELEM(&(listelm)->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
QMD_TAILQ_CHECK_HEAD(head, field); \
|
||||
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
|
||||
TAILQ_FIRST((head))->field.tqe_prev = \
|
||||
&TAILQ_NEXT((elm), field); \
|
||||
else \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
TAILQ_FIRST((head)) = (elm); \
|
||||
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
QMD_TAILQ_CHECK_TAIL(head, field); \
|
||||
TAILQ_NEXT((elm), field) = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
|
||||
QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
|
||||
QMD_TAILQ_CHECK_NEXT(elm, field); \
|
||||
QMD_TAILQ_CHECK_PREV(elm, field); \
|
||||
if ((TAILQ_NEXT((elm), field)) != NULL) \
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else { \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
} \
|
||||
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
|
||||
TRASHIT(*oldnext); \
|
||||
TRASHIT(*oldprev); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_SWAP(head1, head2, type, field) do { \
|
||||
QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \
|
||||
QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \
|
||||
(head1)->tqh_first = (head2)->tqh_first; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
(head2)->tqh_first = swap_first; \
|
||||
(head2)->tqh_last = swap_last; \
|
||||
if ((swap_first = (head1)->tqh_first) != NULL) \
|
||||
swap_first->field.tqe_prev = &(head1)->tqh_first; \
|
||||
else \
|
||||
(head1)->tqh_last = &(head1)->tqh_first; \
|
||||
if ((swap_first = (head2)->tqh_first) != NULL) \
|
||||
swap_first->field.tqe_prev = &(head2)->tqh_first; \
|
||||
else \
|
||||
(head2)->tqh_last = &(head2)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#endif /* !_SYS_QUEUE_H_ */
|
||||
Vendored
+189
@@ -0,0 +1,189 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tcp.h 8.1 (Berkeley) 6/10/93
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar: In one instance (in struct tcphdr), where there are Big Endian
|
||||
* and Little Endian alternatives for ordering two fields, I hardcoded the
|
||||
* Little Endian alternative. If ever we port this to a Big Endian platform,
|
||||
* we should look at that very closely, and consider rewriting it.
|
||||
*/
|
||||
|
||||
#ifndef _NETINET_TCP_H_
|
||||
#define _NETINET_TCP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define __func__ "BSD TCP function"
|
||||
|
||||
#define KASSERT(COND, MSG) if (!(COND)) tcplp_sys_log MSG
|
||||
|
||||
typedef uint32_t tcp_seq;
|
||||
|
||||
#define tcp6_seq tcp_seq /* for KAME src sync over BSD*'s */
|
||||
#define tcp6hdr tcphdr /* for KAME src sync over BSD*'s */
|
||||
|
||||
/*
|
||||
* TCP header.
|
||||
* Per RFC 793, September, 1981.
|
||||
*/
|
||||
struct tcphdr {
|
||||
uint16_t th_sport; /* source port */
|
||||
uint16_t th_dport; /* destination port */
|
||||
tcp_seq th_seq; /* sequence number */
|
||||
tcp_seq th_ack; /* acknowledgement number */
|
||||
#if 1 //BYTE_ORDER == LITTLE_ENDIAN
|
||||
uint8_t th_x2:4, /* (unused) */
|
||||
th_off:4; /* data offset */
|
||||
#endif
|
||||
#if 0 //BYTE_ORDER == BIG_ENDIAN
|
||||
uint8_t th_off:4, /* data offset */
|
||||
th_x2:4; /* (unused) */
|
||||
#endif
|
||||
uint8_t th_flags;
|
||||
#define TH_FIN 0x01
|
||||
#define TH_SYN 0x02
|
||||
#define TH_RST 0x04
|
||||
#define TH_PUSH 0x08
|
||||
#define TH_ACK 0x10
|
||||
#define TH_URG 0x20
|
||||
#define TH_ECE 0x40
|
||||
#define TH_CWR 0x80
|
||||
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG|TH_ECE|TH_CWR)
|
||||
#define PRINT_TH_FLAGS "\20\1FIN\2SYN\3RST\4PUSH\5ACK\6URG\7ECE\10CWR"
|
||||
|
||||
uint16_t th_win; /* window */
|
||||
uint16_t th_sum; /* checksum */
|
||||
uint16_t th_urp; /* urgent pointer */
|
||||
};
|
||||
|
||||
#define TCPOPT_EOL 0
|
||||
#define TCPOLEN_EOL 1
|
||||
#define TCPOPT_PAD 0 /* padding after EOL */
|
||||
#define TCPOLEN_PAD 1
|
||||
#define TCPOPT_NOP 1
|
||||
#define TCPOLEN_NOP 1
|
||||
#define TCPOPT_MAXSEG 2
|
||||
#define TCPOLEN_MAXSEG 4
|
||||
#define TCPOPT_WINDOW 3
|
||||
#define TCPOLEN_WINDOW 3
|
||||
#define TCPOPT_SACK_PERMITTED 4
|
||||
#define TCPOLEN_SACK_PERMITTED 2
|
||||
#define TCPOPT_SACK 5
|
||||
#define TCPOLEN_SACKHDR 2
|
||||
#define TCPOLEN_SACK 8 /* 2*sizeof(tcp_seq) */
|
||||
#define TCPOPT_TIMESTAMP 8
|
||||
#define TCPOLEN_TIMESTAMP 10
|
||||
#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */
|
||||
#define TCPOPT_SIGNATURE 19 /* Keyed MD5: RFC 2385 */
|
||||
#define TCPOLEN_SIGNATURE 18
|
||||
|
||||
/* Miscellaneous constants */
|
||||
#define MAX_SACK_BLKS 6 /* Max # SACK blocks stored at receiver side */
|
||||
#define TCP_MAX_SACK 4 /* MAX # SACKs sent in any segment */
|
||||
|
||||
|
||||
/*
|
||||
* The default maximum segment size (MSS) to be used for new TCP connections
|
||||
* when path MTU discovery is not enabled.
|
||||
*
|
||||
* RFC879 derives the default MSS from the largest datagram size hosts are
|
||||
* minimally required to handle directly or through IP reassembly minus the
|
||||
* size of the IP and TCP header. With IPv6 the minimum MTU is specified
|
||||
* in RFC2460.
|
||||
*
|
||||
* For IPv4 the MSS is 576 - sizeof(struct tcpiphdr)
|
||||
* For IPv6 the MSS is IPV6_MMTU - sizeof(struct ip6_hdr) - sizeof(struct tcphdr)
|
||||
*
|
||||
* We use explicit numerical definition here to avoid header pollution.
|
||||
*/
|
||||
#define TCP_MSS 536
|
||||
#define TCP6_MSS 1220
|
||||
|
||||
/*
|
||||
* Limit the lowest MSS we accept for path MTU discovery and the TCP SYN MSS
|
||||
* option. Allowing low values of MSS can consume significant resources and
|
||||
* be used to mount a resource exhaustion attack.
|
||||
* Connections requesting lower MSS values will be rounded up to this value
|
||||
* and the IP_DF flag will be cleared to allow fragmentation along the path.
|
||||
*
|
||||
* See tcp_subr.c tcp_minmss SYSCTL declaration for more comments. Setting
|
||||
* it to "0" disables the minmss check.
|
||||
*
|
||||
* The default value is fine for TCP across the Internet's smallest official
|
||||
* link MTU (256 bytes for AX.25 packet radio). However, a connection is very
|
||||
* unlikely to come across such low MTU interfaces these days (anno domini 2003).
|
||||
*/
|
||||
#define TCP_MINMSS 216
|
||||
|
||||
#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */
|
||||
#define TTCP_CLIENT_SND_WND 4096 /* dflt send window for T/TCP client */
|
||||
|
||||
#define TCP_MAX_WINSHIFT 14 /* maximum window shift */
|
||||
|
||||
#define TCP_MAXBURST 4 /* maximum segments in a burst */
|
||||
|
||||
#define TCP_MAXHLEN (0xf<<2) /* max length of header in bytes */
|
||||
#define TCP_MAXOLEN (TCP_MAXHLEN - sizeof(struct tcphdr))
|
||||
/* max space left for options */
|
||||
|
||||
/*
|
||||
* User-settable options (used with setsockopt). These are discrete
|
||||
* values and are not masked together. Some values appear to be
|
||||
* bitmasks for historical reasons.
|
||||
*/
|
||||
#define TCP_NODELAY 1 /* don't delay send to coalesce packets */
|
||||
#define TCP_MAXSEG 2 /* set maximum segment size */
|
||||
#define TCP_NOPUSH 4 /* don't push last block of write */
|
||||
#define TCP_NOOPT 8 /* don't use TCP options */
|
||||
#define TCP_MD5SIG 16 /* use MD5 digests (RFC2385) */
|
||||
#define TCP_INFO 32 /* retrieve tcp_info structure */
|
||||
#define TCP_CONGESTION 64 /* get/set congestion control algorithm */
|
||||
#define TCP_KEEPINIT 128 /* N, time to establish connection */
|
||||
#define TCP_KEEPIDLE 256 /* L,N,X start keeplives after this period */
|
||||
#define TCP_KEEPINTVL 512 /* L,N interval between keepalives */
|
||||
#define TCP_KEEPCNT 1024 /* L,N number of keepalives before close */
|
||||
#define TCP_PCAP_OUT 2048 /* number of output packets to keep */
|
||||
#define TCP_PCAP_IN 4096 /* number of input packets to keep */
|
||||
|
||||
/* Start of reserved space for third-party user-settable options. */
|
||||
#define TCP_VENDOR SO_VENDOR
|
||||
|
||||
#define TCP_CA_NAME_MAX 16 /* max congestion control name length */
|
||||
|
||||
#define TCPI_OPT_TIMESTAMPS 0x01
|
||||
#define TCPI_OPT_SACK 0x02
|
||||
#define TCPI_OPT_WSCALE 0x04
|
||||
#define TCPI_OPT_ECN 0x08
|
||||
#define TCPI_OPT_TOE 0x10
|
||||
|
||||
#endif /* !_NETINET_TCP_H_ */
|
||||
Vendored
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sam Kumar <[email protected]>
|
||||
* Copyright (c) 2018, University of California, Berkeley
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar: I created this file to store many of the constants shared by the
|
||||
* various files in the FreeBSD protocol logic. The original variables were
|
||||
* often virtualized ("V_"-prefixed) variables. I've changed the definitions to
|
||||
* be enumerations rather than globals, to save some memory. These variables
|
||||
* often serve to enable, disable, or configure certain TCP-related features.
|
||||
*/
|
||||
|
||||
#ifndef _TCP_CONST_H_
|
||||
#define _TCP_CONST_H_
|
||||
|
||||
#include "../tcplp.h"
|
||||
|
||||
#include "tcp_var.h"
|
||||
#include "tcp_timer.h"
|
||||
|
||||
#define MSS_6LOWPAN ((FRAMES_PER_SEG * FRAMECAP_6LOWPAN) - IP6HDR_SIZE - sizeof(struct tcphdr))
|
||||
|
||||
// I may change some of these flags later
|
||||
enum tcp_input_consts {
|
||||
tcp_keepcnt = TCPTV_KEEPCNT,
|
||||
tcp_fast_finwait2_recycle = 0,
|
||||
tcprexmtthresh = 3,
|
||||
V_drop_synfin = 0,
|
||||
V_tcp_do_ecn = 1,
|
||||
V_tcp_ecn_maxretries = 3,
|
||||
V_tcp_do_rfc3042 = 1,
|
||||
V_path_mtu_discovery = 0,
|
||||
V_tcp_delack_enabled = 1,
|
||||
V_tcp_initcwnd_segments = 0,
|
||||
V_tcp_do_rfc3390 = 0,
|
||||
V_tcp_abc_l_var = 2 // this is what was in the original tcp_input.c
|
||||
};
|
||||
|
||||
enum tcp_subr_consts {
|
||||
tcp_delacktime = TCPTV_DELACK,
|
||||
tcp_keepinit = TCPTV_KEEP_INIT,
|
||||
tcp_keepidle = TCPTV_KEEP_IDLE,
|
||||
tcp_keepintvl = TCPTV_KEEPINTVL,
|
||||
tcp_maxpersistidle = TCPTV_KEEP_IDLE,
|
||||
tcp_msl = TCPTV_MSL,
|
||||
tcp_rexmit_slop = TCPTV_CPU_VAR,
|
||||
tcp_finwait2_timeout = TCPTV_FINWAIT2_TIMEOUT,
|
||||
|
||||
V_tcp_do_rfc1323 = 1,
|
||||
V_tcp_v6mssdflt = MSS_6LOWPAN,
|
||||
/* Normally, this is used to prevent DoS attacks by sending tiny MSS values in the options. */
|
||||
V_tcp_minmss = TCP_MAXOLEN + 1, // Must have enough space for TCP options, and one more byte for data. Default is 216.
|
||||
V_tcp_do_sack = 1
|
||||
};
|
||||
|
||||
enum tcp_timer_consts {
|
||||
// V_tcp_v6pmtud_blackhole_mss = FRAMECAP_6LOWPAN - sizeof(struct ip6_hdr) - sizeof(struct tcphdr), // Doesn't matter unless blackhole_detect is 1.
|
||||
tcp_rexmit_drop_options = 0, // drop options after a few retransmits
|
||||
always_keepalive = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Force a time value to be in a certain range.
|
||||
*/
|
||||
#define TCPT_RANGESET(tv, value, tvmin, tvmax) do { \
|
||||
(tv) = (value) + tcp_rexmit_slop; \
|
||||
if ((uint64_t)(tv) < (uint64_t)(tvmin)) \
|
||||
(tv) = (tvmin); \
|
||||
if ((uint64_t)(tv) > (uint64_t)(tvmax)) \
|
||||
(tv) = (tvmax); \
|
||||
} while(0)
|
||||
|
||||
#endif
|
||||
Vendored
+112
@@ -0,0 +1,112 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tcp_fsm.h 8.1 (Berkeley) 6/10/93
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/* samkumar: Removed some #ifdef guards around constants needed for TCPlp. */
|
||||
|
||||
#ifndef _NETINET_TCP_FSM_H_
|
||||
#define _NETINET_TCP_FSM_H_
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/*
|
||||
* TCP FSM state definitions.
|
||||
*
|
||||
* Per RFC793, September, 1981.
|
||||
*/
|
||||
|
||||
#define TCP_NSTATES 11
|
||||
|
||||
#define TCPS_CLOSED 0 /* closed */
|
||||
#define TCPS_LISTEN 1 /* listening for connection */
|
||||
#define TCPS_SYN_SENT 2 /* active, have sent syn */
|
||||
#define TCPS_SYN_RECEIVED 3 /* have sent and received syn */
|
||||
/* states < TCPS_ESTABLISHED are those where connections not established */
|
||||
#define TCPS_ESTABLISHED 4 /* established */
|
||||
#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */
|
||||
/* states > TCPS_CLOSE_WAIT are those where user has closed */
|
||||
#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */
|
||||
#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */
|
||||
#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */
|
||||
/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */
|
||||
#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */
|
||||
#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */
|
||||
|
||||
/* for KAME src sync over BSD*'s */
|
||||
#define TCP6_NSTATES TCP_NSTATES
|
||||
#define TCP6S_CLOSED TCPS_CLOSED
|
||||
#define TCP6S_LISTEN TCPS_LISTEN
|
||||
#define TCP6S_SYN_SENT TCPS_SYN_SENT
|
||||
#define TCP6S_SYN_RECEIVED TCPS_SYN_RECEIVED
|
||||
#define TCP6S_ESTABLISHED TCPS_ESTABLISHED
|
||||
#define TCP6S_CLOSE_WAIT TCPS_CLOSE_WAIT
|
||||
#define TCP6S_FIN_WAIT_1 TCPS_FIN_WAIT_1
|
||||
#define TCP6S_CLOSING TCPS_CLOSING
|
||||
#define TCP6S_LAST_ACK TCPS_LAST_ACK
|
||||
#define TCP6S_FIN_WAIT_2 TCPS_FIN_WAIT_2
|
||||
#define TCP6S_TIME_WAIT TCPS_TIME_WAIT
|
||||
|
||||
#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED)
|
||||
#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED)
|
||||
#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT)
|
||||
|
||||
/*
|
||||
* Flags used when sending segments in tcp_output. Basic flags (TH_RST,
|
||||
* TH_ACK,TH_SYN,TH_FIN) are totally determined by state, with the proviso
|
||||
* that TH_FIN is sent only if all data queued for output is included in the
|
||||
* segment.
|
||||
*/
|
||||
static const uint8_t tcp_outflags[TCP_NSTATES] = {
|
||||
TH_RST|TH_ACK, /* 0, CLOSED */
|
||||
0, /* 1, LISTEN */
|
||||
TH_SYN, /* 2, SYN_SENT */
|
||||
TH_SYN|TH_ACK, /* 3, SYN_RECEIVED */
|
||||
TH_ACK, /* 4, ESTABLISHED */
|
||||
TH_ACK, /* 5, CLOSE_WAIT */
|
||||
TH_FIN|TH_ACK, /* 6, FIN_WAIT_1 */
|
||||
TH_FIN|TH_ACK, /* 7, CLOSING */
|
||||
TH_FIN|TH_ACK, /* 8, LAST_ACK */
|
||||
TH_ACK, /* 9, FIN_WAIT_2 */
|
||||
TH_ACK, /* 10, TIME_WAIT */
|
||||
};
|
||||
|
||||
#ifdef KPROF
|
||||
int tcp_acounts[TCP_NSTATES][PRU_NREQ];
|
||||
#endif
|
||||
|
||||
static char const * const tcpstates[] = {
|
||||
"CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD",
|
||||
"ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING",
|
||||
"LAST_ACK", "FIN_WAIT_2", "TIME_WAIT",
|
||||
};
|
||||
|
||||
#endif
|
||||
Vendored
+3093
File diff suppressed because it is too large
Load Diff
+1479
File diff suppressed because it is too large
Load Diff
Vendored
+314
@@ -0,0 +1,314 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tcp_input.c 8.12 (Berkeley) 5/24/95
|
||||
*/
|
||||
|
||||
#include "../tcplp.h"
|
||||
#include "../lib/bitmap.h"
|
||||
#include "../lib/cbuf.h"
|
||||
#include "tcp.h"
|
||||
#include "tcp_fsm.h"
|
||||
#include "tcp_seq.h"
|
||||
#include "tcp_var.h"
|
||||
|
||||
/*
|
||||
* samkumar: Segments are only reassembled within the window; data outside the
|
||||
* window is thrown away. So, the total amount of reassembly data cannot exceed
|
||||
* the size of the receive window.
|
||||
*
|
||||
* I have essentially rewritten it to use TCPlp's data structure for the
|
||||
* reassembly buffer. I have kept the original code as a comment below this
|
||||
* function, for reference.
|
||||
*
|
||||
* Looking at the usage of this function in tcp_input, this just has to set
|
||||
* *tlenp to 0 if the received segment is already completely buffered; it does
|
||||
* not need to update it if only part of the segment is trimmed off.
|
||||
*/
|
||||
int
|
||||
tcp_reass(struct tcpcb* tp, struct tcphdr* th, int* tlenp, otMessage* data, off_t data_offset, struct signals* sig)
|
||||
{
|
||||
size_t mergeable, written;
|
||||
size_t offset;
|
||||
size_t start_index;
|
||||
size_t usedbefore;
|
||||
int tlen = *tlenp;
|
||||
size_t merged = 0;
|
||||
int flags = 0;
|
||||
|
||||
/*
|
||||
* Call with th==NULL after become established to
|
||||
* force pre-ESTABLISHED data up to user socket.
|
||||
*/
|
||||
if (th == NULL)
|
||||
goto present;
|
||||
|
||||
/* Insert the new segment queue entry into place. */
|
||||
KASSERT(SEQ_GEQ(th->th_seq, tp->rcv_nxt), ("Adding past segment to the reassembly queue\n"));
|
||||
offset = (size_t) (th->th_seq - tp->rcv_nxt);
|
||||
|
||||
if (cbuf_reass_count_set(&tp->recvbuf, (size_t) offset, tp->reassbmp, tlen) >= (size_t) tlen) {
|
||||
*tlenp = 0;
|
||||
goto present;
|
||||
}
|
||||
written = cbuf_reass_write(&tp->recvbuf, (size_t) offset, data, data_offset, tlen, tp->reassbmp, &start_index, cbuf_copy_from_message);
|
||||
|
||||
if ((th->th_flags & TH_FIN) && (tp->reass_fin_index == -1)) {
|
||||
tp->reass_fin_index = (int16_t) (start_index + tlen);
|
||||
}
|
||||
KASSERT(written == tlen, ("Reassembly write out of bounds: tried to write %d, but wrote %d\n", tlen, (int) written));
|
||||
|
||||
present:
|
||||
/*
|
||||
* Present data to user, advancing rcv_nxt through
|
||||
* completed sequence space.
|
||||
*/
|
||||
mergeable = cbuf_reass_count_set(&tp->recvbuf, 0, tp->reassbmp, (size_t) 0xFFFFFFFF);
|
||||
usedbefore = cbuf_used_space(&tp->recvbuf);
|
||||
if (!tpiscantrcv(tp) || usedbefore == 0) {
|
||||
/* If usedbefore == 0, but we can't receive more, then we still need to move the buffer
|
||||
along by merging and then popping, in case we receive a FIN later on. */
|
||||
if (tp->reass_fin_index >= 0 && cbuf_reass_within_offset(&tp->recvbuf, mergeable, (size_t) tp->reass_fin_index)) {
|
||||
tp->reass_fin_index = -2; // So we won't consider any more FINs
|
||||
flags = TH_FIN;
|
||||
}
|
||||
merged = cbuf_reass_merge(&tp->recvbuf, mergeable, tp->reassbmp);
|
||||
KASSERT(merged == mergeable, ("Reassembly merge out of bounds: tried to merge %d, but merged %d\n", (int) mergeable, (int) merged));
|
||||
if (tpiscantrcv(tp)) {
|
||||
cbuf_pop(&tp->recvbuf, merged); // So no data really enters the buffer
|
||||
} else if (usedbefore == 0 && merged > 0) {
|
||||
sig->recvbuf_notempty = true;
|
||||
}
|
||||
} else {
|
||||
/* If there is data in the buffer AND we can't receive more, then that must be because we received a FIN,
|
||||
but the user hasn't yet emptied the buffer of its contents. */
|
||||
KASSERT (tp->reass_fin_index == -2, ("Can't receive more, and data in buffer, but haven't received a FIN\n"));
|
||||
}
|
||||
|
||||
tp->rcv_nxt += mergeable;
|
||||
|
||||
return flags;
|
||||
}
|
||||
#if 0
|
||||
int
|
||||
tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
|
||||
{
|
||||
struct tseg_qent *q;
|
||||
struct tseg_qent *p = NULL;
|
||||
struct tseg_qent *nq;
|
||||
struct tseg_qent *te = NULL;
|
||||
struct socket *so = tp->t_inpcb->inp_socket;
|
||||
char *s = NULL;
|
||||
int flags;
|
||||
struct tseg_qent tqs;
|
||||
|
||||
INP_WLOCK_ASSERT(tp->t_inpcb);
|
||||
|
||||
/*
|
||||
* XXX: tcp_reass() is rather inefficient with its data structures
|
||||
* and should be rewritten (see NetBSD for optimizations).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Call with th==NULL after become established to
|
||||
* force pre-ESTABLISHED data up to user socket.
|
||||
*/
|
||||
if (th == NULL)
|
||||
goto present;
|
||||
|
||||
/*
|
||||
* Limit the number of segments that can be queued to reduce the
|
||||
* potential for mbuf exhaustion. For best performance, we want to be
|
||||
* able to queue a full window's worth of segments. The size of the
|
||||
* socket receive buffer determines our advertised window and grows
|
||||
* automatically when socket buffer autotuning is enabled. Use it as the
|
||||
* basis for our queue limit.
|
||||
* Always let the missing segment through which caused this queue.
|
||||
* NB: Access to the socket buffer is left intentionally unlocked as we
|
||||
* can tolerate stale information here.
|
||||
*
|
||||
* XXXLAS: Using sbspace(so->so_rcv) instead of so->so_rcv.sb_hiwat
|
||||
* should work but causes packets to be dropped when they shouldn't.
|
||||
* Investigate why and re-evaluate the below limit after the behaviour
|
||||
* is understood.
|
||||
*/
|
||||
if ((th->th_seq != tp->rcv_nxt || !TCPS_HAVEESTABLISHED(tp->t_state)) &&
|
||||
tp->t_segqlen >= (so->so_rcv.sb_hiwat / tp->t_maxseg) + 1) {
|
||||
TCPSTAT_INC(tcps_rcvreassfull);
|
||||
*tlenp = 0;
|
||||
if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL, NULL))) {
|
||||
log(LOG_DEBUG, "%s; %s: queue limit reached, "
|
||||
"segment dropped\n", s, __func__);
|
||||
free(s, M_TCPLOG);
|
||||
}
|
||||
m_freem(m);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new queue entry. If we can't, or hit the zone limit
|
||||
* just drop the pkt.
|
||||
*
|
||||
* Use a temporary structure on the stack for the missing segment
|
||||
* when the zone is exhausted. Otherwise we may get stuck.
|
||||
*/
|
||||
te = uma_zalloc(tcp_reass_zone, M_NOWAIT);
|
||||
if (te == NULL) {
|
||||
if (th->th_seq != tp->rcv_nxt || !TCPS_HAVEESTABLISHED(tp->t_state)) {
|
||||
TCPSTAT_INC(tcps_rcvmemdrop);
|
||||
m_freem(m);
|
||||
*tlenp = 0;
|
||||
if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL,
|
||||
NULL))) {
|
||||
log(LOG_DEBUG, "%s; %s: global zone limit "
|
||||
"reached, segment dropped\n", s, __func__);
|
||||
free(s, M_TCPLOG);
|
||||
}
|
||||
return (0);
|
||||
} else {
|
||||
bzero(&tqs, sizeof(struct tseg_qent));
|
||||
te = &tqs;
|
||||
if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL,
|
||||
NULL))) {
|
||||
log(LOG_DEBUG,
|
||||
"%s; %s: global zone limit reached, using "
|
||||
"stack for missing segment\n", s, __func__);
|
||||
free(s, M_TCPLOG);
|
||||
}
|
||||
}
|
||||
}
|
||||
tp->t_segqlen++;
|
||||
|
||||
/*
|
||||
* Find a segment which begins after this one does.
|
||||
*/
|
||||
LIST_FOREACH(q, &tp->t_segq, tqe_q) {
|
||||
if (SEQ_GT(q->tqe_th->th_seq, th->th_seq))
|
||||
break;
|
||||
p = q;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is a preceding segment, it may provide some of
|
||||
* our data already. If so, drop the data from the incoming
|
||||
* segment. If it provides all of our data, drop us.
|
||||
*/
|
||||
if (p != NULL) {
|
||||
int i;
|
||||
/* conversion to int (in i) handles seq wraparound */
|
||||
i = p->tqe_th->th_seq + p->tqe_len - th->th_seq;
|
||||
if (i > 0) {
|
||||
if (i >= *tlenp) {
|
||||
TCPSTAT_INC(tcps_rcvduppack);
|
||||
TCPSTAT_ADD(tcps_rcvdupbyte, *tlenp);
|
||||
m_freem(m);
|
||||
if (te != &tqs)
|
||||
uma_zfree(tcp_reass_zone, te);
|
||||
tp->t_segqlen--;
|
||||
/*
|
||||
* Try to present any queued data
|
||||
* at the left window edge to the user.
|
||||
* This is needed after the 3-WHS
|
||||
* completes.
|
||||
*/
|
||||
goto present; /* ??? */
|
||||
}
|
||||
m_adj(m, i);
|
||||
*tlenp -= i;
|
||||
th->th_seq += i;
|
||||
}
|
||||
}
|
||||
tp->t_rcvoopack++;
|
||||
TCPSTAT_INC(tcps_rcvoopack);
|
||||
TCPSTAT_ADD(tcps_rcvoobyte, *tlenp);
|
||||
|
||||
/*
|
||||
* While we overlap succeeding segments trim them or,
|
||||
* if they are completely covered, dequeue them.
|
||||
*/
|
||||
while (q) {
|
||||
int i = (th->th_seq + *tlenp) - q->tqe_th->th_seq;
|
||||
if (i <= 0)
|
||||
break;
|
||||
if (i < q->tqe_len) {
|
||||
q->tqe_th->th_seq += i;
|
||||
q->tqe_len -= i;
|
||||
m_adj(q->tqe_m, i);
|
||||
break;
|
||||
}
|
||||
|
||||
nq = LIST_NEXT(q, tqe_q);
|
||||
LIST_REMOVE(q, tqe_q);
|
||||
m_freem(q->tqe_m);
|
||||
uma_zfree(tcp_reass_zone, q);
|
||||
tp->t_segqlen--;
|
||||
q = nq;
|
||||
}
|
||||
|
||||
/* Insert the new segment queue entry into place. */
|
||||
te->tqe_m = m;
|
||||
te->tqe_th = th;
|
||||
te->tqe_len = *tlenp;
|
||||
|
||||
if (p == NULL) {
|
||||
LIST_INSERT_HEAD(&tp->t_segq, te, tqe_q);
|
||||
} else {
|
||||
KASSERT(te != &tqs, ("%s: temporary stack based entry not "
|
||||
"first element in queue", __func__));
|
||||
LIST_INSERT_AFTER(p, te, tqe_q);
|
||||
}
|
||||
|
||||
present:
|
||||
/*
|
||||
* Present data to user, advancing rcv_nxt through
|
||||
* completed sequence space.
|
||||
*/
|
||||
if (!TCPS_HAVEESTABLISHED(tp->t_state))
|
||||
return (0);
|
||||
q = LIST_FIRST(&tp->t_segq);
|
||||
if (!q || q->tqe_th->th_seq != tp->rcv_nxt)
|
||||
return (0);
|
||||
SOCKBUF_LOCK(&so->so_rcv);
|
||||
do {
|
||||
tp->rcv_nxt += q->tqe_len;
|
||||
flags = q->tqe_th->th_flags & TH_FIN;
|
||||
nq = LIST_NEXT(q, tqe_q);
|
||||
LIST_REMOVE(q, tqe_q);
|
||||
if (so->so_rcv.sb_state & SBS_CANTRCVMORE)
|
||||
m_freem(q->tqe_m);
|
||||
else
|
||||
sbappendstream_locked(&so->so_rcv, q->tqe_m, 0);
|
||||
if (q != &tqs)
|
||||
uma_zfree(tcp_reass_zone, q);
|
||||
tp->t_segqlen--;
|
||||
q = nq;
|
||||
} while (q && q->tqe_th->th_seq == tp->rcv_nxt);
|
||||
sorwakeup_locked(so);
|
||||
return (flags);
|
||||
}
|
||||
#endif
|
||||
Vendored
+665
@@ -0,0 +1,665 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
|
||||
* The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tcp_sack.c 8.12 (Berkeley) 5/24/95
|
||||
*/
|
||||
|
||||
/*-
|
||||
* @@(#)COPYRIGHT 1.1 (NRL) 17 January 1995
|
||||
*
|
||||
* NRL grants permission for redistribution and use in source and binary
|
||||
* forms, with or without modification, of the software and documentation
|
||||
* created at NRL provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgements:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* This product includes software developed at the Information
|
||||
* Technology Division, US Naval Research Laboratory.
|
||||
* 4. Neither the name of the NRL nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
|
||||
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* official policies, either expressed or implied, of the US Naval
|
||||
* Research Laboratory (NRL).
|
||||
*/
|
||||
|
||||
/* samkumar: Removed a bunch of #include's and VNET declarations. */
|
||||
|
||||
#include <strings.h>
|
||||
#include "tcp.h"
|
||||
#include "tcp_fsm.h"
|
||||
#include "tcp_seq.h"
|
||||
#include "tcp_timer.h"
|
||||
#include "tcp_var.h"
|
||||
#include "sys/queue.h"
|
||||
|
||||
enum tcp_sack_consts {
|
||||
V_tcp_sack_maxholes = MAX_SACKHOLES
|
||||
};
|
||||
|
||||
/*
|
||||
* samkumar: Removed tcp_sack_globalmaxholes and tcp_sack_globalholes.
|
||||
* There used to be a counter, V_tcp_sack_globalholes, that kept track of the
|
||||
* total number of SACK holes allocated across all TCP connections.
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar: I added these three functions. The first, tcp_sack_init,
|
||||
* initializes a per-connection pool of SACK holes.
|
||||
*
|
||||
* The next two, sackhole_alloc and sackhole_free, allocate and deallocate SACK
|
||||
* holes from the pool. Previously, the FreeBSD code would allocate SACK holes
|
||||
* dynamically, for example, using the code
|
||||
* "hole = (struct sackhole *)uma_zalloc(V_sack_hole_zone, M_NOWAIT);".
|
||||
* TCPlp avoids dynamic memory allocation in the TCP implementation, so we
|
||||
* replace it with this per-connection pool.
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_sack_init(struct tcpcb* tp)
|
||||
{
|
||||
bmp_init(tp->sackhole_bmp, SACKHOLE_BMP_SIZE);
|
||||
}
|
||||
|
||||
struct sackhole* sackhole_alloc(struct tcpcb* tp) {
|
||||
size_t freeindex = bmp_countset(tp->sackhole_bmp, SACKHOLE_BMP_SIZE, 0, SACKHOLE_BMP_SIZE);
|
||||
if (freeindex >= SACKHOLE_BMP_SIZE) {
|
||||
return NULL; // all sackholes are allocated already!
|
||||
}
|
||||
bmp_setrange(tp->sackhole_bmp, freeindex, 1);
|
||||
return &tp->sackhole_pool[freeindex];
|
||||
}
|
||||
|
||||
void sackhole_free(struct tcpcb* tp, struct sackhole* tofree) {
|
||||
size_t freeindex = (size_t) (tofree - &tp->sackhole_pool[0]);
|
||||
KASSERT(tofree == &tp->sackhole_pool[freeindex], ("sackhole pool unaligned\n"));
|
||||
bmp_clrrange(tp->sackhole_bmp, freeindex, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: Throughout the remaining functions, I have replaced allocation and
|
||||
* deallocation of SACK holes, which previously used uma_zalloc and uma_zfree,
|
||||
* with calls to sackhole_alloc and sackhole_free. I've also removed code for
|
||||
* locking, global stats collection, global SACK hole limits, and debugging
|
||||
* probes.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This function is called upon receipt of new valid data (while not in
|
||||
* header prediction mode), and it updates the ordered list of sacks.
|
||||
*/
|
||||
void
|
||||
tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
|
||||
{
|
||||
/*
|
||||
* First reported block MUST be the most recent one. Subsequent
|
||||
* blocks SHOULD be in the order in which they arrived at the
|
||||
* receiver. These two conditions make the implementation fully
|
||||
* compliant with RFC 2018.
|
||||
*/
|
||||
struct sackblk head_blk, saved_blks[MAX_SACK_BLKS];
|
||||
int num_head, num_saved, i;
|
||||
|
||||
/* Check arguments. */
|
||||
KASSERT(SEQ_LT(rcv_start, rcv_end), ("rcv_start < rcv_end"));
|
||||
|
||||
/* SACK block for the received segment. */
|
||||
head_blk.start = rcv_start;
|
||||
head_blk.end = rcv_end;
|
||||
|
||||
/*
|
||||
* Merge updated SACK blocks into head_blk, and save unchanged SACK
|
||||
* blocks into saved_blks[]. num_saved will have the number of the
|
||||
* saved SACK blocks.
|
||||
*/
|
||||
num_saved = 0;
|
||||
for (i = 0; i < tp->rcv_numsacks; i++) {
|
||||
tcp_seq start = tp->sackblks[i].start;
|
||||
tcp_seq end = tp->sackblks[i].end;
|
||||
if (SEQ_GEQ(start, end) || SEQ_LEQ(start, tp->rcv_nxt)) {
|
||||
/*
|
||||
* Discard this SACK block.
|
||||
*/
|
||||
} else if (SEQ_LEQ(head_blk.start, end) &&
|
||||
SEQ_GEQ(head_blk.end, start)) {
|
||||
/*
|
||||
* Merge this SACK block into head_blk. This SACK
|
||||
* block itself will be discarded.
|
||||
*/
|
||||
if (SEQ_GT(head_blk.start, start))
|
||||
head_blk.start = start;
|
||||
if (SEQ_LT(head_blk.end, end))
|
||||
head_blk.end = end;
|
||||
} else {
|
||||
/*
|
||||
* Save this SACK block.
|
||||
*/
|
||||
saved_blks[num_saved].start = start;
|
||||
saved_blks[num_saved].end = end;
|
||||
num_saved++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update SACK list in tp->sackblks[].
|
||||
*/
|
||||
num_head = 0;
|
||||
if (SEQ_GT(head_blk.start, tp->rcv_nxt)) {
|
||||
/*
|
||||
* The received data segment is an out-of-order segment. Put
|
||||
* head_blk at the top of SACK list.
|
||||
*/
|
||||
tp->sackblks[0] = head_blk;
|
||||
num_head = 1;
|
||||
/*
|
||||
* If the number of saved SACK blocks exceeds its limit,
|
||||
* discard the last SACK block.
|
||||
*/
|
||||
if (num_saved >= MAX_SACK_BLKS)
|
||||
num_saved--;
|
||||
}
|
||||
if (num_saved > 0) {
|
||||
/*
|
||||
* Copy the saved SACK blocks back.
|
||||
*/
|
||||
bcopy(saved_blks, &tp->sackblks[num_head],
|
||||
sizeof(struct sackblk) * num_saved);
|
||||
}
|
||||
|
||||
/* Save the number of SACK blocks. */
|
||||
tp->rcv_numsacks = num_head + num_saved;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete all receiver-side SACK information.
|
||||
*/
|
||||
void
|
||||
tcp_clean_sackreport(struct tcpcb *tp)
|
||||
{
|
||||
int i;
|
||||
|
||||
tp->rcv_numsacks = 0;
|
||||
for (i = 0; i < MAX_SACK_BLKS; i++)
|
||||
tp->sackblks[i].start = tp->sackblks[i].end=0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate struct sackhole.
|
||||
*/
|
||||
static struct sackhole *
|
||||
tcp_sackhole_alloc(struct tcpcb *tp, tcp_seq start, tcp_seq end)
|
||||
{
|
||||
struct sackhole *hole;
|
||||
|
||||
/*
|
||||
* samkumar: This if block also used to also return NULL if
|
||||
* V_tcp_sack_globalholes >= V_tcp_sack_globalmaxholes
|
||||
* but I removed that check since it doesn't make sense to enforce a global
|
||||
* limit on SACK holes when we have a fixed-size pool (moreover, a separate
|
||||
* pool per connection). The per-connection limit is sufficient.
|
||||
*/
|
||||
if (tp->snd_numholes >= V_tcp_sack_maxholes) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hole = sackhole_alloc(tp);
|
||||
if (hole == NULL)
|
||||
return NULL;
|
||||
|
||||
hole->start = start;
|
||||
hole->end = end;
|
||||
hole->rxmit = start;
|
||||
|
||||
tp->snd_numholes++;
|
||||
|
||||
return hole;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free struct sackhole.
|
||||
*/
|
||||
static void
|
||||
tcp_sackhole_free(struct tcpcb *tp, struct sackhole *hole)
|
||||
{
|
||||
sackhole_free(tp, hole);
|
||||
|
||||
tp->snd_numholes--;
|
||||
|
||||
KASSERT(tp->snd_numholes >= 0, ("tp->snd_numholes >= 0"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert new SACK hole into scoreboard.
|
||||
*/
|
||||
static struct sackhole *
|
||||
tcp_sackhole_insert(struct tcpcb *tp, tcp_seq start, tcp_seq end,
|
||||
struct sackhole *after)
|
||||
{
|
||||
struct sackhole *hole;
|
||||
|
||||
/* Allocate a new SACK hole. */
|
||||
hole = tcp_sackhole_alloc(tp, start, end);
|
||||
if (hole == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Insert the new SACK hole into scoreboard. */
|
||||
if (after != NULL)
|
||||
TAILQ_INSERT_AFTER(&tp->snd_holes, after, hole, scblink);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&tp->snd_holes, hole, scblink);
|
||||
|
||||
/* Update SACK hint. */
|
||||
if (tp->sackhint.nexthole == NULL)
|
||||
tp->sackhint.nexthole = hole;
|
||||
|
||||
return hole;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove SACK hole from scoreboard.
|
||||
*/
|
||||
static void
|
||||
tcp_sackhole_remove(struct tcpcb *tp, struct sackhole *hole)
|
||||
{
|
||||
|
||||
/* Update SACK hint. */
|
||||
if (tp->sackhint.nexthole == hole)
|
||||
tp->sackhint.nexthole = TAILQ_NEXT(hole, scblink);
|
||||
|
||||
/* Remove this SACK hole. */
|
||||
TAILQ_REMOVE(&tp->snd_holes, hole, scblink);
|
||||
|
||||
/* Free this SACK hole. */
|
||||
tcp_sackhole_free(tp, hole);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process cumulative ACK and the TCP SACK option to update the scoreboard.
|
||||
* tp->snd_holes is an ordered list of holes (oldest to newest, in terms of
|
||||
* the sequence space).
|
||||
*/
|
||||
void
|
||||
tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
|
||||
{
|
||||
struct sackhole *cur, *temp;
|
||||
struct sackblk sack, sack_blocks[TCP_MAX_SACK + 1], *sblkp;
|
||||
int i, j, num_sack_blks;
|
||||
|
||||
num_sack_blks = 0;
|
||||
/*
|
||||
* If SND.UNA will be advanced by SEG.ACK, and if SACK holes exist,
|
||||
* treat [SND.UNA, SEG.ACK) as if it is a SACK block.
|
||||
*/
|
||||
if (SEQ_LT(tp->snd_una, th_ack) && !TAILQ_EMPTY(&tp->snd_holes)) {
|
||||
sack_blocks[num_sack_blks].start = tp->snd_una;
|
||||
sack_blocks[num_sack_blks++].end = th_ack;
|
||||
}
|
||||
/*
|
||||
* Append received valid SACK blocks to sack_blocks[], but only if we
|
||||
* received new blocks from the other side.
|
||||
*/
|
||||
if (to->to_flags & TOF_SACK) {
|
||||
for (i = 0; i < to->to_nsacks; i++) {
|
||||
bcopy((to->to_sacks + i * TCPOLEN_SACK),
|
||||
&sack, sizeof(sack));
|
||||
sack.start = ntohl(sack.start);
|
||||
sack.end = ntohl(sack.end);
|
||||
if (SEQ_GT(sack.end, sack.start) &&
|
||||
SEQ_GT(sack.start, tp->snd_una) &&
|
||||
SEQ_GT(sack.start, th_ack) &&
|
||||
SEQ_LT(sack.start, tp->snd_max) &&
|
||||
SEQ_GT(sack.end, tp->snd_una) &&
|
||||
SEQ_LEQ(sack.end, tp->snd_max))
|
||||
sack_blocks[num_sack_blks++] = sack;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Return if SND.UNA is not advanced and no valid SACK block is
|
||||
* received.
|
||||
*/
|
||||
if (num_sack_blks == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Sort the SACK blocks so we can update the scoreboard with just one
|
||||
* pass. The overhead of sorting upto 4+1 elements is less than
|
||||
* making upto 4+1 passes over the scoreboard.
|
||||
*/
|
||||
for (i = 0; i < num_sack_blks; i++) {
|
||||
for (j = i + 1; j < num_sack_blks; j++) {
|
||||
if (SEQ_GT(sack_blocks[i].end, sack_blocks[j].end)) {
|
||||
sack = sack_blocks[i];
|
||||
sack_blocks[i] = sack_blocks[j];
|
||||
sack_blocks[j] = sack;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TAILQ_EMPTY(&tp->snd_holes))
|
||||
/*
|
||||
* Empty scoreboard. Need to initialize snd_fack (it may be
|
||||
* uninitialized or have a bogus value). Scoreboard holes
|
||||
* (from the sack blocks received) are created later below
|
||||
* (in the logic that adds holes to the tail of the
|
||||
* scoreboard).
|
||||
*/
|
||||
tp->snd_fack = SEQ_MAX(tp->snd_una, th_ack);
|
||||
/*
|
||||
* In the while-loop below, incoming SACK blocks (sack_blocks[]) and
|
||||
* SACK holes (snd_holes) are traversed from their tails with just
|
||||
* one pass in order to reduce the number of compares especially when
|
||||
* the bandwidth-delay product is large.
|
||||
*
|
||||
* Note: Typically, in the first RTT of SACK recovery, the highest
|
||||
* three or four SACK blocks with the same ack number are received.
|
||||
* In the second RTT, if retransmitted data segments are not lost,
|
||||
* the highest three or four SACK blocks with ack number advancing
|
||||
* are received.
|
||||
*/
|
||||
sblkp = &sack_blocks[num_sack_blks - 1]; /* Last SACK block */
|
||||
tp->sackhint.last_sack_ack = sblkp->end;
|
||||
if (SEQ_LT(tp->snd_fack, sblkp->start)) {
|
||||
/*
|
||||
* The highest SACK block is beyond fack. Append new SACK
|
||||
* hole at the tail. If the second or later highest SACK
|
||||
* blocks are also beyond the current fack, they will be
|
||||
* inserted by way of hole splitting in the while-loop below.
|
||||
*/
|
||||
temp = tcp_sackhole_insert(tp, tp->snd_fack,sblkp->start,NULL);
|
||||
if (temp != NULL) {
|
||||
tp->snd_fack = sblkp->end;
|
||||
/* Go to the previous sack block. */
|
||||
sblkp--;
|
||||
} else {
|
||||
/*
|
||||
* We failed to add a new hole based on the current
|
||||
* sack block. Skip over all the sack blocks that
|
||||
* fall completely to the right of snd_fack and
|
||||
* proceed to trim the scoreboard based on the
|
||||
* remaining sack blocks. This also trims the
|
||||
* scoreboard for th_ack (which is sack_blocks[0]).
|
||||
*/
|
||||
while (sblkp >= sack_blocks &&
|
||||
SEQ_LT(tp->snd_fack, sblkp->start))
|
||||
sblkp--;
|
||||
if (sblkp >= sack_blocks &&
|
||||
SEQ_LT(tp->snd_fack, sblkp->end))
|
||||
tp->snd_fack = sblkp->end;
|
||||
}
|
||||
} else if (SEQ_LT(tp->snd_fack, sblkp->end))
|
||||
/* fack is advanced. */
|
||||
tp->snd_fack = sblkp->end;
|
||||
/* We must have at least one SACK hole in scoreboard. */
|
||||
KASSERT(!TAILQ_EMPTY(&tp->snd_holes),
|
||||
("SACK scoreboard must not be empty"));
|
||||
cur = TAILQ_LAST(&tp->snd_holes, sackhole_head); /* Last SACK hole. */
|
||||
/*
|
||||
* Since the incoming sack blocks are sorted, we can process them
|
||||
* making one sweep of the scoreboard.
|
||||
*/
|
||||
while (sblkp >= sack_blocks && cur != NULL) {
|
||||
if (SEQ_GEQ(sblkp->start, cur->end)) {
|
||||
/*
|
||||
* SACKs data beyond the current hole. Go to the
|
||||
* previous sack block.
|
||||
*/
|
||||
sblkp--;
|
||||
continue;
|
||||
}
|
||||
if (SEQ_LEQ(sblkp->end, cur->start)) {
|
||||
/*
|
||||
* SACKs data before the current hole. Go to the
|
||||
* previous hole.
|
||||
*/
|
||||
cur = TAILQ_PREV(cur, sackhole_head, scblink);
|
||||
continue;
|
||||
}
|
||||
tp->sackhint.sack_bytes_rexmit -= (cur->rxmit - cur->start);
|
||||
KASSERT(tp->sackhint.sack_bytes_rexmit >= 0,
|
||||
("sackhint bytes rtx >= 0"));
|
||||
if (SEQ_LEQ(sblkp->start, cur->start)) {
|
||||
/* Data acks at least the beginning of hole. */
|
||||
if (SEQ_GEQ(sblkp->end, cur->end)) {
|
||||
/* Acks entire hole, so delete hole. */
|
||||
temp = cur;
|
||||
cur = TAILQ_PREV(cur, sackhole_head, scblink);
|
||||
tcp_sackhole_remove(tp, temp);
|
||||
/*
|
||||
* The sack block may ack all or part of the
|
||||
* next hole too, so continue onto the next
|
||||
* hole.
|
||||
*/
|
||||
continue;
|
||||
} else {
|
||||
/* Move start of hole forward. */
|
||||
cur->start = sblkp->end;
|
||||
cur->rxmit = SEQ_MAX(cur->rxmit, cur->start);
|
||||
}
|
||||
} else {
|
||||
/* Data acks at least the end of hole. */
|
||||
if (SEQ_GEQ(sblkp->end, cur->end)) {
|
||||
/* Move end of hole backward. */
|
||||
cur->end = sblkp->start;
|
||||
cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
|
||||
} else {
|
||||
/*
|
||||
* ACKs some data in middle of a hole; need
|
||||
* to split current hole
|
||||
*/
|
||||
temp = tcp_sackhole_insert(tp, sblkp->end,
|
||||
cur->end, cur);
|
||||
if (temp != NULL) {
|
||||
if (SEQ_GT(cur->rxmit, temp->rxmit)) {
|
||||
temp->rxmit = cur->rxmit;
|
||||
tp->sackhint.sack_bytes_rexmit
|
||||
+= (temp->rxmit
|
||||
- temp->start);
|
||||
}
|
||||
cur->end = sblkp->start;
|
||||
cur->rxmit = SEQ_MIN(cur->rxmit,
|
||||
cur->end);
|
||||
}
|
||||
}
|
||||
}
|
||||
tp->sackhint.sack_bytes_rexmit += (cur->rxmit - cur->start);
|
||||
/*
|
||||
* Testing sblkp->start against cur->start tells us whether
|
||||
* we're done with the sack block or the sack hole.
|
||||
* Accordingly, we advance one or the other.
|
||||
*/
|
||||
if (SEQ_LEQ(sblkp->start, cur->start))
|
||||
cur = TAILQ_PREV(cur, sackhole_head, scblink);
|
||||
else
|
||||
sblkp--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all SACK holes to clear the scoreboard.
|
||||
*/
|
||||
void
|
||||
tcp_free_sackholes(struct tcpcb *tp)
|
||||
{
|
||||
struct sackhole *q;
|
||||
|
||||
while ((q = TAILQ_FIRST(&tp->snd_holes)) != NULL)
|
||||
tcp_sackhole_remove(tp, q);
|
||||
tp->sackhint.sack_bytes_rexmit = 0;
|
||||
|
||||
KASSERT(tp->snd_numholes == 0, ("tp->snd_numholes == 0"));
|
||||
KASSERT(tp->sackhint.nexthole == NULL,
|
||||
("tp->sackhint.nexthole == NULL"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Partial ack handling within a sack recovery episode. Keeping this very
|
||||
* simple for now. When a partial ack is received, force snd_cwnd to a value
|
||||
* that will allow the sender to transmit no more than 2 segments. If
|
||||
* necessary, a better scheme can be adopted at a later point, but for now,
|
||||
* the goal is to prevent the sender from bursting a large amount of data in
|
||||
* the midst of sack recovery.
|
||||
*/
|
||||
void
|
||||
tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th)
|
||||
{
|
||||
int num_segs = 1;
|
||||
|
||||
tcp_timer_activate(tp, TT_REXMT, 0);
|
||||
tp->t_rtttime = 0;
|
||||
/* Send one or 2 segments based on how much new data was acked. */
|
||||
if ((BYTES_THIS_ACK(tp, th) / tp->t_maxseg) >= 2)
|
||||
num_segs = 2;
|
||||
tp->snd_cwnd = (tp->sackhint.sack_bytes_rexmit +
|
||||
(tp->snd_nxt - tp->sack_newdata) + num_segs * tp->t_maxseg);
|
||||
if (tp->snd_cwnd > tp->snd_ssthresh)
|
||||
tp->snd_cwnd = tp->snd_ssthresh;
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
(void) tcp_output(tp);
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: Removed this function for now, but I left it in as a comment
|
||||
* (using #if 0) in case it is useful later for debugging.
|
||||
*/
|
||||
#if 0
|
||||
/*
|
||||
* Debug version of tcp_sack_output() that walks the scoreboard. Used for
|
||||
* now to sanity check the hint.
|
||||
*/
|
||||
static struct sackhole *
|
||||
tcp_sack_output_debug(struct tcpcb *tp, int *sack_bytes_rexmt)
|
||||
{
|
||||
struct sackhole *p;
|
||||
|
||||
INP_WLOCK_ASSERT(tp->t_inpcb);
|
||||
*sack_bytes_rexmt = 0;
|
||||
TAILQ_FOREACH(p, &tp->snd_holes, scblink) {
|
||||
if (SEQ_LT(p->rxmit, p->end)) {
|
||||
if (SEQ_LT(p->rxmit, tp->snd_una)) {/* old SACK hole */
|
||||
continue;
|
||||
}
|
||||
*sack_bytes_rexmt += (p->rxmit - p->start);
|
||||
break;
|
||||
}
|
||||
*sack_bytes_rexmt += (p->rxmit - p->start);
|
||||
}
|
||||
return (p);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns the next hole to retransmit and the number of retransmitted bytes
|
||||
* from the scoreboard. We store both the next hole and the number of
|
||||
* retransmitted bytes as hints (and recompute these on the fly upon SACK/ACK
|
||||
* reception). This avoids scoreboard traversals completely.
|
||||
*
|
||||
* The loop here will traverse *at most* one link. Here's the argument. For
|
||||
* the loop to traverse more than 1 link before finding the next hole to
|
||||
* retransmit, we would need to have at least 1 node following the current
|
||||
* hint with (rxmit == end). But, for all holes following the current hint,
|
||||
* (start == rxmit), since we have not yet retransmitted from them.
|
||||
* Therefore, in order to traverse more 1 link in the loop below, we need to
|
||||
* have at least one node following the current hint with (start == rxmit ==
|
||||
* end). But that can't happen, (start == end) means that all the data in
|
||||
* that hole has been sacked, in which case, the hole would have been removed
|
||||
* from the scoreboard.
|
||||
*/
|
||||
struct sackhole *
|
||||
tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt)
|
||||
{
|
||||
struct sackhole *hole = NULL;
|
||||
|
||||
*sack_bytes_rexmt = tp->sackhint.sack_bytes_rexmit;
|
||||
hole = tp->sackhint.nexthole;
|
||||
if (hole == NULL || SEQ_LT(hole->rxmit, hole->end))
|
||||
goto out;
|
||||
while ((hole = TAILQ_NEXT(hole, scblink)) != NULL) {
|
||||
if (SEQ_LT(hole->rxmit, hole->end)) {
|
||||
tp->sackhint.nexthole = hole;
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return (hole);
|
||||
}
|
||||
|
||||
/*
|
||||
* After a timeout, the SACK list may be rebuilt. This SACK information
|
||||
* should be used to avoid retransmitting SACKed data. This function
|
||||
* traverses the SACK list to see if snd_nxt should be moved forward.
|
||||
*/
|
||||
void
|
||||
tcp_sack_adjust(struct tcpcb *tp)
|
||||
{
|
||||
struct sackhole *p, *cur = TAILQ_FIRST(&tp->snd_holes);
|
||||
|
||||
if (cur == NULL)
|
||||
return; /* No holes */
|
||||
if (SEQ_GEQ(tp->snd_nxt, tp->snd_fack))
|
||||
return; /* We're already beyond any SACKed blocks */
|
||||
/*-
|
||||
* Two cases for which we want to advance snd_nxt:
|
||||
* i) snd_nxt lies between end of one hole and beginning of another
|
||||
* ii) snd_nxt lies between end of last hole and snd_fack
|
||||
*/
|
||||
while ((p = TAILQ_NEXT(cur, scblink)) != NULL) {
|
||||
if (SEQ_LT(tp->snd_nxt, cur->end))
|
||||
return;
|
||||
if (SEQ_GEQ(tp->snd_nxt, p->start))
|
||||
cur = p;
|
||||
else {
|
||||
tp->snd_nxt = p->start;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (SEQ_LT(tp->snd_nxt, cur->end))
|
||||
return;
|
||||
tp->snd_nxt = tp->snd_fack;
|
||||
}
|
||||
Vendored
+87
@@ -0,0 +1,87 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tcp_seq.h 8.3 (Berkeley) 6/21/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _NETINET_TCP_SEQ_H_
|
||||
#define _NETINET_TCP_SEQ_H_
|
||||
|
||||
#include "../tcplp.h"
|
||||
|
||||
/*
|
||||
* TCP sequence numbers are 32 bit integers operated
|
||||
* on with modular arithmetic. These macros can be
|
||||
* used to compare such integers.
|
||||
*/
|
||||
#define SEQ_LT(a,b) ((int)((a)-(b)) < 0)
|
||||
#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
|
||||
#define SEQ_GT(a,b) ((int)((a)-(b)) > 0)
|
||||
#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0)
|
||||
|
||||
#define SEQ_MIN(a, b) ((SEQ_LT(a, b)) ? (a) : (b))
|
||||
#define SEQ_MAX(a, b) ((SEQ_GT(a, b)) ? (a) : (b))
|
||||
|
||||
/* for modulo comparisons of timestamps */
|
||||
#define TSTMP_LT(a,b) ((int)((a)-(b)) < 0)
|
||||
#define TSTMP_GT(a,b) ((int)((a)-(b)) > 0)
|
||||
#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0)
|
||||
|
||||
/*
|
||||
* Macros to initialize tcp sequence numbers for
|
||||
* send and receive from initial send and receive
|
||||
* sequence numbers.
|
||||
*/
|
||||
#define tcp_rcvseqinit(tp) \
|
||||
(tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1
|
||||
|
||||
#define tcp_sendseqinit(tp) \
|
||||
(tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \
|
||||
(tp)->snd_recover = (tp)->iss
|
||||
|
||||
/*
|
||||
* Clock macros for RFC 1323 timestamps.
|
||||
*/
|
||||
#define TCP_TS_TO_TICKS(_t) ((_t) * hz / 1000)
|
||||
|
||||
/* Timestamp wrap-around time, 24 days. */
|
||||
#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * 1000)
|
||||
|
||||
/*
|
||||
* tcp_ts_getticks() in ms, should be 1ms < x < 1000ms according to RFC 1323.
|
||||
* We always use 1ms granularity independent of hz.
|
||||
*/
|
||||
static __inline uint32_t
|
||||
tcp_ts_getticks(void)
|
||||
{
|
||||
/* samkumar: This used to be implemented using getmicrouptime(). */
|
||||
return tcplp_sys_get_millis();
|
||||
}
|
||||
|
||||
#endif /* _NETINET_TCP_SEQ_H_ */
|
||||
Vendored
+374
@@ -0,0 +1,374 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tcp_subr.c 8.2 (Berkeley) 5/24/95
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../tcplp.h"
|
||||
#include "ip.h"
|
||||
#include "ip6.h"
|
||||
#include "tcp.h"
|
||||
#include "tcp_fsm.h"
|
||||
#include "tcp_var.h"
|
||||
#include "tcp_seq.h"
|
||||
#include "tcp_timer.h"
|
||||
#include "../lib/bitmap.h"
|
||||
#include "../lib/cbuf.h"
|
||||
#include "cc.h"
|
||||
|
||||
#include "tcp_const.h"
|
||||
|
||||
/* samkumar: Eventually, replace this with OpenThread's random generator. */
|
||||
// A simple linear congruential number generator
|
||||
tcp_seq seed = (tcp_seq) 0xbeaddeed;
|
||||
tcp_seq tcp_new_isn(struct tcpcb* tp) {
|
||||
seed = (((tcp_seq) 0xfaded011) * seed) + (tcp_seq) 0x1ead1eaf;
|
||||
return seed;
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: There used to be a function, void tcp_init(void), that would
|
||||
* initialize global state for TCP, including a hash table to store TCBs,
|
||||
* allocating memory zones for sockets, and setting global configurable state.
|
||||
* None of that is needed for TCPlp: TCB allocation and matching is done by
|
||||
* the host system and global configurable state is removed with hardcoded
|
||||
* values in order to save memory, for example. Thus, I've removed the function
|
||||
* entirely.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A subroutine which makes it easy to track TCP state changes with DTrace.
|
||||
* This function shouldn't be called for t_state initializations that don't
|
||||
* correspond to actual TCP state transitions.
|
||||
*/
|
||||
void
|
||||
tcp_state_change(struct tcpcb *tp, int newstate)
|
||||
{
|
||||
#if 0
|
||||
#if defined(KDTRACE_HOOKS)
|
||||
int pstate = tp->t_state;
|
||||
#endif
|
||||
#endif
|
||||
tcplp_sys_log("Socket %p: %s --> %s\n", tp, tcpstates[tp->t_state], tcpstates[newstate]);
|
||||
tp->t_state = newstate;
|
||||
|
||||
// samkumar: may need to do other actions too, so call into the host
|
||||
tcplp_sys_on_state_change(tp, newstate);
|
||||
#if 0
|
||||
TCP_PROBE6(state__change, NULL, tp, NULL, tp, NULL, pstate);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* samkumar: Based on tcp_newtcb in tcp_subr.c, and tcp_usr_attach in tcp_usrreq.c. */
|
||||
__attribute__((used)) void initialize_tcb(struct tcpcb* tp) {
|
||||
uint32_t ticks = tcplp_sys_get_ticks();
|
||||
|
||||
/* samkumar: Clear all fields starting laddr; rest are initialized by the host. */
|
||||
memset(((uint8_t*) tp) + offsetof(struct tcpcb, laddr), 0x00, sizeof(struct tcpcb) - offsetof(struct tcpcb, laddr));
|
||||
tp->reass_fin_index = -1;
|
||||
|
||||
/*
|
||||
* samkumar: Only New Reno congestion control is implemented at the moment,
|
||||
* so there's no need to record the congestion control algorithm used for
|
||||
* each TCB.
|
||||
*/
|
||||
// CC_ALGO(tp) = CC_DEFAULT();
|
||||
// tp->ccv->type = IPPROTO_TCP;
|
||||
tp->ccv->ccvc.tcp = tp;
|
||||
|
||||
/*
|
||||
* samkumar: The original code used to choose a different constant
|
||||
* depending on whether it's an IPv4 or IPv6 connection. In TCPlp, we
|
||||
* unconditionally choose the IPv6 branch.
|
||||
*/
|
||||
tp->t_maxseg = tp->t_maxopd =
|
||||
//#ifdef INET6
|
||||
/*isipv6 ? */V_tcp_v6mssdflt /*:*/
|
||||
//#endif /* INET6 */
|
||||
/*V_tcp_mssdflt*/;
|
||||
|
||||
if (V_tcp_do_rfc1323)
|
||||
tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP);
|
||||
if (V_tcp_do_sack)
|
||||
tp->t_flags |= TF_SACK_PERMIT;
|
||||
TAILQ_INIT(&tp->snd_holes);
|
||||
|
||||
/*
|
||||
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
|
||||
* rtt estimate. Set rttvar so that srtt + 4 * rttvar gives
|
||||
* reasonable initial retransmit time.
|
||||
*/
|
||||
tp->t_srtt = TCPTV_SRTTBASE;
|
||||
tp->t_rttvar = ((TCPTV_RTOBASE - TCPTV_SRTTBASE) << TCP_RTTVAR_SHIFT) / 4;
|
||||
tp->t_rttmin = TCPTV_MIN < 1 ? 1 : TCPTV_MIN; /* samkumar: used to be tcp_rexmit_min, which was set in tcp_init */
|
||||
tp->t_rxtcur = TCPTV_RTOBASE;
|
||||
tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
|
||||
tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
|
||||
tp->t_rcvtime = ticks;
|
||||
|
||||
/* samkumar: Taken from tcp_usr_attach in tcp_usrreq.c. */
|
||||
tp->t_state = TCP6S_CLOSED;
|
||||
|
||||
/* samkumar: Added to initialize the per-TCP sackhole pool. */
|
||||
tcp_sack_init(tp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* samkumar: Most of this function was no longer needed. It did things like
|
||||
* reference-counting for the TCB, updating host cache stats for better
|
||||
* starting values of, e.g., ssthresh, for new connections, freeing resources
|
||||
* for TCP offloading, etc. There's no host cache in TCPlp and the host system
|
||||
* is responsible for managing TCB memory, so much of this isn't needed. I just
|
||||
* kept (and adpated) the few parts of the function that appeared to be needed
|
||||
* for TCPlp.
|
||||
*/
|
||||
void
|
||||
tcp_discardcb(struct tcpcb *tp)
|
||||
{
|
||||
tcp_cancel_timers(tp);
|
||||
|
||||
/* Allow the CC algorithm to clean up after itself. */
|
||||
if (CC_ALGO(tp)->cb_destroy != NULL)
|
||||
CC_ALGO(tp)->cb_destroy(tp->ccv);
|
||||
|
||||
tcp_free_sackholes(tp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Attempt to close a TCP control block, marking it as dropped, and freeing
|
||||
* the socket if we hold the only reference.
|
||||
*/
|
||||
/*
|
||||
* samkumar: Most of this function has to do with dropping the reference to
|
||||
* the inpcb, freeing resources at the socket layer and marking it as
|
||||
* disconnected, and miscellaneous cleanup. I've rewritten this to do what is
|
||||
* needed for TCP.
|
||||
*/
|
||||
struct tcpcb *
|
||||
tcp_close(struct tcpcb *tp)
|
||||
{
|
||||
tcp_state_change(tp, TCP6S_CLOSED); // for the print statement
|
||||
tcp_discardcb(tp);
|
||||
// Don't reset the TCB by calling initialize_tcb, since that overwrites the buffer contents.
|
||||
return tp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create template to be used to send tcp packets on a connection.
|
||||
* Allocates an mbuf and fills in a skeletal tcp/ip header. The only
|
||||
* use for this function is in keepalives, which use tcp_respond.
|
||||
*/
|
||||
/* samkumar: I changed the signature of this function. Instead of allocating
|
||||
* the struct tcptemp using malloc, populating it, and then returning it, I
|
||||
* have the caller allocate it. This function merely populates it now.
|
||||
*/
|
||||
void
|
||||
tcpip_maketemplate(struct tcpcb* tp, struct tcptemp* t)
|
||||
{
|
||||
tcpip_fillheaders(tp, (void *)&t->tt_ipgen, (void *)&t->tt_t);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the IP and TCP headers for an outgoing packet, given the tcpcb.
|
||||
* tcp_template used to store this data in mbufs, but we now recopy it out
|
||||
* of the tcpcb each time to conserve mbufs.
|
||||
*/
|
||||
/*
|
||||
* samkumar: This has a different signature from the original function in
|
||||
* tcp_subr.c. In particular, IP header information is filled into an
|
||||
* otMessageInfo rather than into a struct representing the on-wire header
|
||||
* format. Additionally, I have changed it to always assume IPv6; I removed the
|
||||
* code for IPv4.
|
||||
*/
|
||||
void
|
||||
tcpip_fillheaders(struct tcpcb* tp, otMessageInfo* ip_ptr, void *tcp_ptr)
|
||||
{
|
||||
struct tcphdr *th = (struct tcphdr *)tcp_ptr;
|
||||
|
||||
/* Fill in the IP header */
|
||||
|
||||
/* samkumar: The old IPv6 code, for reference. */
|
||||
// ip6 = (struct ip6_hdr *)ip_ptr;
|
||||
// ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
|
||||
// (inp->inp_flow & IPV6_FLOWINFO_MASK);
|
||||
// ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
|
||||
// (IPV6_VERSION & IPV6_VERSION_MASK);
|
||||
// ip6->ip6_nxt = IPPROTO_TCP;
|
||||
// ip6->ip6_plen = htons(sizeof(struct tcphdr));
|
||||
// ip6->ip6_src = inp->in6p_laddr;
|
||||
// ip6->ip6_dst = inp->in6p_faddr;
|
||||
|
||||
memset(ip_ptr, 0x00, sizeof(otMessageInfo));
|
||||
memcpy(&ip_ptr->mSockAddr, &tp->laddr, sizeof(ip_ptr->mSockAddr));
|
||||
memcpy(&ip_ptr->mPeerAddr, &tp->faddr, sizeof(ip_ptr->mPeerAddr));
|
||||
|
||||
/* Fill in the TCP header */
|
||||
/* samkumar: I kept the old code for ports commented out, for reference. */
|
||||
//th->th_sport = inp->inp_lport;
|
||||
//th->th_dport = inp->inp_fport;
|
||||
th->th_sport = tp->lport;
|
||||
th->th_dport = tp->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_urp = 0;
|
||||
th->th_sum = 0; /* in_pseudo() is called later for ipv4 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a single message to the TCP at address specified by
|
||||
* the given TCP/IP header. If m == NULL, then we make a copy
|
||||
* of the tcpiphdr at th and send directly to the addressed host.
|
||||
* This is used to force keep alive messages out using the TCP
|
||||
* template for a connection. If flags are given then we send
|
||||
* a message back to the TCP which originated the segment th,
|
||||
* and discard the mbuf containing it and any other attached mbufs.
|
||||
*
|
||||
* In any case the ack and sequence number of the transmitted
|
||||
* segment are as specified by the parameters.
|
||||
*
|
||||
* NOTE: If m != NULL, then th must point to *inside* the mbuf.
|
||||
*/
|
||||
/* samkumar: Original signature was
|
||||
void
|
||||
tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
|
||||
tcp_seq ack, tcp_seq seq, int flags)
|
||||
*/
|
||||
/*
|
||||
* samkumar: Essentially all of the code had to be discarded/rewritten since I
|
||||
* have to send out packets by allocating buffers from the host system,
|
||||
* populating them, and passing them back to the host system to send out. I
|
||||
* simplified the code by only using the logic that was fully necessary,
|
||||
* eliminating the code for IPv4 packets and keeping only the code for IPv6
|
||||
* packets. I also removed all of the mbuf logic, instead using the logic for
|
||||
* using the host system's buffering (in particular, the code to reuse the
|
||||
* provided mbuf is no longer there).
|
||||
*/
|
||||
void
|
||||
tcp_respond(struct tcpcb *tp, otInstance* instance, struct ip6_hdr* ip6gen, struct tcphdr *thgen,
|
||||
tcp_seq ack, tcp_seq seq, int flags)
|
||||
{
|
||||
otMessage* message = tcplp_sys_new_message(instance);
|
||||
if (message == NULL) {
|
||||
return;
|
||||
}
|
||||
if (otMessageSetLength(message, sizeof(struct tcphdr)) != OT_ERROR_NONE) {
|
||||
tcplp_sys_free_message(instance, message);
|
||||
return;
|
||||
}
|
||||
|
||||
struct tcphdr th;
|
||||
struct tcphdr* nth = &th;
|
||||
otMessageInfo ip6info;
|
||||
int win = 0;
|
||||
if (tp != NULL) {
|
||||
if (!(flags & TH_RST)) {
|
||||
win = cbuf_free_space(&tp->recvbuf);
|
||||
if (win > (long)TCP_MAXWIN << tp->rcv_scale)
|
||||
win = (long)TCP_MAXWIN << tp->rcv_scale;
|
||||
}
|
||||
}
|
||||
memset(&ip6info, 0x00, sizeof(otMessageInfo));
|
||||
memcpy(&ip6info.mSockAddr, &ip6gen->ip6_dst, sizeof(ip6info.mSockAddr));
|
||||
memcpy(&ip6info.mPeerAddr, &ip6gen->ip6_src, sizeof(ip6info.mPeerAddr));
|
||||
nth->th_sport = thgen->th_dport;
|
||||
nth->th_dport = thgen->th_sport;
|
||||
nth->th_seq = htonl(seq);
|
||||
nth->th_ack = htonl(ack);
|
||||
nth->th_x2 = 0;
|
||||
nth->th_off = sizeof(struct tcphdr) >> 2;
|
||||
nth->th_flags = flags;
|
||||
if (tp != NULL)
|
||||
nth->th_win = htons((uint16_t) (win >> tp->rcv_scale));
|
||||
else
|
||||
nth->th_win = htons((uint16_t)win);
|
||||
nth->th_urp = 0;
|
||||
nth->th_sum = 0;
|
||||
|
||||
otMessageWrite(message, 0, &th, sizeof(struct tcphdr));
|
||||
|
||||
tcplp_sys_send_message(instance, message, &ip6info);
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop a TCP connection, reporting
|
||||
* the specified error. If connection is synchronized,
|
||||
* then send a RST to peer.
|
||||
*/
|
||||
/*
|
||||
* samkumar: I changed the parameter "errno" to "errnum" since it caused
|
||||
* problems during compilation. I also the code for asserting locks,
|
||||
* incermenting stats, and managing the sockets layer.
|
||||
*/
|
||||
struct tcpcb *
|
||||
tcp_drop(struct tcpcb *tp, int errnum)
|
||||
{
|
||||
if (TCPS_HAVERCVDSYN(tp->t_state)) {
|
||||
tcp_state_change(tp, TCPS_CLOSED);
|
||||
(void) tcp_output(tp);
|
||||
}
|
||||
if (errnum == ETIMEDOUT && tp->t_softerror)
|
||||
errnum = tp->t_softerror;
|
||||
tp = tcp_close(tp);
|
||||
tcplp_sys_connection_lost(tp, errnum);
|
||||
return tp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look-up the routing entry to the peer of this inpcb. If no route
|
||||
* is found and it cannot be allocated, then return 0. This routine
|
||||
* is called by TCP routines that access the rmx structure and by
|
||||
* tcp_mss_update to get the peer/interface MTU.
|
||||
*/
|
||||
/*
|
||||
* samkumar: In TCPlp, we don't bother with keeping track of the MTU for each
|
||||
* route. The MSS we choose for the 6LoWPAN/802.15.4 network is probably the
|
||||
* bottleneck, so we just use that. (I also removed the struct in_conninfo *
|
||||
* that was formerly the first argument).
|
||||
*/
|
||||
uint64_t
|
||||
tcp_maxmtu6(struct tcpcb* tp, struct tcp_ifcap *cap)
|
||||
{
|
||||
uint64_t maxmtu = 0;
|
||||
|
||||
KASSERT (tp != NULL, ("tcp_maxmtu6 with NULL tcpcb pointer"));
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&tp->faddr)) {
|
||||
maxmtu = FRAMES_PER_SEG * FRAMECAP_6LOWPAN;
|
||||
}
|
||||
|
||||
return (maxmtu);
|
||||
}
|
||||
Vendored
+489
@@ -0,0 +1,489 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../tcplp.h"
|
||||
#include "../lib/lbuf.h"
|
||||
#include "tcp_fsm.h"
|
||||
#include "tcp_timer.h"
|
||||
#include "tcp_var.h"
|
||||
|
||||
#include "tcp_const.h"
|
||||
|
||||
/*
|
||||
* samkumar: These options only matter if we do blackhole detection, which we
|
||||
* are not doing in TCPlp.
|
||||
*/
|
||||
#if 0
|
||||
int V_tcp_pmtud_blackhole_detect = 0;
|
||||
int V_tcp_pmtud_blackhole_failed = 0;
|
||||
int V_tcp_pmtud_blackhole_activated = 0;
|
||||
int V_tcp_pmtud_blackhole_activated_min_mss = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TCP timer processing.
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar: I changed these functions to accept "struct tcpcb* tp" their
|
||||
* argument instead of "void *xtp". This is possible since we're no longer
|
||||
* relying on FreeBSD's callout subsystem in TCPlp.
|
||||
*/
|
||||
|
||||
void
|
||||
tcp_timer_delack(struct tcpcb* tp)
|
||||
{
|
||||
/* samkumar: I added this, to replace the code I removed below. */
|
||||
KASSERT(tpistimeractive(tp, TT_DELACK), ("Delack timer running, but unmarked\n"));
|
||||
tpcleartimeractive(tp, TT_DELACK);
|
||||
|
||||
/*
|
||||
* samkumar: There used to be code here to properly handle the callout,
|
||||
* including edge cases (return early if the callout was reset after this
|
||||
* function was scheduled for execution, deactivate the callout, return
|
||||
* early if the INP_DROPPED flag is set on the inpcb, and assert that the
|
||||
* tp->t_timers state is correct).
|
||||
*
|
||||
* I also removed stats collection, locking, and vnet, throughout the code.
|
||||
*/
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
(void) tcp_output(tp);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_timer_keep(struct tcpcb* tp)
|
||||
{
|
||||
uint32_t ticks = tcplp_sys_get_ticks();
|
||||
struct tcptemp t_template;
|
||||
|
||||
/* samkumar: I added this, to replace the code I removed below. */
|
||||
KASSERT(tpistimeractive(tp, TT_KEEP), ("Keep timer running, but unmarked\n"));
|
||||
tpcleartimeractive(tp, TT_KEEP);
|
||||
|
||||
/*
|
||||
* samkumar: There used to be code here to properly handle the callout,
|
||||
* including edge cases (return early if the callout was reset after this
|
||||
* function was scheduled for execution, deactivate the callout, return
|
||||
* early if the INP_DROPPED flag is set on the inpcb, and assert that the
|
||||
* tp->t_timers state is correct).
|
||||
*
|
||||
* I also removed stats collection, locking, and vnet, throughout the code.
|
||||
* I commented out checks on socket options (since we don't support those).
|
||||
*
|
||||
* I also allocate t_template on the stack instead of allocating it
|
||||
* dynamically, on the heap.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Keep-alive timer went off; send something
|
||||
* or drop connection if idle for too long.
|
||||
*/
|
||||
if (tp->t_state < TCPS_ESTABLISHED)
|
||||
goto dropit;
|
||||
if ((always_keepalive/* || inp->inp_socket->so_options & SO_KEEPALIVE*/) &&
|
||||
tp->t_state <= TCPS_CLOSING) {
|
||||
if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp))
|
||||
goto dropit;
|
||||
/*
|
||||
* Send a packet designed to force a response
|
||||
* if the peer is up and reachable:
|
||||
* either an ACK if the connection is still alive,
|
||||
* or an RST if the peer has closed the connection
|
||||
* due to timeout or reboot.
|
||||
* Using sequence number tp->snd_una-1
|
||||
* causes the transmitted zero-length segment
|
||||
* to lie outside the receive window;
|
||||
* by the protocol spec, this requires the
|
||||
* correspondent TCP to respond.
|
||||
*/
|
||||
tcpip_maketemplate(tp, &t_template);
|
||||
/*
|
||||
* samkumar: I removed checks to make sure t_template was successfully
|
||||
* allocated and then free it as appropriate. This is not necessary
|
||||
* because I rewrote this part of the code to allocate t_template on
|
||||
* the stack.
|
||||
*/
|
||||
tcp_respond(tp, tp->instance, (struct ip6_hdr*) t_template.tt_ipgen,
|
||||
&t_template.tt_t,
|
||||
tp->rcv_nxt, tp->snd_una - 1, 0);
|
||||
/*
|
||||
* samkumar: I replaced a call to callout_reset with the following
|
||||
* code, which resets the timer the TCPlp way.
|
||||
*/
|
||||
tpmarktimeractive(tp, TT_KEEP);
|
||||
tcplp_sys_set_timer(tp, TT_KEEP, TP_KEEPINTVL(tp));
|
||||
} else {
|
||||
/*
|
||||
* samkumar: I replaced a call to callout_reset with the following
|
||||
* code, which resets the timer the TCPlp way.
|
||||
*/
|
||||
tpmarktimeractive(tp, TT_KEEP);
|
||||
tcplp_sys_set_timer(tp, TT_KEEP, TP_KEEPIDLE(tp));
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: There used to be some code here and below the "dropit" label
|
||||
* that handled debug tracing/probes, vnet, and locking. I removed that
|
||||
* code.
|
||||
*/
|
||||
return;
|
||||
|
||||
dropit:
|
||||
tp = tcp_drop(tp, ETIMEDOUT);
|
||||
(void) tp; /* samkumar: prevent a compiler warning */
|
||||
}
|
||||
|
||||
void
|
||||
tcp_timer_persist(struct tcpcb* tp)
|
||||
{
|
||||
uint32_t ticks = tcplp_sys_get_ticks();
|
||||
|
||||
/* samkumar: I added this, to replace the code I removed below. */
|
||||
KASSERT(tpistimeractive(tp, TT_PERSIST), ("Persist timer running, but unmarked\n"));
|
||||
tpcleartimeractive(tp, TT_PERSIST); // mark that this timer is no longer active
|
||||
|
||||
/*
|
||||
* samkumar: There used to be code here to properly handle the callout,
|
||||
* including edge cases (return early if the callout was reset after this
|
||||
* function was scheduled for execution, deactivate the callout, return
|
||||
* early if the INP_DROPPED flag is set on the inpcb, and assert that the
|
||||
* tp->t_timers state is correct).
|
||||
*
|
||||
* I also removed stats collection, locking, and vnet, throughout the code.
|
||||
* I commented out checks on socket options (since we don't support those).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Persistance timer into zero window.
|
||||
* Force a byte to be output, if possible.
|
||||
*/
|
||||
/*
|
||||
|
||||
* Hack: if the peer is dead/unreachable, we do not
|
||||
* time out if the window is closed. After a full
|
||||
* backoff, drop the connection if the idle time
|
||||
* (no responses to probes) reaches the maximum
|
||||
* backoff that we would use if retransmitting.
|
||||
*/
|
||||
|
||||
if (tp->t_rxtshift == TCP_MAXRXTSHIFT &&
|
||||
(ticks - tp->t_rcvtime >= tcp_maxpersistidle ||
|
||||
ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) {
|
||||
tp = tcp_drop(tp, ETIMEDOUT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the user has closed the socket then drop a persisting
|
||||
* connection after a much reduced timeout.
|
||||
*/
|
||||
if (tp->t_state > TCPS_CLOSE_WAIT &&
|
||||
(ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) {
|
||||
tp = tcp_drop(tp, ETIMEDOUT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
tcp_setpersist(tp);
|
||||
tp->t_flags |= TF_FORCEDATA;
|
||||
tcplp_sys_log("Persist output: %zu bytes in sendbuf\n", lbuf_used_space(&tp->sendbuf));
|
||||
(void) tcp_output(tp);
|
||||
tp->t_flags &= ~TF_FORCEDATA;
|
||||
|
||||
out:
|
||||
/*
|
||||
* samkumar: There used to be some code here that handled debug
|
||||
* tracing/probes, vnet, and locking. I removed that code.
|
||||
*/
|
||||
(void) tp; /* samkumar: prevent a compiler warning */
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
tcp_timer_2msl(struct tcpcb* tp)
|
||||
{
|
||||
uint32_t ticks = tcplp_sys_get_ticks();
|
||||
|
||||
/* samkumar: I added this, to replace the code I removed below. */
|
||||
KASSERT(tpistimeractive(tp, TT_2MSL), ("2MSL timer running, but unmarked\n"));
|
||||
tpcleartimeractive(tp, TT_2MSL);
|
||||
|
||||
/*
|
||||
* samkumar: There used to be code here to properly handle the callout,
|
||||
* including edge cases (return early if the callout was reset after this
|
||||
* function was scheduled for execution, deactivate the callout, return
|
||||
* early if the INP_DROPPED flag is set on the inpcb, and assert that the
|
||||
* tp->t_timers state is correct).
|
||||
*
|
||||
* I also removed stats collection, locking, and vnet, throughout the code.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2 MSL timeout in shutdown went off. If we're closed but
|
||||
* still waiting for peer to close and connection has been idle
|
||||
* too long delete connection control block. Otherwise, check
|
||||
* again in a bit.
|
||||
*
|
||||
* If in TIME_WAIT state just ignore as this timeout is handled in
|
||||
* tcp_tw_2msl_scan().
|
||||
*
|
||||
* If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed,
|
||||
* there's no point in hanging onto FIN_WAIT_2 socket. Just close it.
|
||||
* Ignore fact that there were recent incoming segments.
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar: The above comment about ignoring this timeout if we're in the
|
||||
* TIME_WAIT state no longer is true, since in TCPlp we changed how
|
||||
* TIME_WAIT is handled. In FreeBSD, this timer isn't used for sockets in
|
||||
* the TIME_WAIT state; instead the tcp_tw_2msl_scan method is called
|
||||
* periodically on the slow timer, and expired tcptw structs are closed and
|
||||
* freed. I changed it so that TIME-WAIT connections are still represented
|
||||
* as tcpcb's, not tcptw's, and to rely on this timer to close the
|
||||
* connection.
|
||||
*
|
||||
* Below, there used to be an if statement that checks the inpcb to tell
|
||||
* if we're in TIME-WAIT state, and return early if so. I've replaced this
|
||||
* with an if statement that checks the tcpcb if we're in the TIME-WAIT
|
||||
* state, and acts appropriately if so.
|
||||
*/
|
||||
if (tp->t_state == TCP6S_TIME_WAIT) {
|
||||
tp = tcp_close(tp);
|
||||
tcplp_sys_connection_lost(tp, CONN_LOST_NORMAL);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* samkumar: This if statement also used to check that an inpcb is still
|
||||
* attached and also
|
||||
* (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE).
|
||||
* We replaced the check on that flag with a call to tpiscantrcv. We
|
||||
* haven't received a FIN, since we're in FIN-WAIT-2, so the only way it
|
||||
* would pass the check is if the user called shutdown(SHUT_RD)
|
||||
* or shutdown(SHUT_RDWR), which is impossible unless the host system
|
||||
* provides an API for that.
|
||||
*/
|
||||
if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 &&
|
||||
tpiscantrcv(tp)) {
|
||||
tp = tcp_close(tp);
|
||||
tcplp_sys_connection_lost(tp, CONN_LOST_NORMAL);
|
||||
} else {
|
||||
if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) {
|
||||
/*
|
||||
* samkumar: I replaced a call to callout_reset with the following
|
||||
* code, which resets the timer the TCPlp way.
|
||||
*/
|
||||
tpmarktimeractive(tp, TT_2MSL);
|
||||
tcplp_sys_set_timer(tp, TT_2MSL, TP_KEEPINTVL(tp));
|
||||
} else {
|
||||
tp = tcp_close(tp);
|
||||
tcplp_sys_connection_lost(tp, CONN_LOST_NORMAL);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* samkumar: There used to be some code here that handled debug
|
||||
* tracing/probes, vnet, and locking. I removed that code.
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
tcp_timer_rexmt(struct tcpcb *tp)
|
||||
{
|
||||
int rexmt;
|
||||
uint32_t ticks = tcplp_sys_get_ticks();
|
||||
|
||||
/* samkumar: I added this, to replace the code I removed below. */
|
||||
KASSERT(tpistimeractive(tp, TT_REXMT), ("Rexmt timer running, but unmarked\n"));
|
||||
tpcleartimeractive(tp, TT_REXMT);
|
||||
|
||||
/*
|
||||
* samkumar: There used to be code here to properly handle the callout,
|
||||
* including edge cases (return early if the callout was reset after this
|
||||
* function was scheduled for execution, deactivate the callout, return
|
||||
* early if the INP_DROPPED flag is set on the inpcb, and assert that the
|
||||
* tp->t_timers state is correct).
|
||||
*
|
||||
* I also removed stats collection, locking, and vnet, throughout the code.
|
||||
*/
|
||||
|
||||
tcp_free_sackholes(tp);
|
||||
/*
|
||||
* Retransmission timer went off. Message has not
|
||||
* been acked within retransmit interval. Back off
|
||||
* to a longer retransmit interval and retransmit one segment.
|
||||
*/
|
||||
tcplp_sys_log("rxtshift is %d\n", (int) tp->t_rxtshift);
|
||||
if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
|
||||
tp->t_rxtshift = TCP_MAXRXTSHIFT;
|
||||
|
||||
tp = tcp_drop(tp, tp->t_softerror ?
|
||||
tp->t_softerror : ETIMEDOUT);
|
||||
goto out;
|
||||
}
|
||||
if (tp->t_state == TCPS_SYN_SENT) {
|
||||
/*
|
||||
* If the SYN was retransmitted, indicate CWND to be
|
||||
* limited to 1 segment in cc_conn_init().
|
||||
*/
|
||||
tp->snd_cwnd = 1;
|
||||
} else if (tp->t_rxtshift == 1) {
|
||||
/*
|
||||
* first retransmit; record ssthresh and cwnd so they can
|
||||
* be recovered if this turns out to be a "bad" retransmit.
|
||||
* A retransmit is considered "bad" if an ACK for this
|
||||
* segment is received within RTT/2 interval; the assumption
|
||||
* here is that the ACK was already in flight. See
|
||||
* "On Estimating End-to-End Network Path Properties" by
|
||||
* Allman and Paxson for more details.
|
||||
*/
|
||||
tp->snd_cwnd_prev = tp->snd_cwnd;
|
||||
tp->snd_ssthresh_prev = tp->snd_ssthresh;
|
||||
tp->snd_recover_prev = tp->snd_recover;
|
||||
if (IN_FASTRECOVERY(tp->t_flags))
|
||||
tp->t_flags |= TF_WASFRECOVERY;
|
||||
else
|
||||
tp->t_flags &= ~TF_WASFRECOVERY;
|
||||
if (IN_CONGRECOVERY(tp->t_flags))
|
||||
tp->t_flags |= TF_WASCRECOVERY;
|
||||
else
|
||||
tp->t_flags &= ~TF_WASCRECOVERY;
|
||||
tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1));
|
||||
tp->t_flags |= TF_PREVVALID;
|
||||
} else
|
||||
tp->t_flags &= ~TF_PREVVALID;
|
||||
if (tp->t_state == TCPS_SYN_SENT)
|
||||
rexmt = TCPTV_RTOBASE * tcp_syn_backoff[tp->t_rxtshift];
|
||||
else
|
||||
rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
|
||||
TCPT_RANGESET(tp->t_rxtcur, rexmt,
|
||||
tp->t_rttmin, TCPTV_REXMTMAX);
|
||||
|
||||
/*
|
||||
* samkumar: There used to be more than 100 lines of code here, which
|
||||
* implemented a feature called blackhole detection. The idea here is that
|
||||
* some routers may silently discard packets whose MTU is too large,
|
||||
* instead of fragmenting the packet or sending an ICMP packet to give
|
||||
* feedback to the host. Blackhole detection decreases the MTU in response
|
||||
* to packet loss in case the packets are being dropped by such a router.
|
||||
*
|
||||
* In TCPlp, we do not do blackhole detection because we use a small MTU
|
||||
* (hundreds of bytes) that is unlikely to be too large for intermediate
|
||||
* routers in the Internet. The edge low-power wireless network is
|
||||
* assumed to be engineered to handle 6LoWPAN correctly.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Disable RFC1323 and SACK if we haven't got any response to
|
||||
* our third SYN to work-around some broken terminal servers
|
||||
* (most of which have hopefully been retired) that have bad VJ
|
||||
* header compression code which trashes TCP segments containing
|
||||
* unknown-to-them TCP options.
|
||||
*/
|
||||
if (tcp_rexmit_drop_options && (tp->t_state == TCPS_SYN_SENT) &&
|
||||
(tp->t_rxtshift == 3))
|
||||
tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_SACK_PERMIT);
|
||||
/*
|
||||
* If we backed off this far, our srtt estimate is probably bogus.
|
||||
* Clobber it so we'll take the next rtt measurement as our srtt;
|
||||
* move the current srtt into rttvar to keep the current
|
||||
* retransmit times until then.
|
||||
*/
|
||||
if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
|
||||
/*
|
||||
* samkumar: Here, there used to be a call to "in6_losing", used to
|
||||
* inform the lower layers about bad connectivity so it can search for
|
||||
* different routes. The call was wrapped in a check on the inpcb's
|
||||
* flags to check for IPv6 (which isn't relevant to us, since TCPlp
|
||||
* assumes IPv6).
|
||||
*/
|
||||
tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
|
||||
tp->t_srtt = 0;
|
||||
}
|
||||
tp->snd_nxt = tp->snd_una;
|
||||
tp->snd_recover = tp->snd_max;
|
||||
/*
|
||||
* Force a segment to be sent.
|
||||
*/
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
/*
|
||||
* If timing a segment in this window, stop the timer.
|
||||
*/
|
||||
tp->t_rtttime = 0;
|
||||
|
||||
cc_cong_signal(tp, NULL, CC_RTO);
|
||||
|
||||
(void) tcp_output(tp);
|
||||
|
||||
out:
|
||||
/*
|
||||
* samkumar: There used to be some code here that handled debug
|
||||
* tracing/probes, vnet, and locking. I removed that code.
|
||||
*/
|
||||
(void) tp; /* samkumar: Prevent a compiler warning */
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
tcp_timer_active(struct tcpcb *tp, uint32_t timer_type)
|
||||
{
|
||||
return tpistimeractive(tp, timer_type);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, uint32_t delta) {
|
||||
if (delta) {
|
||||
tpmarktimeractive(tp, timer_type);
|
||||
if (tpistimeractive(tp, TT_REXMT) && tpistimeractive(tp, TT_PERSIST)) {
|
||||
char* msg = "TCP CRITICAL FAILURE: Retransmit and Persist timers are simultaneously running!\n";
|
||||
tcplp_sys_log("%s\n", msg);
|
||||
}
|
||||
tcplp_sys_set_timer(tp, timer_type, (uint32_t) delta);
|
||||
} else {
|
||||
tpcleartimeractive(tp, timer_type);
|
||||
tcplp_sys_stop_timer(tp, timer_type);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tcp_cancel_timers(struct tcpcb* tp) {
|
||||
tpcleartimeractive(tp, TT_DELACK);
|
||||
tcplp_sys_stop_timer(tp, TT_DELACK);
|
||||
tpcleartimeractive(tp, TT_REXMT);
|
||||
tcplp_sys_stop_timer(tp, TT_REXMT);
|
||||
tpcleartimeractive(tp, TT_PERSIST);
|
||||
tcplp_sys_stop_timer(tp, TT_PERSIST);
|
||||
tpcleartimeractive(tp, TT_KEEP);
|
||||
tcplp_sys_stop_timer(tp, TT_KEEP);
|
||||
tpcleartimeractive(tp, TT_2MSL);
|
||||
tcplp_sys_stop_timer(tp, TT_2MSL);
|
||||
}
|
||||
Vendored
+180
@@ -0,0 +1,180 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/**
|
||||
* samkumar: The FreeBSD Operating System uses its callout subsystem to
|
||||
* implement TCP timers. I've removed the relevant definitions/declarations
|
||||
* below, since TCPlp relies on the host system to implement TCP timers. To
|
||||
* save memory, I've removed some configurability (e.g., per-TCB keepalive
|
||||
* parameters) and global statistics (e.g. tcp_keepcnt).
|
||||
*/
|
||||
|
||||
#ifndef _NETINET_TCP_TIMER_H_
|
||||
#define _NETINET_TCP_TIMER_H_
|
||||
|
||||
#include "tcp_var.h"
|
||||
|
||||
/*
|
||||
* The TCPT_REXMT timer is used to force retransmissions.
|
||||
* The TCP has the TCPT_REXMT timer set whenever segments
|
||||
* have been sent for which ACKs are expected but not yet
|
||||
* received. If an ACK is received which advances tp->snd_una,
|
||||
* then the retransmit timer is cleared (if there are no more
|
||||
* outstanding segments) or reset to the base value (if there
|
||||
* are more ACKs expected). Whenever the retransmit timer goes off,
|
||||
* we retransmit one unacknowledged segment, and do a backoff
|
||||
* on the retransmit timer.
|
||||
*
|
||||
* The TCPT_PERSIST timer is used to keep window size information
|
||||
* flowing even if the window goes shut. If all previous transmissions
|
||||
* have been acknowledged (so that there are no retransmissions in progress),
|
||||
* and the window is too small to bother sending anything, then we start
|
||||
* the TCPT_PERSIST timer. When it expires, if the window is nonzero,
|
||||
* we go to transmit state. Otherwise, at intervals send a single byte
|
||||
* into the peer's window to force him to update our window information.
|
||||
* We do this at most as often as TCPT_PERSMIN time intervals,
|
||||
* but no more frequently than the current estimate of round-trip
|
||||
* packet time. The TCPT_PERSIST timer is cleared whenever we receive
|
||||
* a window update from the peer.
|
||||
*
|
||||
* The TCPT_KEEP timer is used to keep connections alive. If an
|
||||
* connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time,
|
||||
* but not yet established, then we drop the connection. Once the connection
|
||||
* is established, if the connection is idle for TCPTV_KEEP_IDLE time
|
||||
* (and keepalives have been enabled on the socket), we begin to probe
|
||||
* the connection. We force the peer to send us a segment by sending:
|
||||
* <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK>
|
||||
* This segment is (deliberately) outside the window, and should elicit
|
||||
* an ack segment in response from the peer. If, despite the TCPT_KEEP
|
||||
* initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE
|
||||
* amount of time probing, then we drop the connection.
|
||||
*/
|
||||
|
||||
#define TT_DELACK 0x0001
|
||||
#define TT_REXMT 0x0002
|
||||
#define TT_PERSIST 0x0004
|
||||
#define TT_KEEP 0x0008
|
||||
#define TT_2MSL 0x0010
|
||||
|
||||
/*
|
||||
* Time constants.
|
||||
*/
|
||||
#define TCPTV_MSL ( 30*hz) /* max seg lifetime (hah!) */
|
||||
#define TCPTV_SRTTBASE 0 /* base roundtrip time;
|
||||
if 0, no idea yet */
|
||||
#define TCPTV_RTOBASE ( 3*hz) /* assumed RTO if no info */
|
||||
|
||||
#define TCPTV_PERSMIN ( 5*hz) /* retransmit persistence */
|
||||
#define TCPTV_PERSMAX ( 60*hz) /* maximum persist interval */
|
||||
|
||||
#define TCPTV_KEEP_INIT ( 75*hz) /* initial connect keepalive */
|
||||
#define TCPTV_KEEP_IDLE (120*60*hz) /* dflt time before probing */
|
||||
#define TCPTV_KEEPINTVL ( 75*hz) /* default probe interval */
|
||||
#define TCPTV_KEEPCNT 8 /* max probes before drop */
|
||||
|
||||
#define TCPTV_FINWAIT2_TIMEOUT (60*hz) /* FIN_WAIT_2 timeout if no receiver */
|
||||
|
||||
/*
|
||||
* Minimum retransmit timer is 3 ticks, for algorithmic stability.
|
||||
* TCPT_RANGESET() will add another TCPTV_CPU_VAR to deal with
|
||||
* the expected worst-case processing variances by the kernels
|
||||
* representing the end points. Such variances do not always show
|
||||
* up in the srtt because the timestamp is often calculated at
|
||||
* the interface rather then at the TCP layer. This value is
|
||||
* typically 50ms. However, it is also possible that delayed
|
||||
* acks (typically 100ms) could create issues so we set the slop
|
||||
* to 200ms to try to cover it. Note that, properly speaking,
|
||||
* delayed-acks should not create a major issue for interactive
|
||||
* environments which 'P'ush the last segment, at least as
|
||||
* long as implementations do the required 'at least one ack
|
||||
* for every two packets' for the non-interactive streaming case.
|
||||
* (maybe the RTO calculation should use 2*RTT instead of RTT
|
||||
* to handle the ack-every-other-packet case).
|
||||
*
|
||||
* The prior minimum of 1*hz (1 second) badly breaks throughput on any
|
||||
* networks faster then a modem that has minor (e.g. 1%) packet loss.
|
||||
*/
|
||||
#define TCPTV_MIN ( hz/33 ) /* minimum allowable value */
|
||||
#define TCPTV_CPU_VAR ( hz/5 ) /* cpu variance allowed (200ms) */
|
||||
#define TCPTV_REXMTMAX ( 64*hz) /* max allowable REXMT value */
|
||||
|
||||
#define TCPTV_TWTRUNC 8 /* RTO factor to truncate TW */
|
||||
|
||||
#define TCP_LINGERTIME 120 /* linger at most 2 minutes */
|
||||
|
||||
#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */
|
||||
|
||||
#define TCPTV_DELACK ( hz/10 ) /* 100ms timeout */
|
||||
|
||||
#ifdef TCPTIMERS
|
||||
static const char *tcptimers[] =
|
||||
{ "REXMT", "PERSIST", "KEEP", "2MSL", "DELACK" };
|
||||
#endif
|
||||
|
||||
int tcp_timer_active(struct tcpcb *tp, uint32_t timer_type);
|
||||
void tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, uint32_t delta);
|
||||
void tcp_cancel_timers(struct tcpcb* tp);
|
||||
|
||||
/* I moved the definition of TCPT_RANGESET to tcp_const.h. */
|
||||
|
||||
static const int tcp_syn_backoff[TCP_MAXRXTSHIFT + 1] =
|
||||
{ 1, 1, 1, 1, 1, 2, 4, 8, 16, 32, 64, 64, 64 };
|
||||
|
||||
static const int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
|
||||
{ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 512, 512, 512 };
|
||||
|
||||
static const int tcp_totbackoff = 2559; /* sum of tcp_backoff[] */
|
||||
|
||||
void tcp_timer_delack(struct tcpcb* tp);
|
||||
void tcp_timer_keep(struct tcpcb* tp);
|
||||
void tcp_timer_persist(struct tcpcb* tp);
|
||||
void tcp_timer_2msl(struct tcpcb* tp);
|
||||
void tcp_timer_rexmt(struct tcpcb *tp);
|
||||
int tcp_timer_active(struct tcpcb *tp, uint32_t timer_type);
|
||||
|
||||
/*
|
||||
* samkumar: Modified to use default keepalive parameters, since we removed
|
||||
* the fields from tcpcb that allow them to be set on a per-connection basis.
|
||||
*/
|
||||
#define TP_KEEPINIT(tp) (/*(tp)->t_keepinit ? (tp)->t_keepinit :*/ tcp_keepinit)
|
||||
#define TP_KEEPIDLE(tp) (/*(tp)->t_keepidle ? (tp)->t_keepidle :*/ tcp_keepidle)
|
||||
#define TP_KEEPINTVL(tp) (/*(tp)->t_keepintvl ? (tp)->t_keepintvl :*/ tcp_keepintvl)
|
||||
#define TP_KEEPCNT(tp) (/*(tp)->t_keepcnt ? (tp)->t_keepcnt :*/ tcp_keepcnt)
|
||||
#define TP_MAXIDLE(tp) (TP_KEEPCNT(tp) * TP_KEEPINTVL(tp))
|
||||
|
||||
/*
|
||||
* samkumar: MOVED NECESSARY EXTERN DECLARATIONS TO TCP_SUBR.C
|
||||
* Removed timer declarations that aren't needed since timers are handled
|
||||
* by the host system (in this case, OpenThread), in TCPlp.
|
||||
*/
|
||||
|
||||
#endif /* !_NETINET_TCP_TIMER_H_ */
|
||||
+396
@@ -0,0 +1,396 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tcp_subr.c 8.2 (Berkeley) 5/24/95
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "tcp.h"
|
||||
#include "tcp_fsm.h"
|
||||
#include "tcp_seq.h"
|
||||
#include "tcp_timer.h"
|
||||
#include "tcp_var.h"
|
||||
|
||||
#include "tcp_const.h"
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/message.h>
|
||||
|
||||
/*
|
||||
* samkumar: The V_nolocaltimewait variable corresponds to the
|
||||
* net.inet.tcp.nolocaltimewait option in FreeBSD. When set to 1, it skips the
|
||||
* TIME-WAIT state for TCP connections where both endpoints are local IP
|
||||
* addresses, to save resources on HTTP accelerators, database servers/clients,
|
||||
* etc. In TCPlp, I eliminated support for this feature, but I have kept the
|
||||
* code for it, commented out with "#if 0", in case we choose to bring it back
|
||||
* at a later time.
|
||||
*
|
||||
* See also the "#if 0" block in tcp_twstart.
|
||||
*/
|
||||
#if 0
|
||||
enum tcp_timewait_consts {
|
||||
V_nolocaltimewait = 0
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* samkumar: The FreeBSD code used a separate, smaller structure, called
|
||||
* struct tcptw, to respresent connections in the TIME-WAIT state. In TCPlp,
|
||||
* we use the full struct tcpcb structure even in the TIME-WAIT state. This
|
||||
* consumes more memory, but switching to a different structure like
|
||||
* struct tcptw to save memory would be difficult because the host system or
|
||||
* application has allocated these structures; we can't simply "free" the
|
||||
* struct tcpcb. It would have to have been done via a callback or something,
|
||||
* and in the common case of statically allocated sockets, this would actually
|
||||
* result in more memory (since an application would need to allocate both the
|
||||
* struct tcpcb and the struct tcptw, if it uses a static allocation approach).
|
||||
*
|
||||
* Below, I've changed the function signatures to accept "struct tcpcb* tp"
|
||||
* instead of "struct tcptw *tw" and I have reimplemented the functions
|
||||
* to work using tp (of type struct tcpcb) instead of tw (of type
|
||||
* struct tcptw).
|
||||
*
|
||||
* Conceptually, the biggest change is in how timers are handled. The FreeBSD
|
||||
* code had a 2MSL timer, which was set for sockets that enter certain
|
||||
* "closing" states of the TCP state machine. But when the TIME-WAIT state was
|
||||
* entered, the state is transferred from struct tcpcb into struct tcptw.
|
||||
* The final timeout is handled as follows; the function tcp_tw_2msl_scan is
|
||||
* called periodically on the slow timer, and it iterates over a linked list
|
||||
* of all the struct tcptw and checks the tw->tw_time field to identify which
|
||||
* TIME-WAIT sockets have expired.
|
||||
*
|
||||
* In our switch to using struct tcpcb even in the TIME-WAIT state, we rely on
|
||||
* the timer system for struct tcpcb. I modified the 2msl callback in
|
||||
* tcp_timer.c to check for the TIME-WAIT case and handle it correctly.
|
||||
*/
|
||||
|
||||
static void
|
||||
tcp_tw_2msl_reset(struct tcpcb* tp, int rearm)
|
||||
{
|
||||
/*
|
||||
* samkumar: This function used to set tw->tw_time to ticks + 2 * tcp_msl
|
||||
* and insert tw into the linked list V_twq_2msl. I've replaced this, along
|
||||
* with the associated locking logic, with the following call, which uses
|
||||
* the timer system in place for full TCBs.
|
||||
*/
|
||||
tcp_timer_activate(tp, TT_2MSL, 2 * tcp_msl);
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: I've rewritten this code since I need to send out packets via the
|
||||
* host system for TCPlp: allocating buffers from the host system, populate
|
||||
* them, and then pass them back to the host system. I simplified the code by
|
||||
* only using the logic that was fully necessary, eliminating the code for IPv4
|
||||
* packets and keeping only the code for IPv6 packets. I also removed all of
|
||||
* the mbuf logic, instead using the logic for using the host system's
|
||||
* buffering.
|
||||
*
|
||||
* This rewritten code always returns 0. The original code would return
|
||||
* whatever is returned by ip_output or ip6_output (FreeBSD's functions for
|
||||
* sending out IP packets). I believe 0 indicates success, and a nonzero
|
||||
* value represents an error code. It seems that the return value of
|
||||
* tcp_twrespond is ignored by all instances of its use in TCPlp (maybe even
|
||||
* in all of FreeBSD), so this is a moot point.
|
||||
*/
|
||||
static int
|
||||
tcp_twrespond(struct tcpcb* tp, int flags)
|
||||
{
|
||||
struct tcphdr* nth;
|
||||
struct tcpopt to;
|
||||
uint32_t optlen = 0;
|
||||
uint8_t opt[TCP_MAXOLEN];
|
||||
|
||||
to.to_flags = 0;
|
||||
|
||||
/*
|
||||
* Send a timestamp and echo-reply if both our side and our peer
|
||||
* have sent timestamps in our SYN's and this is not a RST.
|
||||
*/
|
||||
if ((tp->t_flags & TF_RCVD_TSTMP) && flags == TH_ACK) {
|
||||
to.to_flags |= TOF_TS;
|
||||
to.to_tsval = tcp_ts_getticks() + tp->ts_offset;
|
||||
to.to_tsecr = tp->ts_recent;
|
||||
}
|
||||
optlen = tcp_addoptions(&to, opt);
|
||||
|
||||
otMessage* message = tcplp_sys_new_message(tp->instance);
|
||||
if (message == NULL) {
|
||||
return 0; // drop the message
|
||||
}
|
||||
if (otMessageSetLength(message, sizeof(struct tcphdr) + optlen) != OT_ERROR_NONE) {
|
||||
tcplp_sys_free_message(tp->instance, message);
|
||||
return 0; // drop the message
|
||||
}
|
||||
|
||||
char outbuf[sizeof(struct tcphdr) + optlen];
|
||||
nth = (struct tcphdr*) &outbuf[0];
|
||||
otMessageInfo ip6info;
|
||||
memset(&ip6info, 0x00, sizeof(ip6info));
|
||||
|
||||
memcpy(&ip6info.mSockAddr, &tp->laddr, sizeof(ip6info.mSockAddr));
|
||||
memcpy(&ip6info.mPeerAddr, &tp->faddr, sizeof(ip6info.mPeerAddr));
|
||||
nth->th_sport = tp->lport;
|
||||
nth->th_dport = tp->fport;
|
||||
nth->th_seq = htonl(tp->snd_nxt);
|
||||
nth->th_ack = htonl(tp->rcv_nxt);
|
||||
nth->th_x2 = 0;
|
||||
nth->th_off = (sizeof(struct tcphdr) + optlen) >> 2;
|
||||
nth->th_flags = flags;
|
||||
nth->th_win = htons(tp->tw_last_win);
|
||||
nth->th_urp = 0;
|
||||
nth->th_sum = 0;
|
||||
|
||||
memcpy(nth + 1, opt, optlen);
|
||||
otMessageWrite(message, 0, outbuf, sizeof(struct tcphdr) + optlen);
|
||||
tcplp_sys_send_message(tp->instance, message, &ip6info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move a TCP connection into TIME_WAIT state.
|
||||
* tcbinfo is locked.
|
||||
* inp is locked, and is unlocked before returning.
|
||||
*/
|
||||
/*
|
||||
* samkumar: Locking is removed (so above comments regarding locks are no
|
||||
* not relevant for TCPlp). Rather than allocating a struct tcptw and
|
||||
* discarding the struct tcpcb, this function just switches the tcpcb state
|
||||
* to correspond to TIME-WAIT (updating variables as appropriate). We also
|
||||
* eliminate the "V_nolocaltimewait" optimization.
|
||||
*/
|
||||
void
|
||||
tcp_twstart(struct tcpcb *tp)
|
||||
{
|
||||
int acknow;
|
||||
|
||||
/*
|
||||
* samkumar: The following code, commented out using "#if 0", handles the
|
||||
* net.inet.tcp.nolocaltimewait option in FreeBSD. The option skips the
|
||||
* TIME-WAIT state for TCP connections where both endpoints are local.
|
||||
* I'm removing this optimization for TCPlp, but I've left the code
|
||||
* commented out as it's a potentially useful feature that we may choose
|
||||
* to restore later.
|
||||
*
|
||||
* See also the "#if 0" block near the top of this file.
|
||||
*/
|
||||
#if 0
|
||||
if (V_nolocaltimewait) {
|
||||
int error = 0;
|
||||
#ifdef INET6
|
||||
if (isipv6)
|
||||
error = in6_localaddr(&inp->in6p_faddr);
|
||||
#endif
|
||||
#if defined(INET6) && defined(INET)
|
||||
else
|
||||
#endif
|
||||
#ifdef INET
|
||||
error = in_localip(inp->inp_faddr);
|
||||
#endif
|
||||
if (error) {
|
||||
tp = tcp_close(tp);
|
||||
if (tp != NULL)
|
||||
INP_WUNLOCK(inp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For use only by DTrace. We do not reference the state
|
||||
* after this point so modifying it in place is not a problem.
|
||||
*/
|
||||
/*
|
||||
* samkumar: The above comment is not true anymore. I use this state, since
|
||||
* I don't associate every struct tcpcb with a struct inpcb.
|
||||
*/
|
||||
tcp_state_change(tp, TCPS_TIME_WAIT);
|
||||
|
||||
/*
|
||||
* samkumar: There used to be code here to allocate a struct tcptw
|
||||
* using "tw = uma_zalloc(V_tcptw_zone, M_NOWAIT);" and if it fails, close
|
||||
* an existing TIME-WAIT connection, in LRU fashion, to allocate memory.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Recover last window size sent.
|
||||
*/
|
||||
if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt))
|
||||
tp->tw_last_win = (tp->rcv_adv - tp->rcv_nxt) >> tp->rcv_scale;
|
||||
else
|
||||
tp->tw_last_win = 0;
|
||||
|
||||
/*
|
||||
* Set t_recent if timestamps are used on the connection.
|
||||
*/
|
||||
if ((tp->t_flags & (TF_REQ_TSTMP|TF_RCVD_TSTMP|TF_NOOPT)) ==
|
||||
(TF_REQ_TSTMP|TF_RCVD_TSTMP)) {
|
||||
/*
|
||||
* samkumar: This used to do:
|
||||
* tw->t_recent = tp->ts_recent;
|
||||
* tw->ts_offset = tp->ts_offset;
|
||||
* But since we're keeping the state in tp, we don't need to do this
|
||||
* anymore. */
|
||||
} else {
|
||||
tp->ts_recent = 0;
|
||||
tp->ts_offset = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: There used to be code here to populate various fields in
|
||||
* tw based on their values in tp, but there's no need for that now since
|
||||
* we can just read the values from tp. tw->tw_time was set to 0, but we
|
||||
* don't need to do that either since we're relying on the old timer system
|
||||
* anyway.
|
||||
*/
|
||||
|
||||
/* XXX
|
||||
* If this code will
|
||||
* be used for fin-wait-2 state also, then we may need
|
||||
* a ts_recent from the last segment.
|
||||
*/
|
||||
acknow = tp->t_flags & TF_ACKNOW;
|
||||
|
||||
/*
|
||||
* First, discard tcpcb state, which includes stopping its timers and
|
||||
* freeing it. tcp_discardcb() used to also release the inpcb, but
|
||||
* that work is now done in the caller.
|
||||
*
|
||||
* Note: soisdisconnected() call used to be made in tcp_discardcb(),
|
||||
* and might not be needed here any longer.
|
||||
*/
|
||||
/*
|
||||
* samkumar: Below, I removed the code to discard tp, update inpcb and
|
||||
* release a reference to socket, but kept the rest. I also added a call
|
||||
* to cancel any pending timers on the TCB (which discarding it, as the
|
||||
* original code did, would have done).
|
||||
*/
|
||||
tcp_cancel_timers(tp);
|
||||
if (acknow)
|
||||
tcp_twrespond(tp, TH_ACK);
|
||||
tcp_tw_2msl_reset(tp, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if the TIME_WAIT state was killed and we should start over,
|
||||
* looking for a pcb in the listen state. Returns 0 otherwise.
|
||||
*/
|
||||
/*
|
||||
* samkumar: Old signature was
|
||||
* int
|
||||
* tcp_twcheck(struct inpcb *inp, struct tcpopt *to, struct tcphdr *th,
|
||||
* struct mbuf *m, int tlen)
|
||||
*/
|
||||
int
|
||||
tcp_twcheck(struct tcpcb* tp, struct tcphdr *th, int tlen)
|
||||
{
|
||||
int thflags;
|
||||
tcp_seq seq;
|
||||
|
||||
/*
|
||||
* samkumar: There used to be code here that obtains the struct tcptw from
|
||||
* the inpcb, and does "goto drop" if that fails.
|
||||
*/
|
||||
|
||||
thflags = th->th_flags;
|
||||
|
||||
/*
|
||||
* NOTE: for FIN_WAIT_2 (to be added later),
|
||||
* must validate sequence number before accepting RST
|
||||
*/
|
||||
|
||||
/*
|
||||
* If the segment contains RST:
|
||||
* Drop the segment - see Stevens, vol. 2, p. 964 and
|
||||
* RFC 1337.
|
||||
*/
|
||||
if (thflags & TH_RST)
|
||||
goto drop;
|
||||
|
||||
/*
|
||||
* samkumar: This was commented out (using #if 0) in the original FreeBSD
|
||||
* code.
|
||||
*/
|
||||
#if 0
|
||||
/* PAWS not needed at the moment */
|
||||
/*
|
||||
* RFC 1323 PAWS: If we have a timestamp reply on this segment
|
||||
* and it's less than ts_recent, drop it.
|
||||
*/
|
||||
if ((to.to_flags & TOF_TS) != 0 && tp->ts_recent &&
|
||||
TSTMP_LT(to.to_tsval, tp->ts_recent)) {
|
||||
if ((thflags & TH_ACK) == 0)
|
||||
goto drop;
|
||||
goto ack;
|
||||
}
|
||||
/*
|
||||
* ts_recent is never updated because we never accept new segments.
|
||||
*/
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If a new connection request is received
|
||||
* while in TIME_WAIT, drop the old connection
|
||||
* and start over if the sequence numbers
|
||||
* are above the previous ones.
|
||||
*/
|
||||
if ((thflags & TH_SYN) && SEQ_GT(th->th_seq, tp->rcv_nxt)) {
|
||||
/*
|
||||
* samkumar: The FreeBSD code would call tcp_twclose(tw, 0); but we
|
||||
* do it as below since TCPlp represents TIME-WAIT connects as
|
||||
* struct tcpcb's.
|
||||
*/
|
||||
tcp_close(tp);
|
||||
tcplp_sys_connection_lost(tp, CONN_LOST_NORMAL);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop the segment if it does not contain an ACK.
|
||||
*/
|
||||
if ((thflags & TH_ACK) == 0)
|
||||
goto drop;
|
||||
|
||||
/*
|
||||
* Reset the 2MSL timer if this is a duplicate FIN.
|
||||
*/
|
||||
if (thflags & TH_FIN) {
|
||||
seq = th->th_seq + tlen + (thflags & TH_SYN ? 1 : 0);
|
||||
if (seq + 1 == tp->rcv_nxt)
|
||||
tcp_tw_2msl_reset(tp, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Acknowledge the segment if it has data or is not a duplicate ACK.
|
||||
*/
|
||||
if (thflags != TH_ACK || tlen != 0 ||
|
||||
th->th_seq != tp->rcv_nxt || th->th_ack != tp->snd_nxt)
|
||||
tcp_twrespond(tp, TH_ACK);
|
||||
drop:
|
||||
return (0);
|
||||
}
|
||||
+510
@@ -0,0 +1,510 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1988, 1993
|
||||
* The Regents of the University of California.
|
||||
* Copyright (c) 2006-2007 Robert N. M. Watson
|
||||
* Copyright (c) 2010-2011 Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed by Robert N. M. Watson under
|
||||
* contract to Juniper Networks, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* From: @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "../tcplp.h"
|
||||
#include "../lib/cbuf.h"
|
||||
#include "tcp.h"
|
||||
#include "tcp_fsm.h"
|
||||
#include "tcp_seq.h"
|
||||
#include "tcp_var.h"
|
||||
#include "tcp_timer.h"
|
||||
//#include <sys/socket.h>
|
||||
#include "ip6.h"
|
||||
|
||||
#include "tcp_const.h"
|
||||
|
||||
#include <openthread/tcp.h>
|
||||
|
||||
//static void tcp_disconnect(struct tcpcb *);
|
||||
static void tcp_usrclosed(struct tcpcb *);
|
||||
|
||||
/*
|
||||
* samkumar: Removed tcp6_usr_bind, since checking if an address/port is free
|
||||
* needs to be done at the host system (along with other socket management
|
||||
* duties). TCPlp doesn't know what other sockets are in the system, or which
|
||||
* other addresses/ports are busy.
|
||||
*/
|
||||
|
||||
/* samkumar: This is based on a function in in6_pcb.c. */
|
||||
static int in6_pcbconnect(struct tcpcb* tp, struct sockaddr_in6* nam) {
|
||||
register struct sockaddr_in6 *sin6 = nam;
|
||||
tp->faddr = sin6->sin6_addr;
|
||||
tp->fport = sin6->sin6_port;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate connection to peer.
|
||||
* Create a template for use in transmissions on this connection.
|
||||
* Enter SYN_SENT state, and mark socket as connecting.
|
||||
* Start keep-alive timer, and seed output sequence space.
|
||||
* Send initial segment on connection.
|
||||
*/
|
||||
/*
|
||||
* samkumar: I removed locking, statistics, and inpcb management. The signature
|
||||
* used to be
|
||||
*
|
||||
* static int
|
||||
* tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
||||
*/
|
||||
static int
|
||||
tcp6_connect(struct tcpcb *tp, struct sockaddr_in6 *nam)
|
||||
{
|
||||
int error;
|
||||
|
||||
int sb_max = cbuf_free_space(&tp->recvbuf); // same as sendbuf
|
||||
|
||||
/*
|
||||
* samkumar: For autobind, the original BSD code assigned the port first
|
||||
* (with logic that also looked at the address) and then the address. This
|
||||
* was done by calling into other parts of the FreeBSD network stack,
|
||||
* outside of the TCP stack. Here, we just use the tcplp_sys_autobind
|
||||
* function to do all of that work.
|
||||
*/
|
||||
bool autobind_addr = IN6_IS_ADDR_UNSPECIFIED(&tp->laddr);
|
||||
bool autobind_port = (tp->lport == 0);
|
||||
if (autobind_addr || autobind_port) {
|
||||
otSockAddr foreign;
|
||||
otSockAddr local;
|
||||
|
||||
memcpy(&foreign.mAddress, &nam->sin6_addr, sizeof(foreign.mAddress));
|
||||
foreign.mPort = ntohs(nam->sin6_port);
|
||||
|
||||
if (!autobind_addr) {
|
||||
memcpy(&local.mAddress, &tp->laddr, sizeof(local.mAddress));
|
||||
}
|
||||
|
||||
if (!autobind_port) {
|
||||
local.mPort = ntohs(tp->lport);
|
||||
}
|
||||
|
||||
if (!tcplp_sys_autobind(tp->instance, &foreign, &local, autobind_addr, autobind_port)) {
|
||||
// Autobind failed
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (autobind_addr) {
|
||||
memcpy(&tp->laddr, &local.mAddress, sizeof(tp->laddr));
|
||||
}
|
||||
|
||||
if (autobind_port) {
|
||||
tp->lport = htons(local.mPort);
|
||||
}
|
||||
}
|
||||
error = in6_pcbconnect(tp, nam);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
|
||||
/* Compute window scaling to request. */
|
||||
while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
|
||||
(TCP_MAXWIN << tp->request_r_scale) < sb_max)
|
||||
tp->request_r_scale++;
|
||||
|
||||
tcp_state_change(tp, TCPS_SYN_SENT);
|
||||
tp->iss = tcp_new_isn(tp);
|
||||
tcp_sendseqinit(tp);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: I removed locking, statistics, inpcb management, and debug probes.
|
||||
* I also remove codepaths that check for IPv6, since the address is assumed to
|
||||
* be IPv6. The signature used to be
|
||||
*
|
||||
* static int
|
||||
* tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
*/
|
||||
int
|
||||
tcp6_usr_connect(struct tcpcb* tp, struct sockaddr_in6* sin6p)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (tp->t_state != TCPS_CLOSED) { // samkumar: This is a check that I added
|
||||
return (EISCONN);
|
||||
}
|
||||
|
||||
/* samkumar: I removed the following error check since we receive sin6p
|
||||
* in the function argument and don't need to convert a struct sockaddr to
|
||||
* a struct sockaddr_in6 anymore.
|
||||
*
|
||||
* if (nam->sa_len != sizeof (*sin6p))
|
||||
* return (EINVAL);
|
||||
*/
|
||||
|
||||
/*
|
||||
* Must disallow TCP ``connections'' to multicast addresses.
|
||||
*/
|
||||
/* samkumar: I commented out the check on sin6p->sin6_family. */
|
||||
if (/*sin6p->sin6_family == AF_INET6
|
||||
&& */IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
|
||||
return (EAFNOSUPPORT);
|
||||
|
||||
/*
|
||||
* samkumar: There was some code here that obtained the TCB (struct tcpcb*)
|
||||
* by getting the inpcb from the socket and the TCB from the inpcb. I
|
||||
* removed that code.
|
||||
*/
|
||||
|
||||
/*
|
||||
* XXXRW: Some confusion: V4/V6 flags relate to binding, and
|
||||
* therefore probably require the hash lock, which isn't held here.
|
||||
* Is this a significant problem?
|
||||
*/
|
||||
if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
|
||||
tcplp_sys_log("V4-Mapped Address!\n");
|
||||
|
||||
/*
|
||||
* samkumar: There used to be code that woulf handle the case of
|
||||
* v4-mapped addresses. It would call in6_sin6_2_sin to convert the
|
||||
* struct sockaddr_in6 to a struct sockaddr_in, set the INP_IPV4 flag
|
||||
* and clear the INP_IPV6 flag on inp->inp_vflag, do some other
|
||||
* processing, and finally call tcp_connect and tcp_output. However,
|
||||
* it would first check if the IN6P_IPV6_V6ONLY flag was set in
|
||||
* inp->inp_flags, and if so, it would return with EINVAL. In TCPlp, we
|
||||
* support IPv6 only, so I removed the check for IN6P_IPV6_V6ONLY and
|
||||
* always act as if that flag is set. I kept the code in that if
|
||||
* statement making the check, and removed the other code that actually
|
||||
* handled this case.
|
||||
*/
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: I removed some code here that set/cleared some flags in the`
|
||||
* inpcb and called prison_remote_ip6.
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar: Originally, the struct thread *td was passed along to
|
||||
* tcp6_connect.
|
||||
*/
|
||||
if ((error = tcp6_connect(tp, sin6p)) != 0)
|
||||
goto out;
|
||||
|
||||
tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp));
|
||||
error = tcp_output(tp);
|
||||
|
||||
out:
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do a send by putting data in output queue and updating urgent
|
||||
* marker if URG set. Possibly send more data. Unlike the other
|
||||
* pru_*() routines, the mbuf chains are our responsibility. We
|
||||
* must either enqueue them or free them. The other pru_* routines
|
||||
* generally are caller-frees.
|
||||
*/
|
||||
/*
|
||||
* samkumar: I removed locking, statistics, inpcb management, and debug probes.
|
||||
* I also removed support for the urgent pointer.
|
||||
*
|
||||
* I changed the signature of this function. It used to be
|
||||
* static int
|
||||
* tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
||||
* struct sockaddr *nam, struct mbuf *control, struct thread *td)
|
||||
*
|
||||
* The new function signature works as follows. DATA is a new linked buffer to
|
||||
* add to the end of the send buffer. EXTENDBY is the number of bytes by which
|
||||
* to extend the final linked buffer of the send buffer. Either DATA should be
|
||||
* NULL, or EXTENDBY should be 0.
|
||||
*/
|
||||
int tcp_usr_send(struct tcpcb* tp, int moretocome, otLinkedBuffer* data, size_t extendby)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* samkumar: This if statement and the next are checks that I added
|
||||
*/
|
||||
if (tp->t_state < TCPS_ESTABLISHED) {
|
||||
error = ENOTCONN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tpiscantsend(tp)) {
|
||||
error = EPIPE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: There used to be logic here that acquired locks, dealt with
|
||||
* INP_TIMEWAIT and INP_DROPPED flags on inp->inp_flags, and handled the
|
||||
* control mbuf passed as an argument (which would result in an error since
|
||||
* TCP doesn't support control information). I've deleted that code, but
|
||||
* left the following if block.
|
||||
*/
|
||||
if ((tp->t_state == TCPS_TIME_WAIT) || (tp->t_state == TCPS_CLOSED)) {
|
||||
error = ECONNRESET;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following code used to be wrapped in an if statement:
|
||||
* "if (!(flags & PRUS_OOB))", that only executed it if the "out of band"
|
||||
* flag was not set. In TCB, "out of band" data is conveyed via the urgent
|
||||
* pointer, and TCPlp does not support the urgent pointer. Therefore, I
|
||||
* removed the "if" check and put its body below.
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar; The FreeBSD code calls sbappendstream(&so->so_snd, m, flags);
|
||||
* I've replaced it with the following logic, which appends to the
|
||||
* send buffer according to TCPlp's data structures.
|
||||
*/
|
||||
if (data == NULL) {
|
||||
if (extendby == 0) {
|
||||
goto out;
|
||||
}
|
||||
lbuf_extend(&tp->sendbuf, extendby);
|
||||
} else {
|
||||
if (data->mLength == 0) {
|
||||
goto out;
|
||||
}
|
||||
lbuf_append(&tp->sendbuf, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: There used to be code here to handle "implied connect,"
|
||||
* which initiates the TCP handshake if sending data on a socket that
|
||||
* isn't yet connected. TCPlp doesn't support this at the moment, but
|
||||
* it might be worth revisiting when implementing TCP Fast Open.
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar: There used to be code here handling the PRUS_EOF flag in
|
||||
* the former flags parameter. I've removed this code.
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar: The code below was previously wrapped in an if statement
|
||||
* that checked that the INP_DROPPED flag in inp->inp_flags and the
|
||||
* PRUS_NOTREADY flag in the former flags parameter were both clear.
|
||||
* If either one was set, then tcp_output would not be called.
|
||||
*
|
||||
* The "more to come" functionality was previously triggered via the
|
||||
* PRUS_MORETOCOME flag in the flags parameter to this function. Since
|
||||
* that's the only flag that TCPlp uses here, I replaced the flags
|
||||
* parameter with a "moretocome" parameter, which we check instead.
|
||||
*/
|
||||
if (moretocome)
|
||||
tp->t_flags |= TF_MORETOCOME;
|
||||
error = tcp_output(tp);
|
||||
if (moretocome)
|
||||
tp->t_flags &= ~TF_MORETOCOME;
|
||||
|
||||
/*
|
||||
* samkumar: This is where the "if (!(flags & PRUS_OOB))" block would end.
|
||||
* There used to be a large "else" block handling out-of-band data, but I
|
||||
* removed that entire block since we do not support the urgent pointer in
|
||||
* TCPlp.
|
||||
*/
|
||||
out:
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* After a receive, possibly send window update to peer.
|
||||
*/
|
||||
int
|
||||
tcp_usr_rcvd(struct tcpcb* tp)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* samkumar: There used to be logic here that acquired locks, dealt with
|
||||
* INP_TIMEWAIT and INP_DROPPED flags on inp->inp_flags, and added debug
|
||||
* probes I've deleted that code, but left the following if block.
|
||||
*/
|
||||
if ((tp->t_state == TCPS_TIME_WAIT) || (tp->t_state == TCPS_CLOSED)) {
|
||||
error = ECONNRESET;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tcp_output(tp);
|
||||
|
||||
out:
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: Removed the tcp_disconnect function. It is meant to be a
|
||||
* "friendly" disconnect to complement the unceremonious "abort" functionality
|
||||
* that is also provbided. The FreeBSD implementation called it from
|
||||
* tcp_usr_close, which we removed (see the comment below for the reason why).
|
||||
* It's not called from anywhere else, so I'm removing this function entirely.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Mark the connection as being incapable of further output.
|
||||
*/
|
||||
/*
|
||||
* samkumar: Modified to remove locking, socket/inpcb handling, and debug
|
||||
* probes.
|
||||
*/
|
||||
int
|
||||
tcp_usr_shutdown(struct tcpcb* tp)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* samkumar: replaced checks on the INP_TIMEWAIT and INP_DROPPED flags on
|
||||
* inp->inp_flags with these checks on tp->t_state.
|
||||
*/
|
||||
if ((tp->t_state == TCPS_TIME_WAIT) || (tp->t_state == TCPS_CLOSED)) {
|
||||
error = ECONNRESET;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* samkumar: replaced socantsendmore with tpcantsendmore */
|
||||
tpcantsendmore(tp);
|
||||
tcp_usrclosed(tp);
|
||||
|
||||
/*
|
||||
* samkumar: replaced check on INP_DROPPED flag in inp->inp_flags with
|
||||
* this check on tp->t_state.
|
||||
*/
|
||||
if (tp->t_state != TCPS_CLOSED)
|
||||
error = tcp_output(tp);
|
||||
|
||||
out:
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* User issued close, and wish to trail through shutdown states:
|
||||
* if never received SYN, just forget it. If got a SYN from peer,
|
||||
* but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
|
||||
* If already got a FIN from peer, then almost done; go to LAST_ACK
|
||||
* state. In all other cases, have already sent FIN to peer (e.g.
|
||||
* after PRU_SHUTDOWN), and just have to play tedious game waiting
|
||||
* for peer to send FIN or not respond to keep-alives, etc.
|
||||
* We can let the user exit from the close as soon as the FIN is acked.
|
||||
*/
|
||||
/*
|
||||
* Removed locking, TCP Offload, and socket/inpcb handling.
|
||||
*/
|
||||
static void
|
||||
tcp_usrclosed(struct tcpcb *tp)
|
||||
{
|
||||
switch (tp->t_state) {
|
||||
case TCPS_LISTEN:
|
||||
tcp_state_change(tp, TCPS_CLOSED);
|
||||
/* FALLTHROUGH */
|
||||
case TCPS_CLOSED:
|
||||
tp = tcp_close(tp);
|
||||
tcplp_sys_connection_lost(tp, CONN_LOST_NORMAL);
|
||||
/*
|
||||
* tcp_close() should never return NULL here as the socket is
|
||||
* still open.
|
||||
*/
|
||||
KASSERT(tp != NULL,
|
||||
("tcp_usrclosed: tcp_close() returned NULL"));
|
||||
break;
|
||||
|
||||
case TCPS_SYN_SENT:
|
||||
case TCPS_SYN_RECEIVED:
|
||||
tp->t_flags |= TF_NEEDFIN;
|
||||
break;
|
||||
|
||||
case TCPS_ESTABLISHED:
|
||||
tcp_state_change(tp, TCPS_FIN_WAIT_1);
|
||||
break;
|
||||
|
||||
case TCPS_CLOSE_WAIT:
|
||||
tcp_state_change(tp, TCPS_LAST_ACK);
|
||||
break;
|
||||
}
|
||||
if (tp->t_state >= TCPS_FIN_WAIT_2) {
|
||||
/* samkumar: commented out the following "soisdisconnected" line. */
|
||||
// soisdisconnected(tp->t_inpcb->inp_socket);
|
||||
/* Prevent the connection hanging in FIN_WAIT_2 forever. */
|
||||
if (tp->t_state == TCPS_FIN_WAIT_2) {
|
||||
int timeout;
|
||||
|
||||
timeout = (tcp_fast_finwait2_recycle) ?
|
||||
tcp_finwait2_timeout : TP_MAXIDLE(tp);
|
||||
tcp_timer_activate(tp, TT_2MSL, timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* samkumar: I removed the tcp_usr_close function. It was meant to be called in
|
||||
* case the socket is closed. It calls tcp_disconnect if the underlying TCP
|
||||
* connection is still alive when the socket is closed ("full TCP state").
|
||||
* In TCPlp, we can't handle this because we want to free up the underlying
|
||||
* memory immediately when the user deallocates a TCP connection, making it
|
||||
* unavailable for the somewhat more ceremonious closing that tcp_disconnect
|
||||
* would allow. The host system is expected to simply abort the connection if
|
||||
* the application deallocates it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abort the TCP. Drop the connection abruptly.
|
||||
*/
|
||||
/*
|
||||
* samkumar: Modified to remove locking, socket/inpcb handling, and debug
|
||||
* probes.
|
||||
*/
|
||||
void
|
||||
tcp_usr_abort(struct tcpcb* tp)
|
||||
{
|
||||
/*
|
||||
* If we still have full TCP state, and we're not dropped, drop.
|
||||
*/
|
||||
/*
|
||||
* I replaced the checks on inp->inp_flags (which tested for the absence of
|
||||
* INP_TIMEWAIT and INP_DROPPED flags), with the following checks on
|
||||
* tp->t_state.
|
||||
*/
|
||||
if (tp->t_state != TCP6S_TIME_WAIT &&
|
||||
tp->t_state != TCP6S_CLOSED) {
|
||||
tcp_drop(tp, ECONNABORTED);
|
||||
} else if (tp->t_state == TCPS_TIME_WAIT) { // samkumar: I added this clause
|
||||
tp = tcp_close(tp);
|
||||
tcplp_sys_connection_lost(tp, CONN_LOST_NORMAL);
|
||||
}
|
||||
}
|
||||
Vendored
+591
@@ -0,0 +1,591 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993, 1994, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tcp_var.h 8.4 (Berkeley) 5/24/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _NETINET_TCP_VAR_H_
|
||||
#define _NETINET_TCP_VAR_H_
|
||||
|
||||
/* For memmove(). */
|
||||
#include <string.h>
|
||||
|
||||
/* Dependencies on OpenThread. */
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/message.h>
|
||||
|
||||
/* Dependencies on TCPlp buffering libraries. */
|
||||
#include "../lib/bitmap.h"
|
||||
#include "../lib/cbuf.h"
|
||||
#include "../lib/lbuf.h"
|
||||
|
||||
#include "cc.h"
|
||||
#include "tcp.h"
|
||||
#include "types.h"
|
||||
#include "ip6.h"
|
||||
|
||||
#include "sys/queue.h"
|
||||
|
||||
/* Implement byte-order-specific functions using OpenThread. */
|
||||
uint16_t tcplp_sys_hostswap16(uint16_t hostport);
|
||||
uint32_t tcplp_sys_hostswap32(uint32_t hostport);
|
||||
|
||||
/*
|
||||
* It seems that these are defined as macros in Mac OS X, which is why we need
|
||||
* the #ifndef checks. Simply redefining them as functions would break the
|
||||
* build.
|
||||
*/
|
||||
|
||||
#ifndef htons
|
||||
static inline uint16_t htons(uint16_t hostport) {
|
||||
return tcplp_sys_hostswap16(hostport);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ntohs
|
||||
static inline uint16_t ntohs(uint16_t hostport) {
|
||||
return tcplp_sys_hostswap16(hostport);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef htonl
|
||||
static inline uint32_t htonl(uint32_t hostport) {
|
||||
return tcplp_sys_hostswap32(hostport);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ntohl
|
||||
static inline uint32_t ntohl(uint32_t hostport) {
|
||||
return tcplp_sys_hostswap32(hostport);
|
||||
}
|
||||
#endif
|
||||
|
||||
// From ip_compat.h
|
||||
#ifndef bcopy
|
||||
#define bcopy(a,b,c) memmove(b,a,c)
|
||||
#endif
|
||||
|
||||
#ifndef bzero
|
||||
#define bzero(a,b) memset(a,0x00,b)
|
||||
#endif
|
||||
|
||||
struct sackblk {
|
||||
tcp_seq start; /* start seq no. of sack block */
|
||||
tcp_seq end; /* end seq no. */
|
||||
};
|
||||
|
||||
struct sackhole {
|
||||
tcp_seq start; /* start seq no. of hole */
|
||||
tcp_seq end; /* end seq no. */
|
||||
tcp_seq rxmit; /* next seq. no in hole to be retransmitted */
|
||||
TAILQ_ENTRY(sackhole) scblink; /* scoreboard linkage */
|
||||
};
|
||||
|
||||
struct sackhint {
|
||||
struct sackhole *nexthole;
|
||||
int sack_bytes_rexmit;
|
||||
tcp_seq last_sack_ack; /* Most recent/largest sacked ack */
|
||||
};
|
||||
|
||||
struct tcptemp {
|
||||
uint8_t tt_ipgen[40]; /* the size must be of max ip header, now IPv6 */
|
||||
struct tcphdr tt_t;
|
||||
};
|
||||
|
||||
#define tcp6cb tcpcb /* for KAME src sync over BSD*'s */
|
||||
|
||||
/* Abridged TCB for passive sockets. */
|
||||
struct tcpcb_listen {
|
||||
int t_state; /* Always CLOSED or LISTEN. */
|
||||
otInstance* instance;
|
||||
struct in6_addr laddr;
|
||||
uint16_t lport;
|
||||
};
|
||||
|
||||
#define TCB_CANTRCVMORE 0x20
|
||||
#define TCB_CANTSENDMORE 0x40
|
||||
|
||||
#define TCB_PASSIVE 0x80
|
||||
|
||||
#define tpcantrcvmore(tp) (tp)->miscflags |= TCB_CANTRCVMORE
|
||||
#define tpcantsendmore(tp) (tp)->miscflags |= TCB_CANTSENDMORE
|
||||
#define tpiscantrcv(tp) (((tp)->miscflags & TCB_CANTRCVMORE) != 0)
|
||||
#define tpiscantsend(tp) (((tp)->miscflags & TCB_CANTSENDMORE) != 0)
|
||||
#define tpmarktimeractive(tp, timer) (tp)->miscflags |= timer
|
||||
#define tpistimeractive(tp, timer) (((tp)->miscflags & timer) != 0)
|
||||
#define tpcleartimeractive(tp, timer) (tp)->miscflags &= ~timer
|
||||
#define tpmarkpassiveopen(tp) (tp)->miscflags |= TCB_PASSIVE
|
||||
#define tpispassiveopen(tp) (((tp)->miscflags & TCB_PASSIVE) != 0)
|
||||
|
||||
#define REASSBMP_SIZE(tp) BITS_TO_BYTES((tp)->recvbuf.size)
|
||||
|
||||
/* These estimates are used to allocate sackholes (see tcp_sack.c). */
|
||||
#define AVG_SACKHOLES 2 // per TCB
|
||||
#define MAX_SACKHOLES 5 // per TCB
|
||||
#define SACKHOLE_POOL_SIZE MAX_SACKHOLES
|
||||
#define SACKHOLE_BMP_SIZE BITS_TO_BYTES(SACKHOLE_POOL_SIZE)
|
||||
|
||||
struct signals;
|
||||
|
||||
/*
|
||||
* Tcp control block, one per tcp; fields:
|
||||
* Organized for 16 byte cacheline efficiency.
|
||||
*/
|
||||
/*
|
||||
* samkumar: I added some fields for TCPlp to the beginning of this structure,
|
||||
* replaced the fields for buffering and timers, and deleted unused fields to
|
||||
* save memory. I've left some of the deleted fields in, as comments, for
|
||||
* clarity. At times, I reduced the configurability of the implementation
|
||||
* (e.g., by removing the ability to set keepalive parameters) in order to
|
||||
* reduce the size of this structure.
|
||||
*/
|
||||
struct tcpcb {
|
||||
/*
|
||||
* samkumar: Extra fields that I added. TCPlp doesn't have a struct inpcb,
|
||||
* so some of the fields I added represent data that would normally be
|
||||
* stored in the inpcb.
|
||||
*/
|
||||
otInstance *instance;
|
||||
|
||||
struct tcpcb_listen* accepted_from;
|
||||
|
||||
struct lbufhead sendbuf;
|
||||
struct cbufhead recvbuf;
|
||||
uint8_t* reassbmp;
|
||||
int32_t reass_fin_index;
|
||||
|
||||
struct in6_addr laddr; // local IP address
|
||||
struct in6_addr faddr; // foreign IP address
|
||||
|
||||
uint16_t lport; // local port, network byte order
|
||||
uint16_t fport; // foreign port, network byte order
|
||||
uint8_t miscflags;
|
||||
|
||||
/* samkumar: This field was there previously. */
|
||||
uint8_t t_state; /* state of this connection */
|
||||
|
||||
/* Pool of SACK holes (on per-connection basis, for OpenThread port). */
|
||||
struct sackhole sackhole_pool[SACKHOLE_POOL_SIZE];
|
||||
uint8_t sackhole_bmp[SACKHOLE_BMP_SIZE];
|
||||
|
||||
#if 0
|
||||
struct tsegqe_head t_segq; /* segment reassembly queue */
|
||||
void *t_pspare[2]; /* new reassembly queue */
|
||||
int t_segqlen; /* segment reassembly queue length */
|
||||
#endif
|
||||
|
||||
int t_dupacks; /* consecutive dup acks recd */
|
||||
|
||||
#if 0
|
||||
struct tcp_timer *t_timers; /* All the TCP timers in one struct */
|
||||
|
||||
struct inpcb *t_inpcb; /* back pointer to internet pcb */
|
||||
#endif
|
||||
|
||||
uint16_t tw_last_win; // samkumar: Taken from struct tcptw
|
||||
|
||||
uint32_t t_flags;
|
||||
|
||||
// struct vnet *t_vnet; /* back pointer to parent vnet */
|
||||
|
||||
tcp_seq snd_una; /* sent but unacknowledged */
|
||||
tcp_seq snd_max; /* highest sequence number sent;
|
||||
* used to recognize retransmits
|
||||
*/
|
||||
tcp_seq snd_nxt; /* send next */
|
||||
tcp_seq snd_up; /* send urgent pointer */
|
||||
|
||||
tcp_seq snd_wl1; /* window update seg seq number */
|
||||
tcp_seq snd_wl2; /* window update seg ack number */
|
||||
tcp_seq iss; /* initial send sequence number */
|
||||
tcp_seq irs; /* initial receive sequence number */
|
||||
|
||||
tcp_seq rcv_nxt; /* receive next */
|
||||
tcp_seq rcv_adv; /* advertised window */
|
||||
uint64_t rcv_wnd; /* receive window */
|
||||
tcp_seq rcv_up; /* receive urgent pointer */
|
||||
|
||||
uint64_t snd_wnd; /* send window */
|
||||
uint64_t snd_cwnd; /* congestion-controlled window */
|
||||
// uint64_t snd_spare1; /* unused */
|
||||
uint64_t snd_ssthresh; /* snd_cwnd size threshold for
|
||||
* for slow start exponential to
|
||||
* linear switch
|
||||
*/
|
||||
// uint64_t snd_spare2; /* unused */
|
||||
tcp_seq snd_recover; /* for use in NewReno Fast Recovery */
|
||||
|
||||
uint32_t t_maxopd; /* mss plus options */
|
||||
|
||||
uint32_t t_rcvtime; /* inactivity time */
|
||||
uint32_t t_starttime; /* time connection was established */
|
||||
uint32_t t_rtttime; /* RTT measurement start time */
|
||||
tcp_seq t_rtseq; /* sequence number being timed */
|
||||
|
||||
// uint32_t t_bw_spare1; /* unused */
|
||||
// tcp_seq t_bw_spare2; /* unused */
|
||||
|
||||
int t_rxtcur; /* current retransmit value (ticks) */
|
||||
uint32_t t_maxseg; /* maximum segment size */
|
||||
int t_srtt; /* smoothed round-trip time */
|
||||
int t_rttvar; /* variance in round-trip time */
|
||||
|
||||
int t_rxtshift; /* log(2) of rexmt exp. backoff */
|
||||
uint32_t t_rttmin; /* minimum rtt allowed */
|
||||
uint32_t t_rttbest; /* best rtt we've seen */
|
||||
uint64_t t_rttupdated; /* number of times rtt sampled */
|
||||
uint64_t max_sndwnd; /* largest window peer has offered */
|
||||
|
||||
int t_softerror; /* possible error not yet reported */
|
||||
/* out-of-band data */
|
||||
// char t_oobflags; /* have some */
|
||||
// char t_iobc; /* input character */
|
||||
/* RFC 1323 variables */
|
||||
uint8_t snd_scale; /* window scaling for send window */
|
||||
uint8_t rcv_scale; /* window scaling for recv window */
|
||||
uint8_t request_r_scale; /* pending window scaling */
|
||||
u_int32_t ts_recent; /* timestamp echo data */
|
||||
uint32_t ts_recent_age; /* when last updated */
|
||||
u_int32_t ts_offset; /* our timestamp offset */
|
||||
|
||||
tcp_seq last_ack_sent;
|
||||
/* experimental */
|
||||
uint64_t snd_cwnd_prev; /* cwnd prior to retransmit */
|
||||
uint64_t snd_ssthresh_prev; /* ssthresh prior to retransmit */
|
||||
tcp_seq snd_recover_prev; /* snd_recover prior to retransmit */
|
||||
// int t_sndzerowin; /* zero-window updates sent */
|
||||
uint32_t t_badrxtwin; /* window for retransmit recovery */
|
||||
uint8_t snd_limited; /* segments limited transmitted */
|
||||
|
||||
/* SACK related state */
|
||||
int snd_numholes; /* number of holes seen by sender */
|
||||
TAILQ_HEAD(sackhole_head, sackhole) snd_holes;
|
||||
/* SACK scoreboard (sorted) */
|
||||
tcp_seq snd_fack; /* last seq number(+1) sack'd by rcv'r*/
|
||||
int rcv_numsacks; /* # distinct sack blks present */
|
||||
struct sackblk sackblks[MAX_SACK_BLKS]; /* seq nos. of sack blocks */
|
||||
tcp_seq sack_newdata; /* New data xmitted in this recovery
|
||||
episode starts at this seq number */
|
||||
struct sackhint sackhint; /* SACK scoreboard hint */
|
||||
|
||||
int t_rttlow; /* smallest observed RTT */
|
||||
#if 0
|
||||
u_int32_t rfbuf_ts; /* recv buffer autoscaling timestamp */
|
||||
int rfbuf_cnt; /* recv buffer autoscaling byte count */
|
||||
struct toedev *tod; /* toedev handling this connection */
|
||||
#endif
|
||||
// int t_sndrexmitpack; /* retransmit packets sent */
|
||||
// int t_rcvoopack; /* out-of-order packets received */
|
||||
// void *t_toe; /* TOE pcb pointer */
|
||||
int t_bytes_acked; /* # bytes acked during current RTT */
|
||||
// struct cc_algo *cc_algo; /* congestion control algorithm */
|
||||
struct cc_var ccv[1]; /* congestion control specific vars */
|
||||
#if 0
|
||||
struct osd *osd; /* storage for Khelp module data */
|
||||
#endif
|
||||
#if 0 // Just use the default values for the KEEP constants (see tcp_timer.h)
|
||||
uint32_t t_keepinit; /* time to establish connection */
|
||||
uint32_t t_keepidle; /* time before keepalive probes begin */
|
||||
uint32_t t_keepintvl; /* interval between keepalives */
|
||||
uint32_t t_keepcnt; /* number of keepalives before close */
|
||||
#endif
|
||||
#if 0 // Don't support TCP Segment Offloading
|
||||
uint32_t t_tsomax; /* TSO total burst length limit in bytes */
|
||||
uint32_t t_tsomaxsegcount; /* TSO maximum segment count */
|
||||
uint32_t t_tsomaxsegsize; /* TSO maximum segment size in bytes */
|
||||
#endif
|
||||
// uint32_t t_pmtud_saved_maxopd; /* pre-blackhole MSS */
|
||||
uint32_t t_flags2; /* More tcpcb flags storage */
|
||||
|
||||
// uint32_t t_ispare[8]; /* 5 UTO, 3 TBD */
|
||||
// void *t_pspare2[4]; /* 1 TCP_SIGNATURE, 3 TBD */
|
||||
#if 0
|
||||
#if defined(_KERNEL) && defined(TCPPCAP)
|
||||
struct mbufq t_inpkts; /* List of saved input packets. */
|
||||
struct mbufq t_outpkts; /* List of saved output packets. */
|
||||
#ifdef _LP64
|
||||
uint64_t _pad[0]; /* all used! */
|
||||
#else
|
||||
uint64_t _pad[2]; /* 2 are available */
|
||||
#endif /* _LP64 */
|
||||
#else
|
||||
uint64_t _pad[6];
|
||||
#endif /* defined(_KERNEL) && defined(TCPPCAP) */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Defined in tcp_subr.c. */
|
||||
void initialize_tcb(struct tcpcb* tp);
|
||||
|
||||
/* Copied from the "dead" portions below. */
|
||||
|
||||
void tcp_init(void);
|
||||
void tcp_state_change(struct tcpcb *, int);
|
||||
tcp_seq tcp_new_isn(struct tcpcb *);
|
||||
struct tcpcb *tcp_close(struct tcpcb *);
|
||||
struct tcpcb *tcp_drop(struct tcpcb *, int);
|
||||
void
|
||||
tcp_respond(struct tcpcb *tp, otInstance* instance, struct ip6_hdr* ip6gen, struct tcphdr *thgen,
|
||||
tcp_seq ack, tcp_seq seq, int flags);
|
||||
void tcp_setpersist(struct tcpcb *);
|
||||
void cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type);
|
||||
|
||||
/* Added, since there is no header file for tcp_usrreq.c. */
|
||||
int tcp6_usr_connect(struct tcpcb* tp, struct sockaddr_in6* sinp6);
|
||||
int tcp_usr_send(struct tcpcb* tp, int moretocome, struct otLinkedBuffer* data, size_t extendby);
|
||||
int tcp_usr_rcvd(struct tcpcb* tp);
|
||||
int tcp_usr_shutdown(struct tcpcb* tp);
|
||||
void tcp_usr_abort(struct tcpcb* tp);
|
||||
|
||||
/*
|
||||
* Flags and utility macros for the t_flags field.
|
||||
*/
|
||||
#define TF_ACKNOW 0x000001 /* ack peer immediately */
|
||||
#define TF_DELACK 0x000002 /* ack, but try to delay it */
|
||||
#define TF_NODELAY 0x000004 /* don't delay packets to coalesce */
|
||||
#define TF_NOOPT 0x000008 /* don't use tcp options */
|
||||
#define TF_SENTFIN 0x000010 /* have sent FIN */
|
||||
#define TF_REQ_SCALE 0x000020 /* have/will request window scaling */
|
||||
#define TF_RCVD_SCALE 0x000040 /* other side has requested scaling */
|
||||
#define TF_REQ_TSTMP 0x000080 /* have/will request timestamps */
|
||||
#define TF_RCVD_TSTMP 0x000100 /* a timestamp was received in SYN */
|
||||
#define TF_SACK_PERMIT 0x000200 /* other side said I could SACK */
|
||||
#define TF_NEEDSYN 0x000400 /* send SYN (implicit state) */
|
||||
#define TF_NEEDFIN 0x000800 /* send FIN (implicit state) */
|
||||
#define TF_NOPUSH 0x001000 /* don't push */
|
||||
#define TF_PREVVALID 0x002000 /* saved values for bad rxmit valid */
|
||||
#define TF_MORETOCOME 0x010000 /* More data to be appended to sock */
|
||||
#define TF_LQ_OVERFLOW 0x020000 /* listen queue overflow */
|
||||
#define TF_LASTIDLE 0x040000 /* connection was previously idle */
|
||||
#define TF_RXWIN0SENT 0x080000 /* sent a receiver win 0 in response */
|
||||
#define TF_FASTRECOVERY 0x100000 /* in NewReno Fast Recovery */
|
||||
#define TF_WASFRECOVERY 0x200000 /* was in NewReno Fast Recovery */
|
||||
#define TF_SIGNATURE 0x400000 /* require MD5 digests (RFC2385) */
|
||||
#define TF_FORCEDATA 0x800000 /* force out a byte */
|
||||
#define TF_TSO 0x1000000 /* TSO enabled on this connection */
|
||||
#define TF_TOE 0x2000000 /* this connection is offloaded */
|
||||
#define TF_ECN_PERMIT 0x4000000 /* connection ECN-ready */
|
||||
#define TF_ECN_SND_CWR 0x8000000 /* ECN CWR in queue */
|
||||
#define TF_ECN_SND_ECE 0x10000000 /* ECN ECE in queue */
|
||||
#define TF_CONGRECOVERY 0x20000000 /* congestion recovery mode */
|
||||
#define TF_WASCRECOVERY 0x40000000 /* was in congestion recovery */
|
||||
|
||||
#define IN_FASTRECOVERY(t_flags) (t_flags & TF_FASTRECOVERY)
|
||||
#define ENTER_FASTRECOVERY(t_flags) t_flags |= TF_FASTRECOVERY
|
||||
#define EXIT_FASTRECOVERY(t_flags) t_flags &= ~TF_FASTRECOVERY
|
||||
|
||||
#define IN_CONGRECOVERY(t_flags) (t_flags & TF_CONGRECOVERY)
|
||||
#define ENTER_CONGRECOVERY(t_flags) t_flags |= TF_CONGRECOVERY
|
||||
#define EXIT_CONGRECOVERY(t_flags) t_flags &= ~TF_CONGRECOVERY
|
||||
|
||||
#define IN_RECOVERY(t_flags) (t_flags & (TF_CONGRECOVERY | TF_FASTRECOVERY))
|
||||
#define ENTER_RECOVERY(t_flags) t_flags |= (TF_CONGRECOVERY | TF_FASTRECOVERY)
|
||||
#define EXIT_RECOVERY(t_flags) t_flags &= ~(TF_CONGRECOVERY | TF_FASTRECOVERY)
|
||||
|
||||
#define BYTES_THIS_ACK(tp, th) (th->th_ack - tp->snd_una)
|
||||
|
||||
/*
|
||||
* Flags for the t_oobflags field.
|
||||
*/
|
||||
#define TCPOOB_HAVEDATA 0x01
|
||||
#define TCPOOB_HADDATA 0x02
|
||||
|
||||
#ifdef TCP_SIGNATURE
|
||||
/*
|
||||
* Defines which are needed by the xform_tcp module and tcp_[in|out]put
|
||||
* for SADB verification and lookup.
|
||||
*/
|
||||
#define TCP_SIGLEN 16 /* length of computed digest in bytes */
|
||||
#define TCP_KEYLEN_MIN 1 /* minimum length of TCP-MD5 key */
|
||||
#define TCP_KEYLEN_MAX 80 /* maximum length of TCP-MD5 key */
|
||||
/*
|
||||
* Only a single SA per host may be specified at this time. An SPI is
|
||||
* needed in order for the KEY_ALLOCSA() lookup to work.
|
||||
*/
|
||||
#define TCP_SIG_SPI 0x1000
|
||||
#endif /* TCP_SIGNATURE */
|
||||
|
||||
/*
|
||||
* Flags for PLPMTU handling, t_flags2
|
||||
*/
|
||||
#define TF2_PLPMTU_BLACKHOLE 0x00000001 /* Possible PLPMTUD Black Hole. */
|
||||
#define TF2_PLPMTU_PMTUD 0x00000002 /* Allowed to attempt PLPMTUD. */
|
||||
#define TF2_PLPMTU_MAXSEGSNT 0x00000004 /* Last seg sent was full seg. */
|
||||
|
||||
/*
|
||||
* Structure to hold TCP options that are only used during segment
|
||||
* processing (in tcp_input), but not held in the tcpcb.
|
||||
* It's basically used to reduce the number of parameters
|
||||
* to tcp_dooptions and tcp_addoptions.
|
||||
* The binary order of the to_flags is relevant for packing of the
|
||||
* options in tcp_addoptions.
|
||||
*/
|
||||
struct tcpopt {
|
||||
u_int64_t to_flags; /* which options are present */
|
||||
#define TOF_MSS 0x0001 /* maximum segment size */
|
||||
#define TOF_SCALE 0x0002 /* window scaling */
|
||||
#define TOF_SACKPERM 0x0004 /* SACK permitted */
|
||||
#define TOF_TS 0x0010 /* timestamp */
|
||||
#define TOF_SIGNATURE 0x0040 /* TCP-MD5 signature option (RFC2385) */
|
||||
#define TOF_SACK 0x0080 /* Peer sent SACK option */
|
||||
#define TOF_MAXOPT 0x0100
|
||||
u_int32_t to_tsval; /* new timestamp */
|
||||
u_int32_t to_tsecr; /* reflected timestamp */
|
||||
uint8_t *to_sacks; /* pointer to the first SACK blocks */
|
||||
uint8_t *to_signature; /* pointer to the TCP-MD5 signature */
|
||||
u_int16_t to_mss; /* maximum segment size */
|
||||
u_int8_t to_wscale; /* window scaling */
|
||||
u_int8_t to_nsacks; /* number of SACK blocks */
|
||||
u_int32_t to_spare; /* UTO */
|
||||
};
|
||||
|
||||
/*
|
||||
* Flags for tcp_dooptions.
|
||||
*/
|
||||
#define TO_SYN 0x01 /* parse SYN-only options */
|
||||
|
||||
struct hc_metrics_lite { /* must stay in sync with hc_metrics */
|
||||
uint64_t rmx_mtu; /* MTU for this path */
|
||||
uint64_t rmx_ssthresh; /* outbound gateway buffer limit */
|
||||
uint64_t rmx_rtt; /* estimated round trip time */
|
||||
uint64_t rmx_rttvar; /* estimated rtt variance */
|
||||
uint64_t rmx_bandwidth; /* estimated bandwidth */
|
||||
uint64_t rmx_cwnd; /* congestion window */
|
||||
uint64_t rmx_sendpipe; /* outbound delay-bandwidth product */
|
||||
uint64_t rmx_recvpipe; /* inbound delay-bandwidth product */
|
||||
};
|
||||
|
||||
/*
|
||||
* Used by tcp_maxmtu() to communicate interface specific features
|
||||
* and limits at the time of connection setup.
|
||||
*/
|
||||
struct tcp_ifcap {
|
||||
int ifcap;
|
||||
uint32_t tsomax;
|
||||
uint32_t tsomaxsegcount;
|
||||
uint32_t tsomaxsegsize;
|
||||
};
|
||||
|
||||
void tcp_mss(struct tcpcb *, int);
|
||||
void tcp_mss_update(struct tcpcb *, int, int, struct hc_metrics_lite *,
|
||||
struct tcp_ifcap *);
|
||||
|
||||
/*
|
||||
* The smoothed round-trip time and estimated variance
|
||||
* are stored as fixed point numbers scaled by the values below.
|
||||
* For convenience, these scales are also used in smoothing the average
|
||||
* (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed).
|
||||
* With these scales, srtt has 3 bits to the right of the binary point,
|
||||
* and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the
|
||||
* binary point, and is smoothed with an ALPHA of 0.75.
|
||||
*/
|
||||
#define TCP_RTT_SCALE 32 /* multiplier for srtt; 3 bits frac. */
|
||||
#define TCP_RTT_SHIFT 5 /* shift for srtt; 3 bits frac. */
|
||||
#define TCP_RTTVAR_SCALE 16 /* multiplier for rttvar; 2 bits */
|
||||
#define TCP_RTTVAR_SHIFT 4 /* shift for rttvar; 2 bits */
|
||||
#define TCP_DELTA_SHIFT 2 /* see tcp_input.c */
|
||||
|
||||
/* My definition of the max macro */
|
||||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
/*
|
||||
* The initial retransmission should happen at rtt + 4 * rttvar.
|
||||
* Because of the way we do the smoothing, srtt and rttvar
|
||||
* will each average +1/2 tick of bias. When we compute
|
||||
* the retransmit timer, we want 1/2 tick of rounding and
|
||||
* 1 extra tick because of +-1/2 tick uncertainty in the
|
||||
* firing of the timer. The bias will give us exactly the
|
||||
* 1.5 tick we need. But, because the bias is
|
||||
* statistical, we have to test that we don't drop below
|
||||
* the minimum feasible timer (which is 2 ticks).
|
||||
* This version of the macro adapted from a paper by Lawrence
|
||||
* Brakmo and Larry Peterson which outlines a problem caused
|
||||
* by insufficient precision in the original implementation,
|
||||
* which results in inappropriately large RTO values for very
|
||||
* fast networks.
|
||||
*/
|
||||
#define TCP_REXMTVAL(tp) \
|
||||
max((tp)->t_rttmin, (((tp)->t_srtt >> (TCP_RTT_SHIFT - TCP_DELTA_SHIFT)) \
|
||||
+ (tp)->t_rttvar) >> TCP_DELTA_SHIFT)
|
||||
|
||||
/* Copied from below. */
|
||||
static inline void
|
||||
tcp_fields_to_host(struct tcphdr *th)
|
||||
{
|
||||
|
||||
th->th_seq = ntohl(th->th_seq);
|
||||
th->th_ack = ntohl(th->th_ack);
|
||||
th->th_win = ntohs(th->th_win);
|
||||
th->th_urp = ntohs(th->th_urp);
|
||||
}
|
||||
|
||||
void tcp_twstart(struct tcpcb*);
|
||||
void tcp_twclose(struct tcpcb*, int);
|
||||
int tcp_twcheck(struct tcpcb*, struct tcphdr *, int);
|
||||
void tcp_dropwithreset(struct ip6_hdr* ip6, struct tcphdr *th, struct tcpcb *tp, otInstance* instance,
|
||||
int tlen, int rstreason);
|
||||
int tcp_input(struct ip6_hdr* ip6, struct tcphdr* th, otMessage* msg, struct tcpcb* tp, struct tcpcb_listen* tpl,
|
||||
struct signals* sig);
|
||||
int tcp_output(struct tcpcb *);
|
||||
void tcpip_maketemplate(struct tcpcb *, struct tcptemp*);
|
||||
void tcpip_fillheaders(struct tcpcb *, otMessageInfo *, void *);
|
||||
uint64_t tcp_maxmtu6(struct tcpcb*, struct tcp_ifcap *);
|
||||
int tcp_addoptions(struct tcpopt *, uint8_t *);
|
||||
int tcp_mssopt(struct tcpcb*);
|
||||
int tcp_reass(struct tcpcb *, struct tcphdr *, int *, otMessage *, off_t, struct signals*);
|
||||
void tcp_sack_init(struct tcpcb *); // Sam: new function that I added
|
||||
void tcp_sack_doack(struct tcpcb *, struct tcpopt *, tcp_seq);
|
||||
void tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_laststart, tcp_seq rcv_lastend);
|
||||
void tcp_clean_sackreport(struct tcpcb *tp);
|
||||
void tcp_sack_adjust(struct tcpcb *tp);
|
||||
struct sackhole *tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt);
|
||||
void tcp_sack_partialack(struct tcpcb *, struct tcphdr *);
|
||||
void tcp_free_sackholes(struct tcpcb *tp);
|
||||
|
||||
#define tcps_rcvmemdrop tcps_rcvreassfull /* compat */0
|
||||
|
||||
/*
|
||||
* Identifiers for TCP sysctl nodes
|
||||
*/
|
||||
#define TCPCTL_DO_RFC1323 1 /* use RFC-1323 extensions */
|
||||
#define TCPCTL_MSSDFLT 3 /* MSS default */
|
||||
#define TCPCTL_STATS 4 /* statistics (read-only) */
|
||||
#define TCPCTL_RTTDFLT 5 /* default RTT estimate */
|
||||
#define TCPCTL_KEEPIDLE 6 /* keepalive idle timer */
|
||||
#define TCPCTL_KEEPINTVL 7 /* interval to send keepalives */
|
||||
#define TCPCTL_SENDSPACE 8 /* send buffer space */
|
||||
#define TCPCTL_RECVSPACE 9 /* receive buffer space */
|
||||
#define TCPCTL_KEEPINIT 10 /* timeout for establishing syn */
|
||||
#define TCPCTL_PCBLIST 11 /* list of all outstanding PCBs */
|
||||
#define TCPCTL_DELACKTIME 12 /* time before sending delayed ACK */
|
||||
#define TCPCTL_V6MSSDFLT 13 /* MSS default for IPv6 */
|
||||
#define TCPCTL_SACK 14 /* Selective Acknowledgement,rfc 2018 */
|
||||
#define TCPCTL_DROP 15 /* drop tcp connection */
|
||||
|
||||
#endif /* _NETINET_TCP_VAR_H_ */
|
||||
Vendored
+71
@@ -0,0 +1,71 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1991, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)types.h 8.6 (Berkeley) 2/19/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* samkumar: I've omitted definitions for u_char, u_short, u_int, etc., because
|
||||
* they come predefined by certain compilers, sometimes differently. I just
|
||||
* replaced all usages of these types in the code with the corresponding
|
||||
* standard integer types (uint8_t, uint16_t, etc.).
|
||||
*/
|
||||
|
||||
#ifndef _SYS_TYPES_H_
|
||||
#define _SYS_TYPES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t __uint8_t;
|
||||
typedef uint16_t __uint16_t;
|
||||
typedef uint32_t __uint32_t;
|
||||
typedef uint64_t __uint64_t;
|
||||
typedef int8_t __int8_t;
|
||||
typedef int16_t __int16_t;
|
||||
typedef int32_t __int32_t;
|
||||
typedef int64_t __int64_t;
|
||||
|
||||
typedef __uint8_t u_int8_t; /* unsigned integrals (deprecated) */
|
||||
typedef __uint16_t u_int16_t;
|
||||
typedef __uint32_t u_int32_t;
|
||||
typedef __uint64_t u_int64_t;
|
||||
|
||||
typedef __uint64_t u_quad_t; /* quads (deprecated) */
|
||||
typedef __int64_t quad_t;
|
||||
typedef quad_t * qaddr_t;
|
||||
|
||||
typedef char * caddr_t; /* core address */
|
||||
typedef const char * c_caddr_t; /* core address, pointer to const */
|
||||
|
||||
#endif
|
||||
Vendored
Vendored
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sam Kumar <[email protected]>
|
||||
* Copyright (c) 2018, University of California, Berkeley
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file defines the interface between TCPlp and the host network stack
|
||||
* (OpenThread, in this case). It is based on content taken from TCPlp,
|
||||
* modified to work with this port of TCPlp to OpenThread.
|
||||
*/
|
||||
|
||||
#ifndef TCPLP_H_
|
||||
#define TCPLP_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include "bsdtcp/ip6.h"
|
||||
#include "bsdtcp/tcp.h"
|
||||
#include "bsdtcp/tcp_fsm.h"
|
||||
#include "bsdtcp/tcp_timer.h"
|
||||
#include "bsdtcp/tcp_var.h"
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/message.h>
|
||||
|
||||
#define hz 1000 // number of ticks per second
|
||||
#define MICROS_PER_TICK 1000 // number of microseconds per tick
|
||||
|
||||
#define FRAMES_PER_SEG 5
|
||||
#define FRAMECAP_6LOWPAN (122 - 11 - 5)
|
||||
|
||||
#define IP6HDR_SIZE (2 + 1 + 1 + 16 + 16) // IPHC header (2) + Next header (1) + Hop count (1) + Dest. addr (16) + Src. addr (16)
|
||||
|
||||
#define RELOOKUP_REQUIRED -1
|
||||
#define CONN_LOST_NORMAL 0
|
||||
|
||||
struct signals {
|
||||
int links_popped;
|
||||
bool conn_established;
|
||||
bool recvbuf_notempty;
|
||||
bool rcvd_fin;
|
||||
};
|
||||
|
||||
/*
|
||||
* Functions that the TCP protocol logic can call to interact with the rest of
|
||||
* the system.
|
||||
*/
|
||||
otMessage* tcplp_sys_new_message(otInstance* instance);
|
||||
void tcplp_sys_free_message(otInstance* instance, otMessage* pkt);
|
||||
void tcplp_sys_send_message(otInstance* instance, otMessage* pkt, otMessageInfo* info);
|
||||
uint32_t tcplp_sys_get_ticks();
|
||||
uint32_t tcplp_sys_get_millis();
|
||||
void tcplp_sys_set_timer(struct tcpcb* tcb, uint8_t timer_flag, uint32_t delay);
|
||||
void tcplp_sys_stop_timer(struct tcpcb* tcb, uint8_t timer_flag);
|
||||
struct tcpcb* tcplp_sys_accept_ready(struct tcpcb_listen* tpl, struct in6_addr* addr, uint16_t port);
|
||||
bool tcplp_sys_accepted_connection(struct tcpcb_listen* tpl, struct tcpcb* accepted, struct in6_addr* addr, uint16_t port);
|
||||
void tcplp_sys_connection_lost(struct tcpcb* tcb, uint8_t errnum);
|
||||
void tcplp_sys_on_state_change(struct tcpcb* tcb, int newstate);
|
||||
void tcplp_sys_log(const char* format, ...);
|
||||
bool tcplp_sys_autobind(otInstance *aInstance, const otSockAddr *aPeer, otSockAddr *aToBind, bool aBindAddress, bool aBindPort);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // TCPLP_H_
|
||||
|
||||
Reference in New Issue
Block a user