RealtimeCompLab2

Dependencies:   mbed

Fork of PPP-Blinky by Nicolas Nackel

main.cpp

Committer:
nixnax
Date:
2016-12-29
Revision:
6:fba4c2e817b8
Parent:
5:27624c02189f
Child:
7:ab147f5e97ac

File content as of revision 6:fba4c2e817b8:

#include "mbed.h"

// 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 authentication, passwords, compression etc. Simplest link possible.

// Nice links
// http://atari.kensclassics.org/wcomlog.htm
// https://technet.microsoft.com/en-us/library/cc957992.aspx
// http://www.sunshine2k.de/coding/javascript/crc/crc_js.html

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); // debug port - use a second USB serial port to monitor

DigitalOut led1(LED1);

#define FRAME_7E (0x7e)
#define BUFLEN (1<<14)
char rxbuf[BUFLEN];
char frbuf[3000]; // buffer for ppp frame

struct {
    int online; 
    struct {
        char * buf;
        int head; 
        int tail; 
    } rx; // serial port buffer
    struct {
        int id;
        int len;
        int crc;
        char * buf;
    } pkt; // ppp buffer
} ppp;

void pppInitStruct(){ ppp.online=0; ppp.rx.buf=rxbuf; ppp.rx.tail=0; ppp.rx.head=0; ppp.pkt.buf=frbuf; ppp.pkt.len=0;}

int crcG; // frame check sequence (CRC) holder
void crcDo(int x){for (int i=0;i<8;i++){crcG=((crcG&1)^(x&1))?(crcG>>1)^0x8408:crcG>>1;x>>=1;}} // crc calculator
void crcReset(){crcG=0xffff;} // crc restart

void rxHandler() // serial port receive interrupt handler
{
    ppp.rx.buf[ppp.rx.head]=pc.getc(); // insert in buffer
    __disable_irq();
    ppp.rx.head=(ppp.rx.head+1)&(BUFLEN-1);
    __enable_irq();
}

int pc_readable() // check if buffer has data
{
    return (ppp.rx.head==ppp.rx.tail) ? 0 : 1 ;
}

int pc_getBuf() // get one character from the buffer
{
    if (pc_readable()) {
        int x = ppp.rx.buf[ ppp.rx.tail ];
        ppp.rx.tail=(ppp.rx.tail+1)&(BUFLEN-1);
        return x;
    }
    return -1;
}

void scanForConnectString(); // scan for connect attempts from pc

int main()
{
    pc.baud(19200);
    xx.baud(115200); 
    xx.puts("\x1b[2J\x1b[H"); // VT100 terminal control code for screen clear/home
    
    pppInitStruct(); // structure containing all the PPP stuff

    pc.attach(&rxHandler,Serial::RxIrq); // activate the receive interrupt handler

    int frameStartIndex, frameEndIndex;
    int frameBusy=0;

    while(1) {
        while ( pc_readable() ) {
            int rx = pc_getBuf();
            if (frameBusy) { 
                if (rx==FRAME_7E) {
                    frameBusy=0; // done gathering frame
                    frameEndIndex=ppp.rx.tail-1; // remember where frame ends
                    void processFrame(int start, int end); // process a received frame
                    processFrame(frameStartIndex, frameEndIndex);
                }
            } 
            else {
                if (rx==FRAME_7E) {
                    frameBusy=1; // start gathering frame
                    frameStartIndex=ppp.rx.tail; // remember where frame starts
                }
            }
        }
        if (ppp.online==0) scanForConnectString(); // try to connect
    }
}

void processFrame(int start, int end) {
    crcReset();
    char * dest = ppp.pkt.buf;
    ppp.pkt.len=0;
    int special=0;
    for (int i=start; i<end; i++) {
        if (special==0) {
            if (rxbuf[i]==0x7d) special=1; 
            else { *dest++ = rxbuf[i]; ppp.pkt.len++; crcDo(rxbuf[i]);}
        } else {
            *dest++ = rxbuf[i]-32; ppp.pkt.len++; crcDo(rxbuf[i]-32);
            special=0;
        }
    }
    ppp.rx.head=0; // reuse rxbuf
    ppp.rx.tail=0; // reuse rxbuf
    ppp.pkt.crc = crcG;
    if (crcG == 0xf0b8) { // check for good CRC
        void determinePacketType(); // declare early
        determinePacketType();
    }
}


