379 lines
13 KiB
C
379 lines
13 KiB
C
/*-
|
|
* 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 "sys/queue.h"
|
|
#include "../lib/bitmap.h"
|
|
#include "../lib/cbuf.h"
|
|
#include "cc.h"
|
|
|
|
#include "tcp_const.h"
|
|
|
|
/*
|
|
* samkumar: This is rewritten to have the host network stack to generate the
|
|
* ISN with appropriate randomness.
|
|
*/
|
|
tcp_seq tcp_new_isn(struct tcpcb* tp) {
|
|
return (uint32_t) tcplp_sys_generate_isn();
|
|
}
|
|
|
|
/*
|
|
* 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", 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 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_off_x2 = (5 << TH_OFF_SHIFT);
|
|
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);
|
|
/* samkumar: original code for setting th_x2 and th_off, for reference. */
|
|
// nth->th_x2 = 0;
|
|
// nth->th_off = (sizeof (struct tcphdr) + optlen) >> 2;
|
|
nth->th_off_x2 = (sizeof(struct tcphdr) >> 2) << TH_OFF_SHIFT;
|
|
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);
|
|
}
|