PPPoE application with W5500

Dependencies:   W5500Interface mbed pppoe

- How to connect PPPoE with WIZ550 ioShield and mbed platform (Korean version)

http://hjjeon0608.wordpress.com/2014/09/25/wiz550io-ioshield-a%EC%99%80-mbed-%EB%B3%B4%EB%93%9C%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-pppoe-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0/

- How to connect ioShield to mbed platform(ST nucleo) of ST Microelectronics via SPI (Korean version)

http://hjjeon0608.wordpress.com/2014/09/25/wiz550-ioshield-a-%EC%99%80-mbed-%ED%94%8C%EB%9E%AB%ED%8F%BC-st-nucleo-f030r8-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0/

- Example PPPoE server(RB750) setting (Korean version)

http://hjjeon0608.wordpress.com/2014/10/28/rb750pppoe-server-setting%ED%95%98%EA%B8%B0/

- W5500(PPPoE client) setting (Korean version)

http://hjjeon0608.wordpress.com/2014/10/29/temp/

- PPPoE library

http://developer.mbed.org/teams/EthernetInterfaceW5500-makers/code/pppoe/

Files at this revision

API Documentation at this revision

Comitter:
hjjeon
Date:
Wed Oct 15 06:27:12 2014 +0000
Parent:
0:77e21f1ce73b
Child:
2:d081c17abd1b
Commit message:
PPPoE application with W5500

Changed in this revision

