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 01:58:22 2017 +0000
Revision:
118:54d1936e3768
Parent:
117:c819ae068336
Child:
119:e14dd2bf0ea3
More compact debug dump format, check for input characters while dumping headers, removed 20ms wait before sending, added PUSH flag to outgoing TCP data.

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