Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
ppp.c
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
Generated on Tue Jul 12 2022 17:10:15 by
