#include #include #include #include #include #include #include #include extern WORD rxpos=0; extern WORD txpos=0; extern BYTE rxbuffer[]; extern BYTE txbuffer[]; tcphead tcph; ipheader ip; ipstats ipstat; extern test; extern ulong tcpcounter; void tcp_header(); void tcp_checksum(); bit tcpoptions=0; WORD tcpdatalen; tcpt tcptx; void www(); void show_stats(); /************************************************************************ * void tcp_receive() * This function is called by the IP layer when a TCP packet is * received. It performs every essential task of the TCP layer. * Incoming flag bits are read and responses generated accordingly ***********************************************************************/ void tcp_receive() { WORD tcpseq[2]; BYTE applayer=0; BYTE n; tcpoptions=0; /* increment TCP statistics counter */ ipstat.tcprx++; /* copy various fields of the TCP header */ copy_rx_word(&tcph.src); copy_rx_word(&tcph.dest); copy_rx_word(&tcph.seq[0]); copy_rx_word(&tcph.seq[1]); copy_rx_word(&tcph.ack[0]); copy_rx_word(&tcph.ack[1]); copy_rx_byte(&tcph.headerlen); tcph.headerlen = tcph.headerlen>>4; copy_rx_byte(&tcph.flags); copy_rx_word(&tcph.windowsize); copy_rx_word(&tcph.chksum); copy_rx_word(&tcph.urgent); /* discard any TCP options */ for (n=5;n>16); tcptx.seq[1] = (WORD)tcpcounter; /* and ACK the client's ISN plus one, for the SYN */ tcptx.ack[0] = tcph.seq[0]; tcptx.ack[1] = tcph.seq[1]+1; /* a connection request for the web server port */ if (tcph.dest == HTTP_PORT) { /* acknowledge it */ tcptx.action = SYN|ACK; /* and set flag to send TCP options */ tcpoptions=1; /* connection request for an unused port */ } else { /* so reset it */ tcptx.action = RST|ACK; /* and increment statistics counters */ ipstat.dropped++; ipstat.tcpdrop++; } } /* client is closing the connection */ else if (tcph.flags & FIN) { tcptx.seq[0] = tcph.ack[0]; tcptx.seq[1] = tcph.ack[1]; tcptx.ack[0] = tcph.seq[0]; tcptx.ack[1] = tcph.seq[1]+tcpdatalen+1; tcptx.action = ACK; } else if (tcph.flags & ACK) { tcptx.seq[0] = tcph.ack[0]; tcptx.seq[1] = tcph.ack[1]; tcptx.ack[0] = tcph.seq[0]; tcptx.ack[1] = tcph.seq[1]+tcpdatalen; if (!tcpdatalen) return; /* if the segment contains no data * no action is required */ /* we shouldn't get to this stage unless the destination port * is the HTTP port, but check just in case */ if (tcph.dest == HTTP_PORT) { www(); /* call the www function to read the request * and add HTTP data to the transmit buffer */ } return; } /* place tcp header starting at 20 */ tcp_header(); /* reset transmit buffer position */ txpos=0; /* and place IP header at start */ ip_header(PROTTCP); /* calculate the TCP checksum and insert into header */ tcp_checksum(); /* finally, call the SLIP layer to send out the packet */ slip_send(txbuffer,ip.totallen); } /************************************************************************ * void tcp_header() * adds a TCP header to the transmit buffer, this function is * called either by an application of the tcp_receive function * If requested, TCP options will be sent (only MSS) ***********************************************************************/ void tcp_header() { txpos=IPSIZE; tx_word(tcph.dest); // source port tx_word(tcph.src); // destination port tx_word(tcptx.seq[0]); // sequence number tx_word(tcptx.seq[1]); // tx_word(tcptx.ack[0]); // ack number tx_word(tcptx.ack[1]); // if (tcpoptions) { tx_byte(0x60); // data offset 0101 << 4 } else { tx_byte(0x50); } tx_byte(tcptx.action); tx_word(WINDOWSIZE); // window size tx_word(0); // checksum tx_word(0); // urgent pointer if (tcpoptions) { tx_byte(0x02); // kind tx_byte(0x04); // length tx_word(MSS); // MSS ip.totallen=IPSIZE+TCPHSIZE+4; } else { ip.totallen=IPSIZE+TCPHSIZE; } } /************************************************************************ * void www() * called by the TCP layer when a data segment is received * for the HTTP_PORT. * The HTTP request string is validated before the requested * filename is checked and responded to accordingly. * Requests for an unknown filename result in a 404 ***********************************************************************/ void www() { BYTE request[4]; /* check the incoming packet is a GET request, this is the only type which will be dealt with * so issue a Bad Request HTTP error on anything else */ if (rx_byte() != 'G' || rx_byte() != 'E' || rx_byte() != 'T' || rx_byte() != ' ' || rx_byte() != '/') { tcptx.action = FIN|PSH|ACK; tcp_header(); /* add the response to the transmit buffer */ q_string("HTTP/1.0 400 Bad Request\r\nContent-type: text/html\r\n\r\n",53); q_string("Bad Request",51); q_string("

