📄 tcpin.c
字号:
#pragma O0 // yaxon add
/*
* FILENAME: tcp_in.c
*
* Copyright 1997- 2000 By InterNiche Technologies Inc. All rights reserved
* Version Note: modify by zealea_kuethy yaxon 2004.04
*
* MODULE: INET
*
* ROUTINES: m_tcpreass(), tcp_input(), tcp_dooptions(), tcp_xmit_timer(),
*
* PORTABLE: yes
*/
/* Additional Copyrights: */
/*
* Copyright (c) 1982, 1986, 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#include "ipport.h"
#include "mtcp.h"
#include "icmp.h" /* for icmp_destun() declaration */
#include "minip.h" /* (yaxon add) */
#define DebugTcpin 0xff
#if DebugTcpin <= 0x03
#include "uartdrv.h"
#endif
#include "ZPrint.h"
void tcp_wakeup(void *);/* (yaxon add) */
#define DEBUG_DROP 1
#ifdef DEBUG_DROP /* trace logic for dropped packets */
int dropline;
#define GOTO_DROP { dropline=__LINE__; goto drop; }
#define GOTO_DROPWITHRESET { dropline=__LINE__; goto dropwithreset; }
#else /* the production flavor: */
#define GOTO_DROP { goto drop; }
#define GOTO_DROPWITHRESET { goto dropwithreset; }
#endif
char tcpprintfs = 0;
char tcprexmtthresh = 3;
struct tcpiphdr tcp_saveti;
#ifdef DO_DELAY_ACKS
char _tcp_delay_ack = 1;
#else
char _tcp_delay_ack = 0;
#endif /* DO_DELAY_ACKS */
void tcp_xmit_timer(struct tcpcb * tp);
/* FUNCTION: m_tcpoptions()
*
* Handle TCP options. Only one we do is MSS.
*
* PARAM1: struct tcpcb * tp
* PARAM2: pointer to option string
* PARAM3: length of option string
*
* RETURNS: nothing
*/
void
m_tcpoptions(struct tcpcb * tp, char * opt, int optlen)
{
/* see if it's mss option and length is valid */
while(optlen >= 4)
{
/* we currently only support max seg size */
if(*opt == TCPOPT_MAXSEG)
{
/* set tcpcb mss to the lesser of passed MSS and our own local MSS */
tp->t_maxseg = *(u_short *)(opt + 2);
tp->t_maxseg = ntohs(tp->t_maxseg);
tp->t_maxseg = (u_short)MIN(tp->t_maxseg, TCP_MSS);
}
opt += 4;
optlen -= 4;
}
}
/* FUNCTION: m_tcpreass()
*
* Mini version of tcp_reass(). Puts passed packets in tcpcb's recevied
* packet queue. Any packets not in sequence are kept in the tp->oosq,
* out of sequence queue.
*
*
* PARAM1: struct tcpcb * tp
*
* RETURNS: void
*/
void
m_tcpreass(struct tcpcb * tp, struct tcphdr * ptcp, PACKET pkt)
{
int offset; /* offset of this pkt into rcv seq space */
PACKET tmp; /* scratch */
M_SOCK so; /* scratch */
struct tcpiphdr * ti;/* scratch */
int overlap; /* data overlap with next packet */
PACKET pktptr;
offset = (int)(ptcp->th_seq - tp->rcv_nxt);
so = (M_SOCK)(tp->t_inpcb);
#if DebugTcpin <= 0x03
Printu("m_tcpreass pkt->m_len:%d\toffset:%d\r\n",pkt->m_len,offset);
#endif
/* set flag to ACK received data */
if (_tcp_delay_ack)
tp->t_flags |= TF_DELACK;
else
tp->t_flags |= TF_ACKNOW;
#if DebugTcpin <= 0x03
Printu("2\t");
#endif
if((offset + (int)pkt->m_len) < 0) /* packet is a duplicate */
{
TCP_STAT_INC(tcps_rcvduppack);
TCP_STAT_ADD(tcps_rcvdupbyte, pkt->m_len );
#if DebugTcpin <= 0x03
Printu("2return\r\n");
#endif
return;
}
#if DebugTcpin <= 0x03
Printu("3\t");
#endif
if(offset > 0) /* packet is ahead of seq space */
{
ENTER_CRIT_SECTION(&so->oosq);
/* dtrap("tcpin 0\n");*/ /* (yaxon del) */
/* put packet in order in the oos queue */
tmp = so->oosq.p_head; /* start at head of queue */
if(tmp == NULL) /* no queued OOS packets yet, start que */
{
#if DebugTcpin <= 0x03
Printu("Empty list to insert\r\n");
#endif
so->oosq.p_head = so->oosq.p_tail = pkt;
so->oosq.sb_cc = pkt->m_len;
pkt->m_next = NULL;
}
else /* add to existing OOS queue */
{
while(offset > (int)tmp->m_len) /* loop to packet before new one */
{
//Printu("offset:%d\tm_len:%d\ttmp->m_next:%x\r\n",offset,tmp->m_len,tmp->m_next);
offset -= tmp->m_len;
if((tmp->m_next) == NULL) { //modify by zealea 2004.04
//Printu("(tmp->m_next) == NULL\r\n");
break;
}
tmp = tmp->m_next;
}
/* tmp is now packet in data space prior to new one */
pkt->m_next = tmp->m_next; /* insert pkt into oosq */
tmp->m_next = pkt;
so->oosq.sb_cc += pkt->m_len;
}
EXIT_CRIT_SECTION(&so->oosq);
TCP_STAT_INC(tcps_rcvoopack);
TCP_STAT_ADD(tcps_rcvoobyte, pkt->m_len);
#if DebugTcpin <= 0x03
Printu("3 return\r\n");
#endif
return;
}
/* fall to here if he packet contains the next data in the seq space.
* The packet may also contain previously received data at the front.
*/
#if DebugTcpin <= 0x03
Printu("4\t");
#endif
if(offset < 0) /* packet contains some new data at end, trim it */
{
#if DebugTcpin <= 0x03
Printu("pkt->m_len:%d\toffset:%d\r\n",pkt->m_len,offset);
#endif
pkt->m_data += offset;
pkt->m_len -= offset;
TCP_STAT_ADD(tcps_rcvdupbyte, -((long)offset));
}
put_soq(&so->rcvdq, pkt);
tp->rcv_nxt += pkt->m_len;
/* see if we can process any Out of Order packets */
if(so->oosq.sb_cc)
{
ENTER_CRIT_SECTION(&so->oosq);
while(so->oosq.sb_cc)
{
/* dtrap("tcpin 1\n");*/ /* (yaxon del) */
#if DebugTcpin <= 0x03
Printu("so->oosq.sb_cc:%d\r\n",so->oosq.sb_cc);
#endif
tmp = (PACKET)(so->oosq.p_head);
ti = (struct tcpiphdr *)(tmp->m_next->nb_buff + MaxLnh);
overlap = (int)((ptcp->th_seq + pkt->m_len) - ti->ti_seq);
#if DebugTcpin <= 0x03
Printu("overlap:%d\tpkt->m_len:%d\tptcp->th_seq:%d\r\n",overlap,pkt->m_len,ptcp->th_seq);
#endif
if(overlap >= 0)
{
/* see if next packet is completely covered by new one */
if(overlap > (int)tmp->m_len)
{
pktptr = get_soq(&so->oosq);
#if DebugTcpin <= 0x03
Printu("get_soq sb_cc:%d\r\n",so->oosq.sb_cc);
#endif
if(pktptr==NULL){ //modify by zealea 2004.04
#if DebugTcpin <= 0x03
Printu("non error\r\n");
#endif
break;
}
tcp_pktfree(pktptr); /* dump next oosq pkt */
continue;
}
/* see if next packet is parially covered by new one */
if(overlap > 0)
{
/* adjust data and move tmp from oosq to rcvdq. The data adjustment
* makes tmp's tcp header seq ovsolete, but that;s OK since we
* don't need it anymore once it's in rcvdq.
*/
tmp->m_data += overlap;
tmp->m_len -= overlap;
#if DebugTcpin <= 0x03
Printu("overlaptmp->m_len:%d\r\n",tmp->m_len);
#endif
}
/* get here if data in tmp comes exactly after data in pkt */
pktptr = get_soq(&so->oosq); //modify by zealea 2004.04
if(pktptr) put_soq(&so->rcvdq, pktptr); /* move tmp to rvcdq */
#if DebugTcpin <= 0x03
Printu("put_soq sb_cc:%d\r\n",so->oosq.sb_cc);
#endif
}
else /* next packet in oosq still in future seq numbers */
break;
}
EXIT_CRIT_SECTION(&so->oosq);
}
#if DebugTcpin <= 0x03
Printu("5\r\n");
#endif
tcp_wakeup(&so->rcvdq); /* wake any sockets waiting for recv */
return;
}
/* FUNCTION: tcp_rcv()
*
* TCP input routine, follows pages 65-76 of the
* protocol specification dated September, 1981 very closely.
*
*
* PARAM1: struct mbuf *m0
* PARAM2: unsigned ifindex
*
* RETURNS: int; always SUCCESS (0)
*/
int
tcp_rcv(PACKET pkt)
{
struct tcphdr * ptcp;
struct ip * pip;
struct tcpcb * tp = 0;
M_SOCK so = NULL;
ip_addr mask;
long iss = 0;
char * opts;
int optlen = 0;
int len, tlen, off;
int tiflags;
int todrop, acked, ourfinisacked, needoutput = 0;
int dropsocket = 0;
#ifdef DO_TCPTRACE
int ostate;
#endif
#if DebugTcpin <= 0x03
Printu("tcp0\t");
#endif
TCP_STAT_INC(tcps_rcvtotal);
TCP_MIB_INC(tcpInSegs); /* keep MIB stats */
pip = (struct ip *)pkt->nb_prot;
if (pkt->nb_plen < ((sizeof (struct ip) + sizeof (struct tcphdr))))
{
TCP_STAT_INC(tcps_rcvshort);
GOTO_DROP;
}
ptcp = (struct tcphdr *)ip_data(pip);
if (tcp_cksum(pip) != ptcp->th_sum)
{
TCP_MIB_INC(tcpInErrs); /* keep MIB stats */
TCP_STAT_INC(tcps_rcvbadsum); /* keep BSD stats */
GOTO_DROP;
}
tlen = htons(pip->ip_len); /* this was fudged by IP layer */
/* Check that TCP offset makes sense, */
off = GET_TH_OFF((*ptcp)) << 2;
if (off < sizeof (struct tcphdr) || off > tlen)
{
#ifdef DO_TCPTRACE
tcp_trace("tcp off: src %x off %d\n", ti->ti_src, off);
#endif
TCP_STAT_INC(tcps_rcvbadoff);
TCP_MIB_INC(tcpInErrs); /* keep MIB stats */
GOTO_DROP;
}
tlen -= (int)off;
pip->ip_len = (u_short)tlen; /* ip_len is now length of tcp data */
/* set options pointer and length */
if (off > sizeof (struct tcphdr))
{
opts = (char *)(ptcp + 1);
optlen = off - sizeof (struct tcphdr);
if (pkt->nb_plen < sizeof(struct ip) + off)
{
TCP_STAT_INC(tcps_rcvshort);
GOTO_DROP;
}
}
else /* no options in packet */
{
opts = NULL; /* use opts as flag for option presence */
optlen = 0;
}
tiflags = ptcp->th_flags;
/* Drop TCP and IP headers; and any TCP options. */
// Printu("recv:nb_plen:%d\t",pkt->nb_plen);
pkt->nb_prot += (TCPIPHDRSZ + optlen);
pkt->nb_plen -= (TCPIPHDRSZ + optlen);
/* Set up packet's TCP members. Future reference to TCP data should
* be done via these:
*/
pkt->m_data = pkt->nb_prot;
pkt->m_len = pkt->nb_plen;
// Printu("recv:m_len:%d\r\n",pkt->m_len);
/* Convert TCP protocol specific fields to host format. */
#if(BYTE_ORDER == LITTLE_ENDIAN)
ptcp->th_seq = ntohl(ptcp->th_seq);
ptcp->th_ack = ntohl(ptcp->th_ack);
ptcp->th_win = ntohs(ptcp->th_win);
ptcp->th_urp = ntohs(ptcp->th_urp);
#endif
#ifdef DO_TCPTRACE
tcp_trace("TCPIN: S:%08lx A:%08lx", ptcp->th_seq, ptcp->th_ack);
tcp_trace(" : W:%04x U:%04x F:%02x", ptcp->th_win, ptcp->th_urp, tiflags);
#endif
#if DebugTcpin <= 0x03
Printu("tcp1\t");
#endif
/* find the socket for the segment */
findpcb:
so = so_lookup(pip, ptcp);
if(so == NULL)
{
/* no socket, send ICMP "desination unreachable" packet */
#if DebugTcpin <= 0x03
Printu("====icmp_destun====\r\n");
#endif
icmp_destun(pip->ip_src, pip, DSTPORT, pkt->net);
GOTO_DROPWITHRESET;
}
/*
* If the state is CLOSED (i.e., TCB does not exist) then
* all data in the incoming segment is discarded.
* If the TCB exists but is in CLOSED state, it is embryonic,
* but should either do a listen or a connect soon.
*/
tp = so->tp;
if (tp == NULL)
GOTO_DROPWITHRESET;
if (tp->t_state == TCPS_CLOSED)
GOTO_DROP;
#ifdef DO_TCPTRACE
if (so->so_options & SO_DEBUG)
{
ostate = tp->t_state;
tcp_saveti = *ti;
}
#endif
/* see if the matched socket is listening for a new connection */
if (tp->t_state == TCPS_LISTEN)
{
M_SOCK so_new;
M_SOCK so_tmp;
struct tcpcb * tp_new;
/* clone the socket and the tcpcb for new connection. We DONT
* call m_socket() for this since the NET_RESID is already locked
* If it's being used in this build.
*/
so_new = (M_SOCK)SOC_ALLOC(sizeof(struct msocket));
if (so_new == NULL)
GOTO_DROP;
putq(&msoq, so_new); /* put new socket in queue */
/* copy listen socket data into new socket. */
so_tmp = so_new->next; /* save the link first */
MEMCPY(so_new, so, sizeof(struct msocket));
so_new->next = so_tmp; /* restore the link */
so = so_new; /* make the socket the one to use */
tp_new = m_newtcpcb(so);
if(tp_new == NULL)
{
m_delsocket(so);
GOTO_DROP;
}
tp = tp_new;
tp->t_state = TCPS_LISTEN;
/*
* Mark socket as temporary until we're
* committed to keeping it. The code at
* ``drop'' and ``dropwithreset'' check the
* flag dropsocket to see if the temporary
* socket created here should be discarded.
* We mark the socket as discardable until
* we're committed to it below in TCPS_LISTEN.
*/
dropsocket++;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -