📄 tcp.c
字号:
/*
* tcp.c
*
* TCP Specific functions
*
*/
//TCP Packet contents (PAYLOAD only!)
int8 TCP_DATA[30];
//TCP Header definition
_TCP_HEADER TCP_HEADER;
//Send TCP Header to the NIC
void load_TCP_header(int16 data_flags, int16 tcp_chksum, int16 tcp_length) {
chksum = tcp_chksum;
// calculate checksum of pseudo header
calc_chksum( make16(my_ip[0],my_ip[1]));
calc_chksum( make16(my_ip[2],my_ip[3]));
calc_chksum( make16(IP_HEADER.SourceAddress.ip0,IP_HEADER.SourceAddress.ip1));
calc_chksum( make16(IP_HEADER.SourceAddress.ip2,IP_HEADER.SourceAddress.ip3));
calc_chksum(TCP);
calc_chksum(tcp_length);
// source port
outportw(NIC_DATA, TCP_HEADER.DestPort);
// destination port
outportw(NIC_DATA, TCP_HEADER.SourcePort);
// sequence number
outportw(NIC_DATA, xm_seq >>16);
outportw(NIC_DATA, xm_seq);
// acknowledment number
outportw(NIC_DATA, xm_ack>>16);
outportw(NIC_DATA, xm_ack);
// data offset and flags
outportw(NIC_DATA, data_flags);
// window
outportw(NIC_DATA, 1460);
// checksum
outportw(NIC_DATA, ~chksum);
// urgent pointer
outportw(NIC_DATA, 0);
}
//Invert bytes positions
static void swapTCPHeader(_TCP_HEADER* header) {
header->SourcePort = swap16(header->SourcePort);
header->DestPort = swap16(header->DestPort);
header->SeqNumber = swap32(header->SeqNumber);
header->AckNumber = swap32(header->AckNumber);
header->Window = swap16(header->Window);
header->Checksum = swap16(header->Checksum);
header->UrgentPointer = swap16(header->UrgentPointer);
}
void tcp_response(void) {
int i;
switch(html_socket)
{
case LISTEN:
{
#ifdef DEBUG
puts("LISTEN");
#endif
// *** We are expecting a SYN without an ACK
// *** Could get a RST, FIN, PSH or URG but we'll ignore the PSH or URG
if (TCP_HEADER.Flags.flagSYN)
{
#ifdef DEBUG
puts("flagSYN");
#endif
// SYN set
// We should check to be sure an ACK wasn't also sent
if (TCP_HEADER.Flags.flagACK) break;
// Ignore it for now. We'll add code to handle later
// We shouldn't have a RST or FIN with a SYN
if (TCP_HEADER.Flags.flagRST || TCP_HEADER.Flags.flagFIN) break;
// Ignore it for now. We'll add code to hanlde later
// Everything looks okay so handle the SYN request
// Save the senders sequence number
tcp_listen();
}
}
break;
case SYN_RCVD:
{
#ifdef DEBUG
puts(" Syn Rcvd ");
#endif
// Check if addressed for this socket
if (port!=TCP_HEADER.SourcePort || iphh.ip0!=IP_HEADER.SourceAddress.ip0 ||
iphh.ip1!=IP_HEADER.SourceAddress.ip1 || iphh.ip2!=IP_HEADER.SourceAddress.ip2
|| iphh.ip3!= IP_HEADER.SourceAddress.ip3)
break;
printf("flags %x \n\r",*(&TCP_HEADER.Flags));
// We are expecting an ACK without a SYN
if (TCP_HEADER.Flags.flagACK)
{
#ifdef DEBUG
puts("flagACK\n\r");
#endif
// ACK set
// We should check to be sure an SYN wasn't also sent
if (TCP_HEADER.Flags.flagSYN)
{
#ifdef DEBUG
puts("flagSYN\n\r");
#endif
break; // Ignore it for now. We'll add code to handle later
}
// We shouldn't have a RST or FIN with an ACK
if (TCP_HEADER.Flags.flagRST || TCP_HEADER.Flags.flagFIN)
{
#ifdef DEBUG
puts("flagRST o flagFIN\n\r");
#endif
//html_socket = LISTEN;
break; // Ignore it for now. We'll add code to hanlde later
}
// Everything looks okay so handle the ACK response
tcp_syn_rcvd();
}
else
{
#ifdef DEBUG
puts(" none ");
#endif
html_socket = LISTEN;
}
}
break;
case ESTAB:
{
#ifdef DEBUG
puts(" Estab ");
#endif
// We are expecting an ACK without or SYN
// We could receive a FIN
if (TCP_HEADER.Flags.flagACK) {
// ACK set
// We should check to be sure an SYN wasn't also sent
if (TCP_HEADER.Flags.flagSYN) {
break; // Ignore it for now. We'll add code to handle later
}
// We shouldn't have a RST with an ACK
if (TCP_HEADER.Flags.flagRST ) {
break; // Ignore it for now. We'll add code to hanlde later
}
// ************************************************************
// *** - check received sequence number to be sure it's ***
// *** what we expected ***
// *** - check acknowledgement number to be sure it's what ***
// *** we are going to send ***
// *** - check source ip address and source port to be sure ***
// *** they are correct ***
// ************************************************************
// if (seq[0] != xm_ack[0] || seq[1] != xm_ack[1] ||ack[0] != xm_seq[0] || ack[1] != xm_seq[1])
if(TCP_HEADER.SeqNumber!=xm_ack)
break;
if (port!=TCP_HEADER.SourcePort || iphh.ip0!=IP_HEADER.SourceAddress.ip0 ||
iphh.ip1!=IP_HEADER.SourceAddress.ip1 || iphh.ip2!=IP_HEADER.SourceAddress.ip2 ||
iphh.ip3!= IP_HEADER.SourceAddress.ip3)
break;
// Everything looks okay so handle the ACK response
tcp_estab();
}
}
}
}
void tcp_listen(void)
{
int i;
int16 optionlen;
xm_ack=TCP_HEADER.SeqNumber;
//xm_seq=TCP_HEADER.AckNumber;
port = TCP_HEADER.SourcePort;
// Save the source IP address
iphh = IP_HEADER.SourceAddress;
// Calculate data length
optionlen = (TCP_HEADER.dataoffset.val << 2)-sizeof(TCP_HEADER);
tcp_data_len= IP_HEADER.TotalLength - (40 + optionlen);
// Increment sequence to account for SYN and add data
xm_ack = xm_ack + tcp_data_len + 1;
xm_seq+=1;
#ifdef DEBUG
printf("hdr_:%u\n\r",hdr_len);
printf("option_:%lu\n\r",optionlen);
printf("TotalLength:%lu\n\r",IP_HEADER.TotalLength);
printf("tcplen_:%lu\n\r",tcp_data_len);
printf("xm_ack:%lx\n\r",xm_ack);
printf("xm_seq:%lx\n\r",xm_seq);
#endif
load_ethernet_header(); // 12 bytes (2 bytes for protocol included in load_IP..)
load_IP_header(48,TCP); // Number of bytes included in call (add 2 for protocol)
// 20 for IP header
// 20 for TCP header
// 8 for Options
load_TCP_header( 0x7000 | TCP_SYN | TCP_ACK, 0x07B8, 28);
// Number of bytes include in load_IP_header call 07B8
// Send options
outport(NIC_DATA,0x02);
outport(NIC_DATA,0x04);
outport(NIC_DATA,0x05);
outport(NIC_DATA,0xB4);
outport(NIC_DATA,0x00);
outport(NIC_DATA,0x00);
outport(NIC_DATA,0x00);
outport(NIC_DATA,0x00);
sendPacket(62);
// Calculate the next sequence number to send
// In this case we add 1 since we only sent a SYN
xm_seq+=1;
html_socket = SYN_RCVD;
}
void tcp_syn_rcvd(void) {
int16 optionlen;
printf("tcp_syn_rcvd\n\r");
// Calculate data length
optionlen = (TCP_HEADER.dataoffset.val << 2)-sizeof(TCP_HEADER);
tcp_data_len= IP_HEADER.TotalLength - (40 + optionlen);
printf("tcplen_:%lu\n\r",tcp_data_len);
//tcp_data_len = IP_HEADER.TotalLength - (hdr_len + (int8)TCP_HEADER.dataoffset);
// Increment sequence to account for data
xm_ack+= tcp_data_len;
// *** Need to handle data if any here.
// We'll assume there isn't any for now so no response is needed
html_socket = ESTAB;
}
/////////////////////////////////////////////////////////////////////////////
void tcp_estab(void) {
int16 optionlen;
int16 cks;
int8 dat,dat1, i;
int8 html_request[19];
#ifdef DEBUG
printf("TCP Data: ");
for (i=0; i < 30; i++) {
printf("%c", TCP_DATA[i]);
}
printf("\n\r");
#endif
//Check if the request starts with 'GET' that means its an authentic HTTP request
//This should be done somewhere else, because here we are already sending the answer to the request
/*if (!TCP_DATA[0] == 'G'
|| !TCP_DATA[1] == 'E'
|| !TCP_DATA[2] == 'T'
|| !TCP_DATA[3] == ' '
|| !TCP_DATA[4] == '/') {
printf("Not an HTTP request\n\r");
//fin_rx();
return;
}
printf("Got HTTP Request\r\n");*/
//Get Page Name the user asked
for (i=0; i<=19; i++) {
if (TCP_DATA[i+5] == ' ') {
html_request[i] = 0;
break;
}
html_request[i] = TCP_DATA[i+5];
}
html_request[18] = 0;
//Show page name - up to now the entire page name is okay
#ifdef DEBUG
printf("Asked Page: %s", html_request);
#endif
//tcp_data_len = IP_HEADER.TotalLength - (hdr_len + (int8)TCP_HEADER.dataoffset);
optionlen = (TCP_HEADER.dataoffset.val << 2)-sizeof(TCP_HEADER);
tcp_data_len= IP_HEADER.TotalLength - (40 + optionlen);
// This is the next sequence number we expect
xm_ack+= tcp_data_len;
//Start preparing our answer
load_ethernet_header(); // 12 bytes (2 bytes for protocol included in load_IP..)
//Increase access counter
accessCount++;
//Prepares page - Look! Only first char! I want to pass the entire page name to the function!
preparar_pagina(html_request[0], html_request);
//Now IP and TCP Stuff
load_IP_header(htmlSize + 40,TCP); // Number of bytes included in call (add 2 for protocol)
// 20 for IP header
// 20 for TCP header
// 148 for Data
load_TCP_header( 0x5000 | TCP_ACK | TCP_FIN, htmlChecksum, htmlSize);
//Finish sending the page to NIC and the packet with the page to the client
sendHttpPage();
xm_ack+=htmlSize;
sendPacket(htmlSize + 54);
html_socket = LISTEN;
#ifdef DEBUG
puts("Webpage sent\n\r");
#endif
}
//Ok, we have a TCP Packet
//Read its header and Payload storing in the correct places
void processTCP() {
int8 i,kind;
#ifdef DEBUG
puts(" TCP ");
#endif
//Reads TCP Header and stores in the correct var
getNicData(&TCP_HEADER,sizeof(TCP_HEADER));
swapTCPHeader(&TCP_HEADER);
#ifdef DEBUG
printf("src port: = %Lx\n\r", TCP_HEADER.SourcePort);
printf("dst port: = %Lx\n\r", TCP_HEADER.DestPort);
printf("SeqNum: = %Lx\n\r", TCP_HEADER.SeqNumber);
printf("AckNum: = %Lx\n\r", TCP_HEADER.AckNumber);
printf("offset: = %x\n\r", (int8)TCP_HEADER.dataoffset);
#endif
//Reads TCP Payload and stores in TCP_DATA
//So anything the browser will send such as a "GET / HTTP/1.0", a POST, a page requested name, or whatever will be in this var
//Later we check for the type of request and the pagename, redirecting to the correct page we have stored in flash memory as printfs
getNicData(TCP_DATA,30);
// We only respond to port 80 (HTML requests)
/* Answering on all TCP Ports!
if (TCP_HEADER.DestPort != 80) {
fin_rx();
break;
}
*/
fin_rx();
tcp_response();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -