Small Internet Protocol Stack using a standard serial port.

Dependencies:   mbed

PPP-Blinky - TCP/IP Networking Over a Serial Port

Note: The source code is at the bottom of this page.

/media/uploads/nixnax/blinky-connected.gif
A Windows desktop showing PPP-Blinky in the network connections list.

Describe PPP-Blinky in Three Sentences

PPP-Blinky is a tiny library that enables Internet protocols (IPv4) to any mbed target hardware by using only a serial port.

The code runs on processors with as little as 8k RAM, for example the Nucleo-L053R8 board.

PPP-Blinky uses the industry-standard PPP (Point-to-Point) Protocol and a tiny "stateless" TCP/IP stack.

No Ethernet Port Required

No ethernet port is required - PPP-Blinky uses a serial port to send IP packets to your PC.

PPP-Blinky emulates a standard dial-up modem and therefore connects to Windows, Linux or Adroid machines.

The code runs on most ARM mbed platforms such as the LPC11U24 shown in the picture below:

/media/uploads/nixnax/blinky-to-laptop1.jpg mbed LPC11u24 acting as a webserver to a Windows laptop.

Webserver

The Webserver and WebSocket functions are ideal for building browser-based GUIs on mbed-enabled hardware.

PPP-Blinky's HTTP webserver works with most web clients such as Internet Explorer, Mozilla Firefox, Google Chrome, Safari, Curl, wget and Lynx as well as Microsoft Powershell Invoke-Webrequest command.

In the image below Firefox web browser displays the main web page embedded into PPP-Blinky's code:

/media/uploads/nixnax/ppp-blinky-firefox.jpg Firefox web browser displays a web page embedded into PPP-Blinky's code

WebSocket Service

WebSocket is the most popular protocol standard for real-time bidirectional TCP/IP communication between clients and servers.
In the image below a small Internet Explorer script has connected to PPP-Blinky's WebSocket Service.
A websocket message was then sent by the browser and was echoed back by the WebSocket, triggering the onmessage event in the script.
The WebSocket service enables bidirectional real-time interaction between PPP-Blinky and any element in the browser DOM via JavaScript.
If you already have PPP-Blinky up and running you can test your WebSocket service using this: http://jsfiddle.net/d26cyuh2/112/embedded/result
Websockets are ideal for building browser-based GUIs for mbed hardware.

/media/uploads/nixnax/ppp-blinky-websocke-2.gif

Trying PPP-Blinky on your mbed board

You will need an mbed-enabled hardware board: https://developer.mbed.org/platforms/

Establish a serial port connection between your host PC and your mbed board. The easiest way is to use mbed hardware with a USB serial debug port. I've tried the ST-Micro Nucleo-L476RG, Nucleo-L152RE, Nucleo-F401RE, Nucleo-L432KC, Nucleo-L053R8, mbed-LPC11U24 and mbed-LPC1768 boards and they all work out of the box. Use the mbed online compiler to compile the software for your target board. Save the compiled binary to your hardware.

Before establishing a network connection, you can verify the operation of the code by opening a terminal program such as Tera Term, and setting the baud rate of the COM port on your mbed board to 115200 baud. LED1 should toggle for every two 0x7E (~) (i.e. tilde) characters you type, as 0x7E is the PPP frame start/end marker. Don't forget to close the port when your'e done testing, or else Windows Dial-up Networking will report that the COM port is in use by another program when you try to connect.

Once you are certain that the serial port and firmware is working, proceed to creating a new network connection on your PC -see below.

Creating a Dial-up Connection in Windows

/media/uploads/nixnax/modem.jpg

Setting up Dial-Up Networking (DUN) on your Windows 7 or 8 PC is essentially a two-step process: First, you create a new modem device, because PPP-blinky partially emulates a standard Windows serial port modem device. Second, you create a new Internet connection (in practice, a new network adapter) which is associated with your new "modem".

Step-by-step description of how to configure Windows for PPP-Blinky here:

/users/nixnax/code/PPP-Blinky/wiki/Configuring-Windows-Dial-Up-Networking

There is also a screen on how to set up Linux dial-up networking near the bottom of this page.

Connecting to PPP-Blinky from your PC

Once Windows networking is configured you can establish a dial-up connection to your mbed board over the USB virtual com port.

The IP address you manually assigned to the new dial-up network adapter (172.10.10.1) functions as a gateway to any valid IP address on that subnet. In the screen capture below, I'm sending pings from the Windows 8 command line to my ST-Micro Nucleo-L476RG board over the USB virtual serial Port. I'm also using a second serial port and Tera Term to capture the debug output from a second serial port on the hardware. The optional debug output from the board prints out the IP source and destination address and the first few bytes of the data payload. Note that the source is the adapter IP address, (172.10.10.1 in this case) and the destination is some other address on that subnet - all packets to the subnet are sent to our mbed hardware. For example, you could also ping 172.10.10.123 or, if your PPP-Blinky is running, simply click on this link: http://172.10.10.123

/media/uploads/nixnax/ping-cap-3.gif

One Million Pings!

In the image below the ICMP ("ping") echo reply service was tested by sending one million pings to ppp-Blinky. This took over two hours.
The ping tool used on the Windows 8 PC was psping.exe from PsTools by Mark Russinovich - http://bit.ly/PingFast
The average reply time for a short ping (1 byte of payload data) was 11 milliseconds at 115200 baud on the $10 Nucleo-L053R8 board - barely enough time for 130 bytes to be sent over the port!

/media/uploads/nixnax/ppp-blinky-ping-results.jpg

Monitoring PPP-Blinky Packets

The image below is from a Microsoft Network Monitor 3.4 capture session.

Responses from PPP-Blinky are shown in blue.

Frame 2 - Internet Explorer at IP 172.10.10.1 (the Dial-Up Adapter IP) requests a TCP connection by sending an S (SYN) flag.
Frame 3 - PPP-Blinky at IP 172.10.10.2 responds with an ACK in frame 3. One direction of the link is now established.
Frame 4 - The PC acknowledges the SYN sent by PPP-Blinky in frame 3. The TCP link is now fully established.
Frame 5 - The browser "pushes" (P flag is set) an HTTP GET request to PPP-Blinky.
Frame 6 - PPP-Blinky responds with a standard HTTP response "pushes" (P flag set) back a small web page. It also sets the A (ACK) flag to acknowledge the message sent in frame 6.
Frame 7 - The PC acknowledges reception of the HTTP payload.
Frame 8 - The PC starts to shut down the TCP connection by sending a FIN flag.
Frame 9 - PPP-Blinky acknowledges the FIN request - the connection is now closed in one direction. It also sets a FIN flag in the response to request closure of the opposite direction of the connection.
Frame 10 - The PC acknowledges the FIN request. The closing of the TCP connection is now confirmed in both directions.

/media/uploads/nixnax/ms-network-monitor-http-get-1.gif

Debug Output

PPP-Blinky can output handy debug information to an optional second serial port.
The image below shows the debug output (Ident, Source, Destination, TCP Flags) for a complete HTTP conversation.
The PC messages are displayed in black. PPP-Blinky messages are blue.
Notice how PPP-blinky automatically inserts a blank line after each full HTTP conversation.

/media/uploads/nixnax/tcp-data-3.gif

Creating a Dial-Up Connection in Linux

The screen below shows the required pppd command to connect to PPP-Blinky from a Linux machine. This was much simpler than Windows! The USB serial port of the mbed LPC1768 board registered as /dev/ttyACM0 on my Linux box. Do a websearch on pppd if you want to learn more about pppd, the Linux PPP handler. Near the bottom of the screen below, two webpages are fetched (/ and /y) by using the curl command on the command line. Gnome Webkit and Firefox work fine, too. Also try echo GET / HTTP/1.1 | nc 172.10.10.2 which uses netcat, the "Swiss army knife" of networking tools. PPP-Blinky was also tested with ApacheBench, the Apache server benchmark software. After 100000 fetches, the mean page fetch rate was reported as 6 page fetches per second for a small page.

/media/uploads/nixnax/pppd-screen.png

Caveats

PPP Blinky is an extremely sparse implementation (1.5k lines) of HTTP,WebSocket,TCP, UDP, ICMP, IPCP and LCP over PPP, requiring around 8kB of RAM. The minimum functionality required to establish connectivity is implemented. These are often acceptable tradeoffs for embedded projects as well as a handy tool to learn the practical details of everyday networking implementations.

Committer:
nixnax
Date:
Tue Aug 08 20:02:35 2017 +0000
Revision:
122:963abcbff21e
Parent:
121:705679672685
Child:
123:fc64fc6caae0
Renamed to PPP_max_size

Who changed what in which revision?

