📄 tcp_fsm.c
字号:
tcp_ProcessData (s, tcp, len, flags);
if (s->missed_seg[0]) /* must retransmit to get all data */
return (1);
if (flags & tcp_FlagFIN)
s->locflags |= LF_GOT_FIN;
if ((flags & flag_SYNACK) == flag_SYNACK &&
ack == s->seqnum && seq == s->acknum)
{
s->acknum++;
s->flags = tcp_FlagACK;
s->unhappy = FALSE; /* don't send anything */
s->state = tcp_StateTIMEWT;
s->timeout = set_timeout (tcp_TIMEWT_TO);
TCP_SEND (s);
return (0);
}
return (1);
}
/*
* CLOSING state
*/
static int tcp_closing_state (tcp_Socket **sp, const in_Header *ip,
tcp_Header *tcp, int flags)
{
tcp_Socket *s = *sp;
if ((flags & flag_SYNACK) == tcp_FlagACK) /* ACK, no FIN */
{
/* Per FINWT1 above, tcp->acknum should be s->seqnum+1,
* which should cause us to bump s->seqnum to match
*/
// !! if ((tcp->acknum >= intel(s->seqnum) + 1) &&
if (((long)(intel(tcp->acknum) - s->seqnum) > 0) && /* AGW - moved intel() so +1 OK 6th Jan 2001 */
(tcp->seqnum == intel(s->acknum)))
{
s->seqnum++;
s->state = tcp_StateTIMEWT;
s->unhappy = FALSE;
s->timeout = set_timeout (tcp_TIMEWT_TO);
}
}
ARGSUSED (ip);
return (1);
}
/*
* LASTACK state
*/
static int tcp_lastack_state (tcp_Socket **sp, const in_Header *ip,
tcp_Header *tcp, int flags)
{
tcp_Socket *s = *sp;
if (flags & tcp_FlagFIN)
{
/* they lost our two packets, back up
*/
s->locflags |= LF_GOT_FIN;
s->flags = flag_SYNACK;
TCP_SEND (s);
s->unhappy = TRUE;
return (0);
}
//!! if ((intel(tcp->acknum) == (s->seqnum + 1)) &&
if (((long)(intel(tcp->acknum) - s->seqnum) > 0) && /* AGW allow for any later acks 6th Jan 2001 */
(intel(tcp->seqnum) == s->acknum))
{
s->state = tcp_StateCLOSED; /* no 2msl necessary */
s->unhappy = FALSE; /* we're done */
return (0);
}
ARGSUSED (ip);
return (1);
}
/*
* TIMEWAIT state
*/
static int tcp_timewt_state (tcp_Socket **sp, const in_Header *ip,
tcp_Header *tcp, int flags)
{
tcp_Socket *s = *sp;
if ((flags & flag_SYNACK) == flag_SYNACK)
{
/* our peer needs an ack
*/
s->flags = tcp_FlagACK;
s->unhappy = FALSE;
s->state = tcp_StateCLOSED; /* support 2 msl in RST code */
TCP_SEND (s);
}
ARGSUSED (ip);
ARGSUSED (tcp);
return (1);
}
/*
* Process the data in an incoming packet.
* Called from all states where incoming data can be received:
* SYNSENT, ESTAB, ESTCL, CLOSWT, FIN-WAIT-1 and FIN-WAIT-2
*/
static void tcp_ProcessData (tcp_Socket *s, tcp_Header *tcp, int len, int flags)
{
long ldiff, tmpldiff;
int diff, tmpdiff, data_ofs;
BYTE *data;
if (s->stress > 0)
s->stress--;
s->window = intel16 (tcp->window);
if (s->window > MAX_WINDOW)
s->window = MAX_WINDOW;
ldiff = s->acknum - intel (tcp->seqnum);
if (flags & tcp_FlagSYN)
ldiff--; /* back up to 0 */
diff = abs ((int)ldiff);
/* find the data portion
*/
data_ofs = tcp->offset << 2; /* dword to byte offset */
data = (BYTE*) tcp + data_ofs;
if (data_ofs - sizeof(*tcp) > 0) /* process TCP options */
{
BYTE *opt = (BYTE*)(tcp+1);
while (opt < data)
{
switch (*opt)
{
case TCPOPT_EOL:
opt = data;
break;
case TCPOPT_NOP:
opt++;
break;
case TCPOPT_MAXSEG: /* we are very liberal on MSS stuff */
if (flags & tcp_FlagSYN)
{
WORD max_seg = intel16 (*(WORD*)(opt+2));
if (max_seg < s->max_seg)
s->max_seg = max_seg;
}
opt += 4;
break;
case TCPOPT_TIMESTAMP:
if ((flags & tcp_FlagSYN) ||
((flags & tcp_FlagACK) && ldiff >= 0)) /* only if SEQ-num ACKs new data */
{
s->ts_recent = intel (*(DWORD*)(opt+2));
s->ts_echo = intel (*(DWORD*)(opt+6));
s->locflags |= LF_RCVD_TSTMP;
}
opt += 10;
break;
case TCPOPT_WINDOW:
if (flags & tcp_FlagSYN)
{
s->recv_wscale = min (TCP_MAX_WINSHIFT, *(opt+2));
s->locflags |= LF_RCVD_SCALE;
}
opt += 4;
break;
#if 0
case TCPOPT_SACK_OK:
if (flags & tcp_FlagSYN)
s->locflags |= LF_SACK_PERMIT;
opt += 2;
break;
#endif
default: /* unknown options; type,length,... */
opt += *(opt+1);
}
}
}
len -= data_ofs; /* remove the header length */
#if 0 /* !!to-do */
/*
* Handle Out-of-Order data. Raise SIGURG.
*/
if ((flags & tcp_FlagURG) &&
tcp->urgent && intel16(tcp->urgent) < len)
{
intel16 (tcp->urgent) + intel16 (tcp->seqnum);
STAT (tcpstats.tcps_rcvoopack++);
STAT (tcpstats.tcps_rcvoobyte += len);
}
#endif
/*
* SYN/RST segments shouldn't carry any data.
*/
if ((flags & tcp_FlagSYN) == tcp_FlagSYN ||
(flags & tcp_FlagRST) == tcp_FlagRST)
return;
/* Handle any new data that increments the ACK number
*/
if (ldiff >= 0)
{
data += diff;
len -= diff;
if (s->protoHandler)
s->acknum += (*s->protoHandler) (s, data, len, NULL, NULL);
else
{
/* no handler, just dump to buffer, should be indexed,
* handles goofs limit receive size to our window
*/
if (s->rdatalen >= 0)
{
int room = s->maxrdatalen - s->rdatalen;
if (len > room)
len = room;
if (s->missed_seg[0]) /* don't write into missed segment */
{
tmpldiff = s->missed_seg[0] - s->acknum;
tmpdiff = abs ((int)tmpldiff);
if (tmpldiff >= 0 && len > tmpdiff)
len = tmpdiff;
}
if (len > 0)
{
s->acknum += len; /* our new ack begins at end of data */
memcpy (s->rdata + s->rdatalen, data, len);
s->rdatalen += len;
}
if (s->missed_seg[0] && s->missed_seg[0] == s->acknum)
{
tmpldiff = s->missed_seg[1] - s->acknum;
tmpdiff = abs ((int)tmpldiff);
if (tmpldiff > 0)
{
s->rdatalen += tmpdiff;
s->acknum = s->missed_seg[1];
}
s->missed_seg[0] = 0L;
s->missed_seg[1] = 0L;
}
}
}
s->unhappy = s->datalen ? TRUE : FALSE;
if (ldiff == 0 && s->unacked && chk_timeout(s->rtt_lasttran))
{
#if defined(USE_DEBUG)
if (debug_on > 1)
(*_printf)("data process timeout so set unacked "
"back to 0 from %u\r\n", s->unacked);
#endif
s->unacked = 0;
STAT (tcpstats.tcps_persistdrop++); /* !! a better counter? */
}
}
else /* handle one out-of-segment packet */
{
DWORD seqnum = intel (tcp->seqnum);
#if 0
/* S. Lawson - no out-of-sequence processing of FIN flag
*/
*flags &= ~tcp_FlagFIN;
#endif
if (s->missed_seg[0] == 0L) /* just dropped a segment */
{
len = min (s->maxrdatalen - s->rdatalen - diff, len);
if (len > 0)
{
memcpy (s->rdata + s->rdatalen + diff, data, len);
s->missed_seg[0] = s->missed_seg[1] = seqnum;
s->missed_seg[1] += len;
}
}
else /* haven't seen missing segment yet */
{
tmpldiff = s->missed_seg[0] - seqnum;
tmpdiff = abs ((int)tmpldiff);
if (tmpldiff > 0 && len >= tmpdiff) /* prepend bytes to fragment */
{
memcpy (s->rdata + s->rdatalen + diff, data, tmpdiff);
s->missed_seg[0] -= tmpdiff;
}
tmpldiff = seqnum + len - s->missed_seg[1];
tmpdiff = abs ((int)tmpldiff);
/* append bytes touching fragment
*/
if (tmpldiff > 0)
{
tmpldiff = s->missed_seg[1] - seqnum;
if (tmpldiff >= 0)
{
/* packet source offset
*/
int dst, src = abs ((int)tmpldiff);
tmpldiff = s->missed_seg[1] - s->acknum;
/* buffer destination offset
*/
dst = abs ((int)tmpldiff);
/* length to move
*/
tmpdiff = min (s->maxrdatalen - s->rdatalen - dst, tmpdiff);
if (tmpdiff > 0)
{
memcpy (s->rdata + s->rdatalen + dst, data + src, tmpdiff);
s->missed_seg[1] += tmpdiff;
}
}
}
}
}
}
/*
* Process the ACK value in received packet, but only if it falls within
* current window. Discard queued data that have been acknowledged.
*/
static int tcp_ProcessAck (tcp_Socket *s, tcp_Header *tcp, long *unacked)
{
long ldiff = (long) (intel(tcp->acknum) - s->seqnum);
int diff = (int) ldiff;
if (unacked)
*unacked = ldiff;
if (ldiff >= 0 && diff <= s->datalen)
{
if (s->queuelen)
{
s->queue += diff;
s->queuelen -= diff;
}
else if (diff < s->datalen)
movmem (s->data+diff, s->data, s->datalen-diff);
s->datalen -= diff;
s->unacked -= diff;
s->seqnum += ldiff;
return (1);
}
return (0);
}
/*
* Format and send a reset tcp packet
*/
int _tcp_reset (tcp_Socket *s, const in_Header *his_ip, tcp_Header *old_tcp,
const char *file, unsigned line)
{
#include <sys/packon.h>
struct packet {
in_Header ip;
tcp_Header tcp;
WORD options[2];
} *pkt;
#include <sys/packoff.h>
static DWORD next_RST_time = 0UL;
tcp_PseudoHeader ph;
BYTE oldflags;
in_Header *ip;
tcp_Header *tcp;
int temp;
/* see RFC 793 page 65 for details
*/
if (next_RST_time && !chk_timeout(next_RST_time))
return (-1);
next_RST_time = set_timeout (tcp_RST_TIME);
oldflags = old_tcp->flags;
if (oldflags & tcp_FlagRST)
return (-1);
if (oldflags & tcp_FlagACK) /* ACK */
{
old_tcp->seqnum = old_tcp->acknum;
old_tcp->acknum = 0;
oldflags = tcp_FlagRST;
}
else if ((oldflags & flag_SYNACK) == tcp_FlagSYN) /* SYN, no ACK */
{
old_tcp->acknum = intel (intel(old_tcp->seqnum) + 1);
old_tcp->seqnum = 0;
oldflags = tcp_FlagACK | tcp_FlagRST;
}
else
{
temp = intel16 (his_ip->length) - in_GetHdrLen (his_ip);
old_tcp->acknum = intel (intel(old_tcp->seqnum) + temp);
old_tcp->seqnum = 0;
oldflags = tcp_FlagRST;
}
if (s && (s->locflags & LF_NOPUSH))
oldflags &= ~tcp_FlagPUSH;
pkt = (struct packet*) _eth_formatpacket (MAC_SRC(his_ip), IP_TYPE);
ip = &pkt->ip;
tcp = &pkt->tcp;
/* tcp header
*/
tcp->srcPort = old_tcp->dstPort;
tcp->dstPort = old_tcp->srcPort;
tcp->seqnum = old_tcp->seqnum;
tcp->acknum = old_tcp->acknum;
tcp->window = 0;
tcp->flags = (oldflags | tcp_FlagRST);
tcp->unused = 0;
tcp->offset = sizeof(*tcp) / 4;
tcp->checksum = 0;
tcp->urgent = 0;
memset (&ph, 0, sizeof(ph));
ph.src = his_ip->destination; /* already network order */
ph.dst = his_ip->source;
ph.protocol = TCP_PROTO;
ph.length = intel16 (sizeof(*tcp));
ph.checksum = checksum (tcp, sizeof(*tcp));
tcp->checksum = ~checksum (&ph, sizeof(ph));
return _ip_output (ip, ph.src, ph.dst, TCP_PROTO,
s ? s->ttl : _default_ttl,
his_ip->tos, 0, sizeof(*tcp), s, file, line);
}
#endif /* !USE_UDP_ONLY */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -