Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
main.cpp
- Committer:
- nixnax
- Date:
- 2017-01-05
- Revision:
- 37:2e6689f8b181
- Parent:
- 36:2a9b457f8276
- Child:
- 38:ab582987926e
File content as of revision 37:2e6689f8b181:
#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;
int oldFlags;
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=1000;
ppp.ledState=0;
ppp.oldFlags=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 %u Ack %u", 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 headerSizeTCP = ((offset[0]>>4)&0x0f)*4; // size of tcp header only
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 flagsTCP = ((flagbitstcp[0]&1)<<8)|flagbitstcp[1];
char * dataStart = ppp.pkt.buf + 4 + headerSizeIP + headerSizeTCP; // start of data block after TCP header
int incomingLen = tcpSize - headerSizeTCP; // size of data block after TCP header
#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 dataLen = 0; // most of our responses will have zero TCP data, only a header
int flagsOut = TCP_FLAG_ACK; // the default case is an ack
int fastResponse = 0; // normally we wait 200ms before sending but this can make it faster
if ( ((flagsTCP & ~TCP_FLAG_ACK) == 0) && ((flagsTCP & TCP_FLAG_ACK) != 0) ) {
if (incomingLen == 0) return; // no new data
} else if ( (flagsTCP & TCP_FLAG_FIN) != 0 ) { // got FIN
if ((ppp.oldFlags & TCP_FLAG_FIN) !=0) return;
seq++; // increase sequence by 1 for FIN and SYNC
} else if ( (flagsTCP & TCP_FLAG_SYN) != 0 ) { // got SYN
flagsOut = TCP_FLAG_SYN | TCP_FLAG_ACK; // do a syn-ack
seq++; // increase sequency by for FIN and SYN
} else if ( (flagsTCP & TCP_FLAG_PSH) != 0 ) { // they are pushing data
fastResponse = 1; // we can response fast to a push
// It's a push - let's check the data for an HTTP home page GET request
if ( strncmp(dataStart, "GET / HTTP/1.1", 14) == 0) {
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=1; // 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: 376\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));
}
} else if ( strncmp(dataStart, "GET /", 4) == 0) { // all other files get 404 not found
dataLen = 5*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;
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: 58\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>"); // html
n=n+sprintf(n+dataStart,"<body><h1>File Not Found</h1></body>\r\n</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));
}
} else {
dataLen=0;
}
} else {
dataLen=0;
}
// All the flag checking is now donw
ppp.oldFlags = flagsTCP; // remember the flags for the next round
// Now we have to recalculate all the header sizes
ack = seq + incomingLen; // acknowledge the number of bytes they sent by adding it to seq
seq = ppp.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
int newPacketSize = headerSizeIP + headerSizeTCP + dataLen;
pktLen[0] = (newPacketSize>>8);
pktLen[1]=newPacketSize; // ip total packet size
ppp.pkt.len = newPacketSize+6; // ppp packet length
tcpSize = headerSizeTCP + dataLen; // tcp packet size
flagbitstcp[1] = flagsOut; // set up the new flags
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
// redo all the header stuff
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
if (fastResponse==1) {
fastResponse=0; // reset and skip 200 ms wait
} else {
wait(0.2); // wait 200 ms before sending packet
}
sendFrame(); // return the TCP packet
ppp.seq = ppp.seq + dataLen; // increase OUR sequence by outgoing data length - for the next round
}
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 headerSizeTCP = ((ppp.pkt.buf[4+ipHeaderLen+12]>>4)&0xf)*4;; // length of tcp header
int dataLen = ipPktLen - ipHeaderLen - headerSizeTCP; // data is what's left after the two headers
if (v1) {
debug(("TCP %d ipHeader %d tcpHeader %d Data %d\n", ipPktLen, ipHeaderLen, headerSizeTCP, dataLen)); // 1 for more verbose
}
if (dataLen > 0) {
debug(("%s\n",ppp.pkt.buf+4+ipHeaderLen+headerSizeTCP)); // 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
}
}
}
}
}