void sendFrame(){
    crcReset(); for(int i=0;i<ppp.pkt.len-2;i++) crcDo(ppp.pkt.buf[i]);
    ppp.pkt.buf[ ppp.pkt.len-2 ] = ((~crcG)>>0); // build crc lo
    ppp.pkt.buf[ ppp.pkt.len-1 ] = ((~crcG)>>8); // build crc hi
    pc.putc(0x7e); // start of frame
    for(int i=0;i<ppp.pkt.len;i++) {
        unsigned int cc = (unsigned int)ppp.pkt.buf[i];
        if (cc>32) pc.putc(cc); else {pc.putc(0x7d);pc.putc(cc+32);}
    } 
    pc.putc(0x7e); // end of frame
}



void LCPrequestFrame() {
    ppp.pkt.buf[4]=2; // change to an ACK packet
    sendFrame(); // acknowledge their request
    // this is the right time to send our LCP setup request to them
    ppp.pkt.buf[4]=1; // change back to a request
    ppp.pkt.buf[5] =  ppp.pkt.buf[5]+1; // take the next id
    ppp.pkt.buf[16] = ppp.pkt.buf[16] ^ 0x33; // modify magic number
    ppp.pkt.buf[17] = ppp.pkt.buf[16] ^ 0x33; // modify magic number
    sendFrame(); // send our request

}
    
void LCPackFrame() {
    xx.printf("== PPP is up ==\n");
} 

void generalFrame() {
    xx.printf("== General Frame ==\n");
    for(int i=0;i<ppp.pkt.len;i++) xx.printf("%02x ", ppp.pkt.buf[i]);
    xx.printf(" C %02x %02x L=%d\n", ppp.pkt.crc&0xff, (ppp.pkt.crc>>8)&0xff, ppp.pkt.len);
}    

void rejectIPcompression() {
    xx.printf("== IP Compression Reject Frame ==\n");
    generalFrame();
    static char rejectCompression [] = {0x80,0x21,4,0,0,10,2,6,0,45,15,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    // 128/33=IPCP 4=Rej 0=id 0=sizeHigh 10=sizeLow 2,6,0,45,1=RejectCcompression                         
    ppp.pkt.len=sizeof( rejectCompression );
    memcpy( rejectCompression, ppp.pkt.buf, ppp.pkt.len);
    ppp.pkt.buf[3]=ppp.pkt.id;
    sendFrame();
}    

void ipRequestHandler(){
    xx.printf("== IP Request Frame ==\n");
    //static char compressRequest[] = {2,6,0,45,15,1}; 
    //if(0==memcmp(ppp.pkt.buf+6, compressRequest, 6)) rejectIPcompression();
    generalFrame();
    ppp.pkt.buf[2]=2; // ACK
    sendFrame(); // acknowledge
    
    ppp.pkt.buf[2]=1; // request
    ppp.pkt.buf[3]++; // next sequence
    sendFrame(); // now WE do a request
    
}

void ipAckHandler(){
    xx.printf("== IP Ack Frame ==\n");
}

void ipNackHandler(){
     xx.printf("== IP Nack Frame ==\n");
}

void ipDefaultHandler(){
     xx.printf("== IP Unknown Frame ==\n");
}

void LCPgeneralFrame(){
     xx.printf("== LCP General Handler ==\n");
     generalFrame();
}


void LCPhandler(){
     xx.printf("== LCP Handler ==\n");
     int action = ppp.pkt.buf[4];
     if(0);
     else if ( action == 1 ) LCPrequestFrame();
     else if ( action == 2 ) LCPackFrame();
     else LCPgeneralFrame();
}

void IPFrame() {
    led1 = ppp.pkt.buf[3] & 1; // This is the sequence number so the led blinks on packets
    ppp.pkt.len = (((unsigned int)ppp.pkt.buf[4])<<8) + (((unsigned int)ppp.pkt.buf[5])<<0);
    ppp.pkt.id = ppp.pkt.buf[3]; // remember the sequence number 
    int action = ppp.pkt.buf[2]; // packet type is here
    if(0);
    else if ( action == 1 ) ipRequestHandler();
    else if ( action == 2 ) ipAckHandler();
    else if ( action == 3 ) ipNackHandler();
    else ipDefaultHandler();    
}    

void determinePacketType() {
    static char pktLCPReqType  [] = { 0xff, 3, 0xc0, 0x21 }; // LCP requeswt  packet
    static char pktIPCPtype    [] = { 0x80, 0x21, 1       }; // ip control packet

    if(0);
    else if (0==memcmp( ppp.pkt.buf,pktLCPReqType,4)) LCPhandler(); 
    else if (0==memcmp( ppp.pkt.buf,pktIPCPtype,  3)) IPFrame(); 
    else generalFrame(); // default handler
}    

void scanForConnectString(){
    char * clientFound = strstr( 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
    }
}