UserRevisionLine numberNew contents of line
nixnax 93:9675adc36882 1 // PPP-Blinky - "The Most Basic Internet Of Things"
nixnax 0:2cf4880c312a 2
nixnax 93:9675adc36882 3 // A Tiny Webserver Using Windows XP/7/8/10/Linux Dial-Up Networking Over A Serial Port.
nixnax 41:e58a5a09f411 4 // Also receives UDP packets and responds to ping (ICMP Echo requests)
nixnax 4:a469050d5b80 5
nixnax 93:9675adc36882 6 // Copyright 2016/2017 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.
nixnax 81:9ede60e9a2c8 7
nixnax 41:e58a5a09f411 8 // Notes and Instructions
nixnax 41:e58a5a09f411 9 // http://bit.ly/PPP-Blinky-Instructions
nixnax 114:8a5d70bbc1b2 10 // http://bit.ly/win-rasdial-config
nixnax 0:2cf4880c312a 11
nixnax 41:e58a5a09f411 12 // Handy reading material
nixnax 6:fba4c2e817b8 13 // https://technet.microsoft.com/en-us/library/cc957992.aspx
nixnax 9:0992486d4a30 14 // https://en.wikibooks.org/wiki/Serial_Programming/IP_Over_Serial_Connections
nixnax 39:b90183d35f1e 15 // http://bit.ly/dialup777error - how to solve Dial Up Error 777 in Windows 7/8/10
nixnax 41:e58a5a09f411 16 // http://atari.kensclassics.org/wcomlog.htm
nixnax 6:fba4c2e817b8 17
nixnax 29:30de79d658f6 18 // Handy tools
nixnax 44:d0c61ae49ea5 19 // https://ttssh2.osdn.jp/index.html.en - Tera Term, a good terminal program to monitor the debug output from the second serial port with!
nixnax 109:644a59ebb5b1 20 // https://www.microsoft.com/en-us/download/details.aspx?id=4865 - Microsoft network monitor - real-time monitoring of PPP packets
nixnax 29:30de79d658f6 21 // http://pingtester.net/ - nice tool for high rate ping testing
nixnax 95:40af49390daf 22 // http://www.sunshine2k.de/coding/javascript/crc/crc_js.html - Correctly calculates the 16-bit FCS (crc) on our frames (Choose CRC16_CCITT_FALSE), then custom relected-in=1, reflected-out=1
nixnax 29:30de79d658f6 23 // https://technet.microsoft.com/en-us/sysinternals/pstools.aspx - psping for fast testing of ICMP ping function
nixnax 41:e58a5a09f411 24 // https://eternallybored.org/misc/netcat/ - use netcat -u 172.10.10.1 80 to send/receive UDP packets from PPP-Blinky
nixnax 91:5141ae9fba53 25 // Windows Powershell invoke-webrequest command - use it to stress test the webserver like this: while (1){ invoke-webrequest -uri 172.10.10.1/x }
nixnax 41:e58a5a09f411 26
nixnax 92:cb962b365cce 27 // Connecting PPP-Blinky to Linux
nixnax 93:9675adc36882 28 // PPP-Blinky can be made to talk to Linux - tested on Fedora - the following command, which uses pppd, works:
nixnax 93:9675adc36882 29 // pppd /dev/ttyACM0 115200 debug dump local passive noccp novj nodetach nocrtscts 172.10.10.1:172.10.10.2
nixnax 92:cb962b365cce 30 // in the above command 172.10.10.1 is the adapter IP, and 172.10.10.2 is the IP of PPP-Blinky.
nixnax 93:9675adc36882 31 // See also https://en.wikipedia.org/wiki/Point-to-Point_Protocol_daemon
nixnax 93:9675adc36882 32
nixnax 93:9675adc36882 33 // Ok, enough talking, time to check out some code!!
nixnax 106:d14e6b597ca3 34
nixnax 81:9ede60e9a2c8 35 #include "mbed.h"
nixnax 66:f005b9fdf4d1 36
nixnax 93:9675adc36882 37 // The #define below enables/disables a second (OPTIONAL) serial port that prints out interesting diagnostic messages.
nixnax 66:f005b9fdf4d1 38 // Change to SERIAL_PORT_MONITOR_YES to enable diagnostics messages. You need to wire a second serial port to your mbed hardware to monitor this.
nixnax 110:baec959e1915 39 // Note - the LPC11U24 does NOT have a second serial port
nixnax 120:bef89e4c906e 40 #define SERIAL_PORT_MONITOR_NO /* change to SERIAL_PORT_MONITOR_YES for debug messages */
nixnax 0:2cf4880c312a 41
nixnax 93:9675adc36882 42 // here we define the OPTIONAL, second debug serial port for the various target boards
nixnax 93:9675adc36882 43 // insert your target board's port here if it's not in yet - if it works, please send it to me - thanks!!!
nixnax 114:8a5d70bbc1b2 44 #ifdef SERIAL_PORT_MONITOR_YES
nixnax 117:c819ae068336 45 #if defined(TARGET_LPC1768)
nixnax 117:c819ae068336 46 Serial xx(p9, p10); // Second serial port on LPC1768 - not required to run, if you get compile error here, change #define SERIAL_PORT_MONITOR_YES to #define SERIAL_PORT_MONITOR_NO
nixnax 117:c819ae068336 47 #elif defined(TARGET_NUCLEO_F446RE) || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_L053R8) || defined(TARGET_NUCLEO_L476RG) || defined(TARGET_NUCLEO_F401RE)
nixnax 117:c819ae068336 48 Serial xx(PC_10, PC_11); // Second serial port on NUCLEO boards - not required to run, if you get compile error here, change #define SERIAL_PORT_MONITOR_YES to #define SERIAL_PORT_MONITOR_NO
nixnax 117:c819ae068336 49 #elif defined(TARGET_LPC11U24)
nixnax 117:c819ae068336 50 #error The LPC11U24 does not have a second serial port to use for debugging - change SERIAL_PORT_MONITOR_YES back to SERIAL_PORT_MONITOR_NO
nixnax 118:54d1936e3768 51 #elif defined(YOUR_TARGET_BOARD_NAME_HERE)
nixnax 118:54d1936e3768 52 Serial xx(p9, p10); // insert your board's debug serial port pins here - and please send it to me if it works
nixnax 85:53e57ff1cf05 53 #else
nixnax 117:c819ae068336 54 #error Add your target board's second serial port here if you want to use debugging - or choose SERIAL_PORT_MONITOR_NO
nixnax 117:c819ae068336 55 #endif
nixnax 119:e14dd2bf0ea3 56 #define debugPrintf(x...) xx.printf (x) /* if we have a serial port we print debug messages */
nixnax 119:e14dd2bf0ea3 57 #define debugPutc(x...) xx.putc(x)
nixnax 118:54d1936e3768 58 #define debugBaudRate(x...) xx.baud(x)
nixnax 117:c819ae068336 59 #else
nixnax 119:e14dd2bf0ea3 60 // if we don't have a debug port the debug print functions do nothing
nixnax 119:e14dd2bf0ea3 61 #define debugPrintf(x...) {}
nixnax 119:e14dd2bf0ea3 62 #define debugPutc(x...) {}
nixnax 118:54d1936e3768 63 #define debugBaudRate(x...) {}
nixnax 41:e58a5a09f411 64 #endif
nixnax 41:e58a5a09f411 65
nixnax 110:baec959e1915 66 // verbosity flags used in debug printouts - change to 1 to see increasingly more detailed debug info.
nixnax 112:30172f36bd33 67 #define v0 1
nixnax 120:bef89e4c906e 68 #define v1 1
nixnax 77:abf92baebb42 69 #define v2 0
nixnax 114:8a5d70bbc1b2 70 #define IP_HEADER_DUMP_YES /* YES for ip header dump */
nixnax 114:8a5d70bbc1b2 71 #define TCP_HEADER_DUMP_YES /* YES for tcp header dump */
nixnax 29:30de79d658f6 72
nixnax 93:9675adc36882 73 // this is the webpage we serve when we get an HTTP request to root (/)
nixnax 93:9675adc36882 74 // keep size under ~900 bytes to fit into a single PPP packet
nixnax 93:9675adc36882 75 const static char rootWebPage[] = "\
nixnax 66:f005b9fdf4d1 76 <!DOCTYPE html>\
nixnax 66:f005b9fdf4d1 77 <html>\
nixnax 66:f005b9fdf4d1 78 <head>\
nixnax 66:f005b9fdf4d1 79 <title>mbed-PPP-Blinky</title>\
nixnax 66:f005b9fdf4d1 80 <script>\
nixnax 66:f005b9fdf4d1 81 window.onload=function(){\
nixnax 66:f005b9fdf4d1 82 setInterval(function(){function x(){return document.getElementById('w');};\
nixnax 66:f005b9fdf4d1 83 x().textContent = parseInt(x().textContent)+1;},100);};\
nixnax 66:f005b9fdf4d1 84 </script>\
nixnax 66:f005b9fdf4d1 85 </head>\
nixnax 66:f005b9fdf4d1 86 <body style=\"font-family: sans-serif; font-size:30px; color:#807070\">\
nixnax 66:f005b9fdf4d1 87 <h1>mbed PPP-Blinky Up and Running</h1>\
nixnax 66:f005b9fdf4d1 88 <h1 id=\"w\" style=\"text-align:center;\">0</h1>\
nixnax 66:f005b9fdf4d1 89 <h1><a href=\"http://bit.ly/pppBlink2\">Source on mbed</a></h1>\
nixnax 66:f005b9fdf4d1 90 </body>\
nixnax 69:23f560087c16 91 </html>"; // around 464 bytes long
nixnax 69:23f560087c16 92
nixnax 73:2f56ec87dbe9 93 // The serial port on your mbed hardware. Your PC should be configured to view this port as a standard dial-up networking modem.
nixnax 73:2f56ec87dbe9 94 // On Windows the model type of the modem should be selected as "Communications cable between two computers"
nixnax 72:ad3d12753acf 95 // The modem baud rate should be set to 115200 baud
nixnax 72:ad3d12753acf 96 // See instructions at the top.
nixnax 73:2f56ec87dbe9 97 // On a typical mbed hardware platform this serial port is a USB virtual com port (VCP) and the USB serial driver is supplied by the board vendor.
nixnax 73:2f56ec87dbe9 98 Serial pc(USBTX, USBRX); // usb virtual com port for mbed hardware
nixnax 29:30de79d658f6 99
nixnax 29:30de79d658f6 100 DigitalOut led1(LED1); // this led toggles when a packet is received
nixnax 4:a469050d5b80 101
nixnax 66:f005b9fdf4d1 102 // the standard hdlc frame start/end character. It's the tilde character "~"
nixnax 4:a469050d5b80 103 #define FRAME_7E (0x7e)
nixnax 29:30de79d658f6 104
nixnax 29:30de79d658f6 105 // a structure to keep all our ppp globals in
nixnax 29:30de79d658f6 106 struct pppType {
nixnax 38:ab582987926e 107 int online; // we hunt for a PPP connection if this is zero
nixnax 38:ab582987926e 108 int crc; // for calculating IP and TCP CRCs
nixnax 38:ab582987926e 109 int ledState; // state of LED1
nixnax 98:3babad0d1bd4 110 int httpPageCount;
nixnax 119:e14dd2bf0ea3 111 int firstFrame; // cleared after first frame
nixnax 4:a469050d5b80 112 struct {
nixnax 105:45001195b325 113 #define RXBUFLEN (1<<11)
nixnax 117:c819ae068336 114 // the serial port receive buffer and packet buffer, size is RXBUFLEN (currently 2048 bytes)
nixnax 85:53e57ff1cf05 115 char buf[RXBUFLEN]; // RXBUFLEN MUST be a power of two because we use & operator for fast wrap-around in ring buffer
nixnax 93:9675adc36882 116 int head;
nixnax 93:9675adc36882 117 int tail;
nixnax 95:40af49390daf 118 int rtail;
nixnax 93:9675adc36882 119 int buflevel;
nixnax 38:ab582987926e 120 } rx; // serial port objects
nixnax 4:a469050d5b80 121 struct {
nixnax 38:ab582987926e 122 int len; // number of bytes in buffer
nixnax 38:ab582987926e 123 int crc; // PPP CRC (frame check)
nixnax 122:963abcbff21e 124 #define PPP_max_size 2500
nixnax 122:963abcbff21e 125 // we are assuming 1000 bytes more MTU size of 1500- due to the PPP encoding of special bytes
nixnax 122:963abcbff21e 126 char buf[PPP_max_size]; // send and receive buffer large enough for raw, encoded PPP/HDLC frames
nixnax 38:ab582987926e 127 } pkt; // ppp buffer objects
nixnax 50:ad4e7c3c88e5 128 struct {
nixnax 50:ad4e7c3c88e5 129 int frameStartIndex; // frame start marker
nixnax 50:ad4e7c3c88e5 130 int frameEndIndex; // frame end marker
nixnax 50:ad4e7c3c88e5 131 } hdlc; // hdlc frame objects
nixnax 114:8a5d70bbc1b2 132 struct {
nixnax 114:8a5d70bbc1b2 133 unsigned int ident; // our IP ident value (outgoing frame count)
nixnax 114:8a5d70bbc1b2 134 } ip; // ip related object
nixnax 29:30de79d658f6 135 };
nixnax 31:e000c1b9c565 136
nixnax 29:30de79d658f6 137 pppType ppp; // our global - definitely not thread safe
nixnax 0:2cf4880c312a 138
nixnax 93:9675adc36882 139 // Initialize our global structure, clear the buffer, etc.
nixnax 29:30de79d658f6 140 void pppInitStruct()
nixnax 29:30de79d658f6 141 {
nixnax 81:9ede60e9a2c8 142 memset( ppp.rx.buf, 0, RXBUFLEN);
nixnax 29:30de79d658f6 143 ppp.online=0;
nixnax 29:30de79d658f6 144 ppp.rx.tail=0;
nixnax 93:9675adc36882 145 ppp.rx.rtail=0;
nixnax 29:30de79d658f6 146 ppp.rx.head=0;
nixnax 81:9ede60e9a2c8 147 ppp.rx.buflevel=0;
nixnax 29:30de79d658f6 148 ppp.pkt.len=0;
nixnax 114:8a5d70bbc1b2 149 ppp.ip.ident=10000; // easy to recognize in ip packet dumps
nixnax 29:30de79d658f6 150 ppp.ledState=0;
nixnax 81:9ede60e9a2c8 151 ppp.hdlc.frameStartIndex=0;
nixnax 98:3babad0d1bd4 152 ppp.httpPageCount=0;
nixnax 119:e14dd2bf0ea3 153 ppp.firstFrame=1;
nixnax 29:30de79d658f6 154 }
nixnax 26:11f4eb2663a7 155
nixnax 43:aa57db08995d 156 void led1Toggle()
nixnax 43:aa57db08995d 157 {
nixnax 43:aa57db08995d 158 ppp.ledState = ppp.ledState? 0 : 1;
nixnax 93:9675adc36882 159 led1 = ppp.ledState; // toggle led
nixnax 43:aa57db08995d 160 }
nixnax 43:aa57db08995d 161
nixnax 85:53e57ff1cf05 162 // fill our own receive buffer with characters from the PPP serial port
nixnax 85:53e57ff1cf05 163 void fillbuf()
nixnax 0:2cf4880c312a 164 {
nixnax 107:5fe806713d49 165 char ch;
nixnax 85:53e57ff1cf05 166 if ( pc.readable() ) {
nixnax 85:53e57ff1cf05 167 int hd = (ppp.rx.head+1)&(RXBUFLEN-1); // increment/wrap head index
nixnax 93:9675adc36882 168 if ( hd == ppp.rx.rtail ) {
nixnax 119:e14dd2bf0ea3 169 debugPrintf("\nReceive buffer full\n");
nixnax 85:53e57ff1cf05 170 return;
nixnax 83:cdcb81d1910f 171 }
nixnax 107:5fe806713d49 172 ch = pc.getc(); // read new character
nixnax 107:5fe806713d49 173 ppp.rx.buf[ppp.rx.head] = ch; // insert in our receive buffer
nixnax 107:5fe806713d49 174 if ( ppp.online == 0 ) {
nixnax 107:5fe806713d49 175 if (ch == 0x7E) {
nixnax 107:5fe806713d49 176 ppp.online = 1;
nixnax 114:8a5d70bbc1b2 177 }
nixnax 114:8a5d70bbc1b2 178 }
nixnax 20:5db9b77b38a6 179 ppp.rx.head = hd; // update head pointer
nixnax 81:9ede60e9a2c8 180 ppp.rx.buflevel++;
nixnax 15:b0154c910143 181 }
nixnax 0:2cf4880c312a 182 }
nixnax 0:2cf4880c312a 183
nixnax 118:54d1936e3768 184 // print to debug port while checking for incoming characters
nixnax 119:e14dd2bf0ea3 185 void putcWhileCheckingInput( char outByte )
nixnax 119:e14dd2bf0ea3 186 {
nixnax 119:e14dd2bf0ea3 187 #ifdef SERIAL_PORT_MONITOR_YES
nixnax 119:e14dd2bf0ea3 188 fillbuf();
nixnax 119:e14dd2bf0ea3 189 debugPutc( outByte );
nixnax 119:e14dd2bf0ea3 190 fillbuf();
nixnax 119:e14dd2bf0ea3 191 #endif
nixnax 119:e14dd2bf0ea3 192 }
nixnax 119:e14dd2bf0ea3 193
nixnax 118:54d1936e3768 194 void printWhileCheckingInput( char * data )
nixnax 118:54d1936e3768 195 {
nixnax 118:54d1936e3768 196 #ifdef SERIAL_PORT_MONITOR_YES
nixnax 118:54d1936e3768 197 char * nextChar = data;
nixnax 118:54d1936e3768 198 while( *nextChar != 0 ) {
nixnax 119:e14dd2bf0ea3 199 putcWhileCheckingInput( *nextChar ); // write one character to debug port while checking input
nixnax 118:54d1936e3768 200 nextChar++;
nixnax 118:54d1936e3768 201 }
nixnax 118:54d1936e3768 202 #endif
nixnax 118:54d1936e3768 203 }
nixnax 118:54d1936e3768 204
nixnax 118:54d1936e3768 205 void crcReset()
nixnax 118:54d1936e3768 206 {
nixnax 118:54d1936e3768 207 ppp.crc=0xffff; // crc restart
nixnax 118:54d1936e3768 208 }
nixnax 118:54d1936e3768 209
nixnax 118:54d1936e3768 210 void crcDo(int x) // cumulative crc
nixnax 118:54d1936e3768 211 {
nixnax 118:54d1936e3768 212 for (int i=0; i<8; i++) {
nixnax 118:54d1936e3768 213 ppp.crc=((ppp.crc&1)^(x&1))?(ppp.crc>>1)^0x8408:ppp.crc>>1; // crc calculator
nixnax 118:54d1936e3768 214 x>>=1;
nixnax 118:54d1936e3768 215 }
nixnax 118:54d1936e3768 216 // fillbuf();
nixnax 118:54d1936e3768 217 }
nixnax 118:54d1936e3768 218
nixnax 118:54d1936e3768 219 int crcBuf(char * buf, int size) // crc on an entire block of memory
nixnax 118:54d1936e3768 220 {
nixnax 118:54d1936e3768 221 crcReset();
nixnax 118:54d1936e3768 222 for(int i=0; i<size; i++)crcDo(*buf++);
nixnax 118:54d1936e3768 223 return ppp.crc;
nixnax 118:54d1936e3768 224 }
nixnax 118:54d1936e3768 225
nixnax 85:53e57ff1cf05 226 int rxbufNotEmpty() // check if rx buffer has data
nixnax 0:2cf4880c312a 227 {
nixnax 43:aa57db08995d 228 int emptyStatus = (ppp.rx.head==ppp.rx.tail) ? 0 : 1 ;
nixnax 43:aa57db08995d 229 return emptyStatus;
nixnax 0:2cf4880c312a 230 }
nixnax 0:2cf4880c312a 231
nixnax 85:53e57ff1cf05 232 int pc_getBuf() // get one character from the buffer
nixnax 0:2cf4880c312a 233 {
nixnax 63:9253b0e1b7d8 234 int x = ppp.rx.buf[ ppp.rx.tail ];
nixnax 81:9ede60e9a2c8 235 ppp.rx.tail=(ppp.rx.tail+1)&(RXBUFLEN-1);
nixnax 81:9ede60e9a2c8 236 ppp.rx.buflevel--;
nixnax 63:9253b0e1b7d8 237 return x;
nixnax 0:2cf4880c312a 238 }
nixnax 0:2cf4880c312a 239
nixnax 95:40af49390daf 240 // Note - the hex output of dumpPPPFrame() can be imported into WireShark
nixnax 95:40af49390daf 241 // Capture the frame's hex output in your terminal program and save as a text file
nixnax 95:40af49390daf 242 // In WireShark, use "Import Hex File". Options are: Offset=None, Protocol=PPP.
nixnax 95:40af49390daf 243 void dumpPPPFrame()
nixnax 95:40af49390daf 244 {
nixnax 120:bef89e4c906e 245 char pbuf[30];
nixnax 120:bef89e4c906e 246 for(int i=0; i<ppp.pkt.len; i++) {
nixnax 120:bef89e4c906e 247 fillbuf();
nixnax 120:bef89e4c906e 248 sprintf(pbuf, "%02x ", ppp.pkt.buf[i]);
nixnax 120:bef89e4c906e 249 fillbuf();
nixnax 120:bef89e4c906e 250 printWhileCheckingInput(pbuf);
nixnax 120:bef89e4c906e 251 }
nixnax 120:bef89e4c906e 252 fillbuf();
nixnax 120:bef89e4c906e 253 sprintf(pbuf, " CRC=%04x Len=%d\n", ppp.pkt.crc, ppp.pkt.len);
nixnax 120:bef89e4c906e 254 fillbuf();
nixnax 120:bef89e4c906e 255 printWhileCheckingInput(pbuf);
nixnax 95:40af49390daf 256 }
nixnax 95:40af49390daf 257
nixnax 119:e14dd2bf0ea3 258 void processPPPFrame(int start, int end) // process received frame
nixnax 29:30de79d658f6 259 {
nixnax 38:ab582987926e 260 led1Toggle(); // change led1 state on every frame we receive
nixnax 29:30de79d658f6 261 if(start==end) {
nixnax 111:6a3b77c065c0 262 return; // empty frame
nixnax 29:30de79d658f6 263 }
nixnax 9:0992486d4a30 264 crcReset();
nixnax 9:0992486d4a30 265 char * dest = ppp.pkt.buf;
nixnax 9:0992486d4a30 266 ppp.pkt.len=0;
nixnax 9:0992486d4a30 267 int unstuff=0;
nixnax 17:4918c893d802 268 int idx = start;
nixnax 17:4918c893d802 269 while(1) {
nixnax 9:0992486d4a30 270 if (unstuff==0) {
nixnax 72:ad3d12753acf 271 if (ppp.rx.buf[idx]==0x7d) unstuff=1;
nixnax 29:30de79d658f6 272 else {
nixnax 72:ad3d12753acf 273 *dest = ppp.rx.buf[idx];
nixnax 29:30de79d658f6 274 ppp.pkt.len++;
nixnax 29:30de79d658f6 275 dest++;
nixnax 72:ad3d12753acf 276 crcDo(ppp.rx.buf[idx]);
nixnax 29:30de79d658f6 277 }
nixnax 66:f005b9fdf4d1 278 } else { // unstuff characters prefixed with 0x7d
nixnax 72:ad3d12753acf 279 *dest = ppp.rx.buf[idx]^0x20;
nixnax 29:30de79d658f6 280 ppp.pkt.len++;
nixnax 29:30de79d658f6 281 dest++;
nixnax 72:ad3d12753acf 282 crcDo(ppp.rx.buf[idx]^0x20);
nixnax 9:0992486d4a30 283 unstuff=0;
nixnax 9:0992486d4a30 284 }
nixnax 81:9ede60e9a2c8 285 idx = (idx+1) & (RXBUFLEN-1);
nixnax 17:4918c893d802 286 if (idx == end) break;
nixnax 9:0992486d4a30 287 }
nixnax 29:30de79d658f6 288 ppp.pkt.crc = ppp.crc & 0xffff;
nixnax 120:bef89e4c906e 289 if(0) dumpPPPFrame(); // set to 1 to dump ALL ppp frames
nixnax 9:0992486d4a30 290 if (ppp.pkt.crc == 0xf0b8) { // check for good CRC
nixnax 16:cb0b80c24ba2 291 void determinePacketType(); // declaration only
nixnax 9:0992486d4a30 292 determinePacketType();
nixnax 90:55e0f243a7ce 293 } else {
nixnax 120:bef89e4c906e 294 if (0) { // set to 1 to report FCS errors
nixnax 118:54d1936e3768 295 char pbuf[50]; // local print buffer
nixnax 120:bef89e4c906e 296 fillbuf();
nixnax 119:e14dd2bf0ea3 297 sprintf(pbuf, "PPP FCS(crc) Error CRC=%x Length = %d\n",ppp.pkt.crc,ppp.pkt.len); // print a debug line
nixnax 120:bef89e4c906e 298 fillbuf();
nixnax 118:54d1936e3768 299 printWhileCheckingInput( pbuf );
nixnax 120:bef89e4c906e 300 if(0) dumpPPPFrame(); // set to 1 to dump frames with errors in them
nixnax 95:40af49390daf 301 }
nixnax 9:0992486d4a30 302 }
nixnax 9:0992486d4a30 303 }
nixnax 9:0992486d4a30 304
nixnax 29:30de79d658f6 305 void hdlcPut(int ch) // do hdlc handling of special (flag) characters
nixnax 29:30de79d658f6 306 {
nixnax 29:30de79d658f6 307 if ( (ch<0x20) || (ch==0x7d) || (ch==0x7e) ) {
nixnax 119:e14dd2bf0ea3 308 fillbuf();
nixnax 29:30de79d658f6 309 pc.putc(0x7d);
nixnax 119:e14dd2bf0ea3 310 fillbuf();
nixnax 66:f005b9fdf4d1 311 pc.putc(ch^0x20); // these characters need special handling
nixnax 29:30de79d658f6 312 } else {
nixnax 119:e14dd2bf0ea3 313 fillbuf();
nixnax 29:30de79d658f6 314 pc.putc(ch);
nixnax 29:30de79d658f6 315 }
nixnax 11:f58998c24f0b 316 }
nixnax 9:0992486d4a30 317
nixnax 93:9675adc36882 318 void send_pppFrame() // send a PPP frame in HDLC format
nixnax 29:30de79d658f6 319 {
nixnax 17:4918c893d802 320 int crc = crcBuf(ppp.pkt.buf, ppp.pkt.len-2); // update crc
nixnax 12:db0dc91f0231 321 ppp.pkt.buf[ ppp.pkt.len-2 ] = (~crc>>0); // fcs lo (crc)
nixnax 12:db0dc91f0231 322 ppp.pkt.buf[ ppp.pkt.len-1 ] = (~crc>>8); // fcs hi (crc)
nixnax 16:cb0b80c24ba2 323 pc.putc(0x7e); // hdlc start-of-frame "flag"
nixnax 95:40af49390daf 324 for(int i=0; i<ppp.pkt.len; i++) {
nixnax 93:9675adc36882 325 hdlcPut( ppp.pkt.buf[i] ); // send a character
nixnax 93:9675adc36882 326 }
nixnax 16:cb0b80c24ba2 327 pc.putc(0x7e); // hdlc end-of-frame "flag"
nixnax 9:0992486d4a30 328 }
nixnax 9:0992486d4a30 329
nixnax 93:9675adc36882 330 void ipcpConfigRequestHandler()
nixnax 29:30de79d658f6 331 {
nixnax 119:e14dd2bf0ea3 332 debugPrintf("Their IPCP Config Req, Our Ack\n");
nixnax 92:cb962b365cce 333 ppp.pkt.buf[4]=2; // change code to ack
nixnax 108:f77ec4605945 334 send_pppFrame(); // acknowledge everything they ask for - assume it's IP addresses
nixnax 106:d14e6b597ca3 335
nixnax 119:e14dd2bf0ea3 336 debugPrintf("Our IPCP Ask (no options)\n");
nixnax 92:cb962b365cce 337 ppp.pkt.buf[4]=1; // change code to request
nixnax 106:d14e6b597ca3 338 ppp.pkt.buf[7]=4; // no options in this request
nixnax 106:d14e6b597ca3 339 ppp.pkt.len=10; // no options in this request shortest ipcp packet possible (4 ppp + 4 ipcp + 2 crc)
nixnax 103:4f5512dd11cf 340 send_pppFrame(); // send our request
nixnax 9:0992486d4a30 341 }
nixnax 9:0992486d4a30 342
nixnax 93:9675adc36882 343 void ipcpAckHandler()
nixnax 29:30de79d658f6 344 {
nixnax 119:e14dd2bf0ea3 345 debugPrintf("Their IPCP Grant\n");
nixnax 29:30de79d658f6 346 }
nixnax 9:0992486d4a30 347
nixnax 93:9675adc36882 348 void ipcpNackHandler()
nixnax 29:30de79d658f6 349 {
nixnax 119:e14dd2bf0ea3 350 debugPrintf("Their IPCP Nack, Our ACK\n");
nixnax 107:5fe806713d49 351 if (ppp.pkt.buf[8]==3) { // check if the NACK contains an IP address parameter
nixnax 106:d14e6b597ca3 352 ppp.pkt.buf[4]=1; // assume the NACK contains our "suggested" IP address
nixnax 106:d14e6b597ca3 353 send_pppFrame(); // let's request this IP address as ours
nixnax 106:d14e6b597ca3 354 } // if it's not an IP nack we ignore it
nixnax 29:30de79d658f6 355 }
nixnax 9:0992486d4a30 356
nixnax 93:9675adc36882 357 void ipcpDefaultHandler()
nixnax 29:30de79d658f6 358 {
nixnax 119:e14dd2bf0ea3 359 debugPrintf("Their IPCP Other\n");
nixnax 29:30de79d658f6 360 }
nixnax 29:30de79d658f6 361
nixnax 29:30de79d658f6 362 void IPCPframe()
nixnax 29:30de79d658f6 363 {
nixnax 9:0992486d4a30 364 int code = ppp.pkt.buf[4]; // packet type is here
nixnax 9:0992486d4a30 365 switch (code) {
nixnax 29:30de79d658f6 366 case 1:
nixnax 93:9675adc36882 367 ipcpConfigRequestHandler();
nixnax 29:30de79d658f6 368 break;
nixnax 29:30de79d658f6 369 case 2:
nixnax 93:9675adc36882 370 ipcpAckHandler();
nixnax 29:30de79d658f6 371 break;
nixnax 29:30de79d658f6 372 case 3:
nixnax 93:9675adc36882 373 ipcpNackHandler();
nixnax 29:30de79d658f6 374 break;
nixnax 29:30de79d658f6 375 default:
nixnax 93:9675adc36882 376 ipcpDefaultHandler();
nixnax 9:0992486d4a30 377 }
nixnax 29:30de79d658f6 378 }
nixnax 9:0992486d4a30 379
nixnax 29:30de79d658f6 380 void UDPpacket()
nixnax 29:30de79d658f6 381 {
nixnax 12:db0dc91f0231 382 char * udpPkt = ppp.pkt.buf+4; // udp packet start
nixnax 16:cb0b80c24ba2 383 int headerSizeIP = (( udpPkt[0]&0xf)*4);
nixnax 29:30de79d658f6 384 char * udpBlock = udpPkt + headerSizeIP; // udp info start
nixnax 118:54d1936e3768 385 #ifdef SERIAL_PORT_MONITOR_YES
nixnax 12:db0dc91f0231 386 char * udpSrc = udpBlock; // source port
nixnax 12:db0dc91f0231 387 char * udpDst = udpBlock+2; // destination port
nixnax 63:9253b0e1b7d8 388 #endif
nixnax 12:db0dc91f0231 389 char * udpLen = udpBlock+4; // udp data length
nixnax 12:db0dc91f0231 390 char * udpInf = udpBlock+8; // actual start of info
nixnax 118:54d1936e3768 391 #ifdef SERIAL_PORT_MONITOR_YES
nixnax 12:db0dc91f0231 392 int srcPort = (udpSrc[0]<<8) | udpSrc[1];
nixnax 12:db0dc91f0231 393 int dstPort = (udpDst[0]<<8) | udpDst[1];
nixnax 12:db0dc91f0231 394 char * srcIP = udpPkt+12; // udp src addr
nixnax 12:db0dc91f0231 395 char * dstIP = udpPkt+16; // udp dst addr
nixnax 55:43faae812be3 396 #endif
nixnax 29:30de79d658f6 397 #define UDP_HEADER_SIZE 8
nixnax 12:db0dc91f0231 398 int udpLength = ((udpLen[0]<<8) | udpLen[1]) - UDP_HEADER_SIZE; // size of the actual udp data
nixnax 119:e14dd2bf0ea3 399 if(v0) debugPrintf("UDP %d.%d.%d.%d:%d ", srcIP[0],srcIP[1],srcIP[2],srcIP[3],srcPort);
nixnax 119:e14dd2bf0ea3 400 if(v0) debugPrintf("%d.%d.%d.%d:%d ", dstIP[0],dstIP[1],dstIP[2],dstIP[3],dstPort);
nixnax 119:e14dd2bf0ea3 401 if(v0) debugPrintf("Len %03d", udpLength);
nixnax 29:30de79d658f6 402 int printSize = udpLength;
nixnax 29:30de79d658f6 403 if (printSize > 20) printSize = 20; // print only first 20 characters
nixnax 81:9ede60e9a2c8 404 if (v1) {
nixnax 29:30de79d658f6 405 for (int i=0; i<printSize; i++) {
nixnax 29:30de79d658f6 406 char ch = udpInf[i];
nixnax 29:30de79d658f6 407 if (ch>31 && ch<127) {
nixnax 119:e14dd2bf0ea3 408 debugPrintf("%c", ch);
nixnax 29:30de79d658f6 409 } else {
nixnax 119:e14dd2bf0ea3 410 debugPrintf("_");
nixnax 29:30de79d658f6 411 }
nixnax 29:30de79d658f6 412 }
nixnax 29:30de79d658f6 413 }
nixnax 119:e14dd2bf0ea3 414 if (v0) debugPrintf("\n");
nixnax 12:db0dc91f0231 415 }
nixnax 11:f58998c24f0b 416
nixnax 76:00e208cceb8b 417 unsigned int dataCheckSum(unsigned char * ptr, int len)
nixnax 29:30de79d658f6 418 {
nixnax 75:0d513869231f 419 unsigned int sum=0;
nixnax 76:00e208cceb8b 420 unsigned char placeHolder;
nixnax 29:30de79d658f6 421 if (len&1) {
nixnax 76:00e208cceb8b 422 placeHolder = ptr[len]; // when length is odd stuff in a zero byte
nixnax 76:00e208cceb8b 423 ptr[len]=0;
nixnax 29:30de79d658f6 424 }
nixnax 29:30de79d658f6 425 for (int i=0; i<len/2; i++) {
nixnax 76:00e208cceb8b 426 unsigned int hi = *ptr;
nixnax 29:30de79d658f6 427 ptr++;
nixnax 76:00e208cceb8b 428 unsigned int lo = *ptr;
nixnax 29:30de79d658f6 429 ptr++;
nixnax 76:00e208cceb8b 430 unsigned int val = ( (hi<<8) | lo );
nixnax 11:f58998c24f0b 431 sum = sum + val;
nixnax 11:f58998c24f0b 432 }
nixnax 29:30de79d658f6 433 if (len&1) {
nixnax 76:00e208cceb8b 434 ptr[len] = placeHolder; // restore the last byte for odd lengths
nixnax 29:30de79d658f6 435 }
nixnax 76:00e208cceb8b 436 sum = (sum & 0xffff) + (sum>>16);
nixnax 76:00e208cceb8b 437 sum = (sum & 0xffff) + (sum>>16); // sum one more time to catch any carry from the carry
nixnax 12:db0dc91f0231 438 return ~sum;
nixnax 29:30de79d658f6 439 }
nixnax 11:f58998c24f0b 440
nixnax 29:30de79d658f6 441 void headerCheckSum()
nixnax 29:30de79d658f6 442 {
nixnax 11:f58998c24f0b 443 int len =(ppp.pkt.buf[4]&0xf)*4; // length of header in bytes
nixnax 11:f58998c24f0b 444 char * ptr = ppp.pkt.buf+4; // start of ip packet
nixnax 11:f58998c24f0b 445 int sum=0;
nixnax 11:f58998c24f0b 446
nixnax 29:30de79d658f6 447 for (int i=0; i<len/2; i++) {
nixnax 29:30de79d658f6 448 int hi = *ptr;
nixnax 29:30de79d658f6 449 ptr++;
nixnax 29:30de79d658f6 450 int lo = *ptr;
nixnax 29:30de79d658f6 451 ptr++;
nixnax 11:f58998c24f0b 452 int val = ( lo & 0xff ) | ( (hi<<8) & 0xff00 );
nixnax 11:f58998c24f0b 453 sum = sum + val;
nixnax 11:f58998c24f0b 454 }
nixnax 11:f58998c24f0b 455 sum = sum + (sum>>16);
nixnax 11:f58998c24f0b 456 sum = ~sum;
nixnax 11:f58998c24f0b 457 ppp.pkt.buf[14]= (sum>>8);
nixnax 11:f58998c24f0b 458 ppp.pkt.buf[15]= (sum );
nixnax 29:30de79d658f6 459 }
nixnax 9:0992486d4a30 460
nixnax 29:30de79d658f6 461 void ICMPpacket() // internet control message protocol
nixnax 29:30de79d658f6 462 {
nixnax 12:db0dc91f0231 463 char * ipPkt = ppp.pkt.buf+4; // ip packet start
nixnax 12:db0dc91f0231 464 char * pktLen = ipPkt+2;
nixnax 12:db0dc91f0231 465 int packetLength = (pktLen[0]<<8) | pktLen[1]; // icmp packet length
nixnax 16:cb0b80c24ba2 466 int headerSizeIP = (( ipPkt[0]&0xf)*4);
nixnax 16:cb0b80c24ba2 467 char * icmpType = ipPkt + headerSizeIP; // icmp data start
nixnax 13:d882b8a042b4 468 char * icmpSum = icmpType+2; // icmp checksum
nixnax 29:30de79d658f6 469 #define ICMP_TYPE_PING_REQUEST 8
nixnax 29:30de79d658f6 470 if ( icmpType[0] == ICMP_TYPE_PING_REQUEST ) {
nixnax 12:db0dc91f0231 471 char * ipTTL = ipPkt+8; // time to live
nixnax 12:db0dc91f0231 472 ipTTL[0]--; // decrement time to live
nixnax 12:db0dc91f0231 473 char * srcAdr = ipPkt+12;
nixnax 12:db0dc91f0231 474 char * dstAdr = ipPkt+16;
nixnax 63:9253b0e1b7d8 475 #ifndef SERIAL_PORT_MONITOR_NO
nixnax 18:3e35de1bc877 476 int icmpIdent = (icmpType[4]<<8)|icmpType[5];
nixnax 29:30de79d658f6 477 int icmpSequence = (icmpType[6]<<8)|icmpType[7];
nixnax 63:9253b0e1b7d8 478 #endif
nixnax 119:e14dd2bf0ea3 479 if(v0) debugPrintf("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]);
nixnax 119:e14dd2bf0ea3 480 if(v0) debugPrintf("Ident %04x Sequence %04d ",icmpIdent,icmpSequence);
nixnax 29:30de79d658f6 481 char src[4];
nixnax 29:30de79d658f6 482 char dst[4];
nixnax 12:db0dc91f0231 483 memcpy(src, srcAdr,4);
nixnax 12:db0dc91f0231 484 memcpy(dst, dstAdr,4);
nixnax 12:db0dc91f0231 485 memcpy(srcAdr, dst,4);
nixnax 12:db0dc91f0231 486 memcpy(dstAdr, src,4); // swap src & dest ip
nixnax 12:db0dc91f0231 487 char * chkSum = ipPkt+10;
nixnax 29:30de79d658f6 488 chkSum[0]=0;
nixnax 29:30de79d658f6 489 chkSum[1]=0;
nixnax 12:db0dc91f0231 490 headerCheckSum(); // new ip header checksum
nixnax 29:30de79d658f6 491 #define ICMP_TYPE_ECHO_REPLY 0
nixnax 16:cb0b80c24ba2 492 icmpType[0]=ICMP_TYPE_ECHO_REPLY; // icmp echo reply
nixnax 29:30de79d658f6 493 icmpSum[0]=0;
nixnax 29:30de79d658f6 494 icmpSum[1]=0; // zero the checksum for recalculation
nixnax 16:cb0b80c24ba2 495 int icmpLength = packetLength - headerSizeIP; // length of ICMP data portion
nixnax 76:00e208cceb8b 496 unsigned int sum = dataCheckSum( (unsigned char *)icmpType, icmpLength); // this checksum on icmp data portion
nixnax 76:00e208cceb8b 497 icmpSum[0]=(sum>>8)&0xff;
nixnax 76:00e208cceb8b 498 icmpSum[1]=(sum )&0xff; // new checksum for ICMP data portion
nixnax 16:cb0b80c24ba2 499
nixnax 16:cb0b80c24ba2 500 int printSize = icmpLength-8; // exclude size of icmp header
nixnax 25:0b0450e1b08b 501 char * icmpData = icmpType+8; // the actual payload data is after the header
nixnax 25:0b0450e1b08b 502 if (printSize > 10) printSize = 10; // print up to 20 characters
nixnax 29:30de79d658f6 503 if (v0) {
nixnax 29:30de79d658f6 504 for (int i=0; i<printSize; i++) {
nixnax 29:30de79d658f6 505 char ch = icmpData[i];
nixnax 29:30de79d658f6 506 if (ch>31 && ch<127) {
nixnax 119:e14dd2bf0ea3 507 debugPrintf("%c",ch);
nixnax 29:30de79d658f6 508 } else {
nixnax 119:e14dd2bf0ea3 509 debugPrintf("_");
nixnax 29:30de79d658f6 510 }
nixnax 29:30de79d658f6 511 }
nixnax 119:e14dd2bf0ea3 512 debugPrintf("\n");
nixnax 29:30de79d658f6 513 }
nixnax 93:9675adc36882 514 send_pppFrame(); // reply to the ping
nixnax 29:30de79d658f6 515
nixnax 12:db0dc91f0231 516 } else {
nixnax 29:30de79d658f6 517 if (v0) {
nixnax 119:e14dd2bf0ea3 518 debugPrintf("ICMP type=%d \n", icmpType[0]);
nixnax 29:30de79d658f6 519 }
nixnax 11:f58998c24f0b 520 }
nixnax 11:f58998c24f0b 521 }
nixnax 11:f58998c24f0b 522
nixnax 29:30de79d658f6 523 void IGMPpacket() // internet group management protocol
nixnax 29:30de79d658f6 524 {
nixnax 119:e14dd2bf0ea3 525 if (v0) debugPrintf("IGMP type=%d \n", ppp.pkt.buf[28]);
nixnax 29:30de79d658f6 526 }
nixnax 11:f58998c24f0b 527
nixnax 114:8a5d70bbc1b2 528 void dumpHeaderIP (int outGoing)
nixnax 29:30de79d658f6 529 {
nixnax 114:8a5d70bbc1b2 530 #if defined(IP_HEADER_DUMP_YES) && defined(SERIAL_PORT_MONITOR_YES)
nixnax 119:e14dd2bf0ea3 531 fillbuf(); // we are expecting the first character of the next packet
nixnax 114:8a5d70bbc1b2 532 char * ipPkt = ppp.pkt.buf+4; // ip packet start
nixnax 114:8a5d70bbc1b2 533 char * ident = ipPkt+4; // 2 bytes
nixnax 118:54d1936e3768 534 #ifdef UNUSED_IP_VARIABLES
nixnax 114:8a5d70bbc1b2 535 char * srcAdr = ipPkt+12; // 4 bytes
nixnax 114:8a5d70bbc1b2 536 char * dstAdr = ipPkt+16; // 4 bytes = total of 20 bytes
nixnax 114:8a5d70bbc1b2 537 char * version = ipPkt; // top 4 bits
nixnax 114:8a5d70bbc1b2 538 char * ihl = ipPkt; // bottom 4 bits
nixnax 114:8a5d70bbc1b2 539 char * dscp = ipPkt+1; // top 6 bits
nixnax 114:8a5d70bbc1b2 540 char * ecn = ipPkt+1; // lower 2 bits
nixnax 114:8a5d70bbc1b2 541 char * pktLen = ipPkt+2; // 2 bytes
nixnax 114:8a5d70bbc1b2 542 char * flags = ipPkt+6; // 2 bits
nixnax 114:8a5d70bbc1b2 543 char * ttl = ipPkt+8; // 1 byte
nixnax 114:8a5d70bbc1b2 544 char * protocol = ipPkt+9; // 1 byte
nixnax 114:8a5d70bbc1b2 545 char * headercheck= ipPkt+10; // 2 bytes
nixnax 114:8a5d70bbc1b2 546 int versionIP = (version[0]>>4)&0xf;
nixnax 114:8a5d70bbc1b2 547 int headerSizeIP = (ihl[0]&0xf)*4;
nixnax 114:8a5d70bbc1b2 548 int dscpIP = (dscp[0]>>2)&0x3f;
nixnax 114:8a5d70bbc1b2 549 int ecnIP = ecn[0]&3;
nixnax 114:8a5d70bbc1b2 550 int packetLength = (pktLen[0]<<8)|pktLen[1]; // ip total packet length
nixnax 114:8a5d70bbc1b2 551 int flagsIP = flags[0]>>14&3;
nixnax 114:8a5d70bbc1b2 552 int ttlIP = ttl[0];
nixnax 114:8a5d70bbc1b2 553 int protocolIP = protocol[0];
nixnax 114:8a5d70bbc1b2 554 unsigned int checksumIP = (headercheck[0]<<8)|headercheck[1];
nixnax 63:9253b0e1b7d8 555 #endif
nixnax 119:e14dd2bf0ea3 556 int IPv4Id = (ident[0]<<8)|ident[1];
nixnax 119:e14dd2bf0ea3 557 char pbuf[50]; // local print buffer
nixnax 118:54d1936e3768 558 int n=0;
nixnax 119:e14dd2bf0ea3 559 fillbuf(); // we are expecting the first character of the next packet
nixnax 119:e14dd2bf0ea3 560 n=n+sprintf(pbuf+n, outGoing ? "\x1b[34m" : "\x1b[30m" ); // VT100 color code, print black for incoming, blue for outgoing headers
nixnax 119:e14dd2bf0ea3 561 fillbuf(); // we are expecting the first character of the next packet
nixnax 119:e14dd2bf0ea3 562 n=n+sprintf(pbuf+n, "%05d ",IPv4Id); // IPv4Id is a good way to correlate our dumps with net monitor or wireshark traces
nixnax 119:e14dd2bf0ea3 563 fillbuf(); // we are expecting the first character of the next packet
nixnax 119:e14dd2bf0ea3 564 #define DUMP_FULL_IP_ADDRESS_YES
nixnax 119:e14dd2bf0ea3 565 #ifdef DUMP_FULL_IP_ADDRESS_YES
nixnax 119:e14dd2bf0ea3 566 char * srcAdr = ipPkt+12; // 4 bytes
nixnax 119:e14dd2bf0ea3 567 char * dstAdr = ipPkt+16; // 4 bytes = total of 20 bytes
nixnax 119:e14dd2bf0ea3 568 n=n+sprintf(pbuf+n, " %d.%d.%d.%d %d.%d.%d.%d ",srcAdr[0],srcAdr[1],srcAdr[2],srcAdr[3], dstAdr[0],dstAdr[1],dstAdr[2],dstAdr[3]); // full ip addresses
nixnax 55:43faae812be3 569 #endif
nixnax 118:54d1936e3768 570 printWhileCheckingInput( pbuf );
nixnax 114:8a5d70bbc1b2 571 #ifndef TCP_HEADER_DUMP_YES
nixnax 119:e14dd2bf0ea3 572 printWhileCheckingInput('\x1b[30m\n'); // there is no TCP header dump, so terminate the line with \n and VT100 code for black
nixnax 114:8a5d70bbc1b2 573 #endif
nixnax 114:8a5d70bbc1b2 574 #endif
nixnax 29:30de79d658f6 575 }
nixnax 26:11f4eb2663a7 576
nixnax 114:8a5d70bbc1b2 577 void dumpHeaderTCP(int outGoing)
nixnax 29:30de79d658f6 578 {
nixnax 114:8a5d70bbc1b2 579 #if defined(TCP_HEADER_DUMP_YES) && defined(SERIAL_PORT_MONITOR_YES)
nixnax 114:8a5d70bbc1b2 580 int headerSizeIP = (ppp.pkt.buf[4]&0xf)*4; // header size of ip portion
nixnax 114:8a5d70bbc1b2 581 char * tcpStart = ppp.pkt.buf+4+headerSizeIP; // start of tcp packet
nixnax 114:8a5d70bbc1b2 582 char * seqtcp = tcpStart + 4; // 4 bytes
nixnax 114:8a5d70bbc1b2 583 char * acktcp = tcpStart + 8; // 4 bytes
nixnax 114:8a5d70bbc1b2 584 char * flagbitstcp = tcpStart + 12; // 9 bits
nixnax 114:8a5d70bbc1b2 585 unsigned int seq = (seqtcp[0]<<24)|(seqtcp[1]<<16)|(seqtcp[2]<<8)|(seqtcp[3]);
nixnax 114:8a5d70bbc1b2 586 unsigned int ack = (acktcp[0]<<24)|(acktcp[1]<<16)|(acktcp[2]<<8)|(acktcp[3]);
nixnax 114:8a5d70bbc1b2 587 if (seq && ack) {} // shut up the compiler about unused variables
nixnax 114:8a5d70bbc1b2 588 int flags = ((flagbitstcp[0]&1)<<8)|flagbitstcp[1];
nixnax 10:74f8233f72c0 589
nixnax 119:e14dd2bf0ea3 590 char flagInfo[9]; // text string presenting the 8 most important TCP flags
nixnax 119:e14dd2bf0ea3 591 #define PRINT_ALL_TCP_FLAGS_YES
nixnax 119:e14dd2bf0ea3 592 #ifdef PRINT_ALL_TCP_FLAGS_YES
nixnax 114:8a5d70bbc1b2 593 memset(flagInfo,'.', 8); // fill string with "........"
nixnax 114:8a5d70bbc1b2 594 flagInfo[8]=0; // null terminate string
nixnax 114:8a5d70bbc1b2 595 if (flags & (1<<0)) flagInfo[7]='F';
nixnax 114:8a5d70bbc1b2 596 if (flags & (1<<1)) flagInfo[6]='S';
nixnax 114:8a5d70bbc1b2 597 if (flags & (1<<2)) flagInfo[5]='R';
nixnax 114:8a5d70bbc1b2 598 if (flags & (1<<3)) flagInfo[4]='P';
nixnax 114:8a5d70bbc1b2 599 if (flags & (1<<4)) flagInfo[3]='A';
nixnax 114:8a5d70bbc1b2 600 if (flags & (1<<5)) flagInfo[2]='U';
nixnax 114:8a5d70bbc1b2 601 if (flags & (1<<6)) flagInfo[1]='E';
nixnax 114:8a5d70bbc1b2 602 if (flags & (1<<7)) flagInfo[0]='C';
nixnax 118:54d1936e3768 603 #else
nixnax 119:e14dd2bf0ea3 604 if (flags & (1<<4)) flagInfo[0]='A'; // choose the most important flag to print
nixnax 119:e14dd2bf0ea3 605 if (flags & (1<<1)) flagInfo[0]='S';
nixnax 119:e14dd2bf0ea3 606 if (flags & (1<<0)) flagInfo[0]='F';
nixnax 119:e14dd2bf0ea3 607 if (flags & (1<<3)) flagInfo[0]='P';
nixnax 119:e14dd2bf0ea3 608 if (flags & (1<<2)) flagInfo[0]='R';
nixnax 119:e14dd2bf0ea3 609 flagInfo[1]=' ';
nixnax 119:e14dd2bf0ea3 610 flagInfo[2]=0;
nixnax 118:54d1936e3768 611 #endif
nixnax 119:e14dd2bf0ea3 612 printWhileCheckingInput( flagInfo );
nixnax 119:e14dd2bf0ea3 613 #define EVERY_PACKET_ON_A_NEW_LINE_YES
nixnax 119:e14dd2bf0ea3 614 #ifdef EVERY_PACKET_ON_A_NEW_LINE_YES
nixnax 119:e14dd2bf0ea3 615 putcWhileCheckingInput('\n'); // write a newline after every packet
nixnax 119:e14dd2bf0ea3 616 #endif
nixnax 119:e14dd2bf0ea3 617 if( outGoing && ( flags == 0x11 ) ) { // ACK/FIN - if this is an outgoing ACK/FIN its the end of a tcp conversation
nixnax 119:e14dd2bf0ea3 618 putcWhileCheckingInput('\n'); // insert an extra new line to mark the end of an HTTP the conversation
nixnax 118:54d1936e3768 619 }
nixnax 114:8a5d70bbc1b2 620 #endif
nixnax 29:30de79d658f6 621 }
nixnax 29:30de79d658f6 622
nixnax 68:0b74763ae67f 623 int httpResponse(char * dataStart)
nixnax 67:a63e3486bcda 624 {
nixnax 67:a63e3486bcda 625 int n=0; // number of bytes we have printed so far
nixnax 77:abf92baebb42 626 int nHeader; // byte size of HTTP header
nixnax 83:cdcb81d1910f 627 int contentLengthStart; // index where HTML starts
nixnax 93:9675adc36882 628 int xFetch, httpGetRoot; // temporary storage of strncmp results
nixnax 85:53e57ff1cf05 629
nixnax 98:3babad0d1bd4 630 ppp.httpPageCount++; // increment the number of frames we have made
nixnax 85:53e57ff1cf05 631
nixnax 98:3babad0d1bd4 632 httpGetRoot = strncmp(dataStart, "GET / HTTP/1.", 13); // found GET, respond to both HTTP/1.<anything>
nixnax 99:3f56162e703e 633 xFetch = strncmp(dataStart, "GET /x", 6); // found GET /x , respond to both HTTP/1.<anything>
nixnax 119:e14dd2bf0ea3 634 // for example, you could try this using netcat (nc): echo "GET /x" | nc 172.10.10.2
nixnax 93:9675adc36882 635 if( (httpGetRoot==0) || (xFetch==0) ) {
nixnax 115:b8ddff0e782f 636 n=n+sprintf(n+dataStart,"HTTP/1.1 200 OK\r\nServer: mbed-PPP-Blinky\r\n"); // 200 OK header
nixnax 83:cdcb81d1910f 637 } else {
nixnax 89:2c8dd0c2a426 638 n=n+sprintf(n+dataStart,"HTTP/1.1 404 Not Found\r\nServer: mbed-PPP-Blinky\r\n"); // 404 header
nixnax 83:cdcb81d1910f 639 }
nixnax 83:cdcb81d1910f 640 n=n+sprintf(n+dataStart,"Content-Length: "); // http header
nixnax 83:cdcb81d1910f 641 contentLengthStart = n; // remember where Content-Length is in buffer
nixnax 83:cdcb81d1910f 642 n=n+sprintf(n+dataStart,"?????\r\n"); // leave five spaces for content length - will be updated later
nixnax 83:cdcb81d1910f 643 n=n+sprintf(n+dataStart,"Connection: close\r\n"); // close connection immediately
nixnax 83:cdcb81d1910f 644 n=n+sprintf(n+dataStart,"Content-Type: text/html; charset=us-ascii\r\n\r\n"); // http header must end with empty line (\r\n)
nixnax 83:cdcb81d1910f 645 nHeader=n; // size of HTTP header
nixnax 93:9675adc36882 646 if( httpGetRoot == 0 ) {
nixnax 83:cdcb81d1910f 647 // this is where we insert our web page into the buffer
nixnax 93:9675adc36882 648 memcpy(n+dataStart,rootWebPage,sizeof(rootWebPage));
nixnax 93:9675adc36882 649 n = n + sizeof(rootWebPage);
nixnax 85:53e57ff1cf05 650 } else {
nixnax 109:644a59ebb5b1 651 if (xFetch == 0) { // the page request started with "GET /x"
nixnax 89:2c8dd0c2a426 652
nixnax 89:2c8dd0c2a426 653 #define W3C_COMPLIANT_RESPONSE_NO
nixnax 89:2c8dd0c2a426 654 // change the above to W3C_COMPLIANT_RESPONSE_YES if you want a W3C.org compliant HTTP response
nixnax 89:2c8dd0c2a426 655 #ifdef W3C_COMPLIANT_RESPONSE_YES
nixnax 106:d14e6b597ca3 656 n=n+sprintf(n+dataStart,"<!DOCTYPE html><title>mbed-ppp-blinky</title>"); // html title (W3C.org required elements)
nixnax 98:3babad0d1bd4 657 n=n+sprintf(n+dataStart,"<body>%d</body>",ppp.httpPageCount); // body = the http frame count
nixnax 89:2c8dd0c2a426 658 #else
nixnax 109:644a59ebb5b1 659 #define BENCHMARK_USING_BROWSER_NO /* set to _YES if you want to use your browser as a benchmark tool */
nixnax 98:3babad0d1bd4 660 #ifndef BENCHMARK_USING_BROWSER_NO
nixnax 119:e14dd2bf0ea3 661 // semd a small browser script that will reload the page after 10 ms - handy for benchmarking with your web browser, use http://172.10.10.2/x
nixnax 98:3babad0d1bd4 662 n=n+sprintf(n+dataStart, "<script>setTimeout(function(){location.reload();},10);</script><body>%d</body>",ppp.httpPageCount);
nixnax 98:3babad0d1bd4 663 #else
nixnax 98:3babad0d1bd4 664 n=n+sprintf(n+dataStart,"%d",ppp.httpPageCount); // not valid html but fast, most browsers and curl are ok with it
nixnax 98:3babad0d1bd4 665 #endif
nixnax 89:2c8dd0c2a426 666 #endif
nixnax 89:2c8dd0c2a426 667
nixnax 89:2c8dd0c2a426 668 } else {
nixnax 89:2c8dd0c2a426 669 // all other requests get 404 Not Found response with a http frame count - nice for debugging
nixnax 89:2c8dd0c2a426 670 n=n+sprintf(n+dataStart,"<!DOCTYPE html><title>ppp-blinky-mbed</title>"); // html title (required element)
nixnax 89:2c8dd0c2a426 671 n=n+sprintf(n+dataStart,"<body>Not Found</body>"); // not found message
nixnax 89:2c8dd0c2a426 672 }
nixnax 83:cdcb81d1910f 673 }
nixnax 87:9f5ac1fabd95 674 while( (n%4)!= 2) n=n+sprintf(n+dataStart," "); // insert spaces until n is exactly two away from a multiple of four
nixnax 87:9f5ac1fabd95 675 n=n+sprintf(n+dataStart,"\r\n"); // add the last two characters (\r\n) - n is now an exact multiple of four
nixnax 87:9f5ac1fabd95 676
nixnax 83:cdcb81d1910f 677 #define CONTENTLENGTHSIZE 5
nixnax 83:cdcb81d1910f 678 char contentLengthString[CONTENTLENGTHSIZE+1];
nixnax 83:cdcb81d1910f 679 snprintf(contentLengthString,CONTENTLENGTHSIZE+1,"%*d",CONTENTLENGTHSIZE,n-nHeader); // print Content-Length with leading spaces and fixed width equal to csize
nixnax 83:cdcb81d1910f 680 memcpy(dataStart+contentLengthStart, contentLengthString, CONTENTLENGTHSIZE); // copy Content-Length to it's place in the send buffer
nixnax 67:a63e3486bcda 681
nixnax 77:abf92baebb42 682 if (v2) {
nixnax 120:bef89e4c906e 683 // debugPrintf("HTTP Response: HTTP-header %d HTTP-content %d HTTP-total %d\n",nHeader,n-nHeader,n);
nixnax 77:abf92baebb42 684 }
nixnax 67:a63e3486bcda 685 return n; // total byte size of our response
nixnax 67:a63e3486bcda 686 }
nixnax 67:a63e3486bcda 687
nixnax 98:3babad0d1bd4 688 // if not an http response we just report the number of bytes received
nixnax 98:3babad0d1bd4 689 // this is handy when you for example want to use netcat (nc.exe) to talk to PPP-Blinky
nixnax 98:3babad0d1bd4 690 int tcpResponse(char * dataStart, int len)
nixnax 98:3babad0d1bd4 691 {
nixnax 98:3babad0d1bd4 692 int n=0; // number of bytes we have printed so far
nixnax 98:3babad0d1bd4 693 n=n+sprintf(n+dataStart,"Got %04d bytes.\n",len); // report the number of bytes received
nixnax 98:3babad0d1bd4 694 while( (n%4)!= 0) n=n+sprintf(n+dataStart,"*"); // insert spaces until n is exactly two away from a multiple of four
nixnax 98:3babad0d1bd4 695 if (v2) {
nixnax 120:bef89e4c906e 696 // debugPrintf("TCP response %d bytes\n",n);
nixnax 98:3babad0d1bd4 697 }
nixnax 98:3babad0d1bd4 698 return n; // total byte size of our response
nixnax 98:3babad0d1bd4 699 }
nixnax 98:3babad0d1bd4 700
nixnax 29:30de79d658f6 701 void tcpHandler()
nixnax 29:30de79d658f6 702 {
nixnax 87:9f5ac1fabd95 703 // IP header
nixnax 119:e14dd2bf0ea3 704
nixnax 26:11f4eb2663a7 705 char * ipPkt = ppp.pkt.buf+4; // ip packet start
nixnax 26:11f4eb2663a7 706 char * ihl = ipPkt; // bottom 4 bits
nixnax 83:cdcb81d1910f 707 char * pktLen = ipPkt+2; // 2 bytes
nixnax 26:11f4eb2663a7 708 char * ident = ipPkt+4; // 2 bytes
nixnax 28:1aa629be05e7 709 char * protocol = ipPkt+9; // 1 byte
nixnax 83:cdcb81d1910f 710 char * headercheck= ipPkt+10; // 2 bytes
nixnax 26:11f4eb2663a7 711 char * srcAdr = ipPkt+12; // 4 bytes
nixnax 26:11f4eb2663a7 712 char * dstAdr = ipPkt+16; // 4 bytes = total of 20 bytes
nixnax 26:11f4eb2663a7 713 int headerSizeIP = (ihl[0]&0xf)*4;
nixnax 26:11f4eb2663a7 714 int packetLength = (pktLen[0]<<8)|pktLen[1]; // ip total packet length
nixnax 26:11f4eb2663a7 715
nixnax 87:9f5ac1fabd95 716 // TCP header
nixnax 87:9f5ac1fabd95 717
nixnax 87:9f5ac1fabd95 718 char * tcp = ppp.pkt.buf+4+headerSizeIP; // start of tcp packet
nixnax 87:9f5ac1fabd95 719 char * srctcp = tcp + 0; // 2 bytes
nixnax 87:9f5ac1fabd95 720 char * dsttcp = tcp + 2; // 2 bytes
nixnax 87:9f5ac1fabd95 721 char * seqtcp = tcp + 4; // 4 bytes
nixnax 87:9f5ac1fabd95 722 char * acktcp = tcp + 8; // 4 bytes
nixnax 87:9f5ac1fabd95 723 char * offset = tcp + 12; // 4 bits
nixnax 87:9f5ac1fabd95 724 char * flagbitstcp = tcp + 12; // 9 bits
nixnax 87:9f5ac1fabd95 725 char * windowsizetcp = tcp + 14; // 2 bytes
nixnax 87:9f5ac1fabd95 726 char * checksumtcp = tcp + 16; // 2 bytes
nixnax 26:11f4eb2663a7 727
nixnax 26:11f4eb2663a7 728 int tcpSize = packetLength - headerSizeIP;
nixnax 35:e7068df4d971 729 int headerSizeTCP = ((offset[0]>>4)&0x0f)*4; // size of tcp header only
nixnax 61:b3c1a04efd0a 730 int protocolIP = protocol[0];
nixnax 29:30de79d658f6 731
nixnax 87:9f5ac1fabd95 732 char * tcpDataIn = tcp + headerSizeTCP; // start of data block after TCP header
nixnax 67:a63e3486bcda 733 int tcpDataSize = tcpSize - headerSizeTCP; // size of data block after TCP header
nixnax 87:9f5ac1fabd95 734 char * tcpDataOut = tcp + 20; // start of outgoing data
nixnax 81:9ede60e9a2c8 735
nixnax 85:53e57ff1cf05 736 unsigned int seq_in = (seqtcp[0]<<24)|(seqtcp[1]<<16)|(seqtcp[2]<<8)|(seqtcp[3]);
nixnax 85:53e57ff1cf05 737 unsigned int ack_in = (acktcp[0]<<24)|(acktcp[1]<<16)|(acktcp[2]<<8)|(acktcp[3]);
nixnax 85:53e57ff1cf05 738
nixnax 85:53e57ff1cf05 739 unsigned int ack_out = seq_in + tcpDataSize;
nixnax 87:9f5ac1fabd95 740 unsigned int seq_out = ack_in; // use their version of our current sequence number
nixnax 81:9ede60e9a2c8 741
nixnax 29:30de79d658f6 742 #define TCP_FLAG_ACK (1<<4)
nixnax 29:30de79d658f6 743 #define TCP_FLAG_SYN (1<<1)
nixnax 29:30de79d658f6 744 #define TCP_FLAG_PSH (1<<3)
nixnax 29:30de79d658f6 745 #define TCP_FLAG_RST (1<<2)
nixnax 29:30de79d658f6 746 #define TCP_FLAG_FIN (1<<0)
nixnax 28:1aa629be05e7 747
nixnax 87:9f5ac1fabd95 748 // first we shorten the TCP response header to only 20 bytes.
nixnax 87:9f5ac1fabd95 749 // this means we ignore all TCP option requests
nixnax 87:9f5ac1fabd95 750
nixnax 87:9f5ac1fabd95 751 tcpSize = 20; // shorten total TCP packet size to 20 bytes (no data)
nixnax 87:9f5ac1fabd95 752 headerSizeTCP = 20; // shorten outgoing TCP header size 20 bytes
nixnax 87:9f5ac1fabd95 753 offset[0] = (headerSizeTCP/4)<<4; // shorten tcp header size to 20 bytes
nixnax 87:9f5ac1fabd95 754 packetLength = 40; // shorten total packet size to 40 bytes (20 ip + 20 tcp)
nixnax 87:9f5ac1fabd95 755 pktLen[1] = 40; // set total packet size to 40 bytes (20 ip + 20 tcp)
nixnax 87:9f5ac1fabd95 756 pktLen[0] = 0; // set total packet size to 40 bytes (20 ip + 20 tcp)
nixnax 87:9f5ac1fabd95 757
nixnax 35:e7068df4d971 758 int dataLen = 0; // most of our responses will have zero TCP data, only a header
nixnax 38:ab582987926e 759 int flagsOut = TCP_FLAG_ACK; // the default case is an ACK packet
nixnax 87:9f5ac1fabd95 760 int flagsTCP = ((flagbitstcp[0]&1)<<8)|flagbitstcp[1]; // the tcp flags we received
nixnax 92:cb962b365cce 761
nixnax 119:e14dd2bf0ea3 762 windowsizetcp[0] = (700 >> 8 ); // tcp window size hi byte
nixnax 119:e14dd2bf0ea3 763 windowsizetcp[1] = (700 & 0xff); // tcp window size lo byte
nixnax 38:ab582987926e 764
nixnax 106:d14e6b597ca3 765 // A sparse TCP flag interpreter that implements stateless TCP connections
nixnax 77:abf92baebb42 766
nixnax 69:23f560087c16 767 switch ( flagsTCP ) {
nixnax 69:23f560087c16 768 case TCP_FLAG_SYN:
nixnax 87:9f5ac1fabd95 769 flagsOut = TCP_FLAG_SYN | TCP_FLAG_ACK; // something wants to connect - acknowledge it
nixnax 119:e14dd2bf0ea3 770 seq_out = seq_in+0x10000000U; // create a new sequence number using their sequence as a starting point, increase the highest digit
nixnax 85:53e57ff1cf05 771 ack_out++; // for SYN flag we have to increase the sequence by 1
nixnax 69:23f560087c16 772 break;
nixnax 77:abf92baebb42 773 case TCP_FLAG_ACK | TCP_FLAG_PSH:
nixnax 98:3babad0d1bd4 774 if ( strncmp(tcpDataIn, "GET /", 5) == 0) { // check for an http GET command
nixnax 118:54d1936e3768 775 flagsOut = TCP_FLAG_ACK | TCP_FLAG_FIN | TCP_FLAG_PSH; // set outgoing FIN flag to ask them to close from their side
nixnax 87:9f5ac1fabd95 776 dataLen = httpResponse(tcpDataOut); // send an http response
nixnax 98:3babad0d1bd4 777 } else {
nixnax 106:d14e6b597ca3 778 dataLen = tcpResponse(tcpDataOut,tcpDataSize); // not a web request, send a packet reporting number of received bytes
nixnax 69:23f560087c16 779 }
nixnax 69:23f560087c16 780 break;
nixnax 116:1272e9f7ad70 781 case TCP_FLAG_FIN:
nixnax 116:1272e9f7ad70 782 case TCP_FLAG_FIN | TCP_FLAG_ACK:
nixnax 98:3babad0d1bd4 783 case TCP_FLAG_FIN | TCP_FLAG_PSH | TCP_FLAG_ACK:
nixnax 117:c819ae068336 784 flagsOut = TCP_FLAG_ACK | TCP_FLAG_FIN; // set outgoing FIN flag to ask them to close from their side
nixnax 85:53e57ff1cf05 785 ack_out++; // for FIN flag we always have to increase sequence by 1
nixnax 69:23f560087c16 786 break;
nixnax 77:abf92baebb42 787 default:
nixnax 69:23f560087c16 788 return; // ignore remaining packets
nixnax 93:9675adc36882 789 } // switch
nixnax 77:abf92baebb42 790
nixnax 69:23f560087c16 791 // The TCP flag handling is now done
nixnax 105:45001195b325 792 // first we swap source and destination TCP addresses and insert the new ack and seq numbers
nixnax 95:40af49390daf 793
nixnax 65:23b17c43aa0f 794 char tempHold[12]; // it's 12 long because we later reuse it when building the TCP pseudo-header
nixnax 60:2b770949c911 795 memcpy(tempHold, srcAdr,4);
nixnax 65:23b17c43aa0f 796 memcpy(srcAdr, dstAdr,4);
nixnax 60:2b770949c911 797 memcpy(dstAdr, tempHold,4); // swap ip address source/dest
nixnax 60:2b770949c911 798
nixnax 60:2b770949c911 799 memcpy(tempHold, srctcp,2);
nixnax 65:23b17c43aa0f 800 memcpy(srctcp, dsttcp,2);
nixnax 60:2b770949c911 801 memcpy(dsttcp, tempHold,2); // swap ip port source/dest
nixnax 95:40af49390daf 802
nixnax 85:53e57ff1cf05 803 acktcp[0]=ack_out>>24;
nixnax 85:53e57ff1cf05 804 acktcp[1]=ack_out>>16;
nixnax 85:53e57ff1cf05 805 acktcp[2]=ack_out>>8;
nixnax 85:53e57ff1cf05 806 acktcp[3]=ack_out>>0; // save ack 32-bit integer
nixnax 38:ab582987926e 807
nixnax 85:53e57ff1cf05 808 seqtcp[0]=seq_out>>24;
nixnax 85:53e57ff1cf05 809 seqtcp[1]=seq_out>>16;
nixnax 85:53e57ff1cf05 810 seqtcp[2]=seq_out>>8;
nixnax 85:53e57ff1cf05 811 seqtcp[3]=seq_out>>0; // save seq 32-bit integer
nixnax 38:ab582987926e 812
nixnax 93:9675adc36882 813 flagbitstcp[1] = flagsOut; // update the TCP flags
nixnax 93:9675adc36882 814
nixnax 114:8a5d70bbc1b2 815 // increment our outgoing ip packet counter
nixnax 114:8a5d70bbc1b2 816 ppp.ip.ident++; // get next ident number for our packet
nixnax 114:8a5d70bbc1b2 817 ident[0] = ppp.ip.ident>>8;
nixnax 114:8a5d70bbc1b2 818 ident[1] = ppp.ip.ident>>0; // insert OUR ident
nixnax 93:9675adc36882 819
nixnax 106:d14e6b597ca3 820 // Now we recalculate all the header sizes
nixnax 38:ab582987926e 821 int newPacketSize = headerSizeIP + headerSizeTCP + dataLen; // calculate size of the outgoing packet
nixnax 36:2a9b457f8276 822 pktLen[0] = (newPacketSize>>8);
nixnax 36:2a9b457f8276 823 pktLen[1]=newPacketSize; // ip total packet size
nixnax 36:2a9b457f8276 824 ppp.pkt.len = newPacketSize+6; // ppp packet length
nixnax 36:2a9b457f8276 825 tcpSize = headerSizeTCP + dataLen; // tcp packet size
nixnax 36:2a9b457f8276 826
nixnax 38:ab582987926e 827 // the header is all set up, now do the IP and TCP checksums
nixnax 61:b3c1a04efd0a 828 headercheck[0]=0; // IP header checksum
nixnax 61:b3c1a04efd0a 829 headercheck[1]=0; // IP header checksum
nixnax 61:b3c1a04efd0a 830 headerCheckSum(); // calculate the IP header checksum
nixnax 63:9253b0e1b7d8 831
nixnax 64:677b9713a120 832 // now we have to build the so-called 12-byte TCP "pseudo-header" in front of the TCP header (containing some IP header values) in order to correctly calculate the TCP checksum
nixnax 63:9253b0e1b7d8 833 // this header contains the most important parts of the IP header, i.e. source and destination address, protocol number and data length.
nixnax 63:9253b0e1b7d8 834
nixnax 87:9f5ac1fabd95 835 char * pseudoHeader = tcp-12; // mark the start of the TCP pseudo-header
nixnax 67:a63e3486bcda 836 memcpy(tempHold, pseudoHeader, 12); // preserve the 12 bytes of the IP header where the TCP pseudo-Header will be built
nixnax 61:b3c1a04efd0a 837 memcpy( pseudoHeader+0, srcAdr, 8); // IP source and destination addresses from IP header
nixnax 61:b3c1a04efd0a 838 memset( pseudoHeader+8, 0, 1); // reserved, set to zero
nixnax 61:b3c1a04efd0a 839 memset( pseudoHeader+9, protocolIP, 1); // protocol from IP header
nixnax 62:f192926e42f1 840 memset( pseudoHeader+10, tcpSize>>8, 1); // size of IP data (TCP packet size)
nixnax 62:f192926e42f1 841 memset( pseudoHeader+11, tcpSize, 1); // size of IP data (TCP packet size)
nixnax 38:ab582987926e 842
nixnax 61:b3c1a04efd0a 843 // pseudo-header built, now we can calculate TCP checksum
nixnax 29:30de79d658f6 844 checksumtcp[0]=0;
nixnax 29:30de79d658f6 845 checksumtcp[1]=0;
nixnax 76:00e208cceb8b 846 unsigned int pseudoHeaderSum=dataCheckSum((unsigned char *)pseudoHeader,tcpSize+12); // calculate the TCP checksum starting at the pseudo-header
nixnax 61:b3c1a04efd0a 847 checksumtcp[0]=pseudoHeaderSum>>8;
nixnax 61:b3c1a04efd0a 848 checksumtcp[1]=pseudoHeaderSum;
nixnax 87:9f5ac1fabd95 849 memcpy( tcp-12, tempHold, 12); // restore the 12 bytes that the pseudo-header overwrote
nixnax 114:8a5d70bbc1b2 850 dumpHeaderIP(1); // dump outgoing IP header
nixnax 114:8a5d70bbc1b2 851 dumpHeaderTCP(1); // dump outgoing TCP header
nixnax 120:bef89e4c906e 852 for (int i=0; i<60000/50; i++) { // a 60 ms delay before sending frame - typical internet delay time
nixnax 119:e14dd2bf0ea3 853 fillbuf(); // catch any incoming characters
nixnax 119:e14dd2bf0ea3 854 wait_us(50); // wait less than 1 character duration at 115200
nixnax 119:e14dd2bf0ea3 855 }
nixnax 93:9675adc36882 856 send_pppFrame(); // All preparation complete - send the TCP response
nixnax 29:30de79d658f6 857 }
nixnax 26:11f4eb2663a7 858
nixnax 29:30de79d658f6 859 void dumpDataTCP()
nixnax 29:30de79d658f6 860 {
nixnax 26:11f4eb2663a7 861 int ipPktLen = (ppp.pkt.buf[6]<<8)|ppp.pkt.buf[7]; // overall length of ip packet
nixnax 26:11f4eb2663a7 862 int ipHeaderLen = (ppp.pkt.buf[4]&0xf)*4; // length of ip header
nixnax 35:e7068df4d971 863 int headerSizeTCP = ((ppp.pkt.buf[4+ipHeaderLen+12]>>4)&0xf)*4;; // length of tcp header
nixnax 35:e7068df4d971 864 int dataLen = ipPktLen - ipHeaderLen - headerSizeTCP; // data is what's left after the two headers
nixnax 29:30de79d658f6 865 if (v1) {
nixnax 120:bef89e4c906e 866 char pbuf[50]; // local print buffer
nixnax 120:bef89e4c906e 867 fillbuf();
nixnax 120:bef89e4c906e 868 sprintf(pbuf, "TCP %d ipHeader %d tcpHeader %d Data %d\n", ipPktLen, ipHeaderLen, headerSizeTCP, dataLen); // 1 for more verbose
nixnax 120:bef89e4c906e 869 fillbuf();
nixnax 120:bef89e4c906e 870 printWhileCheckingInput( pbuf );
nixnax 29:30de79d658f6 871 }
nixnax 29:30de79d658f6 872 if (dataLen > 0) {
nixnax 47:00a5ca075f8f 873 ppp.pkt.buf[4+ipHeaderLen+headerSizeTCP+dataLen]=0; // insert a null after the data so debug printf stops printing after the data
nixnax 120:bef89e4c906e 874 printWhileCheckingInput( ppp.pkt.buf+4+ipHeaderLen+headerSizeTCP ); // print the tcp payload data
nixnax 120:bef89e4c906e 875 printWhileCheckingInput("\n");
nixnax 29:30de79d658f6 876 }
nixnax 29:30de79d658f6 877 }
nixnax 26:11f4eb2663a7 878
nixnax 29:30de79d658f6 879 void TCPpacket()
nixnax 29:30de79d658f6 880 {
nixnax 114:8a5d70bbc1b2 881 dumpHeaderIP(0); // dump incoming packet header
nixnax 114:8a5d70bbc1b2 882 dumpHeaderTCP(0); // dump incoming packet header
nixnax 77:abf92baebb42 883 if (v2) {
nixnax 77:abf92baebb42 884 dumpDataTCP();
nixnax 77:abf92baebb42 885 }
nixnax 26:11f4eb2663a7 886 tcpHandler();
nixnax 11:f58998c24f0b 887 }
nixnax 11:f58998c24f0b 888
nixnax 29:30de79d658f6 889 void otherProtocol()
nixnax 29:30de79d658f6 890 {
nixnax 119:e14dd2bf0ea3 891 debugPrintf("Other IP protocol");
nixnax 29:30de79d658f6 892 }
nixnax 26:11f4eb2663a7 893
nixnax 29:30de79d658f6 894 void IPframe()
nixnax 29:30de79d658f6 895 {
nixnax 10:74f8233f72c0 896 int protocol = ppp.pkt.buf[13];
nixnax 10:74f8233f72c0 897 switch (protocol) {
nixnax 29:30de79d658f6 898 case 1:
nixnax 29:30de79d658f6 899 ICMPpacket();
nixnax 29:30de79d658f6 900 break;
nixnax 29:30de79d658f6 901 case 2:
nixnax 29:30de79d658f6 902 IGMPpacket();
nixnax 29:30de79d658f6 903 break;
nixnax 29:30de79d658f6 904 case 17:
nixnax 29:30de79d658f6 905 UDPpacket();
nixnax 29:30de79d658f6 906 break;
nixnax 29:30de79d658f6 907 case 6:
nixnax 29:30de79d658f6 908 TCPpacket();
nixnax 29:30de79d658f6 909 break;
nixnax 29:30de79d658f6 910 default:
nixnax 29:30de79d658f6 911 otherProtocol();
nixnax 29:30de79d658f6 912 }
nixnax 29:30de79d658f6 913 }
nixnax 9:0992486d4a30 914
nixnax 29:30de79d658f6 915 void LCPconfReq()
nixnax 29:30de79d658f6 916 {
nixnax 119:e14dd2bf0ea3 917 debugPrintf("LCP Config ");
nixnax 9:0992486d4a30 918 if (ppp.pkt.buf[7] != 4) {
nixnax 111:6a3b77c065c0 919 ppp.pkt.buf[4]=4; // allow only "no options" which means Maximum Receive Unit (MRU) is default 1500 bytes
nixnax 119:e14dd2bf0ea3 920 debugPrintf("Reject\n");
nixnax 93:9675adc36882 921 send_pppFrame();
nixnax 9:0992486d4a30 922 } else {
nixnax 9:0992486d4a30 923 ppp.pkt.buf[4]=2; // ack zero conf
nixnax 119:e14dd2bf0ea3 924 debugPrintf("Ack\n");
nixnax 93:9675adc36882 925 send_pppFrame();
nixnax 119:e14dd2bf0ea3 926 debugPrintf("LCP Ask\n");
nixnax 11:f58998c24f0b 927 ppp.pkt.buf[4]=1; // request no options
nixnax 93:9675adc36882 928 send_pppFrame();
nixnax 9:0992486d4a30 929 }
nixnax 9:0992486d4a30 930 }
nixnax 9:0992486d4a30 931
nixnax 29:30de79d658f6 932 void LCPconfAck()
nixnax 29:30de79d658f6 933 {
nixnax 119:e14dd2bf0ea3 934 debugPrintf("LCP Ack\n");
nixnax 29:30de79d658f6 935 }
nixnax 9:0992486d4a30 936
nixnax 29:30de79d658f6 937 void LCPend()
nixnax 29:30de79d658f6 938 {
nixnax 29:30de79d658f6 939 ppp.pkt.buf[4]=6;
nixnax 93:9675adc36882 940 send_pppFrame(); // acknowledge
nixnax 81:9ede60e9a2c8 941 ppp.online=0; // start hunting for connect string again
nixnax 81:9ede60e9a2c8 942 pppInitStruct(); // flush the receive buffer
nixnax 119:e14dd2bf0ea3 943 debugPrintf("LCP End\n");
nixnax 9:0992486d4a30 944 }
nixnax 9:0992486d4a30 945
nixnax 29:30de79d658f6 946 void LCPother()
nixnax 29:30de79d658f6 947 {
nixnax 119:e14dd2bf0ea3 948 debugPrintf("LCP Other\n");
nixnax 95:40af49390daf 949 dumpPPPFrame();
nixnax 29:30de79d658f6 950 }
nixnax 29:30de79d658f6 951
nixnax 29:30de79d658f6 952 void LCPframe()
nixnax 29:30de79d658f6 953 {
nixnax 29:30de79d658f6 954 int code = ppp.pkt.buf[4];
nixnax 29:30de79d658f6 955 switch (code) {
nixnax 29:30de79d658f6 956 case 1:
nixnax 29:30de79d658f6 957 LCPconfReq();
nixnax 29:30de79d658f6 958 break; // config request
nixnax 29:30de79d658f6 959 case 2:
nixnax 29:30de79d658f6 960 LCPconfAck();
nixnax 29:30de79d658f6 961 break; // config ack
nixnax 29:30de79d658f6 962 case 5:
nixnax 29:30de79d658f6 963 LCPend();
nixnax 29:30de79d658f6 964 break; // end connection
nixnax 29:30de79d658f6 965 default:
nixnax 29:30de79d658f6 966 LCPother();
nixnax 29:30de79d658f6 967 }
nixnax 9:0992486d4a30 968 }
nixnax 9:0992486d4a30 969
nixnax 29:30de79d658f6 970 void discardedFrame()
nixnax 29:30de79d658f6 971 {
nixnax 29:30de79d658f6 972 if (v0) {
nixnax 119:e14dd2bf0ea3 973 debugPrintf("Frame is not IP, IPCP or LCP: %02x %02x %02x %02x\n", ppp.pkt.buf[0],ppp.pkt.buf[1],ppp.pkt.buf[2],ppp.pkt.buf[3]);
nixnax 29:30de79d658f6 974 }
nixnax 9:0992486d4a30 975 }
nixnax 9:0992486d4a30 976
nixnax 29:30de79d658f6 977 void determinePacketType()
nixnax 29:30de79d658f6 978 {
nixnax 29:30de79d658f6 979 if ( ppp.pkt.buf[0] != 0xff ) {
nixnax 119:e14dd2bf0ea3 980 debugPrintf("byte0 != ff\n");
nixnax 29:30de79d658f6 981 return;
nixnax 29:30de79d658f6 982 }
nixnax 29:30de79d658f6 983 if ( ppp.pkt.buf[1] != 3 ) {
nixnax 119:e14dd2bf0ea3 984 debugPrintf("byte1 != 3\n");
nixnax 29:30de79d658f6 985 return;
nixnax 29:30de79d658f6 986 }
nixnax 29:30de79d658f6 987 if ( ppp.pkt.buf[3] != 0x21 ) {
nixnax 119:e14dd2bf0ea3 988 debugPrintf("byte2 != 21\n");
nixnax 29:30de79d658f6 989 return;
nixnax 29:30de79d658f6 990 }
nixnax 9:0992486d4a30 991 int packetType = ppp.pkt.buf[2];
nixnax 9:0992486d4a30 992 switch (packetType) {
nixnax 29:30de79d658f6 993 case 0xc0:
nixnax 29:30de79d658f6 994 LCPframe();
nixnax 29:30de79d658f6 995 break; // link control
nixnax 29:30de79d658f6 996 case 0x80:
nixnax 29:30de79d658f6 997 IPCPframe();
nixnax 29:30de79d658f6 998 break; // IP control
nixnax 29:30de79d658f6 999 case 0x00:
nixnax 29:30de79d658f6 1000 IPframe();
nixnax 29:30de79d658f6 1001 break; // IP itself
nixnax 29:30de79d658f6 1002 default:
nixnax 29:30de79d658f6 1003 discardedFrame();
nixnax 9:0992486d4a30 1004 }
nixnax 29:30de79d658f6 1005 }
nixnax 9:0992486d4a30 1006
nixnax 119:e14dd2bf0ea3 1007 void wait_for_PPP_frame()
nixnax 50:ad4e7c3c88e5 1008 {
nixnax 85:53e57ff1cf05 1009 while(1) {
nixnax 93:9675adc36882 1010 fillbuf(); // handle received characters
nixnax 81:9ede60e9a2c8 1011 if ( rxbufNotEmpty() ) {
nixnax 81:9ede60e9a2c8 1012 int oldTail = ppp.rx.tail; // remember where the character is located in the buffer
nixnax 81:9ede60e9a2c8 1013 int rx = pc_getBuf(); // get the character
nixnax 50:ad4e7c3c88e5 1014 if (rx==FRAME_7E) {
nixnax 120:bef89e4c906e 1015 if (ppp.firstFrame) { // is this the start of the first frame start
nixnax 119:e14dd2bf0ea3 1016 ppp.firstFrame=0;
nixnax 120:bef89e4c906e 1017 ppp.rx.rtail = ppp.rx.tail; // update real-time tail with virtual tail
nixnax 120:bef89e4c906e 1018 ppp.hdlc.frameStartIndex = ppp.rx.tail; // remember where first frame started
nixnax 119:e14dd2bf0ea3 1019 } else {
nixnax 119:e14dd2bf0ea3 1020 ppp.hdlc.frameEndIndex=oldTail; // mark the frame end character
nixnax 119:e14dd2bf0ea3 1021 processPPPFrame(ppp.hdlc.frameStartIndex, ppp.hdlc.frameEndIndex); // process the frame
nixnax 120:bef89e4c906e 1022 ppp.rx.rtail = ppp.rx.tail; // update real-time tail with virtual tail
nixnax 119:e14dd2bf0ea3 1023 ppp.hdlc.frameStartIndex = ppp.rx.tail; // where next frame will start
nixnax 119:e14dd2bf0ea3 1024 break;
nixnax 119:e14dd2bf0ea3 1025 }
nixnax 50:ad4e7c3c88e5 1026 }
nixnax 50:ad4e7c3c88e5 1027 }
nixnax 85:53e57ff1cf05 1028 }
nixnax 50:ad4e7c3c88e5 1029 }
nixnax 50:ad4e7c3c88e5 1030
nixnax 29:30de79d658f6 1031 void scanForConnectString()
nixnax 29:30de79d658f6 1032 {
nixnax 81:9ede60e9a2c8 1033 while(ppp.online == 0) {
nixnax 114:8a5d70bbc1b2 1034 fillbuf(); // gather received characters
nixnax 81:9ede60e9a2c8 1035 // search for Windows Dialup Networking "Direct Connection Between Two Computers" expected connect string
nixnax 106:d14e6b597ca3 1036 char * found1 = strstr( (char *)ppp.rx.buf, "CLIENT" );
nixnax 107:5fe806713d49 1037 if (found1 != NULL) {
nixnax 107:5fe806713d49 1038 // respond with Windows Dialup networking expected "Direct Connection Between Two Computers" response string
nixnax 119:e14dd2bf0ea3 1039 if (v0) debugPrintf("Found connect string \"CLIENT\", sent \"CLIENTSERVER\"\n");
nixnax 107:5fe806713d49 1040 pc.puts("CLIENTSERVER");
nixnax 120:bef89e4c906e 1041 ppp.online=1; // we are connected - set flag so we stop looking for the connect string
nixnax 119:e14dd2bf0ea3 1042 fillbuf();
nixnax 9:0992486d4a30 1043 }
nixnax 9:0992486d4a30 1044 }
nixnax 103:4f5512dd11cf 1045 }
nixnax 81:9ede60e9a2c8 1046
nixnax 0:2cf4880c312a 1047 int main()
nixnax 0:2cf4880c312a 1048 {
nixnax 120:bef89e4c906e 1049 pc.baud(115200); // USB serial port
nixnax 120:bef89e4c906e 1050 debugBaudRate(115200); // baud rate for our debug port - if we have one
nixnax 120:bef89e4c906e 1051 debugPrintf("\x1b[2J\x1b[H\x1b[30mPPP-Blinky Ready.\n"); // VT100 codes for clear_screen, home, black_text - Tera Term is a handy VT100 terminal
nixnax 9:0992486d4a30 1052 pppInitStruct(); // initialize all the PPP properties
nixnax 0:2cf4880c312a 1053 while(1) {
nixnax 120:bef89e4c906e 1054 scanForConnectString(); // wait for connect
nixnax 81:9ede60e9a2c8 1055 while(ppp.online) {
nixnax 120:bef89e4c906e 1056 wait_for_PPP_frame(); // wait for a PPP frame
nixnax 81:9ede60e9a2c8 1057 }
nixnax 7:ab147f5e97ac 1058 }
nixnax 105:45001195b325 1059 }