Bad Request

",20); q_string("The request could not be understood.",36); q_string("",14); } else { /* read the requested filename */ copy_rx_byte(&request[0]); copy_rx_byte(&request[1]); copy_rx_byte(&request[2]); copy_rx_byte(&request[3]); tcptx.action = FIN|PSH|ACK; tcp_header(); /* client requested / */ if (request[0] == ' ') { q_string("HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n",44); q_string("TCP/IP Stack",52); q_string("

Welcome!

",17); q_string("

This is an httpd running on a minimal TCP/IP stack",53); q_string(" written by Stuart Haslam.

",30); q_string("

The implementation provides at least partial support ",56); q_string("for the following protocols: ",29); q_string("SLIP, IP, ICMP, UDP, TCP, TFTP, HTTP.",37); q_string("

TCP/IP packet statistics

",48); q_string("",14); } /* client requested /1 */ else if (request[0] == '1' && request[1] == ' ') { show_stats(); } /* client requested /1?c * there are some repeated lines here to overcome a bug in the compiler */ else if (request[0] == '1' && request[1] == '?' && request[2] == 'c') { ipstat.rxpackets=0; ipstat.rxpackets=0; ipstat.txpackets=0; ipstat.tcptx=0; ipstat.tcprx=0; ipstat.udprx=0; ipstat.udptx=0; ipstat.icmprx=0; ipstat.icmptx=0; ipstat.icmpdrop=0; ipstat.tcpdrop=0; ipstat.udpdrop=0; ipstat.dropped=0; show_stats(); } /* client requested unknown filename, send a 404 error */ else { q_string("HTTP/1.0 404 Not Found\r\n\r\n",26); q_string("TCP/IP Stack",52); q_string("

404 - File Not Found!

",30); q_string("The requested file could not be found.",38); q_string("

index

",28); q_string("",14); } } ip.totallen=txpos; /* set length of outgoing packet */ txpos=0; /* reset transmit buffer position */ ip_header(PROTTCP); /* and place IP header at start */ txpos+=20; tcp_checksum(); slip_send(txbuffer,ip.totallen); } /************************************************************************ * void show_stats() * simple function to add HTTP headers and HTML content to the transmit * buffer, to display some basic packet statistics. ***********************************************************************/ void show_stats() { q_string("HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n",44); q_string("TCP/IP Stack",39); q_string("",36); q_string("",13); q_string("

Packet Statistics

",26); q_string("",57); q_string("",73); q_string("",10); q_string("",10); q_string("",10); q_string("",10); q_string("
 ReceivedTransmittedDropped
Total",22); q_num(ipstat.rxpackets); q_string("",9); q_num(ipstat.txpackets); q_string("",9); q_num(ipstat.dropped); q_string("
ICMP",21); q_num(ipstat.icmprx); q_string("",9); q_num(ipstat.icmptx); q_string("",9); q_num(ipstat.icmpdrop); q_string("
UDP",20); q_num(ipstat.udprx); q_string("",9); q_num(ipstat.udptx); q_string("",9); q_num(ipstat.udpdrop); q_string("
TCP",20); q_num(ipstat.tcprx); q_string("",9); q_num(ipstat.tcptx); q_string("",9); q_num(ipstat.tcpdrop); q_string("
",8); q_string("

index - ",27); q_string("clear stats

",34); q_string("",14); } /************************************************************************ * void tcp_checksum() * calculates the internet checksum of the packet waiting in the * transmit buffer, and inserts it into the header field ***********************************************************************/ void tcp_checksum() { WORD csum; bool odd=0; /* increment transmit counter */ ipstat.tcptx++; txpos=ip.totallen; /* odd length, so add pad byte */ if (ip.totallen % 2) { tx_byte(0x00); odd=1; } /* add parts of pseudo header */ tx_byte(IP1); tx_byte(IP2); tx_byte(IP3); tx_byte(IP4); tx_byte(ip.destaddr[0]); tx_byte(ip.destaddr[1]); tx_byte(ip.destaddr[2]); tx_byte(ip.destaddr[3]); tx_word(PROTTCP); tx_word(ip.totallen-IPSIZE); /* length is total length minus length of IP header (20) * plus length of TCP pseudo header (12) */ csum = chksm(&txbuffer[20],ip.totallen-8+odd); put_checksum(csum,&txbuffer[IPSIZE+16]); }