Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ppp.c Source File

ppp.c

Go to the documentation of this file.
00001 /**
00002  * @file ppp.c
00003  * @brief PPP (Point-to-Point Protocol)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL PPP_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "ppp/ppp.h"
00035 #include "ppp/ppp_hdlc.h"
00036 #include "ppp/ppp_debug.h"
00037 #include "ppp/lcp.h"
00038 #include "ppp/ipcp.h"
00039 #include "ppp/ipv6cp.h"
00040 #include "ppp/pap.h"
00041 #include "ppp/chap.h"
00042 #include "str.h"
00043 #include "debug.h"
00044 
00045 //Check TCP/IP stack configuration
00046 #if (PPP_SUPPORT == ENABLED)
00047 
00048 //Tick counter to handle periodic operations
00049 systime_t pppTickCounter;
00050 
00051 //FCS lookup table
00052 static const uint16_t fcsTable[256] =
00053 {
00054    0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
00055    0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
00056    0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
00057    0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
00058    0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
00059    0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
00060    0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
00061    0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
00062    0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
00063    0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
00064    0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
00065    0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
00066    0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
00067    0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
00068    0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
00069    0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
00070    0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
00071    0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
00072    0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
00073    0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
00074    0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
00075    0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
00076    0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
00077    0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
00078    0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
00079    0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
00080    0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
00081    0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
00082    0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
00083    0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
00084    0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
00085    0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
00086 };
00087 
00088 
00089 /**
00090  * @brief Initialize settings with default values
00091  * @param[out] settings Structure that contains PPP settings
00092  **/
00093 
00094 void pppGetDefaultSettings(PppSettings *settings)
00095 {
00096    //Use default interface
00097    settings->interface = netGetDefaultInterface();
00098 
00099    //Default MRU
00100    settings->mru = PPP_DEFAULT_MRU;
00101    //Default async control character map
00102    settings->accm = PPP_DEFAULT_ACCM;
00103    //Allowed authentication protocols
00104    settings->authProtocol = PPP_AUTH_PROTOCOL_PAP | PPP_AUTH_PROTOCOL_CHAP_MD5;
00105 
00106    //Random data generation callback function
00107    settings->randCallback = NULL;
00108    //PPP authentication callback function
00109    settings->authCallback = NULL;
00110 }
00111 
00112 
00113 /**
00114  * @brief PPP initialization
00115  * @param[in] context Pointer to the PPP context
00116  * @param[in] settings PPP specific settings
00117  * @return Error code
00118  **/
00119 
00120 error_t pppInit(PppContext *context, const PppSettings *settings)
00121 {
00122    error_t error;
00123    NetInterface *interface;
00124 
00125    //Debug message
00126    TRACE_INFO("PPP initialization\r\n");
00127 
00128    //Underlying network interface
00129    interface = settings->interface;
00130 
00131    //Initialize PPP context
00132    memset(context, 0, sizeof(PppContext));
00133 
00134    //Save user settings
00135    context->settings = *settings;
00136 
00137 #if (PAP_SUPPORT == DISABLED)
00138    //PAP authentication is not supported
00139    context->settings.authProtocol &= ~PPP_AUTH_PROTOCOL_PAP;
00140 #endif
00141 
00142 #if (PAP_SUPPORT == DISABLED)
00143    //CHAP with MD5 authentication is not supported
00144    context->settings.authProtocol &= ~PPP_AUTH_PROTOCOL_CHAP_MD5;
00145 #endif
00146 
00147    //Attach the PPP context to the network interface
00148    interface->pppContext = context;
00149 
00150    //Initialize structure
00151    context->interface = interface;
00152    context->timeout = INFINITE_DELAY;
00153 
00154    //Initialize PPP finite state machine
00155    context->pppPhase = PPP_PHASE_DEAD;
00156    context->lcpFsm.state = PPP_STATE_0_INITIAL;
00157 
00158 #if (IPV4_SUPPORT == ENABLED)
00159    //Initialize IPCP finite state machine
00160    context->ipcpFsm.state = PPP_STATE_0_INITIAL;
00161 #endif
00162 
00163 #if (IPV6_SUPPORT == ENABLED)
00164    //Initialize IPV6CP finite state machine
00165    context->ipv6cpFsm.state = PPP_STATE_0_INITIAL;
00166 #endif
00167 
00168 #if (PAP_SUPPORT == ENABLED)
00169    //Initialize PAP finite state machine
00170    context->papFsm.localState = PAP_STATE_0_INITIAL;
00171    context->papFsm.peerState = PAP_STATE_0_INITIAL;
00172 #endif
00173 
00174 #if (CHAP_SUPPORT == ENABLED)
00175    //Initialize CHAP finite state machine
00176    context->chapFsm.localState = CHAP_STATE_0_INITIAL;
00177    context->chapFsm.peerState = CHAP_STATE_0_INITIAL;
00178 #endif
00179 
00180    //Attach PPP HDLC driver
00181    error = netSetDriver(interface, &pppHdlcDriver);
00182 
00183    //Return status code
00184    return error;
00185 }
00186 
00187 
00188 /**
00189  * @brief Set timeout value for blocking operations
00190  * @param[in] interface Underlying network interface
00191  * @param[in] timeout Maximum time to wait
00192  * @return Error code
00193  **/
00194 
00195 error_t pppSetTimeout(NetInterface *interface, systime_t timeout)
00196 {
00197    PppContext *context;
00198 
00199    //Check parameters
00200    if(interface == NULL)
00201       return ERROR_INVALID_PARAMETER;
00202    //Make sure PPP has been properly configured
00203    if(interface->pppContext == NULL)
00204       return ERROR_NOT_CONFIGURED;
00205 
00206    //Point to the PPP context
00207    context = interface->pppContext;
00208 
00209    //Get exclusive access
00210    osAcquireMutex(&netMutex);
00211 
00212    //Set timeout value
00213    context->timeout = timeout;
00214 
00215    //Release exclusive access
00216    osReleaseMutex(&netMutex);
00217 
00218    //No error to report
00219    return NO_ERROR;
00220 }
00221 
00222 
00223 /**
00224  * @brief Set PPP authentication information
00225  * @param[in] interface Underlying network interface
00226  * @param[in] username NULL-terminated string containing the user name to be used
00227  * @param[in] password NULL-terminated string containing the password to be used
00228  * @return Error code
00229  **/
00230 
00231 error_t pppSetAuthInfo(NetInterface *interface,
00232    const char_t *username, const char_t *password)
00233 {
00234    PppContext *context;
00235 
00236    //Check parameters
00237    if(interface == NULL || username == NULL || password == NULL)
00238       return ERROR_INVALID_PARAMETER;
00239    //Make sure PPP has been properly configured
00240    if(interface->pppContext == NULL)
00241       return ERROR_NOT_CONFIGURED;
00242 
00243    //Point to the PPP context
00244    context = interface->pppContext;
00245 
00246    //Get exclusive access
00247    osAcquireMutex(&netMutex);
00248 
00249    //Save user name
00250    strSafeCopy(context->username, username, PPP_MAX_USERNAME_LEN);
00251    //Save password
00252    strSafeCopy(context->password, password, PPP_MAX_PASSWORD_LEN);
00253 
00254    //Release exclusive access
00255    osReleaseMutex(&netMutex);
00256 
00257    //No error to report
00258    return NO_ERROR;
00259 }
00260 
00261 
00262 /**
00263  * @brief Password verification
00264  * @param[in] interface Underlying network interface
00265  * @param[in] password NULL-terminated string containing the password to be checked
00266  * @return TRUE if the password is valid, else FALSE
00267  **/
00268 
00269 bool_t pppCheckPassword(NetInterface *interface, const char_t *password)
00270 {
00271    bool_t status;
00272    PppContext *context;
00273 
00274    //Debug message
00275    TRACE_DEBUG("PPP password verification...\r\n");
00276 
00277    //The password has not been verified yet
00278    status = FALSE;
00279 
00280    //Point to the PPP context
00281    context = interface->pppContext;
00282 
00283    //Make sure PPP has been properly configured
00284    if(context != NULL)
00285    {
00286       //Check authentication protocol
00287       if(context->localConfig.authProtocol == PPP_PROTOCOL_PAP)
00288       {
00289 #if (PAP_SUPPORT == ENABLED)
00290          //PAP authentication protocol
00291          status = papCheckPassword(context, password);
00292 #endif
00293       }
00294       //CHAP authentication protocol?
00295       else if(context->localConfig.authProtocol == PPP_PROTOCOL_CHAP)
00296       {
00297 #if (CHAP_SUPPORT == ENABLED)
00298          //CHAP authentication protocol
00299          status = chapCheckPassword(context, password);
00300 #endif
00301       }
00302    }
00303 
00304    //Return TRUE is the password is valid, else FALSE
00305    return status;
00306 }
00307 
00308 
00309 /**
00310  * @brief Send AT command
00311  * @param[in] interface Underlying network interface
00312  * @param[in] data NULL-terminated string that contains the AT command to be sent
00313  * @return Error code
00314  **/
00315 
00316 error_t pppSendAtCommand(NetInterface *interface, const char_t *data)
00317 {
00318    error_t error;
00319    bool_t status;
00320    PppContext *context;
00321 
00322    //Check parameters
00323    if(interface == NULL)
00324       return ERROR_INVALID_PARAMETER;
00325    //Make sure PPP has been properly configured
00326    if(interface->pppContext == NULL)
00327       return ERROR_NOT_CONFIGURED;
00328 
00329    //Point to the PPP context
00330    context = interface->pppContext;
00331 
00332    //Wait for the send buffer to be available for writing
00333    status = osWaitForEvent(&interface->nicTxEvent, context->timeout);
00334 
00335    //Check status
00336    if(status)
00337    {
00338       //Get exclusive access
00339       osAcquireMutex(&netMutex);
00340 
00341       //Check current PPP state
00342       if(context->pppPhase == PPP_PHASE_DEAD)
00343       {
00344          //Purge receive buffer
00345          error = pppHdlcDriverPurgeRxBuffer(context);
00346 
00347          //Send AT command
00348          if(!error)
00349             error = pppHdlcDriverSendAtCommand(interface, data);
00350       }
00351       else
00352       {
00353          //Report an error
00354          error = ERROR_ALREADY_CONNECTED;
00355       }
00356 
00357       //Release exclusive access
00358       osReleaseMutex(&netMutex);
00359    }
00360    else
00361    {
00362       //Timeout error
00363       return ERROR_TIMEOUT;
00364    }
00365 
00366    //Return status code
00367    return error;
00368 }
00369 
00370 
00371 /**
00372  * @brief Wait for an incoming AT command
00373  * @param[in] interface Underlying network interface
00374  * @param[out] data Buffer where to store the incoming AT command
00375  * @param[in] size Size of the buffer, in bytes
00376  * @return Error code
00377  **/
00378 
00379 error_t pppReceiveAtCommand(NetInterface *interface, char_t *data, size_t size)
00380 {
00381    error_t error;
00382    systime_t time;
00383    systime_t start;
00384    PppContext *context;
00385 
00386    //Check parameters
00387    if(interface == NULL)
00388       return ERROR_INVALID_PARAMETER;
00389    //Make sure PPP has been properly configured
00390    if(interface->pppContext == NULL)
00391       return ERROR_NOT_CONFIGURED;
00392 
00393    //Point to the PPP context
00394    context = interface->pppContext;
00395    //Save current time
00396    start = osGetSystemTime();
00397 
00398    //Wait for an incoming AT command
00399    while(1)
00400    {
00401       //Get exclusive access
00402       osAcquireMutex(&netMutex);
00403 
00404       //Check current PPP state
00405       if(context->pppPhase == PPP_PHASE_DEAD)
00406       {
00407          //Wait for an incoming AT command
00408          error = pppHdlcDriverReceiveAtCommand(interface, data, size);
00409       }
00410       else
00411       {
00412          //Report an error
00413          error = ERROR_ALREADY_CONNECTED;
00414       }
00415 
00416       //Release exclusive access
00417       osReleaseMutex(&netMutex);
00418 
00419       //No data received?
00420       if(error == ERROR_BUFFER_EMPTY || data[0] == '\0')
00421       {
00422          //Get current time
00423          time = osGetSystemTime();
00424 
00425          //Check whether the timeout period has elapsed
00426          if(timeCompare(time, start + context->timeout) >= 0)
00427          {
00428             //Timeout error
00429             error = ERROR_TIMEOUT;
00430             //Exit immediately
00431             break;
00432          }
00433          else
00434          {
00435             //Wait for more data to be received
00436             osDelayTask(PPP_POLLING_INTERVAL);
00437          }
00438       }
00439       else
00440       {
00441          //We are done
00442          break;
00443       }
00444    }
00445 
00446    //Return status code
00447    return error;
00448 }
00449 
00450 
00451 /**
00452  * @brief Establish a PPP connection
00453  * @param[in] interface Underlying network interface
00454  * @return Error code
00455  **/
00456 
00457 error_t pppConnect(NetInterface *interface)
00458 {
00459    error_t error;
00460    PppContext *context;
00461 #if (NET_RTOS_SUPPORT == ENABLED)
00462    systime_t time;
00463    systime_t start;
00464 #endif
00465 
00466    //Check parameters
00467    if(interface == NULL)
00468       return ERROR_INVALID_PARAMETER;
00469    //Make sure PPP has been properly configured
00470    if(interface->pppContext == NULL)
00471       return ERROR_NOT_CONFIGURED;
00472 
00473    //Point to the PPP context
00474    context = interface->pppContext;
00475 
00476    //Get exclusive access
00477    osAcquireMutex(&netMutex);
00478 
00479    //Default PPP phase
00480    context->pppPhase = PPP_PHASE_DEAD;
00481 
00482    //Initialize LCP FSM
00483    context->lcpFsm.state = PPP_STATE_0_INITIAL;
00484    context->lcpFsm.identifier = 0;
00485    context->lcpFsm.restartCounter = 0;
00486    context->lcpFsm.failureCounter = 0;
00487 
00488 #if (IPV4_SUPPORT == ENABLED)
00489    //Initialize IPCP FSM
00490    context->ipcpFsm.state = PPP_STATE_0_INITIAL;
00491    context->ipcpFsm.identifier = 0;
00492    context->ipcpFsm.restartCounter = 0;
00493    context->ipcpFsm.failureCounter = 0;
00494 #endif
00495 
00496 #if (IPV6_SUPPORT == ENABLED)
00497    //Initialize IPV6CP FSM
00498    context->ipv6cpFsm.state = PPP_STATE_0_INITIAL;
00499    context->ipv6cpFsm.identifier = 0;
00500    context->ipv6cpFsm.restartCounter = 0;
00501    context->ipv6cpFsm.failureCounter = 0;
00502 #endif
00503 
00504    //Authentication has not been completed
00505    context->localAuthDone = FALSE;
00506    context->peerAuthDone = FALSE;
00507 
00508 #if (PAP_SUPPORT == ENABLED)
00509    //Initialize PAP FSM
00510    context->papFsm.localState = PAP_STATE_0_INITIAL;
00511    context->papFsm.peerState = PAP_STATE_0_INITIAL;
00512    context->papFsm.identifier = 0;
00513    context->papFsm.restartCounter = 0;
00514 #endif
00515 
00516 #if (CHAP_SUPPORT == ENABLED)
00517    //Initialize CHAP FSM
00518    context->chapFsm.localState = CHAP_STATE_0_INITIAL;
00519    context->chapFsm.localIdentifier = 0;
00520    context->chapFsm.peerState = CHAP_STATE_0_INITIAL;
00521    context->chapFsm.peerIdentifier = 0;
00522 #endif
00523 
00524    //Default local configuration
00525    context->localConfig.mru = context->settings.mru;
00526    context->localConfig.mruRejected = FALSE;
00527    context->localConfig.accm = context->settings.accm;
00528    context->localConfig.accmRejected = FALSE;
00529    context->localConfig.authProtocol = 0;
00530    context->localConfig.authAlgo = 0;
00531    context->localConfig.authProtocolRejected = FALSE;
00532    context->localConfig.magicNumber = PPP_DEFAULT_MAGIC_NUMBER;
00533    context->localConfig.magicNumberRejected = FALSE;
00534    context->localConfig.pfc = TRUE;
00535    context->localConfig.pfcRejected = FALSE;
00536    context->localConfig.acfc = TRUE;
00537    context->localConfig.acfcRejected = FALSE;
00538 
00539    //Check whether the other end of the PPP link must be authenticated
00540    if(context->settings.authCallback != NULL)
00541    {
00542 #if (PAP_SUPPORT == ENABLED)
00543       //PAP provides an easy implementation of peer authentication
00544       if(context->settings.authProtocol & PPP_AUTH_PROTOCOL_PAP)
00545       {
00546          //Select PAP authentication protocol
00547          context->localConfig.authProtocol = PPP_PROTOCOL_PAP;
00548       }
00549 #endif
00550 #if (CHAP_SUPPORT == ENABLED)
00551       //CHAP with MD5 ensures greater security in the implementation
00552       if(context->settings.authProtocol & PPP_AUTH_PROTOCOL_CHAP_MD5)
00553       {
00554          //Select CHAP with MD5 authentication protocol
00555          context->localConfig.authProtocol = PPP_PROTOCOL_CHAP;
00556          context->localConfig.authAlgo = CHAP_ALGO_ID_CHAP_MD5;
00557       }
00558 #endif
00559    }
00560 
00561    //Default peer's configuration
00562    context->peerConfig.mru = PPP_DEFAULT_MRU;
00563    context->peerConfig.accm = PPP_DEFAULT_ACCM;
00564    context->peerConfig.authProtocol = 0;
00565    context->peerConfig.magicNumber = PPP_DEFAULT_MAGIC_NUMBER;
00566    context->peerConfig.pfc = FALSE;
00567    context->peerConfig.acfc = FALSE;
00568 
00569 #if (IPV4_SUPPORT == ENABLED)
00570    //Default local configuration
00571    context->localConfig.ipAddr = interface->ipv4Context.addr;
00572    context->localConfig.ipAddrRejected = FALSE;
00573    context->localConfig.primaryDns = interface->ipv4Context.dnsServerList[0];
00574    context->localConfig.primaryDnsRejected = FALSE;
00575 
00576 #if (IPV4_DNS_SERVER_LIST_SIZE >= 2)
00577    context->localConfig.secondaryDns = interface->ipv4Context.dnsServerList[1];
00578    context->localConfig.secondaryDnsRejected = FALSE;
00579 #else
00580    context->localConfig.secondaryDns = IPV4_UNSPECIFIED_ADDR;
00581    context->localConfig.secondaryDnsRejected = FALSE;
00582 #endif
00583 
00584    //Manual primary DNS configuration?
00585    if(context->localConfig.primaryDns != IPV4_UNSPECIFIED_ADDR)
00586       context->localConfig.primaryDnsRejected = TRUE;
00587 
00588    //Manual secondary DNS configuration?
00589    if(context->localConfig.secondaryDns != IPV4_UNSPECIFIED_ADDR)
00590       context->localConfig.secondaryDnsRejected = TRUE;
00591 
00592    //Default peer's configuration
00593    context->peerConfig.ipAddr = interface->ipv4Context.defaultGateway;
00594 #endif
00595 
00596 #if (IPV6_SUPPORT == ENABLED)
00597    //Default local configuration
00598    eui64CopyAddr(&context->localConfig.interfaceId,
00599       interface->ipv6Context.addrList[0].addr.b + 8);
00600 
00601    context->localConfig.interfaceIdRejected = FALSE;
00602 
00603    //Default peer's configuration
00604    eui64CopyAddr(&context->peerConfig.interfaceId,
00605       interface->ipv6Context.routerList[0].addr.b + 8);
00606 #endif
00607 
00608    //The link is available for traffic
00609    error = lcpOpen(context);
00610 
00611    //Release exclusive access
00612    osReleaseMutex(&netMutex);
00613 
00614    //Any error to report?
00615    if(error)
00616       return error;
00617 
00618 #if (NET_RTOS_SUPPORT == ENABLED)
00619    //Save current time
00620    start = osGetSystemTime();
00621 
00622    //Wait for the connection to be established
00623    while(1)
00624    {
00625       //Check current PPP phase
00626       if(context->pppPhase == PPP_PHASE_NETWORK)
00627       {
00628 #if (IPV4_SUPPORT == ENABLED)
00629          //Check current IPCP state
00630          if(context->ipcpFsm.state == PPP_STATE_9_OPENED)
00631          {
00632             //Connection successfully established
00633             error = NO_ERROR;
00634             //Exit immediately
00635             break;
00636          }
00637 #endif
00638 #if (IPV6_SUPPORT == ENABLED)
00639          //Check current IPV6CP state
00640          if(context->ipv6cpFsm.state == PPP_STATE_9_OPENED)
00641          {
00642             //Connection successfully established
00643             error = NO_ERROR;
00644             //Exit immediately
00645             break;
00646          }
00647 #endif
00648       }
00649       else if(context->pppPhase == PPP_PHASE_DEAD)
00650       {
00651          //Failed to establish connection
00652          error = ERROR_CONNECTION_FAILED;
00653          //Exit immediately
00654          break;
00655       }
00656 
00657       //Check timeout value
00658       if(context->timeout != INFINITE_DELAY)
00659       {
00660          //Get current time
00661          time = osGetSystemTime();
00662 
00663          //Check whether the timeout period has elapsed
00664          if(timeCompare(time, start + context->timeout) >= 0)
00665          {
00666             //Report an error
00667             error = ERROR_TIMEOUT;
00668             //Exit immediately
00669             break;
00670          }
00671       }
00672 
00673       //Polling delay
00674       osDelayTask(PPP_POLLING_INTERVAL);
00675    }
00676 
00677    //Failed to establish connection?
00678    if(error)
00679    {
00680       //Get exclusive access
00681       osAcquireMutex(&netMutex);
00682 
00683       //Abort the PPP connection
00684       context->pppPhase = PPP_PHASE_DEAD;
00685       context->lcpFsm.state = PPP_STATE_0_INITIAL;
00686 
00687 #if (IPV4_SUPPORT == ENABLED)
00688       //Reset IPCP finite state machine
00689       context->ipcpFsm.state = PPP_STATE_0_INITIAL;
00690 #endif
00691 
00692 #if (IPV6_SUPPORT == ENABLED)
00693       //Reset IPV6CP finite state machine
00694       context->ipv6cpFsm.state = PPP_STATE_0_INITIAL;
00695 #endif
00696 
00697 #if (PAP_SUPPORT == ENABLED)
00698       //Abort PAP authentication process
00699       context->papFsm.localState = PAP_STATE_0_INITIAL;
00700       context->papFsm.peerState = PAP_STATE_0_INITIAL;
00701 #endif
00702 
00703 #if (CHAP_SUPPORT == ENABLED)
00704       //Abort CHAP authentication process
00705       context->chapFsm.localState = CHAP_STATE_0_INITIAL;
00706       context->chapFsm.peerState = CHAP_STATE_0_INITIAL;
00707 #endif
00708 
00709       //Release exclusive access
00710       osReleaseMutex(&netMutex);
00711    }
00712 #endif
00713 
00714    //Return status code
00715    return error;
00716 }
00717 
00718 
00719 /**
00720  * @brief Close a PPP connection
00721  * @param[in] interface Underlying network interface
00722  * @return Error code
00723  **/
00724 
00725 error_t pppClose(NetInterface *interface)
00726 {
00727    error_t error;
00728    PppContext *context;
00729 #if (NET_RTOS_SUPPORT == ENABLED)
00730    systime_t time;
00731    systime_t start;
00732 #endif
00733 
00734    //Check parameters
00735    if(interface == NULL)
00736       return ERROR_INVALID_PARAMETER;
00737    //Make sure PPP has been properly configured
00738    if(interface->pppContext == NULL)
00739       return ERROR_NOT_CONFIGURED;
00740 
00741    //Point to the PPP context
00742    context = interface->pppContext;
00743 
00744    //Get exclusive access
00745    osAcquireMutex(&netMutex);
00746 
00747    //The link is no longer available for traffic
00748    error = lcpClose(context);
00749 
00750    //Release exclusive access
00751    osReleaseMutex(&netMutex);
00752 
00753    //Any error to report?
00754    if(error)
00755       return error;
00756 
00757 #if (NET_RTOS_SUPPORT == ENABLED)
00758    //Save current time
00759    start = osGetSystemTime();
00760 
00761    //Wait for the connection to be closed
00762    while(1)
00763    {
00764       //Check current PPP phase
00765       if(context->pppPhase == PPP_PHASE_DEAD)
00766       {
00767          //PPP connection is closed
00768          error = NO_ERROR;
00769          //Exit immediately
00770          break;
00771       }
00772 
00773       //Check timeout value
00774       if(context->timeout != INFINITE_DELAY)
00775       {
00776          //Get current time
00777          time = osGetSystemTime();
00778 
00779          //Check whether the timeout period has elapsed
00780          if(timeCompare(time, start + context->timeout) >= 0)
00781          {
00782             //Report an error
00783             error = ERROR_TIMEOUT;
00784             //Exit immediately
00785             break;
00786          }
00787       }
00788 
00789       //Poll the state
00790       osDelayTask(PPP_POLLING_INTERVAL);
00791    }
00792 
00793    //Failed to properly close the connection?
00794    if(error)
00795    {
00796       //Get exclusive access
00797       osAcquireMutex(&netMutex);
00798 
00799       //Abort the PPP connection
00800       context->pppPhase = PPP_PHASE_DEAD;
00801       context->lcpFsm.state = PPP_STATE_0_INITIAL;
00802 
00803 #if (IPV4_SUPPORT == ENABLED)
00804       //Reset IPCP finite state machine
00805       context->ipcpFsm.state = PPP_STATE_0_INITIAL;
00806 #endif
00807 
00808 #if (IPV6_SUPPORT == ENABLED)
00809       //Reset IPV6CP finite state machine
00810       context->ipv6cpFsm.state = PPP_STATE_0_INITIAL;
00811 #endif
00812 
00813 #if (PAP_SUPPORT == ENABLED)
00814       //Abort PAP authentication process
00815       context->papFsm.localState = PAP_STATE_0_INITIAL;
00816       context->papFsm.peerState = PAP_STATE_0_INITIAL;
00817 #endif
00818 
00819 #if (CHAP_SUPPORT == ENABLED)
00820       //Abort CHAP authentication process
00821       context->chapFsm.localState = CHAP_STATE_0_INITIAL;
00822       context->chapFsm.peerState = CHAP_STATE_0_INITIAL;
00823 #endif
00824 
00825       //Release exclusive access
00826       osReleaseMutex(&netMutex);
00827    }
00828 #endif
00829 
00830    //Return status code
00831    return error;
00832 }
00833 
00834 
00835 /**
00836  * @brief PPP timer handler
00837  *
00838  * This routine must be periodically called by the TCP/IP stack to
00839  * manage retransmissions
00840  *
00841  * @param[in] interface Underlying network interface
00842  **/
00843 
00844 void pppTick(NetInterface *interface)
00845 {
00846    PppContext *context;
00847 
00848    //PPP driver?
00849    if(interface->nicDriver->type == NIC_TYPE_PPP)
00850    {
00851       //Point to the PPP context
00852       context = interface->pppContext;
00853 
00854       //Handle LCP retransmission timer
00855       lcpTick(context);
00856 
00857 #if (IPV4_SUPPORT == ENABLED)
00858       //Handle IPCP retransmission timer
00859       ipcpTick(context);
00860 #endif
00861 
00862 #if (IPV6_SUPPORT == ENABLED)
00863       //Handle IPV6CP retransmission timer
00864       ipv6cpTick(context);
00865 #endif
00866 
00867 #if (PAP_SUPPORT == ENABLED)
00868       //Handle PAP timer
00869       papTick(context);
00870 #endif
00871 
00872 #if (CHAP_SUPPORT == ENABLED)
00873       //Handle CHAP timer
00874       chapTick(context);
00875 #endif
00876    }
00877 }
00878 
00879 
00880 /**
00881  * @brief Process an incoming PPP frame
00882  * @param[in] interface Underlying network interface
00883  * @param[in] frame Incoming PPP frame to process
00884  * @param[in] length Total frame length
00885  **/
00886 
00887 void pppProcessFrame(NetInterface *interface, uint8_t *frame, size_t length)
00888 {
00889    size_t n;
00890    uint16_t protocol;
00891    PppContext *context;
00892 #if (IPV6_SUPPORT == ENABLED)
00893    NetBuffer1 buffer;
00894 #endif
00895 
00896    //Point to the PPP context
00897    context = interface->pppContext;
00898 
00899    //Check the length of the PPP frame
00900    if(length < PPP_FCS_SIZE)
00901       return;
00902 
00903    //Debug message
00904    TRACE_DEBUG("PPP frame received (%" PRIuSIZE " bytes)...\r\n", length);
00905 
00906    //The value of the residue is 0x0F47 when no FCS errors are detected
00907    if(pppCalcFcs(frame, length) != 0x0F47)
00908    {
00909       //Debug message
00910       TRACE_WARNING("Wrong FCS detected!\r\n");
00911       //Drop the received frame
00912       return;
00913    }
00914 
00915    //Calculate the length of PPP frame excluding the FCS field
00916    length -= PPP_FCS_SIZE;
00917 
00918    //Decompress the frame header
00919    n = pppParseFrameHeader(frame, length, &protocol);
00920    //Malformed PPP frame?
00921    if(!n)
00922       return;
00923 
00924    //Point to the payload field
00925    frame += n;
00926    length -= n;
00927 
00928    //Check protocol field
00929    switch(protocol)
00930    {
00931    //Link control protocol?
00932    case PPP_PROTOCOL_LCP:
00933       //Process incoming LCP packet
00934       lcpProcessPacket(context, (PppPacket *) frame, length);
00935       break;
00936 
00937 #if (IPV4_SUPPORT == ENABLED)
00938    //IP control protocol?
00939    case PPP_PROTOCOL_IPCP:
00940       //Process incoming IPCP packet
00941       ipcpProcessPacket(context, (PppPacket *) frame, length);
00942       break;
00943    //IP protocol?
00944    case PPP_PROTOCOL_IP:
00945       //Process incoming IPv4 packet
00946       ipv4ProcessPacket(interface, (Ipv4Header *) frame, length);
00947       break;
00948 #endif
00949 
00950 #if (IPV6_SUPPORT == ENABLED)
00951    //IPv6 control protocol?
00952    case PPP_PROTOCOL_IPV6CP:
00953       //Process incoming IPV6CP packet
00954       ipv6cpProcessPacket(context, (PppPacket *) frame, length);
00955       break;
00956    //IPv6 protocol?
00957    case PPP_PROTOCOL_IPV6:
00958       //The incoming PPP frame fits in a single chunk
00959       buffer.chunkCount = 1;
00960       buffer.maxChunkCount = 1;
00961       buffer.chunk[0].address = frame;
00962       buffer.chunk[0].length = length;
00963       buffer.chunk[0].size = 0;
00964 
00965       //Process incoming IPv6 packet
00966       ipv6ProcessPacket(interface, (NetBuffer *) &buffer, 0);
00967       break;
00968 #endif
00969 
00970 #if (PAP_SUPPORT == ENABLED)
00971    //PAP protocol?
00972    case PPP_PROTOCOL_PAP:
00973       //Process incoming PAP packet
00974       papProcessPacket(context, (PppPacket *) frame, length);
00975       break;
00976 #endif
00977 
00978 #if (CHAP_SUPPORT == ENABLED)
00979    //CHAP protocol?
00980    case PPP_PROTOCOL_CHAP:
00981       //Process incoming CHAP packet
00982       chapProcessPacket(context, (PppPacket *) frame, length);
00983       break;
00984 #endif
00985 
00986    //Unknown protocol field
00987    default:
00988       //The peer is attempting to use a protocol which is unsupported
00989       lcpProcessUnknownProtocol(context, protocol, frame, length);
00990       break;
00991    }
00992 }
00993 
00994 
00995 /**
00996  * @brief Send a PPP frame
00997  * @param[in] interface Underlying network interface
00998  * @param[in] buffer Multi-part buffer containing the data
00999  * @param[in] offset Offset to the first data byte
01000  * @param[in] protocol Protocol field value
01001  * @return Error code
01002  **/
01003 
01004 error_t pppSendFrame(NetInterface *interface,
01005    NetBuffer *buffer, size_t offset, uint16_t protocol)
01006 {
01007    error_t error;
01008    size_t length;
01009    uint16_t fcs;
01010    uint8_t *p;
01011    PppContext *context;
01012 
01013    //Point to the PPP context
01014    context = interface->pppContext;
01015 
01016    //Check whether the Protocol field can be compressed
01017    if(context->peerConfig.pfc && MSB(protocol) == 0)
01018    {
01019       //Is there enough space in the buffer to store the compressed
01020       //Protocol field?
01021       if(offset < 1)
01022          return ERROR_FAILURE;
01023 
01024       //Make room for the Protocol field
01025       offset--;
01026       //Move backward
01027       p = netBufferAt(buffer, offset);
01028       //Compress the Protocol field
01029       p[0] = LSB(protocol);
01030    }
01031    else
01032    {
01033       //Is there enough space in the buffer to store the uncompressed
01034       //Protocol field?
01035       if(offset < 2)
01036          return ERROR_FAILURE;
01037 
01038       //Make room for the Protocol field
01039       offset -= 2;
01040       //Move backward
01041       p = netBufferAt(buffer, offset);
01042       //Do not compress the Protocol field
01043       p[0] = MSB(protocol);
01044       p[1] = LSB(protocol);
01045    }
01046 
01047    //Check whether the Address and Control fields can be compressed
01048    if(context->peerConfig.acfc && protocol != PPP_PROTOCOL_LCP)
01049    {
01050       //On transmission, compressed Address and Control fields
01051       //are simply omitted...
01052    }
01053    else
01054    {
01055       //Is there enough space in the buffer to store the uncompressed
01056       //Address and Control fields?
01057       if(offset < 2)
01058          return ERROR_FAILURE;
01059 
01060       //Make room for the Address and Control fields
01061       offset -= 2;
01062       //Move backward
01063       p = netBufferAt(buffer, offset);
01064       //Do not compress the Address and Control fields
01065       p[0] = PPP_ADDR_FIELD;
01066       p[1] = PPP_CTRL_FIELD;
01067    }
01068 
01069    //Retrieve the length of the frame
01070    length = netBufferGetLength(buffer) - offset;
01071 
01072    //Compute FCS over the header and payload
01073    fcs = pppCalcFcsEx(buffer, offset, length);
01074    //The FCS is transmitted least significant octet first
01075    fcs = htole16(fcs);
01076 
01077    //Append the calculated FCS value
01078    error = netBufferAppend(buffer, &fcs, PPP_FCS_SIZE);
01079    //Any error to report?
01080    if(error)
01081       return error;
01082 
01083    //Adjust frame length
01084    length += PPP_FCS_SIZE;
01085 
01086    //Debug message
01087    TRACE_DEBUG("Sending PPP frame (%" PRIuSIZE " bytes)...\r\n", length);
01088    TRACE_DEBUG("  Protocol = 0x%04" PRIX16 "\r\n", protocol);
01089 
01090    //Send the resulting frame over the specified link
01091    error = nicSendPacket(interface, buffer, offset);
01092    //Return status code
01093    return error;
01094 }
01095 
01096 
01097 /**
01098  * @brief Parse PPP frame header
01099  * @param[in] frame Pointer to the PPP frame
01100  * @param[in] length Length of the frame, in bytes
01101  * @param[out] protocol Value of the Protocol field
01102  * @return If the PPP header was successfully parsed, the function returns the size
01103  *   of the PPP header, in bytes. If a parsing error occurred, zero is returned
01104  **/
01105 
01106 size_t pppParseFrameHeader(const uint8_t *frame, size_t length, uint16_t *protocol)
01107 {
01108    size_t n;
01109 
01110    //Size of the PPP header, in bytes
01111    n = 0;
01112 
01113    //On reception, the Address and Control fields are decompressed by
01114    //examining the first two octets
01115    if(length >= 2)
01116    {
01117       //If they contain the values 0xff and 0x03, they are assumed to be
01118       //the Address and Control fields. If not, it is assumed that the
01119       //fields were compressed and were not transmitted
01120       if(frame[0] == PPP_ADDR_FIELD && frame[1] == PPP_CTRL_FIELD)
01121       {
01122          //Move to the Protocol field
01123          n = 2;
01124       }
01125    }
01126 
01127    //Check the length of the PPP frame
01128    if(length >= (n + 1))
01129    {
01130       //PPP Protocol field numbers are chosen such that some values may be
01131       //compressed into a single octet form which is clearly distinguishable
01132       //from the two octet form
01133       if(frame[n] & 0x01)
01134       {
01135          //The presence of a binary 1 as the LSB marks the last octet of
01136          //the Protocol field
01137          *protocol = frame[n];
01138 
01139          //Update the length of the header
01140          n++;
01141       }
01142       else
01143       {
01144          //Check the length of the PPP frame
01145          if(length >= (n + 2))
01146          {
01147             //The Protocol field is not compressed
01148             *protocol = (frame[n] << 8) | frame[n + 1];
01149 
01150             //Update the length of the header
01151             n += 2;
01152          }
01153          else
01154          {
01155             //Malformed PPP frame
01156             n = 0;
01157          }
01158       }
01159    }
01160    else
01161    {
01162       //Malformed PPP frame
01163       n = 0;
01164    }
01165 
01166    //Return the size of the PPP header, in bytes
01167    return n;
01168 }
01169 
01170 
01171 /**
01172  * @brief FCS calculation
01173  * @param[in] data Pointer to the data over which to calculate the FCS
01174  * @param[in] length Number of bytes to process
01175  * @return Resulting FCS value
01176  **/
01177 
01178 uint16_t pppCalcFcs(const uint8_t *data, size_t length)
01179 {
01180    size_t i;
01181    uint16_t fcs;
01182 
01183    //FCS preset value
01184    fcs = 0xFFFF;
01185 
01186    //Loop through data
01187    for(i = 0; i < length; i++)
01188    {
01189       //The message is processed byte by byte
01190       fcs = (fcs >> 8) ^ fcsTable[(fcs & 0xFF) ^ data[i]];
01191    }
01192 
01193    //Return 1's complement value
01194    return ~fcs;
01195 }
01196 
01197 
01198 /**
01199  * @brief Calculate FCS over a multi-part buffer
01200  * @param[in] buffer Pointer to the multi-part buffer
01201  * @param[in] offset Offset from the beginning of the buffer
01202  * @param[in] length Number of bytes to process
01203  * @return Resulting FCS value
01204  **/
01205 
01206 uint16_t pppCalcFcsEx(const NetBuffer *buffer, size_t offset, size_t length)
01207 {
01208    uint_t i;
01209    uint_t n;
01210    uint16_t fcs;
01211    uint8_t *p;
01212 
01213    //FCS preset value
01214    fcs = 0xFFFF;
01215 
01216    //Loop through data chunks
01217    for(i = 0; i < buffer->chunkCount && length > 0; i++)
01218    {
01219       //Is there any data to process in the current chunk?
01220       if(offset < buffer->chunk[i].length)
01221       {
01222          //Point to the first data byte
01223          p = (uint8_t *) buffer->chunk[i].address + offset;
01224          //Compute the number of bytes to process
01225          n = MIN(buffer->chunk[i].length - offset, length);
01226          //Adjust byte counter
01227          length -= n;
01228 
01229          //Process current chunk
01230          while(n > 0)
01231          {
01232             //The message is processed byte by byte
01233             fcs = (fcs >> 8) ^ fcsTable[(fcs & 0xFF) ^ *p];
01234 
01235             //Next byte
01236             p++;
01237             n--;
01238          }
01239 
01240          //Process the next block from the start
01241          offset = 0;
01242       }
01243       else
01244       {
01245          //Skip the current chunk
01246          offset -= buffer->chunk[i].length;
01247       }
01248    }
01249 
01250    //Return 1's complement value
01251    return ~fcs;
01252 }
01253 
01254 
01255 /**
01256  * @brief Allocate a buffer to hold a PPP frame
01257  * @param[in] length Desired payload length
01258  * @param[out] offset Offset to the first byte of the payload
01259  * @return The function returns a pointer to the newly allocated
01260  *   buffer. If the system is out of resources, NULL is returned
01261  **/
01262 
01263 NetBuffer *pppAllocBuffer(size_t length, size_t *offset)
01264 {
01265    NetBuffer *buffer;
01266 
01267    //Allocate a buffer to hold the Ethernet header and the payload
01268    buffer = netBufferAlloc(length + PPP_FRAME_HEADER_SIZE);
01269    //Failed to allocate buffer?
01270    if(buffer == NULL)
01271       return NULL;
01272 
01273    //Offset to the first byte of the payload
01274    *offset = PPP_FRAME_HEADER_SIZE;
01275 
01276    //Return a pointer to the freshly allocated buffer
01277    return buffer;
01278 }
01279 
01280 #endif
01281