RealtimeCompLab2
Dependencies: mbed
Fork of PPP-Blinky by
main.cpp
- Committer:
- nixnax
- Date:
- 2017-01-05
- Revision:
- 31:e000c1b9c565
- Parent:
- 30:273431bccb02
- Child:
- 32:512228c29209
File content as of revision 31:e000c1b9c565:
#include "mbed.h" // Copyright 2016 Nicolas Nackel aka Nixnax. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // Proof-of-concept for TCP/IP using Windows 7/8/10 Dial Up Networking over MBED USB Virtual COM Port // Toggles LED1 every time the PC sends an IP packet over the PPP link // Note - turn off all Dial Up authentication, passwords, compression options - Simplest link possible. // Be sure to read the section on mbed on "Windows 7/8/10 PPP bug" if you keep on getting Dial Up Error 777. // Handy links // https://developer.mbed.org/users/nixnax/code/PPP-Blinky/ - Handy Notes, Instructions and introduction // http://atari.kensclassics.org/wcomlog.htm // https://technet.microsoft.com/en-us/library/cc957992.aspx // https://en.wikibooks.org/wiki/Serial_Programming/IP_Over_Serial_Connections // Handy tools // https://ttssh2.osdn.jp/index.html.en - A good terminal program to monitor the debug output from the second serial port with! // Wireshark - can't monitor Dial-Up network packets on windows, but very hand - can import our dumpFrame routine's hex output // Microsoft network monitor - real-time monitoring of all our packets // http://pingtester.net/ - nice tool for high rate ping testing // http://www.sunshine2k.de/coding/javascript/crc/crc_js.html - Correctly calculates the 16-bit FCS (crc) on our frames (Choose CRC16_CCITT_FALSE) // The curl program in Windows Powershell - use like this to test the webserver: while (1) { curl 172.10.10.1 } // https://technet.microsoft.com/en-us/sysinternals/pstools.aspx - psping for fast testing of ICMP ping function // https://eternallybored.org/misc/netcat/ - use netcat -u 172.10.10.1 80 to send/receive UDP packets from our board Serial pc(USBTX, USBRX); // The USB com port - Set this up as a Dial-Up Modem on your pc Serial xx(PC_10, PC_11); // See debug messages here. Not necessary to work, but VERY interesting output! int v0=1; int v1=1; // verbosity flags used in debug printouts - change to 1/0 to see more/less debug info // the commented #define below gets rid of ALL the debug printfs #define debug(x) xx.printf x //#define debug(x) {} DigitalOut led1(LED1); // this led toggles when a packet is received // the standard hdlc frame start/end character #define FRAME_7E (0x7e) // the serial port receive buffer and packet buffer #define BUFLEN (1<<12) char rxbuf[BUFLEN]; char frbuf[3000]; // send/receive buffer for ppp frames // a structure to keep all our ppp globals in struct pppType { int online; int ident; int sync; unsigned int seq; int crc; int ledState; struct { char * buf; volatile int head; volatile int tail; int total; } rx; // serial port buffer struct { int id; int len; int crc; char * buf; } pkt; // ppp buffer }; pppType ppp; // our global - definitely not thread safe // intitialize our globals void pppInitStruct() { ppp.online=0; ppp.rx.buf=rxbuf; ppp.rx.tail=0; ppp.rx.head=0; ppp.rx.total=0; ppp.pkt.buf=frbuf; ppp.pkt.len=0; ppp.ident=0; ppp.sync=0; ppp.seq=77; ppp.ledState=0; } void crcReset() { ppp.crc=0xffff; // crc restart } void crcDo(int x) // cumulative crc { for (int i=0; i<8; i++) { ppp.crc=((ppp.crc&1)^(x&1))?(ppp.crc>>1)^0x8408:ppp.crc>>1; // crc calculator x>>=1; } } int crcBuf(char * buf, int size) // crc on an entire block of memory { crcReset(); for(int i=0; i<size; i++)crcDo(*buf++); return ppp.crc; } void rxHandler() // serial port receive interrupt handler { while ( pc.readable() ) { int hd = (ppp.rx.head+1)&(BUFLEN-1); // increment/wrap if ( hd == ppp.rx.tail ) break; // watch for buffer full ppp.rx.buf[ppp.rx.head]=pc.getc(); // insert in rx buffer ppp.rx.head = hd; // update head pointer } } void led1Toggle() { ppp.ledState = ppp.ledState? 0 : 1; led1 = ppp.ledState; } int rxbufNotEmpty() // check if rx buffer has data { __disable_irq(); // critical section start int notEmpty = (ppp.rx.head==ppp.rx.tail) ? 0 : 1 ; __enable_irq(); // critical section end return notEmpty; } int pc_getBuf() // get one character from the buffer { if ( rxbufNotEmpty() ) { int x = ppp.rx.buf[ ppp.rx.tail ]; __disable_irq(); // critical section start ppp.rx.tail=(ppp.rx.tail+1)&(BUFLEN-1); __enable_irq(); // critical section end return x; } else return -1; } void scanForConnectString(); // scan for connect attempts from pc void processFrame(int start, int end) // process received frame { led1Toggle(); // change led1 state when frames are received if(start==end) { pc.putc(0x7e); return; } crcReset(); char * dest = ppp.pkt.buf; ppp.pkt.len=0; int unstuff=0; int idx = start; while(1) { if (unstuff==0) { if (rxbuf[idx]==0x7d) unstuff=1; else { *dest = rxbuf[idx]; ppp.pkt.len++; dest++; crcDo(rxbuf[idx]); } } else { // unstuff *dest = rxbuf[idx]^0x20; ppp.pkt.len++; dest++; crcDo(rxbuf[idx]^0x20); unstuff=0; } idx = (idx+1) & (BUFLEN-1); if (idx == end) break; } ppp.pkt.crc = ppp.crc & 0xffff; if (ppp.pkt.crc == 0xf0b8) { // check for good CRC void determinePacketType(); // declaration only determinePacketType(); } else if (v0) { debug(("PPP FCS(crc) Error CRC=%x Length = %d\n",ppp.pkt.crc,ppp.pkt.len)); } } // Note - the hex output of dumpframe can be imported into WireShark // Copy the frame's hex output from your terminal program and save as a text file // In WireShark, use "Import Hex File". Options are No Offset, protocol=PPP. void dumpFrame() { for(int i=0; i<ppp.pkt.len; i++) debug(("%02x ", ppp.pkt.buf[i])); debug((" C=%02x %02x L=%d\n", ppp.pkt.crc&0xff, (ppp.pkt.crc>>8)&0xff, ppp.pkt.len)); } void hdlcPut(int ch) // do hdlc handling of special (flag) characters { if ( (ch<0x20) || (ch==0x7d) || (ch==0x7e) ) { pc.putc(0x7d); pc.putc(ch^0x20); } else { pc.putc(ch); } } void sendFrame() { int crc = crcBuf(ppp.pkt.buf, ppp.pkt.len-2); // update crc ppp.pkt.buf[ ppp.pkt.len-2 ] = (~crc>>0); // fcs lo (crc) ppp.pkt.buf[ ppp.pkt.len-1 ] = (~crc>>8); // fcs hi (crc) pc.putc(0x7e); // hdlc start-of-frame "flag" for(int i=0; i<ppp.pkt.len; i++) hdlcPut( ppp.pkt.buf[i] ); pc.putc(0x7e); // hdlc end-of-frame "flag" } void ipRequestHandler() { debug(("IPCP Conf ")); if ( ppp.pkt.buf[7] != 4 ) { debug(("Rej\n")); // reject if any options are requested ppp.pkt.buf[4]=4; sendFrame(); } else { debug(("Ack\n")); ppp.pkt.buf[4]=2; // ack the minimum sendFrame(); // acknowledge debug(("IPCP Ask\n")); // send our own request now ppp.pkt.buf[4]=1; // request no options ppp.pkt.buf[5]++; // next sequence sendFrame(); // this is our request } } void ipAckHandler() { debug(("IPCP Grant\n")); } void ipNackHandler() { debug(("IPCP Nack\n")); } void ipDefaultHandler() { debug(("IPCP Other\n")); } void IPCPframe() { int code = ppp.pkt.buf[4]; // packet type is here switch (code) { case 1: ipRequestHandler(); break; case 2: ipAckHandler(); break; case 3: ipNackHandler(); break; default: ipDefaultHandler(); } } void UDPpacket() { char * udpPkt = ppp.pkt.buf+4; // udp packet start int headerSizeIP = (( udpPkt[0]&0xf)*4); char * udpBlock = udpPkt + headerSizeIP; // udp info start char * udpSrc = udpBlock; // source port char * udpDst = udpBlock+2; // destination port char * udpLen = udpBlock+4; // udp data length char * udpInf = udpBlock+8; // actual start of info int srcPort = (udpSrc[0]<<8) | udpSrc[1]; int dstPort = (udpDst[0]<<8) | udpDst[1]; char * srcIP = udpPkt+12; // udp src addr char * dstIP = udpPkt+16; // udp dst addr #define UDP_HEADER_SIZE 8 int udpLength = ((udpLen[0]<<8) | udpLen[1]) - UDP_HEADER_SIZE; // size of the actual udp data if(v1) debug(("UDP %d.%d.%d.%d:%d ", srcIP[0],srcIP[1],srcIP[2],srcIP[3],srcPort)); if(v1) debug(("%d.%d.%d.%d:%d ", dstIP[1],dstIP[1],dstIP[1],dstIP[1],dstPort)); debug(("Len %d ", udpLength)); int printSize = udpLength; if (printSize > 20) printSize = 20; // print only first 20 characters if (v0) { for (int i=0; i<printSize; i++) { char ch = udpInf[i]; if (ch>31 && ch<127) { debug(("%c", ch)); } else { debug(("_")); } } debug(("\n")); } } int dataCheckSum(char * ptr, int len) { int sum=0; int placeHolder; if (len&1) { placeHolder = ptr[len-1]; // when length is odd zero stuff ptr[len-1]=0; } for (int i=0; i<len/2; i++) { int hi = *ptr; ptr++; int lo = *ptr; ptr++; int val = ( lo & 0xff ) | ( (hi<<8) & 0xff00 ); sum = sum + val; } sum = sum + (sum>>16); if (len&1) { ptr[len-1] = placeHolder; // restore the last byte for odd lengths } return ~sum; } void headerCheckSum() { int len =(ppp.pkt.buf[4]&0xf)*4; // length of header in bytes char * ptr = ppp.pkt.buf+4; // start of ip packet int sum=0; for (int i=0; i<len/2; i++) { int hi = *ptr; ptr++; int lo = *ptr; ptr++; int val = ( lo & 0xff ) | ( (hi<<8) & 0xff00 ); sum = sum + val; } sum = sum + (sum>>16); sum = ~sum; ppp.pkt.buf[14]= (sum>>8); ppp.pkt.buf[15]= (sum ); } void ICMPpacket() // internet control message protocol { char * ipPkt = ppp.pkt.buf+4; // ip packet start char * pktLen = ipPkt+2; int packetLength = (pktLen[0]<<8) | pktLen[1]; // icmp packet length int headerSizeIP = (( ipPkt[0]&0xf)*4); char * icmpType = ipPkt + headerSizeIP; // icmp data start char * icmpSum = icmpType+2; // icmp checksum #define ICMP_TYPE_PING_REQUEST 8 if ( icmpType[0] == ICMP_TYPE_PING_REQUEST ) { char * ipTTL = ipPkt+8; // time to live ipTTL[0]--; // decrement time to live char * srcAdr = ipPkt+12; char * dstAdr = ipPkt+16; int icmpIdent = (icmpType[4]<<8)|icmpType[5]; int icmpSequence = (icmpType[6]<<8)|icmpType[7]; debug(("ICMP PING %d.%d.%d.d %d.%d.%d.%d ", srcAdr[0],srcAdr[1],srcAdr[2],srcAdr[3],dstAdr[0],dstAdr[1],dstAdr[2],dstAdr[3])); debug(("Ident %04x Sequence %04d ",icmpIdent,icmpSequence)); char src[4]; char dst[4]; memcpy(src, srcAdr,4); memcpy(dst, dstAdr,4); memcpy(srcAdr, dst,4); memcpy(dstAdr, src,4); // swap src & dest ip char * chkSum = ipPkt+10; chkSum[0]=0; chkSum[1]=0; headerCheckSum(); // new ip header checksum #define ICMP_TYPE_ECHO_REPLY 0 icmpType[0]=ICMP_TYPE_ECHO_REPLY; // icmp echo reply icmpSum[0]=0; icmpSum[1]=0; // zero the checksum for recalculation int icmpLength = packetLength - headerSizeIP; // length of ICMP data portion int sum = dataCheckSum( icmpType, icmpLength); // this checksum on icmp data portion icmpSum[0]=sum>>8; icmpSum[1]=sum; // new checksum for ICMP data portion int printSize = icmpLength-8; // exclude size of icmp header char * icmpData = icmpType+8; // the actual payload data is after the header if (printSize > 10) printSize = 10; // print up to 20 characters if (v0) { for (int i=0; i<printSize; i++) { char ch = icmpData[i]; if (ch>31 && ch<127) { debug(("%c",ch)); } else { debug(("_")); } } debug(("\n")); } sendFrame(); // reply to the ping } else { if (v0) { debug(("ICMP type=%d \n", icmpType[0])); } } } void IGMPpacket() // internet group management protocol { if (v0) { debug(("IGMP type=%d \n", ppp.pkt.buf[28])); } } void dumpHeaderIP () { char * ipPkt = ppp.pkt.buf+4; // ip packet start char * version = ipPkt; // top 4 bits char * ihl = ipPkt; // bottom 4 bits char * dscp = ipPkt+1; // top 6 bits char * ecn = ipPkt+1; // lower 2 bits char * pktLen = ipPkt+2; // 2 bytes char * ident = ipPkt+4; // 2 bytes char * flags = ipPkt+6; // 2 bits char * ttl = ipPkt+8; // 1 byte char * protocol = ipPkt+9; // 1 byte char * headercheck= ipPkt+10; // 2 bytes char * srcAdr = ipPkt+12; // 4 bytes char * dstAdr = ipPkt+16; // 4 bytes = total of 20 bytes int versionIP = (version[0]>>4)&0xf; int headerSizeIP = (ihl[0]&0xf)*4; int dscpIP = (dscp[0]>>2)&0x3f; int ecnIP = ecn[0]&3; int packetLength = (pktLen[0]<<8)|pktLen[1]; // ip total packet length int identIP = (ident[0]<<8)|ident[1]; int flagsIP = flags[0]>>14&3; int ttlIP = ttl[0]; int protocolIP = protocol[0]; int checksumIP = (headercheck[0]<<8)|headercheck[1]; char srcIP [16]; snprintf(srcIP,16, "%d.%d.%d.%d", srcAdr[0],srcAdr[1],srcAdr[2],srcAdr[3]); char dstIP [16]; snprintf(dstIP,16, "%d.%d.%d.%d", dstAdr[0],dstAdr[1],dstAdr[2],dstAdr[3]); debug(("IP %s %s v%d h%d d%d e%d L%d ",srcIP,dstIP,versionIP,headerSizeIP,dscpIP,ecnIP,packetLength)); if (v1) debug(("i%04x f%d t%d p%d C%04x\n",identIP,flagsIP,ttlIP,protocolIP,checksumIP)); } void dumpHeaderTCP() { int headerSizeIP = (ppp.pkt.buf[4]&0xf)*4; // header size of ip portion char * tcpStart = ppp.pkt.buf+4+headerSizeIP; // start of tcp packet char * seqtcp = tcpStart + 4; // 4 bytes char * acktcp = tcpStart + 8; // 4 bytes char * flagbitstcp = tcpStart + 12; // 9 bits unsigned int seq = (seqtcp[0]<<24)|(seqtcp[1]<<16)|(seqtcp[2]<<8)|(seqtcp[3]); unsigned int ack = (acktcp[0]<<24)|(acktcp[1]<<16)|(acktcp[2]<<8)|(acktcp[3]); int flags = ((flagbitstcp[0]&1)<<8)|flagbitstcp[1]; char flagInfo[10]; memset(flagInfo,'.',10); // text presentation of TCP flags if (flags & (1<<0)) flagInfo[0]='F'; if (flags & (1<<1)) flagInfo[1]='S'; if (flags & (1<<2)) flagInfo[2]='R'; if (flags & (1<<3)) flagInfo[3]='P'; if (flags & (1<<4)) flagInfo[4]='A'; if (flags & (1<<5)) flagInfo[5]='U'; if (flags & (1<<6)) flagInfo[6]='E'; if (flags & (1<<7)) flagInfo[7]='C'; if (flags & (1<<8)) flagInfo[8]='N'; flagInfo[9]=0; // null terminate string if (v0) { debug(("Flags %s Seq %d Ack %d", flagInfo, seq, ack)); } } void tcpHandler() { char * ipPkt = ppp.pkt.buf+4; // ip packet start char * headercheck= ipPkt+10; // 2 bytes char * ihl = ipPkt; // bottom 4 bits char * ident = ipPkt+4; // 2 bytes char * pktLen = ipPkt+2; // 2 bytes char * protocol = ipPkt+9; // 1 byte char * srcAdr = ipPkt+12; // 4 bytes char * dstAdr = ipPkt+16; // 4 bytes = total of 20 bytes int headerSizeIP = (ihl[0]&0xf)*4; int packetLength = (pktLen[0]<<8)|pktLen[1]; // ip total packet length ident[0] = ppp.ident>>8; ident[1] = ppp.ident>>0; // insert OUR ident char * s = ppp.pkt.buf+4+headerSizeIP; // start of tcp packet char * srctcp = s + 0; // 2 bytes char * dsttcp = s + 2; // 2 bytes char * seqtcp = s + 4; // 4 bytes char * acktcp = s + 8; // 4 bytes char * offset = s + 12; // 4 bits char * flagbitstcp = s + 12; // 9 bits char * checksumtcp = s + 16; // 2 bytes int tcpSize = packetLength - headerSizeIP; int tcpHeaderLen = ((offset[0]>>4)&0x0f)*4; // size of tcp header only int dataLen = tcpSize - tcpHeaderLen; // data is what's left after the header unsigned int seq = (seqtcp[0]<<24)|(seqtcp[1]<<16)|(seqtcp[2]<<8)|(seqtcp[3]); unsigned int ack = (acktcp[0]<<24)|(acktcp[1]<<16)|(acktcp[2]<<8)|(acktcp[3]); char * dataStart = s + tcpHeaderLen; // start of data int flagsTCP = ((flagbitstcp[0]&1)<<8)|flagbitstcp[1]; #define TCP_FLAG_ACK (1<<4) #define TCP_FLAG_SYN (1<<1) #define TCP_FLAG_PSH (1<<3) #define TCP_FLAG_RST (1<<2) #define TCP_FLAG_FIN (1<<0) // A sparse TCP flag interpreter that implements basic TCP connections from a single source int incomingLen = dataLen; // remember length of incoming packet dataLen = 0; // most of our responses will have zero TCP data, only a header if ( ((flagsTCP & ~TCP_FLAG_ACK) == 0) && ((flagsTCP & TCP_FLAG_ACK) != 0) ) { if (incomingLen > 0) { // they sent data in the ack ack = seq + incomingLen; // acknowledge the number of bytes they sent seq = ppp.seq; // confirm our current sequence position } else { if (ack <= ppp.seq) return; // their idea of our sequence is larger int temp = ack; // remember what they thought ack = seq; // ack their sequence ppp.seq = temp; // adopt their calculation of our sequence seq = ppp.seq; } } else if ( (flagsTCP & TCP_FLAG_FIN) != 0 ) { // got FIN flagbitstcp[1] |= TCP_FLAG_ACK; // do a fin-ack ack = seq; seq = ppp.seq; } else if ( (flagsTCP & TCP_FLAG_SYN) != 0 ) { // got SYN flagbitstcp[1] |= TCP_FLAG_ACK; // do a syn-ack ack = seq + 1; // when you see SYN you increment their sequence seq = ppp.seq-1; // we cheat - our sequence will be one higher hereafter } else if ( (flagsTCP & TCP_FLAG_PSH) != 0 ) { // they are pushing data // Ok, we are done with figuring out the flags. Now we start preparing to respond int temp = ack; ack = seq + incomingLen; // acknowledge the number of bytes they sent by adding it to seq ppp.seq = temp; // adopt their calculation of our sequence number seq = ppp.seq; // let's check incoming text for an HTTP home page GET request if ( strncmp(dataStart, "GET / HTTP/1.1", 14) == 0) { flagbitstcp[1] = TCP_FLAG_FIN; // close connection after delivering page dataLen = 15*32; // this block has to hold the web page below, but keep it under 1k memset(dataStart,'x', dataLen ); // initialize the block int n=0; // number of bytes we have printed so far n=n+sprintf(n+dataStart,"HTTP/1.1 200 OK\r\nServer: PPP-Blinky\r\n"); // http header n=n+sprintf(n+dataStart,"Content-Length: 378\r\n"); // http header n=n+sprintf(n+dataStart,"Content-Type: text/html;charset=us-ascii\r\n\r\n"); // http header int nHeader=n; // byte total of all headers n=n+sprintf(n+dataStart,"<html><head><title>mbed-PPP-Blinky</title><script>window.onload=function()"); // html n=n+sprintf(n+dataStart,"{setInterval(function(){function x(){return document.getElementById('w');};"); // html n=n+sprintf(n+dataStart,"x().innerText = parseInt(x().innerText)+1;},100);};</script></head><body>"); // html n=n+sprintf(n+dataStart,"<h1>mbed-PPP-Blinky Up and Running</h1><h1 id=\"w\" style=\"text-align:"); // html n=n+sprintf(n+dataStart," center\";>0</h1><h1><a href=\"http://bit.ly/pppBlinky\">Source on mbed</h1></body></html>"); // html int contentLength = dataLen-nHeader; // this is how to calculate Content-Length, but using curl -v is easier contentLength = contentLength+0; // get around unreferenced variable warning if (v0) { debug(("HTTP GET dataLen %d*32=%d Header %d Content-Length %d Total %d Margin %d\n",dataLen/32,dataLen,nHeader,contentLength,n,dataLen-n-1)); } } else if ( strncmp(dataStart, "GET /", 4) == 0) { flagbitstcp[1] = TCP_FLAG_FIN; // close connection after delivering page dataLen = 2*32; // this block has to hold the web page below, but keep it under 1k memset(dataStart,'x', dataLen ); // initialize the block int n=0; // number of bytes we have printed so far n=n+sprintf(n+dataStart,"HTTP/1.1 404 Not Found\r\n\r\n\r\n\r\n"); // http header if (v0) { debug(("HTTP 404 Not Found\n")); } } } // now we have to recalculate all the header sizes int newPacketSize = headerSizeIP + tcpHeaderLen + dataLen; pktLen[0] = (newPacketSize>>8); pktLen[1]=newPacketSize; // ip total packet size ppp.pkt.len = newPacketSize+6; // ppp packet length tcpSize = tcpHeaderLen + dataLen; // tcp packet size // redo all the header stuff acktcp[0]=ack>>24; acktcp[1]=ack>>16; acktcp[2]=ack>>8; acktcp[3]=ack>>0; // save ack seqtcp[0]=seq>>24; seqtcp[1]=seq>>16; seqtcp[2]=seq>>8; seqtcp[3]=seq>>0; // save seq char src[4]; char dst[4]; memcpy(src, srcAdr,4); memcpy(dst, dstAdr,4); memcpy(srcAdr, dst,4); memcpy(dstAdr, src,4); // swap ip address source/dest char psrc[2]; char pdst[2]; memcpy(psrc, srctcp,2); memcpy(pdst, dsttcp,2); memcpy(srctcp, pdst,2); memcpy(dsttcp, psrc,2); // swap ip port source/dest headercheck[0]=0; headercheck[1]=0; headerCheckSum(); // redo the ip header checksum char pseudoHeader[12]; int sum; char temp[12]; // for the terrible pseudoheader checksum memcpy( pseudoHeader+0, srcAdr, 8); // source and destination addresses. pseudoHeader[8]=0; pseudoHeader[9]=protocol[0]; pseudoHeader[10]=tcpSize>>8; pseudoHeader[11]=tcpSize; memcpy(temp, s-12, 12); // keep a copy memcpy( s-12, pseudoHeader, 12); // put the header on the tcp packet checksumtcp[0]=0; checksumtcp[1]=0; sum=dataCheckSum(s-12,tcpSize+12); // update TCP checksum checksumtcp[0]=sum>>8; checksumtcp[1]=sum; memcpy( s-12, temp, 12); // overwrite the pseudoheader sendFrame(); // return the TCP packet } void dumpDataTCP() { int ipPktLen = (ppp.pkt.buf[6]<<8)|ppp.pkt.buf[7]; // overall length of ip packet int ipHeaderLen = (ppp.pkt.buf[4]&0xf)*4; // length of ip header int tcpHeaderLen = ((ppp.pkt.buf[4+ipHeaderLen+12]>>4)&0xf)*4;; // length of tcp header int dataLen = ipPktLen - ipHeaderLen - tcpHeaderLen; // data is what's left after the two headers if (v1) { debug(("TCP %d ipHeader %d tcpHeader %d Data %d\n", ipPktLen, ipHeaderLen, tcpHeaderLen, dataLen)); // 1 for more verbose } if (dataLen > 0) { debug(("%s\n",ppp.pkt.buf+4+ipHeaderLen+tcpHeaderLen)); // show the data } } void TCPpacket() { char * ipPkt = ppp.pkt.buf+4; // ip packet start char * version = ipPkt; // top 4 bits char * ihl = ipPkt; // bottom 4 bits char * dscp = ipPkt+1; // top 6 bits char * ecn = ipPkt+1; // lower 2 bits char * pktLen = ipPkt+2; // 2 bytes char * ident = ipPkt+4; // 2 bytes char * flags = ipPkt+6; // 2 bits char * ttl = ipPkt+8; // 1 byte char * protocol = ipPkt+9; // 1 byte char * headercheck= ipPkt+10; // 2 bytes char * srcAdr = ipPkt+12; // 4 bytes char * dstAdr = ipPkt+16; // 4 bytes = total of 20 bytes int versionIP = (version[0]>>4)&0xf; int headerSizeIP = (ihl[0]&0xf)*4; int dscpIP = (dscp[0]>>2)&0x3f; int ecnIP = ecn[0]&3; int packetLength = (pktLen[0]<<8)|pktLen[1]; // ip total packet length int identIP = (ident[0]<<8)|ident[1]; int flagsIP = flags[0]>>14&3; int ttlIP = ttl[0]; int protocolIP = protocol[0]; int checksumIP = (headercheck[0]<<8)|headercheck[1]; char srcIP [16]; snprintf(srcIP,16, "%d.%d.%d.%d", srcAdr[0],srcAdr[1],srcAdr[2],srcAdr[3]); char dstIP [16]; snprintf(dstIP,16, "%d.%d.%d.%d", dstAdr[0],dstAdr[1],dstAdr[2],dstAdr[3]); if (v0) { debug(("IP %s %s v%d h%d d%d e%d L%d ",srcIP,dstIP,versionIP,headerSizeIP,dscpIP,ecnIP,packetLength)); } if (v0) { debug(("i%04x f%d t%d p%d C%04x\n",identIP,flagsIP,ttlIP,protocolIP,checksumIP)); } dumpHeaderTCP(); dumpDataTCP(); tcpHandler(); } void otherProtocol() { debug(("Other IP protocol")); } void IPframe() { int protocol = ppp.pkt.buf[13]; switch (protocol) { case 1: ICMPpacket(); break; case 2: IGMPpacket(); break; case 17: UDPpacket(); break; case 6: TCPpacket(); break; default: otherProtocol(); } } void LCPconfReq() { debug(("LCP Config ")); if (ppp.pkt.buf[7] != 4) { ppp.pkt.buf[4]=4; // allow only no options debug(("Reject\n")); sendFrame(); } else { ppp.pkt.buf[4]=2; // ack zero conf debug(("Ack\n")); sendFrame(); debug(("LCP Ask\n")); ppp.pkt.buf[4]=1; // request no options sendFrame(); } } void LCPconfAck() { debug(("LCP Ack\n")); } void LCPend() { debug(("LCP End\n")); ppp.online=0; // start hunting for connect string again ppp.pkt.buf[4]=6; sendFrame(); // acknowledge } void LCPother() { debug(("LCP Other\n")); dumpFrame(); } void LCPframe() { int code = ppp.pkt.buf[4]; switch (code) { case 1: LCPconfReq(); break; // config request case 2: LCPconfAck(); break; // config ack case 5: LCPend(); break; // end connection default: LCPother(); } } void discardedFrame() { if (v0) { debug(("Dropping frame %02x %02x %02x %02x\n", ppp.pkt.buf[0],ppp.pkt.buf[1],ppp.pkt.buf[2],ppp.pkt.buf[3])); } } void determinePacketType() { if ( ppp.pkt.buf[0] != 0xff ) { debug(("byte0 != ff\n")); return; } if ( ppp.pkt.buf[1] != 3 ) { debug(("byte1 != 3\n")); return; } if ( ppp.pkt.buf[3] != 0x21 ) { debug(("byte2 != 21\n")); return; } int packetType = ppp.pkt.buf[2]; switch (packetType) { case 0xc0: LCPframe(); break; // link control case 0x80: IPCPframe(); break; // IP control case 0x00: IPframe(); break; // IP itself default: discardedFrame(); } } void scanForConnectString() { if ( ppp.online==0 ) { char * clientFound = strstr( (char *)rxbuf, "CLIENTCLIENT" ); // look for PC string if( clientFound ) { strcpy( clientFound, "FOUND!FOUND!" ); // overwrite so we don't get fixated pc.printf("CLIENTSERVER"); // respond to PC ppp.online=1; // we can stop looking for the string debug(("Connect string found\n")); } } } int main() { pc.baud(115200); // USB virtual serial port xx.baud(115200); // second serial port for debug(((((((( messages xx.puts("\x1b[2J\x1b[HReady\n"); // VT100 code for clear screen & home pppInitStruct(); // initialize all the PPP properties pc.attach(&rxHandler,Serial::RxIrq); // start the receive handler int frameStartIndex, frameEndIndex; int frameBusy=0; while(1) { if ( ppp.online==0 ) scanForConnectString(); // try to connect while ( rxbufNotEmpty() ) { int rx = pc_getBuf(); if (frameBusy) { if (rx==FRAME_7E) { frameBusy=0; // done gathering frame frameEndIndex=ppp.rx.tail-1; // remember where frame ends processFrame(frameStartIndex, frameEndIndex); } } else { if (rx==FRAME_7E) { frameBusy=1; // start gathering frame frameStartIndex=ppp.rx.tail; // remember where frame started } } } } }