W5500Interface.lib Show annotated file Show diff for this revision Revisions of this file
WIZnet_PPPoE.lib Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
pppoe/PPPoE.cpp Show annotated file Show diff for this revision Revisions of this file
pppoe/PPPoE.h Show annotated file Show diff for this revision Revisions of this file
pppoe/md5.cpp Show annotated file Show diff for this revision Revisions of this file
pppoe/md5.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/W5500Interface.lib	Wed Oct 15 06:27:12 2014 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/teams/EthernetInterfaceW5500-makers/code/W5500Interface_pppoe/#dfffa4d6f022
--- a/WIZnet_PPPoE.lib	Fri Sep 26 01:31:07 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/hjjeon/code/WIZnet_PPPoE/#ec9b01a52dd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Oct 15 06:27:12 2014 +0000
@@ -0,0 +1,193 @@
+#include "mbed.h"
+#include "EthernetInterface.h"
+#include <stdio.h>
+#include <string.h>
+#include "PPPoE.h"
+
+
+/////////////////////////////////////////
+// SOCKET NUMBER DEFINION for Examples //
+/////////////////////////////////////////
+#define SOCK_TCPS        1
+#define SOCK_UDPS        2
+
+
+
+////////////////////////////////////////////////
+// Shared Buffer Definition for LOOPBACK TEST //
+////////////////////////////////////////////////
+#define DATA_BUF_SIZE   2048
+uint8_t gDATABUF[DATA_BUF_SIZE];
+
+
+///////////////////////////////////
+// Default Network Configuration //
+///////////////////////////////////
+/*
+wiz_NetInfo gWIZNETINFO = { .mac = {0x00, 0x08, 0xdc,0x00, 0xab, 0xcd},
+                            .ip = {192, 168, 200, 123},
+                            .sn = {255,255,255,0},
+                            .gw = {192, 168, 200, 1},
+                            .dns = {0,0,0,0},
+                            .dhcp = NETINFO_STATIC };
+*/
+
+///////////////////////////////////////
+// ID and Password for PAP for PPPoE //
+///////////////////////////////////////
+//TODO : fill these variables before start ppp_init
+uint8_t pppoe_id[] = "wiznet";
+uint8_t pppoe_id_len = 6;
+uint8_t pppoe_pw[] = "wiz1206";
+uint8_t pppoe_pw_len = 7;
+uint8_t pppoe_ip[4] = {0,};
+uint8_t pppoe_pdns[4] = {0,};
+uint8_t pppoe_sdns[4] = {0,};
+uint16_t pppoe_retry_count = 0;
+
+
+
+int main() {
+//    EthernetInterface eth;
+// change for W5500 interface.
+#if defined(TARGET_LPC1114)
+    SPI spi(dp2, dp1, dp6); // mosi, miso, sclk
+    EthernetInterface eth(&spi, dp25, dp26); // spi, cs, reset
+
+#elif defined(TARGET_LPC1768)
+    SPI spi(p11, p12, p13); // mosi, miso, sclk
+    EthernetInterface eth(&spi, p14, p15); // spi, cs, reset
+#elif defined(TARGET_LPC11U68)
+    SPI spi(P0_9, P0_8, P1_29); // mosi, miso, sclk
+    EthernetInterface eth(&spi, P0_2, P1_28);//, nRESET(p9); // reset pin is dummy, don't affect any pin of WIZ550io
+    spi.format(8,0); // 8bit, mode 0
+    spi.frequency(7000000); // 7MHz
+    wait(1); // 1 second for stable state
+#elif defined(TARGET_KL25Z)
+    Serial pc(USBTX, USBRX);
+    pc.baud(115200);
+    printf("spi init\r\n");
+    SPI spi(D11, D12, D13); // mosi, miso, sclk
+    wait(1); // 1 second for stable state
+    EthernetInterface eth(&spi, D10, D9);//scs(D10), nRESET(PTA20)
+    printf("App Start\r\n");
+    wait(1); // 1 second for stable state
+    wait(1); // 1 second for stable state
+#elif defined (TARGET_NUCLEO_F030R8)
+    Serial pc(USBTX, USBRX);
+    pc.baud(115200);
+    SPI spi(SPI_MOSI, SPI_MISO, SPI_SCK); // mosi, miso, sclk
+    EthernetInterface eth(&spi, PB_6, PA_9);//, nRESET(p9); // reset pin is dummy, don't affect any pin of WIZ550io
+    spi.format(8,0); // 8bit, mode 0
+    spi.frequency(7000000); // 7MHz
+    wait(1); // 1 second for stable state
+#elif defined (TARGET_NUCLEO_F334R8)
+    Serial pc(USBTX, USBRX);
+    pc.baud(115200);
+    SPI spi(SPI_MOSI, SPI_MISO, SPI_SCK); // mosi, miso, sclk
+    EthernetInterface eth(&spi, PB_6, PA_9);//, nRESET(p9); // reset pin is dummy, don't affect any pin of WIZ550io
+    spi.format(8,0); // 8bit, mode 0
+    spi.frequency(7000000); // 7MHz
+    wait(1); // 1 second for stable state
+#endif
+
+
+    int8_t tmp = 0;
+    uint8_t mac_addr[6] = {0x00, 0x08, 0xdc,0x00, 0xab, 0xcd};
+    int32_t ret;
+    uint8_t str[15];
+
+    printf("platform init done\r\n");
+
+
+
+    /* PHY link status check */
+
+    do
+    {
+        if(eth.getPHYCFGR() & PHYCFGR_LNK_ON)
+            tmp = PHY_LINK_ON;
+        else
+            tmp = PHY_LINK_OFF;
+            
+        if(tmp == -1)
+            printf("Unknown PHY Link stauts.\r\n");
+    }while(tmp == PHY_LINK_OFF);
+
+
+    /* Network initialization */    
+    eth.init((uint8_t *)mac_addr, "192.168.200.123", "255.255.255.0", "192.168.200.1");
+
+    printf("\r\n====== MACRAW:PPPoE Start ======\r\n");
+
+/*
+    md5_init(&context);
+    md5_update(&context, str, str_len);
+    md5_final(digest, &context);
+
+*/
+    PPPOEClient pppoe;
+
+    while(1)
+    {
+        ret = pppoe.ppp_start(gDATABUF);//ppp start function
+        if(ret == PPP_SUCCESS || pppoe_retry_count > PPP_MAX_RETRY_COUNT) break;    // PPPoE Connected or connect failed by over retry count
+
+    }
+
+
+
+    if(ret == PPP_SUCCESS)//1 : success
+    {
+
+        printf("\r\n<<<< PPPoE Success >>>>\r\n");
+        printf("Assigned IP address : %.3u.%.3u.%.3u.%.3u\r\n", pppoe_ip[0], pppoe_ip[1], pppoe_ip[2], pppoe_ip[3]);
+
+        printf( "\r\n==================================================\r\n");
+        printf( "    AFTER PPPoE, Net Configuration Information        \r\n");
+        printf( "==================================================\r\n");
+
+
+        eth.getSHAR(str);
+        printf( "MAC address  : %x:%x:%x:%x:%x:%x\r\n", str[0], str[1], str[2], str[3], str[4], str[5] );
+        eth.getSUBR(str);
+        printf( "SUBNET MASK  : %.3u.%.3u.%.3u.%.3u\r\n", str[0], str[1], str[2], str[3] );
+        eth.getGAR(str);
+        printf( "G/W IP ADDRESS : %.3u.%.3u.%.3u.%.3u\r\n",str[0], str[1], str[2], str[3]);
+        eth.getSIPR(str);
+        printf( "SOURCE IP ADDRESS : %.3u.%.3u.%.3u.%.3u\r\n\r\n", str[0], str[1], str[2], str[3]);
+
+
+    }
+    else//failed
+    {
+        printf("\r\n<<<< PPPoE Failed >>>>\r\n");
+        eth.init((uint8_t *)mac_addr, "192.168.200.123", "255.255.255.0", "192.168.200.1");
+    }
+
+
+
+    /*******************************/
+    /* WIZnet W5500 Code Examples  */
+    /* TCPS/UDPS Loopback test     */
+    /*******************************/
+    /* Main loop */
+    /*
+    while(1)
+    {
+        // Loopback Test
+        // TCP server loopback test
+        if( (ret = loopback_tcps(SOCK_TCPS, gDATABUF, 5000)) < 0) {
+            printf("SOCKET ERROR : %ld\r\n", ret);
+        }
+
+        // UDP server loopback test
+        if( (ret = loopback_udps(SOCK_UDPS, gDATABUF, 3000)) < 0) {
+            printf("SOCKET ERROR : %ld\r\n", ret);
+        }
+    } // end of Main loop
+    */
+} // end of main()
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pppoe/PPPoE.cpp	Wed Oct 15 06:27:12 2014 +0000
@@ -0,0 +1,1658 @@
+#include <stdint.h>
+#include "PPPoE.h"
+
+
+// ID and Password for PAP from main.c
+extern uint8_t pppoe_id[];//={};
+extern uint8_t pppoe_id_len;
+extern uint8_t pppoe_ip[];//={};
+extern uint8_t pppoe_pdns[];//={};
+extern uint8_t pppoe_sdns[];//={};
+extern uint8_t pppoe_pw[];//={};
+extern uint8_t pppoe_pw_len;
+
+
+//IPCP Reject flag
+uint8_t ip_rjt;
+uint8_t pdns_rjt;
+uint8_t sdns_rjt;
+
+
+// PPPoE Frame structure for send
+PPPMSG     PPPMSG_req; // PPPoE frame
+PROTOCOL   PPPPROTO; // Tag and Protocol data
+
+// TxRx Buffers pointer from main
+uint8_t* buf;
+
+// Server MAC and Assigned Session ID and IP address from NAS using PPPoE
+uint8_t    NAS_mac[6];
+uint16_t   NAS_sessionid = 0;
+
+// kind of authentication protocol and algorithm; decided by LCP phase
+// Authentication protocol : PAP - 0xC023, CHAP - 0xC223
+// Algorithm : MD5 - 0x05, MS-CHAP - 0x80, MS-CHAP-V2 - 0x81
+uint16_t  auth_protocol;
+uint8_t   chap_algorithm;
+
+// For MD5 calculation
+MD5_CTX   context;
+uint8_t   digest[16];
+
+// Identifier for PPPoE Protocols (increase per message sending)
+uint8_t   protocol_id = 0x01;
+
+
+
+uint16_t   pppoe_state = PPPoE_DISCOVERY;
+// PPPoE stage control flags
+uint16_t   pppoe_control_flag = 0;
+
+//PPPoE retry count and send retry count
+uint8_t   pppoe_retry_send_count = 0;
+extern uint16_t  pppoe_retry_count;
+uint8_t  pppoe_recv_count = 0;
+
+
+// Tmp variable
+uint16_t   tmp_protocol;
+uint8_t   tmp_pcode;
+
+PPPOEClient::PPPOEClient()
+{
+    eth = WIZnet_Chip::getInstance();
+}
+
+
+void PPPOEClient::set_pppinfo(uint8_t * nas_mac, uint8_t * ppp_ip, uint16_t nas_sessionid)
+{
+
+#ifdef __DEF_PPP_DBG1__
+    uint8_t str[8];//debug var    
+    uint16_t psid;
+    
+    printf("set_pppinfo() Start...\r\n");
+#endif
+    /* Set PPPoE bit in MR(Common Mode Register) : enable PPPoE */
+    eth->setMR(eth->getMR() | MR_PPPOE);
+
+    // Write PPPoE server's MAC address, Session ID and IP address.
+    // must be setted these value.
+#ifdef __DEF_PPP_DBG1__
+    printf("Server's MAC : %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\r\n", nas_mac[0], nas_mac[1], nas_mac[2], nas_mac[3], nas_mac[4], nas_mac[5]);
+    printf("PPPoE IP : %.3d.%.3d.%.3d.%.3d\r\n", ppp_ip[0], ppp_ip[1], ppp_ip[2], ppp_ip[3]);
+    printf("Session ID : 0x%.2x%.2x\r\n", (uint8_t)(nas_sessionid >> 8), (uint8_t)nas_sessionid);
+#endif  
+   
+    eth->setPHAR(nas_mac);
+    eth->setSIPR(ppp_ip);
+    eth->setPSID(nas_sessionid);
+    
+#ifdef __DEF_PPP_DBG1__
+    eth->getPHAR(str);
+    printf( "Read PHAR register : %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\r\n", str[0], str[1], str[2], str[3], str[4], str[5]);
+    eth->getSIPR(str);
+    printf( "Read SIP register : %.3d.%.3d.%.3d.%.3d\r\n", str[0], str[1], str[2], str[3]);    
+    psid = eth->getPSID();
+    printf("Read PSID register : %x\r\n", psid);
+#endif
+
+    //open socket in pppoe mode
+    eth->setPTIMER(0);
+    
+    
+#ifdef __DEF_PPP_DBG1__
+    printf("set_pppinfo() End...\r\n");
+#endif
+#ifdef __DEF_PPP_DBG1__
+    printf("pppoe PDNS : %.3d.%.3d.%.3d.%.3d\r\n", pppoe_pdns[0], pppoe_pdns[1], pppoe_pdns[2], pppoe_pdns[3]);
+    printf("pppoe SDNS : %.3d.%.3d.%.3d.%.3d\r\n", pppoe_sdns[0], pppoe_sdns[1], pppoe_sdns[2], pppoe_sdns[3]);
+#endif
+
+}
+
+
+void PPPOEClient::ppp_send(void)
+{       
+    uint8_t  *ptr;
+    uint8_t  sn = 0;
+    uint16_t tmp16 = 0;
+    uint16_t txbuf_len = 0;
+
+    txbuf_len = sizeof(PPPMSG_req);
+
+
+
+    if(pppoe_state == PPPoE_DISCOVERY)
+        ptr = (uint8_t *)&PPPPROTO.opt;
+    else
+        ptr = (uint8_t *)&PPPPROTO;
+
+
+    // Fill the Tx buffer
+    //memcpy(txbuf, (uint8_t *)&PPPMSG_req, txbuf_len);
+    memcpy(buf, (uint8_t *)&PPPMSG_req, txbuf_len);
+    //change MSB and LSB because of different endian.
+    tmp16 = 0;
+    tmp16 = (PPPMSG_req.len & 0xFF) << 8;
+    tmp16 |= ((PPPMSG_req.len >> 8) & 0xFF);
+
+    //memcpy(txbuf + txbuf_len, ptr, tmp16);
+    memcpy(buf + txbuf_len, ptr, tmp16);
+    txbuf_len += tmp16;
+
+#ifdef __DEF_PPP_DBG2__
+    printf("Send data : ");
+    for(i=0; i<txbuf_len; i++)
+    {
+        if((i % 16) == 0) printf("\r\n");
+        printf("%.2x ", buf[i]);
+    }
+    printf("\r\n\r\n");
+#endif
+    // Send MACRAW data    
+    eth->send(sn, (char*)buf, txbuf_len);
+    //setSn_CR(sn, Sn_CR_SEND);
+    eth->setSn_CR(sn, Sn_CR_SEND);    
+    while( eth->getSn_CR(sn) ) ;
+}
+ 
+
+void PPPOEClient::ppp_recv( uint16_t received_len )
+{
+    
+    uint16_t i;
+    uint8_t  sn = 0;
+    uint8_t  head[2] ={0,};
+    
+    uint16_t  ethertype = 0;
+    uint8_t   pppoecode = 0;
+    uint16_t  taglen = 0;
+    uint16_t  tagname;
+
+    uint8_t   get_protocol_id = 0;
+    uint16_t  t_idx = 0, acknak_idx = 0, rjt_idx = 0;
+    uint16_t  ppp_tag_len = 0, getlen = 0, opt_len = 0;
+    uint8_t   acknak_opt[OPTMSG_LEN];
+    uint8_t   rjt_opt[OPTMSG_LEN];
+    uint8_t   opt_code;
+    uint8_t   ppp_code;
+
+    uint8_t   str[OPTMSG_LEN];
+    uint16_t  str_len = 0;
+    uint8_t   tmp8 = 0;
+    uint8_t   mac[6];
+
+    //reset servicename flag
+    pppoe_control_flag = pppoe_control_flag & ~FLAG_PADO_SERVICENAME;
+
+
+    //getSHAR(mac);
+    eth->getSHAR(mac);
+
+    // MACRAW Receive
+    //receive header(packet length) of macraw packet
+
+    eth->recv(sn, (char*) head, 2);
+    
+    eth->setSn_CR(sn,Sn_CR_RECV);
+
+    while( eth->getSn_CR(sn) ) ;
+
+    received_len = 0;
+    received_len = head[0] << 8;
+    received_len = received_len | head[1];
+    received_len = received_len - 2;
+
+        
+    eth->recv(sn, (char*) buf, received_len);
+    
+    eth->setSn_CR(sn,Sn_CR_RECV);
+
+    while( eth->getSn_CR(sn) ) ;
+
+
+    // Check the MAC in received packet     
+    tmp8 = buf[0] - mac[0] + buf[1] - mac[1]    + buf[2] - mac[2]   + buf[3] - mac[3]   + buf[4] - mac[4]   + buf[5] - mac[5];
+
+    if(tmp8==0)
+    {       
+#ifdef __DEF_PPP_DBG2__
+        printf("Received packet  :");
+        for(i = 0; i < received_len; i++)
+            {
+                if((i % 16) == 0) printf("\r\n");
+                printf("%.2x ", buf[i]);
+            }
+        printf("\r\n");
+#endif          
+        ethertype = buf[12];
+        ethertype = (ethertype << 8) + buf[13];
+        
+        pppoecode = buf[15];
+
+        taglen = buf[18];
+        taglen = (taglen << 8) + buf[19];
+        ppp_code = buf[22];
+        
+        //Check the Ether-Type and Code in received packet      
+        t_idx = 20;         
+        switch (ethertype)
+        {
+        case  PPPoE_DISCOVERY :
+            if (pppoecode == PPPoE_PADO)
+            {
+#ifdef __DEF_PPP_DBG1__     
+                          printf("PPPoE Discovery: PADO received\r\n\r\n");
+#endif
+                for(i = 0; i < 6; i++) NAS_mac[i] = buf[6+i];
+                // PPPoE Frame  
+                while(taglen)
+                {                   
+                    tagname = buf[t_idx];
+                    tagname = (tagname << 8) + buf[t_idx+1];
+                                            
+                    ppp_tag_len = buf[t_idx+2];
+                    ppp_tag_len = (ppp_tag_len << 8) + buf[t_idx+3];
+                    
+                    // Check option field overflow
+                    // (OPTMSG_LEN defined maximum option field length.)
+                    if((acknak_idx + (ppp_tag_len+4)) > OPTMSG_LEN)                 
+                    {
+#ifdef __DEF_PPP_DBG__
+                        printf("PPPoE Protocol option field overflow occuerd!\r\n");
+#endif
+                        break;
+                    }
+                    else
+                    {
+                        switch(tagname)
+                        {                       
+                        case PPPoED_SERVICE_NAME :
+                            if ((pppoe_control_flag & FLAG_PADO_SERVICENAME) == 0)
+                            {                                                       
+                                memcpy(&acknak_opt[acknak_idx], &buf[t_idx], ppp_tag_len+4);
+                                acknak_idx += (ppp_tag_len+4);                          
+                                pppoe_control_flag = pppoe_control_flag | FLAG_PADO_SERVICENAME;
+                            }
+                            break;
+                        case PPPoED_HOST_UNIQ :
+                        case PPPoED_AC_COOKIE :                         
+                            memcpy(&acknak_opt[acknak_idx], &buf[t_idx], ppp_tag_len+4);
+                            acknak_idx += (ppp_tag_len+4);                          
+                            break;                  
+                        default :
+                        //case PPPoED_AC_NAME :
+                            break;
+                        }                       
+                    }
+                    t_idx += (ppp_tag_len+4);
+                    taglen -= (ppp_tag_len+4);                       
+                }               
+                
+                memcpy(&PPPPROTO.opt[0], &acknak_opt[0], acknak_idx);
+        
+                for(i = 0; i < 6; i++)
+                {
+                    PPPMSG_req.dst_mac[i] = NAS_mac[i];     // NAS MAC address
+                }
+                PPPMSG_req.frame_code = PPPoE_PADR;
+                //change MSB and LSB because of different endian.
+                PPPMSG_req.len = 0;
+                PPPMSG_req.len = (acknak_idx & 0xFF) << 8;
+                PPPMSG_req.len |= ((acknak_idx >> 8) & 0xFF);
+
+#ifdef __DEF_PPP_DBG1__
+                printf("PPPoE Discovery : PADR send\r\n");
+#endif
+                ppp_send();
+                pppoe_control_flag = pppoe_control_flag | FLAG_DISCOVERY_RCV_PADO;
+                
+
+            }
+            else if(pppoecode == PPPoE_PADS)
+            {   
+#ifdef __DEF_PPP_DBG1__
+                printf("PPPoE Discovery: PADS received\r\n\r\n");
+#endif
+                pppoe_control_flag = pppoe_control_flag | FLAG_DISCOVERY_RCV_PADS;
+
+                NAS_sessionid = buf[16];
+                NAS_sessionid = (NAS_sessionid << 8) + buf[17];
+            }
+#ifdef __DEF_PPP_DBG1__
+            else printf("Not necessary packet received\r\n");
+#endif
+            break;
+        case  PPPoE_SESSION :
+
+            // Process LCP     
+            if ((buf[20] == 0xc0) && (buf[21] == 0x21))
+            {
+                //change MSB and LSB because of different endian.
+                PPPPROTO.protocol = 0;
+                PPPPROTO.protocol = (PPPoE_LCP & 0xFF) << 8;
+                PPPPROTO.protocol |= ((PPPoE_LCP >> 8) & 0xFF);
+
+                switch (ppp_code)
+                {
+                // when lcp_cr_rcv flag set && lcp_cr_sent flag set, goto PAP or CHAP
+                case PPP_CONFIG_REQ : //Configuration Request receive, and then ack or reject send
+                // when ack sent, lcp_cr_rcv flag set
+#ifdef __DEF_PPP_DBG1__
+                    printf("PPPoE Session LCP: Configure-Request received\r\n\r\n");
+#endif          
+                    get_protocol_id = buf[23];
+                    getlen = buf[24];
+                    getlen = (getlen<<8) + buf[25];
+
+                    getlen -= 4;
+                    t_idx = 26;
+                    while (getlen)
+                    {
+                        opt_code = buf[t_idx];
+                        opt_len = buf[t_idx+1];
+                        // Check option field overflow
+                        // (OPTMSG_LEN defined maximum option field length.)
+                        if((acknak_idx + opt_len) > OPTMSG_LEN || (rjt_idx + opt_len) > OPTMSG_LEN)                 
+                        {
+#ifdef __DEF_PPP_DBG__
+                            printf("PPPoE Protocol option field overflow occuerd!\r\n");
+#endif
+                            break;
+                        }
+                        else
+                        {
+                              switch (opt_code)
+                              {
+                              case LCP_AUTH : // Authentication-Protocol                            
+                                    auth_protocol = buf[t_idx+2];
+                                    auth_protocol = (auth_protocol << 8) + buf[t_idx+3];
+                                    chap_algorithm = buf[t_idx+4];
+                                    memcpy(&acknak_opt[acknak_idx], &buf[t_idx], opt_len);
+                                    acknak_idx += opt_len;
+                                    break;
+                              case LCP_MRU : // MRU (Maximum-Receive-Unit)
+                                    memcpy(&acknak_opt[acknak_idx], &buf[t_idx], opt_len);
+                                    acknak_idx += opt_len;
+                                    break;
+                              case LCP_MAGICNUM : // Magic-Number 
+                                    // opt_code : 0x01, 0x03, 0x05 shared process part
+                                    memcpy(&acknak_opt[acknak_idx], &buf[t_idx], opt_len);
+                                    acknak_idx += opt_len;
+
+                                    break;
+                              default :
+                                memcpy(&rjt_opt[rjt_idx], &buf[t_idx], opt_len);
+                                    rjt_idx += opt_len;
+                                break;
+                              }
+                          }
+                          t_idx += opt_len;
+                          getlen -= opt_len;
+                    }
+
+
+
+                    if (rjt_idx)
+                    {
+                        // reject send, then wait cr
+                        PPPPROTO.pcode = PPP_CONFIG_REJ; // Reject
+                        memcpy(&PPPPROTO.opt[0], &rjt_opt[0], rjt_idx);
+                        PPPPROTO.id = get_protocol_id;
+
+                        //change MSB and LSB because of different endian.
+                        PPPPROTO.len = 0;
+                        PPPPROTO.len = ((rjt_idx+4) & 0xFF) << 8;
+                        PPPPROTO.len |= (((rjt_idx+4) >> 8) & 0xFF);
+
+                        //change MSB and LSB because of different endian.
+                        PPPMSG_req.len = 0;
+                        PPPMSG_req.len = ((rjt_idx+6) & 0xFF) << 8;
+                        PPPMSG_req.len |= (((rjt_idx+6) >> 8) & 0xFF);
+
+                        ppp_send();
+                    }
+                    else
+                    {
+                        // ack send, lcp_cr_rcv flag set
+                        //change MSB and LSB because of different endian.
+                        PPPPROTO.protocol = 0;
+                        PPPPROTO.protocol = (PPPoE_LCP & 0xFF) << 8;
+                        PPPPROTO.protocol |= ((PPPoE_LCP >> 8) & 0xFF);
+
+                        PPPPROTO.pcode = PPP_CONFIG_ACK; // ack
+                        memcpy(&PPPPROTO.opt[0], &acknak_opt[0], acknak_idx);
+                        PPPPROTO.id = get_protocol_id;
+                        //change MSB and LSB because of different endian.
+                        PPPPROTO.len = 0;
+                        PPPPROTO.len = ((acknak_idx+4) & 0xFF) << 8;
+                        PPPPROTO.len |= (((acknak_idx+4) >> 8) & 0xFF);
+
+                        //change MSB and LSB because of different endian.
+                        PPPMSG_req.len = 0;
+                        PPPMSG_req.len = ((acknak_idx+6) & 0xFF) << 8;
+                        PPPMSG_req.len |= (((acknak_idx+6) >> 8) & 0xFF);
+#ifdef __DEF_PPP_DBG1__
+                        printf("LCP Configuration Ack send\r\n");
+#endif
+                        ppp_send();//ack send
+                        pppoe_control_flag = pppoe_control_flag | FLAG_LCP_CR_RCV;
+
+                    }
+                    break;
+
+
+                case PPP_CONFIG_ACK : //ack, then lcp_cr_sent flag set
+#ifdef __DEF_PPP_DBG1__
+                    printf("PPPoE Session LCP: Configuration Ack received\r\n\r\n");
+#endif
+                    pppoe_control_flag = pppoe_control_flag | FLAG_LCP_CR_SNT;
+                    break;
+
+
+                case PPP_TERM_ACK :
+#ifdef __DEF_PPP_DBG1__
+                    printf("Termination Ack received\r\n\r\n");
+#endif
+                    pppoe_control_flag = pppoe_control_flag | FLAG_TERMINATION_ACK_RCV;
+
+                    break;
+
+
+                case PPP_TERM_REQ:
+#ifdef __DEF_PPP_DBG1__
+                    printf("Termination request received\r\n\r\n");
+#endif
+
+                    //change MSB and LSB because of different endian.
+                    PPPMSG_req.ether_type = 0;
+                    PPPMSG_req.ether_type = (PPPoE_SESSION & 0xFF) << 8;
+                    PPPMSG_req.ether_type |= ((PPPoE_SESSION >> 8) & 0xFF);// session
+
+                    PPPMSG_req.frame_code = 0x00;           // session data
+                    //change MSB and LSB because of different endian.
+                    PPPMSG_req.session_id = 0;
+                    PPPMSG_req.session_id = (NAS_sessionid & 0xFF) << 8;
+                    PPPMSG_req.session_id |= ((NAS_sessionid >> 8) & 0xFF);
+
+                    //change MSB and LSB because of different endian.
+                    PPPPROTO.protocol = 0;
+                    PPPPROTO.protocol = (PPPoE_LCP & 0xFF) << 8;
+                    PPPPROTO.protocol |= ((PPPoE_LCP >> 8) & 0xFF);
+
+                    PPPPROTO.pcode = PPP_TERM_ACK;  // Terminate-ack
+
+                    PPPPROTO.opt[0] = 0x00; // Magic number
+                    PPPPROTO.opt[1] = 0x01;
+                    PPPPROTO.opt[2] = 0x02;
+                    PPPPROTO.opt[3] = 0x03;
+
+                    PPPPROTO.id = protocol_id++;
+                    //change MSB and LSB because of different endian.
+                    PPPPROTO.len = 0;
+                    PPPPROTO.len = (8 & 0xFF) << 8;
+                    PPPPROTO.len |= ((8 >> 8) & 0xFF);
+
+                    //change MSB and LSB because of different endian.
+                    PPPMSG_req.len = 0;
+                    PPPMSG_req.len = (10 & 0xFF) << 8;
+                    PPPMSG_req.len |= ((10 >> 8) & 0xFF);
+
+                    pppoe_control_flag = pppoe_control_flag | FLAG_TERMINATION_REQ_RCV;
+
+#ifdef __DEF_PPP_DBG1__
+                    printf("Termination ack send\r\n");
+#endif
+                    ppp_send();
+
+                    break;
+
+
+/*
+* Notice :  This part is not implemented.  
+*           If necessary, please implement more for reply for request from NAS.
+*
+                case 0x04 : //reject
+                    break;
+
+                case 0x09 : // Echo-Response
+                    // Backup
+                    tmp_protocol = PPPPROTO.protocol;
+                    tmp_pcode = PPPPROTO.pcode;
+
+                    PPPPROTO.protocol = PPPoE_LCP;
+                    PPPPROTO.pcode = PPP_ECHO_REP;
+                    
+                    PPPPROTO.id = buf[23];
+
+                    PPPPROTO.len = buf[24];
+                    PPPPROTO.len = (PPPPROTO.len << 8) + buf[25];
+                                        
+                    memcpy(&PPPPROTO.opt[0], &buf[26], PPPPROTO.len-4);
+                    ppp_send();
+
+                    // Recover
+                    PPPPROTO.protocol = tmp_protocol;
+                    PPPPROTO.pcode = tmp_pcode;
+                    break;              
+*/
+
+                default:
+#ifdef __DEF_PPP_DBG1__
+                    printf("Not necessary packet received\r\n");
+#endif
+                    break;
+                }
+            }
+            // Process PAP
+            else if ((buf[20] == 0xc0) && (buf[21] == 0x23))
+            {
+                if(ppp_code == PPP_CONFIG_ACK) // PPP_CONFIG_ACK = 0x02
+                {
+                    pppoe_control_flag = pppoe_control_flag | FLAG_PAP_ACK_RCV;// receice ack
+
+#ifdef __DEF_PPP_DBG1__
+                    printf("PPPoE Session PAP: Authentication ACK received\r\n\r\n");
+#endif     
+                }
+                else if(ppp_code == PPP_TERM_ACK)
+                {
+#ifdef __DEF_PPP_DBG1__
+                    printf("Termination Ack received\r\n\r\n");
+#endif
+                    pppoe_control_flag = pppoe_control_flag | FLAG_TERMINATION_ACK_RCV;
+                }
+            }
+            // Process CHAP
+            
+            else if ((buf[20] == 0xc2) && (buf[21] == 0x23))
+            {                   
+                switch(chap_algorithm)
+                {
+                case MD5 : // 0x05, MD5
+
+                    get_protocol_id = buf[23];
+                    // length of [code ~ packet end]
+                    getlen = buf[24];
+                    getlen = (getlen<<8) + buf[25];
+                    // so, 'CHAP data' length is getlen - length of [code(1), ID(1), Length(2)]. 
+                    getlen -= 4; //PPP CHAP total(getlen) - 4(header) = data length(value size(1) + value + name )
+                    t_idx = 26;
+                    
+                    switch(ppp_code)
+                    {
+                        case 0x01 :
+#ifdef __DEF_PPP_DBG1__
+                            printf("PPPoE Session CHAP: CHAP Challenge received\r\n\r\n");
+#endif
+                            // Challenge, parse the packet and return 'Response' to NAS
+                            //-- MD5 calc input consist of ID(1), password(pwlen) and Challenge value(16).
+                        
+                            //-- buf[t_idx] => CV(challenge value) size, buf[t_idx+1] => start byte of CV
+
+                            memcpy(&str[str_len], &get_protocol_id, 1);     // ID(value)
+                            str_len += 1;
+                            memcpy(&str[str_len], &pppoe_pw[0], pppoe_pw_len);      // user password
+                            str_len += pppoe_pw_len;
+                            memcpy(&str[str_len], &buf[t_idx+1], buf[t_idx]);   // CV(value)
+                            str_len += buf[t_idx];
+
+                            /*
+                            memcpy(&str[str_len], &buf[t_idx+1], buf[t_idx]);   // CV(value)
+                            str_len += buf[t_idx];
+                            memcpy(&str[str_len], &pppoe_pw, pppoe_pw_len);         // user password                    
+                            str_len += pppoe_pw_len;
+                            memcpy(&str[str_len], &pppoe_id, pppoe_id_len);         // user id
+                            str_len += pppoe_id_len;
+                            */
+
+                            /*
+                            MD5Init(&context);
+                            MD5Update(&context, str, str_len);
+                            MD5Final(digest, &context);
+                            */
+
+
+                            MD5Init(&context);
+                            MD5Update(&context, &get_protocol_id, 1);
+                            MD5Update(&context, pppoe_pw, pppoe_pw_len);
+                            MD5Update(&context, (unsigned char *)(&buf[t_idx+1]), 16);
+                            MD5Final(digest, &context);
+
+                            // making response msg
+                            acknak_opt[acknak_idx++] = CV_HV_LEN; // fixed value, 16                                                                            
+                            memcpy(&acknak_opt[acknak_idx], &digest, CV_HV_LEN);
+                            acknak_idx += CV_HV_LEN;                            
+                            
+
+                            memcpy(&acknak_opt[acknak_idx], &pppoe_id, pppoe_id_len); // Name: User ID
+                            acknak_idx += pppoe_id_len;
+
+
+                            //change MSB and LSB because of different endian.
+                            PPPPROTO.protocol = 0;
+                            PPPPROTO.protocol = (PPPoE_CHAP & 0xFF) << 8;
+                            PPPPROTO.protocol |= ((PPPoE_CHAP >> 8) & 0xFF);
+
+                            PPPPROTO.pcode = 0x02; // response
+                            PPPPROTO.id = get_protocol_id;
+                            //change MSB and LSB because of different endian.
+                            PPPPROTO.len = 0;
+                            PPPPROTO.len = ((acknak_idx + 4) & 0xFF) << 8;
+                            PPPPROTO.len |= (((acknak_idx + 4) >> 8) & 0xFF);
+
+                            //change MSB and LSB because of different endian.
+                            PPPMSG_req.len = 0;
+                            PPPMSG_req.len = ((acknak_idx + 6) & 0xFF) << 8;
+                            PPPMSG_req.len |= (((acknak_idx + 6) >> 8) & 0xFF);
+
+
+                            memcpy(&PPPPROTO.opt[0], &acknak_opt[0], acknak_idx);
+#ifdef __DEF_PPP_DBG1__
+                            printf("CHAP response MSG send \r\n\r\n");
+#endif
+                            ppp_send();                                                                                                             
+                            break;
+
+
+                        case 0x03 : // PPP_SUCCESS
+#ifdef __DEF_PPP_DBG1__
+                            printf("PPPoE Session CHAP: CHAP Succeed packet received\r\n\r\n");
+#endif    
+                            pppoe_control_flag = pppoe_control_flag | FLAG_CHAP_SUC_RCV;
+
+                            break;
+
+
+                        case 0x04 : // PPP_FAIL
+#ifdef __DEF_PPP_DBG1__
+                            printf("PPPoE Session CHAP: CHAP failure packet received\r\n\r\n");
+#endif                      
+
+                            break;
+
+                        default :
+                            break;
+                    }
+                    break;
+#ifdef __DEF_PPP_DBG1__
+                case MS_CHAP : // 0x80, MS-CHAP
+                case MS_CHAP_V2 : // 0x81, MS-CHAP-V2 
+                    printf("This CHAP Algorithm is not supported : ");
+                    if(chap_algorithm == MS_CHAP) printf("MS-CHAP\r\n");
+                    else printf("MS-CHAP-V2\r\n"); 
+                    break; 
+#endif
+                default :
+                    break;
+                }
+            }
+            // Process IPCP
+            else if ((buf[20] == 0x80) && (buf[21] == 0x21))
+            {               
+                switch(ppp_code)
+                {
+                    case PPP_CONFIG_REQ : // cr, send ack
+                    case PPP_CONFIG_NAK : // nak, save ip addr and send config requset
+
+#ifdef __DEF_PPP_DBG1__
+                        if(ppp_code == 0x01) printf("PPPoE Session IPCP: Configure-Request received\r\n\r\n");
+                        else if (ppp_code == 0x03) printf("PPPoE Session IPCP: Configure-Nak received\r\n\r\n");
+#endif                                                                                                                                  
+                        get_protocol_id = buf[23];
+                        getlen = buf[24];
+                        getlen = (getlen<<8) + buf[25];
+                    
+                        getlen -= 4;
+                        t_idx = 26;
+                    
+                        while (getlen)
+                        {
+                            opt_code = buf[t_idx];
+                            opt_len = buf[t_idx+1];
+                        
+                            // Check option field overflow
+                            // (OPTMSG_LEN defined maximum option field length.)
+                            if((acknak_idx + opt_len) > OPTMSG_LEN || (rjt_idx + opt_len) > OPTMSG_LEN)
+                            {
+#ifdef __DEF_PPP_DBG__
+                                printf("PPPoE Protocol option field overflow occuerd!\r\n");
+#endif                          
+                                break;
+                            }
+                            else
+                            {
+                                switch (opt_code)
+                                {                         
+                                    //case 0x02 : // type : ip compression protocol
+                                    case 0x03 : // type : ip address
+                                        memcpy(&acknak_opt[acknak_idx], &buf[t_idx], opt_len);
+                                        memcpy(&pppoe_ip, &buf[t_idx+2], opt_len-2);
+
+                                        acknak_idx += opt_len;
+                                        break;
+                                    case 0x81 : //PDNS
+                                        memcpy(&acknak_opt[acknak_idx], &buf[t_idx], opt_len);
+                                        memcpy(&pppoe_pdns, &buf[t_idx+2], opt_len-2);
+
+                                        acknak_idx += opt_len;
+                                        break;
+                                    case 0x83 : //SDNS
+                                        memcpy(&acknak_opt[acknak_idx], &buf[t_idx], opt_len);
+                                        memcpy(&pppoe_sdns, &buf[t_idx+2], opt_len-2);
+
+                                        acknak_idx += opt_len;
+                                        break;
+                                    default : // reject
+                                        memcpy(&rjt_opt[rjt_idx], &buf[t_idx], opt_len);
+                                        rjt_idx += opt_len;
+                                        break;
+                                }
+                            }
+                            t_idx += opt_len;
+                            getlen -= opt_len;
+                        }
+
+
+
+                        if (rjt_idx)//if reject
+                        {
+#ifdef __DEF_PPP_DBG1__
+                            printf("reject send!\r\n");
+#endif
+                            // reject send, then wait cr
+                            //change MSB and LSB because of different endian.
+                            PPPPROTO.protocol = 0;
+                            PPPPROTO.protocol = (PPPoE_IPCP & 0xFF) << 8;
+                            PPPPROTO.protocol |= ((PPPoE_IPCP >> 8) & 0xFF);
+
+                            PPPPROTO.pcode = 0x04; // Reject
+                      
+                            memcpy(&PPPPROTO.opt[0], &rjt_opt[0], rjt_idx);
+                    
+                            PPPPROTO.id = get_protocol_id;
+                            //change MSB and LSB because of different endian.
+                            PPPPROTO.len = 0;
+                            PPPPROTO.len = ((rjt_idx+4) & 0xFF) << 8;
+                            PPPPROTO.len |= (((rjt_idx+4) >> 8) & 0xFF);
+                            //change MSB and LSB because of different endian.
+                            PPPMSG_req.len = 0;
+                            PPPMSG_req.len = ((rjt_idx+6) & 0xFF) << 8;
+                            PPPMSG_req.len |= (((rjt_idx+6) >> 8) & 0xFF);
+                            
+                            ppp_send();
+                        }
+                        else // if not reject
+                        {
+                            // ack send, lcp_cr_rcv flag set
+                            //change MSB and LSB because of different endian.
+                            PPPPROTO.protocol = 0;
+                            PPPPROTO.protocol = (PPPoE_IPCP & 0xFF) << 8;
+                            PPPPROTO.protocol |= ((PPPoE_IPCP >> 8) & 0xFF);
+
+                            if(ppp_code == PPP_CONFIG_REQ)
+                            {
+                                PPPPROTO.pcode = 0x02; // if configuration request MSG received, send ack
+#ifdef __DEF_PPP_DBG1__
+                                printf("IPCP configuration ack send!\r\n");
+#endif
+                            }
+                            else
+                            {
+                                PPPPROTO.pcode = 0x01; // if nak received, send cr
+#ifdef __DEF_PPP_DBG1__
+                                printf("IPCP Configuration Request send!\r\n");
+#endif
+                            }
+                    
+                            memcpy(&PPPPROTO.opt[0], &acknak_opt[0], acknak_idx);
+                                        
+                            PPPPROTO.id = get_protocol_id;
+                            //change MSB and LSB because of different endian.
+                            PPPPROTO.len = 0;
+                            PPPPROTO.len = ((acknak_idx+4) & 0xFF) << 8;
+                            PPPPROTO.len |= (((acknak_idx+4) >> 8) & 0xFF);
+                            //change MSB and LSB because of different endian.
+                            PPPMSG_req.len = 0;
+                            PPPMSG_req.len = ((acknak_idx+6) & 0xFF) << 8;
+                            PPPMSG_req.len |= (((acknak_idx+6) >> 8) & 0xFF);
+
+                            ppp_send();
+                            if(ppp_code == 0x01) pppoe_control_flag = pppoe_control_flag | FLAG_IPCP_CR_RCV;
+                            else pppoe_control_flag = pppoe_control_flag | FLAG_IPCP_NAK_RCV;
+                        }
+                        break;
+
+
+                    case PPP_CONFIG_REJ : // Reject receive.
+#ifdef __DEF_PPP_DBG1__
+                        printf("IPCP reject message received!!\r\n");
+#endif
+    
+                        get_protocol_id = buf[23];
+                        getlen = buf[24];
+                        getlen = (getlen<<8) + buf[25];
+                    
+                        getlen -= 4;
+                        t_idx = 26;
+
+                        ip_rjt = 0;
+                        pdns_rjt =0;
+                        sdns_rjt = 0;
+
+                        while (getlen)
+                        {
+                            opt_code = buf[t_idx];
+                            opt_len = buf[t_idx+1];
+
+                            switch (opt_code)
+                            {
+                                //case 0x02 : // type : ip compression protocol
+                                case 0x03 : // ip address
+                                    ip_rjt = 1;
+                                    break;
+                                case 0x81 : // PDNS
+                                    pdns_rjt = 1;
+                                    break;
+                                case 0x83 : // SDNS
+                                    sdns_rjt = 1;
+                                    break;
+                                default :
+                                    break;
+                            }
+                            t_idx += opt_len;
+                            getlen -= opt_len;
+                        }
+
+                        // Configuration send without reject protocol.
+
+                        //change MSB and LSB because of different endian.
+                        PPPPROTO.protocol = 0;
+                        PPPPROTO.protocol = (PPPoE_IPCP & 0xFF) << 8;
+                        PPPPROTO.protocol |= ((PPPoE_IPCP >> 8) & 0xFF);
+
+                        PPPPROTO.pcode = PPP_CONFIG_REQ ;
+                        t_idx = 0;
+                        if( ip_rjt == 0 )
+                        {
+                            PPPPROTO.opt[t_idx++] = 0x03;   // option code, IP address
+                            PPPPROTO.opt[t_idx++] = 0x06;   // option len
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                        }
+
+                        if( pdns_rjt == 0 )
+                        {
+                            PPPPROTO.opt[t_idx++] = 0x81;   // option code, PDNS address
+                            PPPPROTO.opt[t_idx++] = 0x06;   // option len
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                        }
+
+                        if( sdns_rjt == 0 )
+                        {
+                            PPPPROTO.opt[t_idx++] = 0x83;   // option code, SDNS address
+                            PPPPROTO.opt[t_idx++] = 0x06;   // option len
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                            PPPPROTO.opt[t_idx++] = 0x00;
+                        }
+                
+                        PPPPROTO.id = get_protocol_id;
+                        //change MSB and LSB because of different endian.
+                        PPPPROTO.len = 0;
+                        PPPPROTO.len = ((t_idx+4) & 0xFF) << 8;
+                        PPPPROTO.len |= (((t_idx+4) >> 8) & 0xFF);
+                        //change MSB and LSB because of different endian.
+                        PPPMSG_req.len = 0;
+                        PPPMSG_req.len = ((t_idx+6) & 0xFF) << 8;
+                        PPPMSG_req.len |= (((t_idx+6) >> 8) & 0xFF);
+
+                        if( ip_rjt && pdns_rjt && sdns_rjt)
+                        {
+#ifdef __DEF_PPP_DBG1__
+                            printf("IPCP session : All IPCP options are rejected!!\r\n");
+#endif
+                            do_lcp_terminate();
+                        }
+                        else
+                        {
+#ifdef __DEF_PPP_DBG1__
+                            printf("IPCP configuration request send without reject protocol\r\n");
+#endif
+                            ppp_send();
+                        }
+
+                        
+                        break;
+                    case PPP_CONFIG_ACK : // ack, then ipcp_cr_snt flag set
+#ifdef __DEF_PPP_DBG1__
+                        printf("PPPoE Session IPCP: Configure-Ack received\r\n");
+#endif
+                        if((pppoe_control_flag & FLAG_IPCP_NAK_RCV) == FLAG_IPCP_NAK_RCV) pppoe_control_flag = pppoe_control_flag | FLAG_IPCP_CR_SNT;
+                        break;
+                    }
+                }
+                break;
+            default:
+                break;
+        }       
+    }   
+}  
+
+
+
+void PPPOEClient::do_discovery(void)
+{
+    uint16_t i = 0;
+    uint8_t mac[6] = {0,};
+    //getSHAR(mac);
+    eth->getSHAR(mac);
+
+    // PPPoE Frame  
+    for(i = 0; i < 6; i++)
+    {
+        PPPMSG_req.dst_mac[i] = 0xFF;           // Broadcast MAC address
+        PPPMSG_req.src_mac[i] = mac[i];     // Source MAC address
+        //-- Opt. Device MAC Address
+        PPPPROTO.opt[10+i] = mac[i];
+    }
+    //Reset control flag.
+    pppoe_control_flag = 0;
+
+    //change MSB and LSB because of different endian.
+    PPPMSG_req.ether_type = 0;
+    PPPMSG_req.ether_type = (PPPoE_DISCOVERY & 0xFF) << 8;//session data
+    PPPMSG_req.ether_type |= ((PPPoE_DISCOVERY >> 8) & 0xFF);//session data
+
+    PPPMSG_req.version_type = PPPoE_VER_TYPE; // Ver : 0001, Type : 0001     
+    PPPMSG_req.frame_code = PPPoE_PADI; // PADI
+
+    PPPMSG_req.session_id = 0;
+
+
+    // Tag name : PPPoED_SERVICE_NAME
+    PPPPROTO.opt[0] = 0x01;
+    PPPPROTO.opt[1] = 0x01;
+    // Tag len 
+    PPPPROTO.opt[2] = 0x00;
+    PPPPROTO.opt[3] = 0x00;
+
+    // Tag name : PPPoED_HOST_UNIQ
+    PPPPROTO.opt[4] = 0x01;
+    PPPPROTO.opt[5] = 0x03;
+    // Tag len (2bytes)
+    PPPPROTO.opt[6] = 0x00;
+    PPPPROTO.opt[7] = 0x08;
+    // Fill the Host-Uniq field using MAC address
+    PPPPROTO.opt[8] = 0x00;
+    PPPPROTO.opt[9] = 0x00;
+    //PPPPROTO.opt[10~15] refer to "//-- Opt. Device MAC Address"
+
+    //change MSB and LSB because of different endian.
+    PPPMSG_req.len = 0;
+    PPPMSG_req.len = (16 & 0xFF) << 8;
+    PPPMSG_req.len |= ((16 >> 8) & 0xFF);//size of opt[0-9]+ opt[10-15]
+
+#ifdef __DEF_PPP_DBG1__
+    printf("PPPoE Discovery : PADI send\r\n");
+#endif
+    ppp_send();
+
+}
+
+void PPPOEClient::do_lcp(void)
+{
+
+    //change MSB and LSB because of different endian.
+    PPPMSG_req.ether_type = 0;
+    PPPMSG_req.ether_type = (PPPoE_SESSION & 0xFF) << 8;
+    PPPMSG_req.ether_type |= ((PPPoE_SESSION >> 8) & 0xFF);//session data
+
+    PPPMSG_req.frame_code = 0x00; //session data
+    //change MSB and LSB because of different endian.
+    PPPMSG_req.session_id = 0;
+    PPPMSG_req.session_id = (NAS_sessionid & 0xFF) << 8;
+    PPPMSG_req.session_id |= ((NAS_sessionid >> 8) & 0xFF);//session data
+
+    //change MSB and LSB because of different endian.
+    PPPPROTO.protocol = 0;
+    PPPPROTO.protocol = (PPPoE_LCP & 0xFF) << 8;
+    PPPPROTO.protocol |= ((PPPoE_LCP >> 8) & 0xFF);
+
+                                                       
+    PPPPROTO.pcode = PPP_CONFIG_REQ; // CR
+                                                           
+    PPPPROTO.opt[0] = 0x05;
+    PPPPROTO.opt[1] = 0x06;
+    PPPPROTO.opt[2] = 0x00;
+    PPPPROTO.opt[3] = 0x01;
+    PPPPROTO.opt[4] = 0x02;
+    PPPPROTO.opt[5] = 0x03;
+                                                       
+    PPPPROTO.id = protocol_id++;
+    //change MSB and LSB because of different endian.
+    PPPPROTO.len = 0;
+    PPPPROTO.len = (10 & 0xFF) << 8;
+    PPPPROTO.len |= ((10 >> 8) & 0xFF);
+
+    //change MSB and LSB because of different endian.
+    PPPMSG_req.len = 0;
+    PPPMSG_req.len = (12 & 0xFF) << 8;
+    PPPMSG_req.len |= ((12 >> 8) & 0xFF);
+
+#ifdef __DEF_PPP_DBG1__
+    printf("LCP configuration Request send\r\n");
+#endif
+    ppp_send();
+    
+}                             
+
+void PPPOEClient::do_lcp_echo(void)
+{
+
+    //change MSB and LSB because of different endian.
+    PPPMSG_req.ether_type = 0;
+    PPPMSG_req.ether_type = (PPPoE_SESSION & 0xFF) << 8;
+    PPPMSG_req.ether_type |= ((PPPoE_SESSION >> 8) & 0xFF);// session
+
+    PPPMSG_req.frame_code = 0x00;           // session data    
+    //change MSB and LSB because of different endian.
+    PPPMSG_req.session_id = 0;
+    PPPMSG_req.session_id = (NAS_sessionid & 0xFF) << 8;
+    PPPMSG_req.session_id |= ((NAS_sessionid >> 8) & 0xFF);// session id
+
+    //change MSB and LSB because of different endian.
+    PPPPROTO.protocol = 0;
+    PPPPROTO.protocol = (PPPoE_LCP & 0xFF) << 8;
+    PPPPROTO.protocol |= ((PPPoE_LCP >> 8) & 0xFF);
+
+    PPPPROTO.pcode = PPP_ECHO_REQ;  // Echo-Requset
+                                                       
+    PPPPROTO.opt[0] = 0x00; // Magic number
+    PPPPROTO.opt[1] = 0x01;
+    PPPPROTO.opt[2] = 0x02;
+    PPPPROTO.opt[3] = 0x03;
+                                                       
+    PPPPROTO.id = protocol_id++;
+    //change MSB and LSB because of different endian.
+    PPPPROTO.len = 0;
+    PPPPROTO.len = (8 & 0xFF) << 8;
+    PPPPROTO.len |= ((8 >> 8) & 0xFF);
+    //change MSB and LSB because of different endian.
+    PPPMSG_req.len = 0;
+    PPPMSG_req.len = (10 & 0xFF) << 8;
+    PPPMSG_req.len |= ((10 >> 8) & 0xFF);
+#ifdef __DEF_PPP_DBG1__
+    printf("LCP echo request send\r\n");
+#endif
+    ppp_send();
+    
+}
+
+//return --    1 : success, 0 : failed
+uint8_t PPPOEClient::do_lcp_terminate(void)
+{
+    uint16_t received_len = 0;
+    uint8_t sock_num = 0;
+
+
+    pppoe_retry_count = 0;
+
+    //while( (pppoe_control_flag & FLAG_TERMINATION_ACK_RCV) == 0 )
+    while(1)
+    {
+        //change MSB and LSB because of different endian.
+        PPPMSG_req.ether_type = 0;
+        PPPMSG_req.ether_type = (PPPoE_SESSION & 0xFF) << 8;
+        PPPMSG_req.ether_type |= ((PPPoE_SESSION >> 8) & 0xFF);// session
+
+        PPPMSG_req.frame_code = 0x00;           // session data 
+        //change MSB and LSB because of different endian.
+        PPPMSG_req.session_id = 0;
+        PPPMSG_req.session_id = (NAS_sessionid & 0xFF) << 8;
+        PPPMSG_req.session_id |= ((NAS_sessionid >> 8) & 0xFF);
+
+        //change MSB and LSB because of different endian.
+        PPPPROTO.protocol = 0;
+        PPPPROTO.protocol = (PPPoE_LCP & 0xFF) << 8;
+        PPPPROTO.protocol |= ((PPPoE_LCP >> 8) & 0xFF);
+
+        PPPPROTO.pcode = PPP_TERM_REQ;  // Terminate-Requset
+
+        PPPPROTO.opt[0] = 0x00; // Magic number
+        PPPPROTO.opt[1] = 0x01;
+        PPPPROTO.opt[2] = 0x02;
+        PPPPROTO.opt[3] = 0x03;
+                                             
+        PPPPROTO.id = protocol_id++;
+        //change MSB and LSB because of different endian.
+        PPPPROTO.len = 0;
+        PPPPROTO.len = (8 & 0xFF) << 8;
+        PPPPROTO.len |= ((8 >> 8) & 0xFF);
+
+        //change MSB and LSB because of different endian.
+        PPPMSG_req.len = 0;
+        PPPMSG_req.len = (10 & 0xFF) << 8;
+        PPPMSG_req.len |= ((10 >> 8) & 0xFF);
+
+
+#ifdef __DEF_PPP_DBG1__
+        printf("Termination Request send\r\n");
+#endif
+        ppp_send();
+        pppoe_retry_count++;
+
+
+        if(pppoe_retry_count > PPP_MAX_RETRY_COUNT)
+        {
+            printf("Termination Failed\r\n");
+            return 0;//termination fail
+        }
+
+
+        pppoe_recv_count = 0;
+        while((pppoe_control_flag & FLAG_TERMINATION_ACK_RCV) == 0 && pppoe_recv_count < PPP_MAX_RETRYRECV_COUNT)
+        {
+            wait(0.4);
+            pppoe_recv_count ++;
+
+            
+            received_len = eth->getSn_RX_RSR(sock_num);
+
+            if(received_len > 0)
+            {
+                ppp_recv(received_len);
+                if((pppoe_control_flag & FLAG_TERMINATION_ACK_RCV) == FLAG_TERMINATION_ACK_RCV) // Termination success
+                {
+                    pppoe_state = PPPoE_FAILED;
+
+                    // Flags reset
+                    pppoe_control_flag = 0;
+                    // Clear Session ID for new PPPoE Discovery process
+                    NAS_sessionid = 0;
+
+                    NAS_mac[0] = 0;
+                    NAS_mac[1] = 0;
+                    NAS_mac[2] = 0;
+                    NAS_mac[3] = 0;
+                    NAS_mac[4] = 0;
+                    NAS_mac[5] = 0;
+
+                    pppoe_ip[0] = 0;
+                    pppoe_ip[1] = 0;
+                    pppoe_ip[2] = 0;
+                    pppoe_ip[3] = 0;
+
+                    printf("Termination completed\r\n");
+                    return 1;//termination success
+                }
+            }
+        }
+
+    }
+
+}
+
+
+void PPPOEClient::do_pap(void)
+{
+
+    uint16_t   i=0, j=0;
+
+    //change MSB and LSB because of different endian.
+    PPPPROTO.protocol = 0;
+    PPPPROTO.protocol = (PPPoE_PAP & 0xFF) << 8;
+    PPPPROTO.protocol |= ((PPPoE_PAP >> 8) & 0xFF);
+
+    PPPPROTO.pcode = PPP_CONFIG_REQ;        // cr
+    PPPPROTO.opt[i++] = pppoe_id_len;
+
+    for(j = 0; j < pppoe_id_len; j++)
+    {
+        PPPPROTO.opt[i++] = pppoe_id[j];
+    } 
+    
+    PPPPROTO.opt[i++] = pppoe_pw_len;
+    for(j = 0; j < pppoe_pw_len; j++)
+    {
+        PPPPROTO.opt[i++] = pppoe_pw[j];
+    }
+
+    PPPPROTO.id = protocol_id++;
+    //change MSB and LSB because of different endian.
+    PPPPROTO.len = 0;
+    PPPPROTO.len = ((i+4) & 0xFF) << 8;
+    PPPPROTO.len |= (((i+4) >> 8) & 0xFF);
+    //change MSB and LSB because of different endian.
+    PPPMSG_req.len = 0;
+    PPPMSG_req.len = (((i+4)+2) & 0xFF) << 8;
+    PPPMSG_req.len |= ((((i+4)+2) >> 8) & 0xFF);
+
+#ifdef __DEF_PPP_DBG1__
+    printf("PAP authenticate-Request send\r\n");
+#endif
+
+    ppp_send();
+    
+}                 
+
+void PPPOEClient::do_ipcp(void)
+{
+        
+    //change MSB and LSB because of different endian.
+    PPPPROTO.protocol = 0;
+    PPPPROTO.protocol = (PPPoE_IPCP & 0xFF) << 8;
+    PPPPROTO.protocol |= ((PPPoE_IPCP >> 8) & 0xFF);
+
+    PPPPROTO.pcode = PPP_CONFIG_REQ;    // configuration-req
+
+    PPPPROTO.opt[0] = 0x03;     // option code, IP address
+    PPPPROTO.opt[1] = 0x06;     // option len
+    PPPPROTO.opt[2] = 0x00;
+    PPPPROTO.opt[3] = 0x00;
+    PPPPROTO.opt[4] = 0x00;
+    PPPPROTO.opt[5] = 0x00;
+    //Option PDNS
+    PPPPROTO.opt[6] = 0x81; //op code, PDNS
+    PPPPROTO.opt[7] = 0x06; //option len
+    PPPPROTO.opt[8] = 0x00;
+    PPPPROTO.opt[9] = 0x00;
+    PPPPROTO.opt[10] = 0x00;
+    PPPPROTO.opt[11] = 0x00;
+    //Option SDNS
+    PPPPROTO.opt[12] = 0x83;    //op code, SDNS
+    PPPPROTO.opt[13] = 0x06; //option len
+    PPPPROTO.opt[14] = 0x00;
+    PPPPROTO.opt[15] = 0x00;
+    PPPPROTO.opt[16] = 0x00;
+    PPPPROTO.opt[17] = 0x00;
+
+
+    PPPPROTO.id = protocol_id++;
+
+    //change MSB and LSB because of different endian.
+    /*
+    PPPPROTO.len = 0;
+    PPPPROTO.len = (10 & 0xFF) << 8;
+    PPPPROTO.len |= ((10 >> 8) & 0xFF);
+
+    //change MSB and LSB because of different endian.
+    PPPMSG_req.len = 0;
+    PPPMSG_req.len = (12 & 0xFF) << 8;
+    PPPMSG_req.len |= ((12 >> 8) & 0xFF);
+    */
+    PPPPROTO.len = 0;
+    PPPPROTO.len = (22 & 0xFF) << 8;
+    PPPPROTO.len |= ((22 >> 8) & 0xFF);
+
+    //change MSB and LSB because of different endian.
+    PPPMSG_req.len = 0;
+    PPPMSG_req.len = (24 & 0xFF) << 8;
+    PPPMSG_req.len |= ((24 >> 8) & 0xFF);
+#ifdef __DEF_PPP_DBG1__
+    printf("IPCP Configuration request send\r\n");
+#endif
+
+    ppp_send();
+    
+}
+
+
+
+// PPPoE start
+//ret = Success : 1, Fail : 0, continue : 2
+uint8_t PPPOEClient::ppp_start(uint8_t * pppoe_buf)
+{   
+    uint8_t sock_num;
+    uint8_t mFlag;
+    uint16_t dummyPort;
+    uint8_t ret = 2;
+    uint16_t received_len = 0;
+    
+    buf = pppoe_buf;
+    //-- Init. param
+    sock_num = 0;
+    dummyPort = 0;
+    mFlag = 0x80; //MAC filter enable in MACRAW
+    
+    
+    switch(eth->getSn_SR(sock_num))
+    {
+        case SOCK_CLOSED:
+            eth->close(sock_num);                                        // Close the SOCKET
+            Socket_macraw(sock_num, dummyPort, mFlag);       // Open the SOCKET with MACRAW mode
+#ifdef __DEF_PPP_DBG1__
+            printf("No.%d socket is opened with MACRAW and flag is 0x%2x\r\n", sock_num, mFlag);
+#endif
+#ifdef __DEF_PPP_DBG__
+            printf("\r\n=======================================\r\n");
+            printf("PHASE 0. PPPoE setup\r\n");
+            printf("=======================================\r\n");
+#endif  
+        break;
+            
+        case SOCK_MACRAW:       
+
+            if(pppoe_retry_send_count > PPP_MAX_RETRYSEND_COUNT) pppoe_state = PPPoE_FAILED;
+
+            switch(pppoe_state)
+            {
+                case PPPoE_DISCOVERY :                                          // Discovery                    
+                    // PPPoE Discoveryecv(
+                    //if((pppoe_control_flag & FLAG_DISCOVERY_RCV_PADO) == 0)
+                    if((pppoe_control_flag & FLAG_DISCOVERY_RCV_PADO) == 0 || (pppoe_control_flag & FLAG_DISCOVERY_RCV_PADS) == 0) //Not recv PADO or PADS
+                    {
+#ifdef __DEF_PPP_DBG__
+                        printf("\r\n=======================================\r\n");
+                        printf("PHASE 1. PPPoE Discovery\r\n");
+                        printf("=======================================\r\n");
+#endif  
+#ifdef __DEF_PPP_DBG1__
+                        printf("Retry send count : %d\r\n", pppoe_retry_send_count);
+#endif
+                        do_discovery(); // Send PADI
+                        pppoe_retry_send_count++;
+                    }               
+
+                    pppoe_recv_count = 0;
+                    while((pppoe_control_flag & FLAG_DISCOVERY_RCV_PADS) == 0 && pppoe_recv_count < (PPP_MAX_RETRYRECV_COUNT) * 2)
+                    {
+                        wait(0.2);
+                        pppoe_recv_count ++;
+                        
+                        received_len = eth->getSn_RX_RSR(sock_num);
+
+                        if(received_len > 0)
+                        {
+                            ppp_recv(received_len);
+
+
+                            if((pppoe_control_flag & FLAG_DISCOVERY_RCV_PADS) == FLAG_DISCOVERY_RCV_PADS)// Discovery success
+                            {
+                                pppoe_state = PPPoE_LCP;
+                                pppoe_retry_send_count = 0;//reset
+                            }
+                        }
+                    }
+
+                    break;
+
+                case PPPoE_LCP :                                                // LCP                  
+                    if((pppoe_control_flag & FLAG_LCP_CR_RCV) == 0)
+                    {                           
+#ifdef __DEF_PPP_DBG__
+                        printf("\r\n=======================================\r\n");
+                        printf("PHASE 2. PPPoE LCP\r\n");
+                        printf("=======================================\r\n");
+#endif                                  
+                        do_lcp_echo();
+
+#ifdef __DEF_PPP_DBG1__
+                        printf("Retry send count : %d\r\n", pppoe_retry_send_count);
+#endif
+                        pppoe_retry_send_count++;
+                    }
+
+                    pppoe_recv_count = 0;
+                    while((pppoe_control_flag & FLAG_LCP_CR_RCV) == 0 && pppoe_recv_count < PPP_MAX_RETRYRECV_COUNT)
+                    {
+                        wait(0.2);
+                        pppoe_recv_count++;
+
+                        received_len = eth->getSn_RX_RSR(sock_num);
+                        if(received_len > 0)
+                        {
+                            ppp_recv(received_len);
+                            if((pppoe_control_flag & FLAG_LCP_CR_RCV) == FLAG_LCP_CR_RCV) pppoe_retry_send_count = 0;//reset
+                        }
+                    }
+
+
+                    if((pppoe_control_flag & FLAG_LCP_CR_RCV) == FLAG_LCP_CR_RCV)
+                    {
+                        do_lcp();
+
+#ifdef __DEF_PPP_DBG1__
+                        printf("Retry send count : %d\r\n", pppoe_retry_send_count);
+#endif
+                        pppoe_retry_send_count++;
+
+                        pppoe_recv_count = 0;
+                        while((pppoe_control_flag & FLAG_LCP_CR_SNT) == 0 && pppoe_recv_count < PPP_MAX_RETRYRECV_COUNT)
+                        {
+                            wait(0.2);
+                            pppoe_recv_count++;
+
+                            received_len = eth->getSn_RX_RSR(sock_num);
+                            if(received_len > 0)                                                    
+                            {
+                                ppp_recv(received_len);
+                                if((pppoe_control_flag & FLAG_LCP_CR_SNT) == FLAG_LCP_CR_SNT)
+                                {                                                                                                                                                                               
+                                    // PAP
+                                    if(auth_protocol == PPPoE_PAP)
+                                    {
+                                        pppoe_state = PPPoE_PAP;
+                                        pppoe_retry_send_count = 0;//reset
+                                    }
+                                    // CHAP                             
+                                    else if(auth_protocol == PPPoE_CHAP)
+                                    {
+                                        pppoe_state = PPPoE_CHAP;
+                                        pppoe_retry_send_count = 0;//reset
+                                    }
+                                    // unknown auth protocol
+                                    else
+                                    {
+#ifdef __DEF_PPP_DBG1__
+                                        printf("\r\nError : Unknown authentication protocol");
+#endif
+                                        pppoe_state = PPPoE_FAILED;
+                                    }
+
+                                }
+                            }
+                        }                       
+                    }                   
+                    break;
+
+                case PPPoE_PAP :                                                // PAP
+#ifdef __DEF_PPP_DBG__
+                    printf("\r\n=======================================\r\n");
+                    printf("PHASE 3. PPPoE PAP\r\n");
+                    printf("=======================================\r\n");
+#endif                          
+
+
+                    if((pppoe_control_flag & FLAG_PAP_ACK_RCV) == 0 )
+                    {
+                        do_pap();                           
+                        pppoe_retry_send_count++;
+#ifdef __DEF_PPP_DBG1__
+                        printf("Retry send count : %d\r\n", pppoe_retry_send_count );
+#endif
+                    }
+
+                    pppoe_recv_count = 0;
+                    while((pppoe_control_flag & FLAG_PAP_ACK_RCV) == 0 && pppoe_recv_count < PPP_MAX_RETRYRECV_COUNT)
+                    {
+                        wait(0.4);
+                        pppoe_recv_count++;
+
+                        received_len = eth->getSn_RX_RSR(sock_num);
+                        if(received_len > 0)                        
+                        {
+                            ppp_recv(received_len);
+
+                            if((pppoe_control_flag & FLAG_PAP_ACK_RCV) == FLAG_PAP_ACK_RCV)// pap auth success
+                            {
+                                pppoe_state = PPPoE_IPCP;
+                                pppoe_retry_send_count = 0;//reset
+                            }
+                        }
+                    }                                       
+                    break;
+
+                case PPPoE_CHAP :                                               // CHAP
+#ifdef __DEF_PPP_DBG__
+                    printf("\r\n=======================================\r\n");
+                    printf("PHASE 3. PPPoE CHAP\r\n");
+                    printf("=======================================\r\n");
+#endif                  
+
+
+                    pppoe_recv_count = 0;
+                    while((pppoe_control_flag & FLAG_CHAP_SUC_RCV) == 0 && pppoe_recv_count < 50)
+                    {
+                        wait(0.4);
+                        pppoe_recv_count++;
+                        
+                        printf("test\r\n");
+
+                        received_len = eth->getSn_RX_RSR(sock_num);
+                        if(received_len > 0)                                                    
+                        {
+                            ppp_recv(received_len);
+                            
+                            if((pppoe_control_flag & FLAG_CHAP_SUC_RCV) == FLAG_CHAP_SUC_RCV)
+                            {
+                                pppoe_state = PPPoE_IPCP;
+                            }
+
+                            if((pppoe_control_flag & FLAG_TERMINATION_REQ_RCV) == FLAG_TERMINATION_REQ_RCV)
+                            {
+                                pppoe_state = PPPoE_FAILED;
+
+                                break;
+                            }
+                        }
+                    }
+
+                    if( pppoe_recv_count >= 50)
+                    {
+                        if(do_lcp_terminate() == 0) //if termination is failed.
+                            return 0;
+                    }
+
+                    break;
+
+                case PPPoE_IPCP :                                               // IPCP                 
+#ifdef __DEF_PPP_DBG__
+                    printf("\r\n=======================================\r\n");
+                    printf("PHASE 4. PPPoE IPCP\r\n");
+                    printf("=======================================\r\n");
+#endif                 
+
+                    pppoe_recv_count = 0;
+                    while((pppoe_control_flag & FLAG_IPCP_CR_RCV) == 0 && pppoe_recv_count < PPP_MAX_RETRYRECV_COUNT)
+                    {
+                        wait(1);
+                        pppoe_recv_count++;
+
+                        received_len = eth->getSn_RX_RSR(sock_num);
+                        if(received_len > 0)                        
+                        {               
+                            ppp_recv(received_len);
+                            
+                            if((pppoe_control_flag & FLAG_IPCP_CR_RCV) == FLAG_IPCP_CR_RCV) pppoe_retry_send_count = 0;//reset
+
+                        }  
+
+                    }         
+                    // After received IPCP Configuration-Request and sent ACK,
+                    // User device have to send IPCP Configuration-Request and receive ACK.  
+                    if((pppoe_control_flag & FLAG_IPCP_CR_RCV) == FLAG_IPCP_CR_RCV)
+                    {
+                        do_ipcp();
+                        pppoe_retry_send_count++;
+
+                        pppoe_recv_count = 0;
+                        while((pppoe_control_flag & FLAG_IPCP_CR_SNT) == 0 && pppoe_recv_count < PPP_MAX_RETRYRECV_COUNT)
+                        {
+                            wait(1);
+                            pppoe_recv_count++;
+
+                            received_len = eth->getSn_RX_RSR(sock_num);
+                            if(received_len > 0)
+                            {
+                                ppp_recv(received_len);
+
+                                if((pppoe_control_flag & FLAG_IPCP_CR_SNT) == FLAG_IPCP_CR_SNT)
+                                {           
+                                    pppoe_retry_send_count = 0;//reset
+#ifdef __DEF_PPP_DBG__
+                                    printf("\r\n=======================================\r\n");
+                                    printf("PHASE 5. PPPoE Socket open\r\n");
+                                    printf("=======================================\r\n");
+#endif
+                                    set_pppinfo(NAS_mac, pppoe_ip, NAS_sessionid);                              
+                                    ret = PPP_SUCCESS;                                  
+                                }
+                                else if( (pppoe_control_flag & FLAG_TERMINATION_ACK_RCV) == FLAG_TERMINATION_ACK_RCV)
+                                {
+                                    return 0;
+                                }
+                                else if( (pppoe_control_flag & FLAG_TERMINATION_REQ_RCV) == FLAG_TERMINATION_REQ_RCV)
+                                {
+                                    return 0;
+                                }
+                            }                                                                                           
+                        }
+                    }                   
+                    break;
+
+                case PPPoE_FAILED :
+                    pppoe_retry_count++;
+#ifdef __DEF_PPP_DBG__
+                    printf("\r\nPPPoE FAILED !!!\r\n");
+#endif
+#ifdef __DEF_PPP_DBG1__
+                    printf("Retry count : %d\r\n", pppoe_retry_count);
+#endif
+                    // All flags reset
+                    pppoe_control_flag = 0;
+
+                    // Clear Session ID for new PPPoE Discovery process
+                    //NAS_sessionid = 0;
+
+                    pppoe_retry_send_count = 0;
+                    pppoe_state = PPPoE_DISCOVERY;
+
+                    break;
+
+
+                default :
+#ifdef __DEF_PPP_DBG__
+                    printf("\r\nUndefined state!\r\n");
+#endif
+                    pppoe_state = PPPoE_FAILED;
+                    break;
+            }
+
+            // PPPoE packet send count over : connection terminate 
+            if(pppoe_retry_send_count >= PPP_MAX_RETRYSEND_COUNT) pppoe_state = PPPoE_FAILED;
+            break;
+            
+        default:
+            break;
+    }   
+    return ret;
+}
+/*
+void PPPOEClient::delay_ms(uint32_t time)
+{
+    uint32_t i;
+
+    for(i=0; i<time; i++)
+    {
+        xSysCtlDelay((xSysCtlClockGet()/1000)); // wait 1ms
+    }
+}
+*/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pppoe/PPPoE.h	Wed Oct 15 06:27:12 2014 +0000
@@ -0,0 +1,167 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include "W5500.h"
+#include "Socket.h"
+#include "md5.h"
+
+
+
+
+
+
+#define __DEF_PPP_DBG__ // debug message for [Phase] and [Network Init]
+#define __DEF_PPP_DBG1__ // debug message for checking 'Txbuf overflow' and etc.
+//#define __DEF_PPP_DBG2__ // debug received and send packet.
+
+
+
+//PPPoE retry count value
+//#define     PPP_MAX_RETRYRECV_COUNT     50
+#define     PPP_MAX_RETRYSEND_COUNT     5
+#define     PPP_MAX_RETRYRECV_COUNT     32
+#define     PPP_MAX_RETRY_COUNT         5
+// PPPoE EtherType definition
+#define     PPPoE_DISCOVERY     0x8863
+#define     PPPoE_SESSION       0x8864
+
+// PPPoE Frame field definition
+#define     PPPoE_VER_TYPE      0x11      
+
+// PPPoE Code definition
+#define     PPPoE_PADI          0x09            
+#define     PPPoE_PADO          0x07
+#define     PPPoE_PADR          0x19
+#define     PPPoE_PADS          0x65
+#define     PPPoE_PADT          0xa7
+#define     PPPoE_SESSIONDATA   0x00
+
+// PPPoE Discovery Tag type definition
+#define     PPPoED_END_OF_LIST          0x0000
+#define     PPPoED_SERVICE_NAME         0x0101
+#define     PPPoED_AC_NAME              0x0102
+#define     PPPoED_HOST_UNIQ            0x0103
+#define     PPPoED_AC_COOKIE            0x0104
+#define     PPPoED_VENDER_SPECIFIC      0x0105  
+
+// PPPoE Protocol definition
+#define     PPPoE_LCP           0xC021
+#define     PPPoE_PAP           0xC023
+#define     PPPoE_CHAP          0xC223
+#define     PPPoE_IPCP          0x8021
+
+// PPPoE Protocol Code definition
+    // LCP using 0x01 ~ 0x0b
+    // PAP using 0x01 ~ 0x03
+    // IPCP using 0x01 ~ 0x07
+#define     PPP_CONFIG_REQ      0x01        
+#define     PPP_CONFIG_ACK      0x02
+#define     PPP_CONFIG_NAK      0x03
+#define     PPP_CONFIG_REJ      0x04
+#define     PPP_TERM_REQ        0x05
+#define     PPP_TERM_ACK        0x06
+#define     PPP_CODE_REJ        0x07
+#define     PPP_PROT_REJ        0x08
+#define     PPP_ECHO_REQ        0x09
+#define     PPP_ECHO_REP        0x0a
+#define     PPP_DIS_REQ         0x0b
+
+// PPPoE LCP Type definition
+#define     LCP_MRU             0x01
+#define     LCP_AUTH            0x03
+#define     LCP_MAGICNUM        0x05
+#define     LCP_PROTOCOMP       0x07
+#define     LCP_ADDRCOMP        0x08        
+
+// PPPoE CHAP Algorithm
+#define     MD5                 0x05 
+#define     MS_CHAP             0x80
+#define     MS_CHAP_V2          0x81
+
+// PPPoE stage control flags
+#define   FLAG_DISCOVERY_RCV_PADO   0x0001
+#define   FLAG_DISCOVERY_RCV_PADS   0x0002
+#define   FLAG_LCP_CR_RCV           0x0004
+#define   FLAG_LCP_CR_SNT           0x0008
+#define   FLAG_PAP_ACK_RCV          0x0010
+#define   FLAG_CHAP_SUC_RCV         0x0020
+#define   FLAG_IPCP_CR_SNT          0x0040
+#define   FLAG_IPCP_CR_RCV          0x0080
+#define   FLAG_IPCP_NAK_RCV         0x0100
+#define   FLAG_TERMINATION_ACK_RCV  0x0200
+#define   FLAG_TERMINATION_REQ_RCV  0x0400
+#define   FLAG_PADO_SERVICENAME     0x0800
+
+/*
+// PPPoE Field value definition 
+// -> not used.     
+#define     PPPoE_SESSION_ID    0x0000
+#define     LCP_MAGICNUM_VAL    0x00112299
+*/
+
+// Logical variable definition
+#define     PPP_SUCCESS         1
+//#define       PPP_FAIL            0
+#define     PPP_RETRY           2
+
+#define     OPTMSG_LEN          80
+#define     CV_HV_LEN           16
+
+
+#define     PPPoE_FAILED        0
+
+
+#define PPP_FRAME_SIZE      128
+#define PPP_RXFRAME_SIZE    1514
+
+
+
+class PPPOEClient 
+{
+public:
+    PPPOEClient();
+    void set_pppinfo(uint8_t * nas_mac, uint8_t * ppp_ip, uint16_t nas_sessionid);
+    void ppp_send(void);
+    void ppp_recv( uint16_t received_len );
+    void do_discovery(void);
+    void do_lcp(void);
+    void do_lcp_echo(void);
+    uint8_t do_lcp_terminate(void);
+    void do_pap(void);
+    void do_ipcp(void);
+    uint8_t ppp_start(uint8_t * pppoe_buf);
+    //void delay_ms(uint32_t time);
+    
+
+
+private:
+    WIZnet_Chip* eth;
+    
+};
+
+// PPPoE message
+typedef struct _PPPMSG
+{
+    uint8_t dst_mac[6];
+    uint8_t src_mac[6];
+    uint16_t ether_type;            // 0x8863 : PPPoE Discovery, 0x8864 : PPPoE Session
+    uint8_t version_type;       // 4-bit 'version' = 0001, 4-bit 'type' = 0001 default
+    uint8_t frame_code;
+    uint16_t session_id;
+    uint16_t len;
+}PPPMSG;   
+
+// PPPoE Protocol
+typedef struct _PROTOCOL
+{
+    uint16_t protocol;
+    uint8_t pcode;
+    uint8_t id;
+    uint16_t len;
+    uint8_t opt[OPTMSG_LEN];
+}PROTOCOL;
+
+// PPPoE Start function
+uint8_t ppp_start(uint8_t * pppoe_buf);
+//PPPoE termination function
+uint8_t do_lcp_terminate(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pppoe/md5.cpp	Wed Oct 15 06:27:12 2014 +0000
@@ -0,0 +1,319 @@
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines                         **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+//#include "lwip/opt.h"
+
+//#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+//#if CHAP_SUPPORT || MD5_SUPPORT
+
+//#include "ppp.h"
+//#include "pppdebug.h"
+
+#include "md5.h"
+
+#include <string.h>
+
+/*
+ ***********************************************************************
+ **  Message-digest routines:                                         **
+ **  To form the message digest for a message M                       **
+ **    (1) Initialize a context buffer mdContext using MD5Init        **
+ **    (2) Call MD5Update on mdContext and M                          **
+ **    (3) Call MD5Final on mdContext                                 **
+ **  The message digest is now in mdContext->digest[0...15]           **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform (uint32_t *buf, uint32_t *in);
+
+static unsigned char PADDING[64] = {
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+  {(a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) \
+  {(a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) \
+  {(a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) \
+  {(a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+
+#ifdef __STDC__
+#define UL(x) x##UL
+#else
+#ifdef WIN32
+#define UL(x) x##UL
+#else
+#define UL(x) x
+#endif
+#endif
+
+/* The routine MD5Init initializes the message-digest context
+   mdContext. All fields are set to zero.
+ */
+void
+MD5Init (MD5_CTX *mdContext)
+{
+  mdContext->i[0] = mdContext->i[1] = (uint32_t)0;
+
+  /* Load magic initialization constants. */
+  mdContext->buf[0] = (uint32_t)0x67452301UL;
+  mdContext->buf[1] = (uint32_t)0xefcdab89UL;
+  mdContext->buf[2] = (uint32_t)0x98badcfeUL;
+  mdContext->buf[3] = (uint32_t)0x10325476UL;
+}
+
+/* The routine MD5Update updates the message-digest context to
+   account for the presence of each of the characters inBuf[0..inLen-1]
+   in the message whose digest is being computed.
+ */
+void
+MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen)
+{
+  uint32_t in[16];
+  int mdi;
+  unsigned int i, ii;
+
+#if 0
+  PPPDEBUG(LOG_INFO, ("MD5Update: %u:%.*H\n", inLen, LWIP_MIN(inLen, 20) * 2, inBuf));
+  PPPDEBUG(LOG_INFO, ("MD5Update: %u:%s\n", inLen, inBuf));
+#endif
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* update number of bits */
+  if ((mdContext->i[0] + ((uint32_t)inLen << 3)) < mdContext->i[0]) {
+    mdContext->i[1]++;
+  }
+  mdContext->i[0] += ((uint32_t)inLen << 3);
+  mdContext->i[1] += ((uint32_t)inLen >> 29);
+
+  while (inLen--) {
+    /* add new character to buffer, increment mdi */
+    mdContext->in[mdi++] = *inBuf++;
+
+    /* transform if necessary */
+    if (mdi == 0x40) {
+      for (i = 0, ii = 0; i < 16; i++, ii += 4) {
+        in[i] = (((uint32_t)mdContext->in[ii+3]) << 24) |
+                (((uint32_t)mdContext->in[ii+2]) << 16) |
+                (((uint32_t)mdContext->in[ii+1]) << 8)  |
+                ((uint32_t)mdContext->in[ii]);
+      }
+      Transform (mdContext->buf, in);
+      mdi = 0;
+    }
+  }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+   ends with the desired message digest in mdContext->digest[0...15].
+ */
+void
+MD5Final (unsigned char hash[], MD5_CTX *mdContext)
+{
+  uint32_t in[16];
+  int mdi;
+  unsigned int i, ii;
+  unsigned int padLen;
+
+  /* save number of bits */
+  in[14] = mdContext->i[0];
+  in[15] = mdContext->i[1];
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* pad out to 56 mod 64 */
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+  MD5Update (mdContext, PADDING, padLen);
+
+  /* append length in bits and transform */
+  for (i = 0, ii = 0; i < 14; i++, ii += 4) {
+    in[i] = (((uint32_t)mdContext->in[ii+3]) << 24) |
+            (((uint32_t)mdContext->in[ii+2]) << 16) |
+            (((uint32_t)mdContext->in[ii+1]) << 8)  |
+            ((uint32_t)mdContext->in[ii]);
+  }
+  Transform (mdContext->buf, in);
+
+  /* store buffer in digest */
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+    mdContext->digest[ii]   = (unsigned char)(mdContext->buf[i] & 0xFF);
+    mdContext->digest[ii+1] =
+      (unsigned char)((mdContext->buf[i] >> 8)  & 0xFF);
+    mdContext->digest[ii+2] =
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+    mdContext->digest[ii+3] =
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+  }
+  //SMEMCPY(hash, mdContext->digest, 16);
+  memcpy(hash, mdContext->digest, 16);
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void
+Transform (uint32_t *buf, uint32_t *in)
+{
+  uint32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+  /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+  FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+  FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+  FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+  FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+  FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+  FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+  FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+  FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+  FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+  FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+  FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+  FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+  FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+  FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+  FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+  FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
+
+  /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+  GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+  GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+  GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+  GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+  GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+  GG ( d, a, b, c, in[10], S22, UL(  38016083)); /* 22 */
+  GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+  GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+  GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+  GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+  GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+  GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+  GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+  GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+  GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+  GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
+
+  /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+  HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+  HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+  HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+  HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+  HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+  HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+  HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+  HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+  HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+  HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+  HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+  HH ( b, c, d, a, in[ 6], S34, UL(  76029189)); /* 44 */
+  HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+  HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+  HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+  HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
+
+  /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+  II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+  II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+  II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+  II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+  II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+  II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+  II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+  II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+  II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+  II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+  II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+  II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+  II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+  II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+  II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+  II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pppoe/md5.h	Wed Oct 15 06:27:12 2014 +0000
@@ -0,0 +1,59 @@
+/**
+ @file      md5.h
+ */
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5                    **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               **
+ ** Revised (for MD5): RLR 4/27/91                                    **
+ **   -- G modified to have y&~z instead of y&z                       **
+ **   -- FF, GG, HH modified to add in last register done             **
+ **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     **
+ **   -- distinct additive constant for each step                     **
+ **   -- round 4 added, working mod 7                                 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#include <stdint.h>
+#ifndef __MD5_H
+#define __MD5_H
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+  uint32_t i[2];               /* number of _bits_ handled mod 2^64 */
+  uint32_t buf[4];             /* scratch buffer */
+  unsigned char in[64];     /* input buffer */
+  unsigned char digest[16]; /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5Init  ( MD5_CTX *mdContext);
+void MD5Update( MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen);
+void MD5Final ( unsigned char hash[], MD5_CTX *mdContext);
+
+#endif /* MD5_H */