📄 tcp_ip.c
字号:
// clear all flags, stop timers etc.
TCP_Flags = 0;
}
// clear tx-flag
TCP_TransmitControl &= ~TCP_SEND_FRAME1;
}
}
/******************************************************************************
* TCP_IP_STACK: TCP_ProcessEthBroadcastFrame()
*
* Purpose:
* handles an incoming broadcast frame to prepare ARP reply
*
* Actions:
*
*****************************************************************************/
MC void TCP_Proc_EthBroadcast_Frame()
{
WORD TargetIP[2];
WORD* data = (WORD*) LAN_rx_packet.data;
WORD cmp[5];
//check protocol if (LAN_hdr.Protocol == FRAME_ARP)
if (data[6] == FRAME_ARP)
{
// store sender's MAC
memcpy(&TCP_Recd_Frame_MAC, data+(ETH_SA_OFS>>1), 6);
// offset pointer by 6 for ARP
data += (ETH_TYPE_OFS >> 1);
// parse for proper ARP by completing compare string
cmp[0] = FRAME_ARP;
cmp[1] = HARDW_ETH10;
cmp[2] = FRAME_IP;
cmp[3] = IP_HLEN_PLEN;
cmp[4] = OP_ARP_REQUEST;
if (!memcmp(data, cmp, 10))
{
// skip five flag words and sender's MAC addr
data += 8;
TCP_Recd_Frame_IP[0] = *data++;
TCP_Recd_Frame_IP[1] = *data++;
// skip Dst MAC addr
data += 3;
// read target IP
TargetIP[0] = *data++;
TargetIP[1] = *data;
// is it for us?
if (!memcmp(&TCP_Local_IP, &TargetIP, 4))
// yes->create ARP_ANSWER frame
TCP_Prep_ARP_ANSWER();
}
}
// free LAN packet as we've processed or discarded it
LAN_rx_packet.busy = 0;
}
/******************************************************************************
* TCP_IP_STACK: TCP_Proc_EthIA_Frame()
*
* Purpose:
* handles an incoming frame that passed IA address filter
*
* Actions:
*
*****************************************************************************/
MC void TCP_Proc_EthIA_Frame()
{
WORD TargetIP[2];
WORD ProtocolType;
WORD* data = (WORD*) LAN_rx_packet.data;
// store sender's MAC
memcpy(&TCP_Recd_Frame_MAC, data+(ETH_SA_OFS>>1), 6);
// ignore dst_addr, src_addr
data += 6;
// get frame type and switch upon
switch (*data++)
{
// check for ARP
case FRAME_ARP :
{
if ((TCP_Flags & (TCP_ACTIVE_OPEN | TCP_IP_ADDR_RESOLVED)) == TCP_ACTIVE_OPEN)
// check for the right prot. etc.
if (*data++ == HARDW_ETH10)
// check protocol
if (*data++ == FRAME_IP)
// check HLEN, PLEN
if (*data++ == IP_HLEN_PLEN)
// check for ARP request
if (*data++ == OP_ARP_ANSWER)
{
// OK, now we've the MAC we wanted ;-)
TCP_StopTimer();
// extract remote station's MAC
TCP_RemoteMAC[0] = *data++;
TCP_RemoteMAC[1] = *data++;
TCP_RemoteMAC[2] = *data++;
// Update flags
TCP_Flags |= TCP_IP_ADDR_RESOLVED;
}
break; // FRAME_ARP
}
// check for IP-type
case FRAME_IP :
{
// check for IPv4, IHL=5 (20 Bytes Header)
// ignore Type Of Service
if ((*data++ & 0xFF ) == swap_bytes(IP_VER_IHL))
{
// get IP frame's length
TCP_Recd_IP_Frame_Length = swap_bytes(*data++);
// ignore identification
data++;
// only unfragm. frames
if (! (swap_bytes(*data++)&(IP_FLAG_MOREFRAG|IP_FRAGOFS_MASK)))
{
// get protocol, ignore TTL
ProtocolType = (*data++ >> 8) & 0xff;
// ignore checksum
*data++;
// get source IP
TCP_Recd_Frame_IP[0] = *data++;
TCP_Recd_Frame_IP[1] = *data++;
// get destination IP
TargetIP[0] = *data++;
TargetIP[1] = *data++;
// is it for us?
if (!memcmp(&TCP_Local_IP, &TargetIP, 4))
switch (ProtocolType)
{
case PROT_ICMP :
{
TCP_Proc_ICMP_Frame();
break;
}
case PROT_TCP :
{
TCP_Proc_TCP_Frame();
break;
}
case PROT_UDP :
// not implemented yet
break;
}
}
}
break; // FRAME_IP
}
}
// free packet as we've processed or discarded it
LAN_rx_packet.busy = 0;
}
/******************************************************************************
* TCP_IP_STACK: TCP_Proc_ICMP_Frame()
*
* Purpose:
* ICMP-frame (Internet Control Message Protocol) handling
*
* Actions:
*
*****************************************************************************/
MC void TCP_Proc_ICMP_Frame()
{
WORD ICMPTypeAndCode;
WORD* data = (WORD*) LAN_rx_packet.data;
// get Message Type and Code
data += (ICMP_TYPE_CODE_OFS>>1);
ICMPTypeAndCode = *data;
// ignore ICMP checksum
data++;
// check ICMP type
switch (ICMPTypeAndCode)
{
// is echo request - ping request
case ICMP_ECHO :
{
// echo as much as we can...
TCP_Prep_ICMP_ECHO_REPLY();
break;
}
}
}
/******************************************************************************
* TCP_IP_STACK: TCP_Proc_TCP_Frame()
*
* Purpose:
* TCP-frame (Transmission Control Protocol) handling
*
* Actions:
*
*****************************************************************************/
MC void TCP_Proc_TCP_Frame()
{
WORD TCPSegSourcePort; // segment's source port
WORD TCPSegDestPort; // segment's destination port
DWORD TCPSegSeq; // segment's sequence number
DWORD TCPSegAck; // segment's acknowledge number
WORD TCPCode; // TCP code and header length
BYTE TCPHeaderSize; // real TCP header length
WORD NrOfDataBytes; // real number of data
WORD* data = (WORD*) LAN_rx_packet.data;
// get offset of TCP/IP ports
data += (TCP_SRCPORT_OFS>>1);
TCPSegSourcePort = swap_bytes(*data++);
TCPSegDestPort = swap_bytes(*data++);
// drop segment if port doesn't match
if (TCPSegDestPort != TCP_LocalPort) return;
// get segment sequence nr.
TCPSegSeq = (swap_bytes(*data++) << 16) | swap_bytes(*data++);
// get segment acknowledge nr.
TCPSegAck = (swap_bytes(*data++) << 16) | swap_bytes(*data++);
// get control bits, header length...
// TCPCode = swap_bytes(*data);
TCPCode = swap_bytes(*data++);
// header length in bytes
TCPHeaderSize = (TCPCode & DATA_OFS_MASK) >> 10;
// seg. text length
NrOfDataBytes = TCP_Recd_IP_Frame_Length - IP_HEADER_SIZE - TCPHeaderSize;
// packet too large for us
if (NrOfDataBytes > MAX_TCP_RX_SIZE) return;
// ignore options if any
if (TCPHeaderSize > TCP_HEADER_SIZE)
// data += (TCPHeaderSize - TCP_HEADER_SIZE);
data += (TCPHeaderSize - TCP_HEADER_SIZE)>>1;
// implement the TCP state machine
switch (TCP_StateMachine)
{
case CLOSED :
{
if (!(TCPCode & TCP_CODE_RST))
{
TCP_RemotePort = TCPSegSourcePort;
// save partner's MAC and IP for later use
memcpy(&TCP_RemoteMAC, &TCP_Recd_Frame_MAC, 6);
memcpy(&TCP_RemoteIP, &TCP_Recd_Frame_IP, 4);
// make the reset sequence
if (TCPCode & TCP_CODE_ACK)
{
// acceptable to the other TCP
TCP_Seq_Nr = TCPSegAck;
TCP_Prep_TCP_FRAME(TCP_CODE_RST);
}
else
{
TCP_Seq_Nr = 0;
TCP_Ack_Nr = TCPSegSeq + NrOfDataBytes;
if (TCPCode & (TCP_CODE_SYN | TCP_CODE_FIN))
TCP_Ack_Nr++;
TCP_Prep_TCP_FRAME(TCP_CODE_RST | TCP_CODE_ACK);
}
}
break;
}
case LISTENING :
{
// ignore segment containing RST
if (!(TCPCode & TCP_CODE_RST))
{
TCP_RemotePort = TCPSegSourcePort;
// save partner's MAC and IP for later use
memcpy(&TCP_RemoteMAC, &TCP_Recd_Frame_MAC, 6);
memcpy(&TCP_RemoteIP, &TCP_Recd_Frame_IP, 4);
// reset a bad acknowledgement
if (TCPCode & TCP_CODE_ACK)
{
TCP_Seq_Nr = TCPSegAck;
TCP_Prep_TCP_FRAME(TCP_CODE_RST);
}
else if (TCPCode & TCP_CODE_SYN)
{
// get remote ISN, next byte we expect
TCP_Ack_Nr = TCPSegSeq + 1;
// set local ISN
TCP_Seq_Nr = ((TCP_ISN_Gen_High << 16) | get_cycles());
// one byte out -> increase by one
TCP_UNA_Seq_Nr = TCP_Seq_Nr + 1;
TCP_Prep_TCP_FRAME(TCP_CODE_SYN | TCP_CODE_ACK);
TCP_LastFrameSent = TCP_SYN_ACK_FRAME;
TCP_StartRetryTimer();
TCP_StateMachine = SYN_RECD;
}
}
break;
}
case SYN_SENT :
{
// drop segment if its IP doesn't belong to current session
if (memcmp(&TCP_RemoteIP, &TCP_Recd_Frame_IP, 4)) break;
// drop segment if port doesn't match
if (TCPSegSourcePort != TCP_RemotePort) break;
// ACK field significant?
if (TCPCode & TCP_CODE_ACK)
// is our ISN ACKed?
if (TCPSegAck != TCP_UNA_Seq_Nr)
{
if (!(TCPCode & TCP_CODE_RST))
{
TCP_Seq_Nr = TCPSegAck;
TCP_Prep_TCP_FRAME(TCP_CODE_RST);
}
// drop segment
break;
}
// RST??
if (TCPCode & TCP_CODE_RST)
{
// if ACK was acceptable, reset connection
if (TCPCode & TCP_CODE_ACK)
{
// reset all flags, stop retransmission...
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -