Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
ppp_hdlc.c
Go to the documentation of this file.
00001 /** 00002 * @file ppp_hdlc.c 00003 * @brief PPP HDLC driver 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 NIC_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include <stdio.h> 00034 #include "core/net.h" 00035 #include "ppp/ppp.h" 00036 #include "ppp/ppp_hdlc.h" 00037 #include "debug.h" 00038 00039 //Check TCP/IP stack configuration 00040 #if (PPP_SUPPORT == ENABLED) 00041 00042 00043 /** 00044 * @brief PPP HDLC driver 00045 **/ 00046 00047 const NicDriver pppHdlcDriver = 00048 { 00049 NIC_TYPE_PPP, 00050 PPP_DEFAULT_MRU, 00051 pppHdlcDriverInit, 00052 pppHdlcDriverTick, 00053 pppHdlcDriverEnableIrq, 00054 pppHdlcDriverDisableIrq, 00055 pppHdlcDriverEventHandler, 00056 pppHdlcDriverSendPacket, 00057 pppHdlcDriverSetMulticastFilter, 00058 NULL, 00059 NULL, 00060 NULL, 00061 FALSE, 00062 FALSE, 00063 FALSE, 00064 FALSE 00065 }; 00066 00067 00068 /** 00069 * @brief PPP HDLC driver initialization 00070 * @param[in] interface Underlying network interface 00071 * @return Error code 00072 **/ 00073 00074 error_t pppHdlcDriverInit(NetInterface *interface) 00075 { 00076 PppContext *context; 00077 00078 //Debug message 00079 TRACE_INFO("Initializing PPP HDLC driver...\r\n"); 00080 00081 //Point to the PPP context 00082 context = interface->pppContext; 00083 00084 //Initialize variables 00085 context->txBufferLen = 0; 00086 context->txWriteIndex = 0; 00087 context->txReadIndex = 0; 00088 context->rxBufferLen = 0; 00089 context->rxWriteIndex = 0; 00090 context->rxReadIndex = 0; 00091 context->rxFrameCount = 0; 00092 00093 //Initialize UART 00094 interface->uartDriver->init(); 00095 00096 //Accept any packets from the upper layer 00097 osSetEvent(&interface->nicTxEvent); 00098 00099 //Successful initialization 00100 return NO_ERROR; 00101 } 00102 00103 00104 /** 00105 * @brief PPP HDLC driver timer handler 00106 * 00107 * This routine is periodically called by the TCP/IP stack to 00108 * handle periodic operations such as polling the link state 00109 * 00110 * @param[in] interface Underlying network interface 00111 **/ 00112 00113 void pppHdlcDriverTick(NetInterface *interface) 00114 { 00115 } 00116 00117 00118 /** 00119 * @brief Enable interrupts 00120 * @param[in] interface Underlying network interface 00121 **/ 00122 00123 void pppHdlcDriverEnableIrq(NetInterface *interface) 00124 { 00125 //Enable UART interrupts 00126 interface->uartDriver->enableIrq(); 00127 } 00128 00129 00130 /** 00131 * @brief Disable interrupts 00132 * @param[in] interface Underlying network interface 00133 **/ 00134 00135 void pppHdlcDriverDisableIrq(NetInterface *interface) 00136 { 00137 //USART interrupts are always enabled 00138 } 00139 00140 00141 /** 00142 * @brief PPP HDLC driver event handler 00143 * @param[in] interface Underlying network interface 00144 **/ 00145 00146 void pppHdlcDriverEventHandler(NetInterface *interface) 00147 { 00148 PppContext *context; 00149 00150 //Point to the PPP context 00151 context = interface->pppContext; 00152 00153 //Check PPP state 00154 if(interface->pppContext->pppPhase != PPP_PHASE_DEAD) 00155 { 00156 //Process all pending packets 00157 while(context->rxFrameCount > 0) 00158 { 00159 //Read incoming packet 00160 pppHdlcDriverReceivePacket(interface); 00161 00162 //Enter critical section 00163 __disable_irq(); 00164 //Decrement frame counter 00165 context->rxFrameCount--; 00166 //Exit critical section 00167 __enable_irq(); 00168 } 00169 } 00170 } 00171 00172 00173 /** 00174 * @brief Send a packet 00175 * @param[in] interface Underlying network interface 00176 * @param[in] buffer Multi-part buffer containing the data to send 00177 * @param[in] offset Offset to the first data byte 00178 * @return Error code 00179 **/ 00180 00181 error_t pppHdlcDriverSendPacket(NetInterface *interface, 00182 const NetBuffer *buffer, size_t offset) 00183 { 00184 uint_t i; 00185 size_t j; 00186 size_t n; 00187 uint8_t *p; 00188 uint16_t protocol; 00189 uint32_t accm; 00190 PppContext *context; 00191 00192 //Point to the PPP context 00193 context = interface->pppContext; 00194 00195 //Point to the beginning of the frame 00196 p = netBufferAt(buffer, offset); 00197 00198 //Parse the PPP frame header 00199 pppParseFrameHeader(p, PPP_FRAME_HEADER_SIZE, &protocol); 00200 00201 //Check Protocol field 00202 if(protocol == PPP_PROTOCOL_IP || protocol == PPP_PROTOCOL_IPV6) 00203 { 00204 //Use the ACCM value that has been negotiated 00205 accm = context->peerConfig.accm; 00206 } 00207 else 00208 { 00209 //Use default ACCM mapping 00210 accm = PPP_DEFAULT_ACCM; 00211 } 00212 00213 //Send flag 00214 pppHdlcDriverWriteTxQueue(context, PPP_FLAG_CHAR); 00215 00216 //Loop through data chunks 00217 for(i = 0; i < buffer->chunkCount; i++) 00218 { 00219 //Is there any data to copy from the current chunk? 00220 if(offset < buffer->chunk[i].length) 00221 { 00222 //Point to the first byte to be read 00223 p = (uint8_t *) buffer->chunk[i].address + offset; 00224 //Compute the number of bytes to copy at a time 00225 n = buffer->chunk[i].length - offset; 00226 00227 //Copy data to TX queue 00228 for(j = 0; j < n; j++) 00229 { 00230 if(p[j] < PPP_MASK_CHAR) 00231 { 00232 //Check whether the character is flagged 00233 if(accm & (1 << p[j])) 00234 { 00235 pppHdlcDriverWriteTxQueue(context, PPP_ESC_CHAR); 00236 pppHdlcDriverWriteTxQueue(context, p[j] ^ PPP_MASK_CHAR); 00237 } 00238 else 00239 { 00240 //Enqueue current character 00241 pppHdlcDriverWriteTxQueue(context, p[j]); 00242 } 00243 } 00244 else if(p[j] == PPP_ESC_CHAR || p[j] == PPP_FLAG_CHAR) 00245 { 00246 pppHdlcDriverWriteTxQueue(context, PPP_ESC_CHAR); 00247 pppHdlcDriverWriteTxQueue(context, p[j] ^ PPP_MASK_CHAR); 00248 } 00249 else 00250 { 00251 //Enqueue current character 00252 pppHdlcDriverWriteTxQueue(context, p[j]); 00253 } 00254 } 00255 00256 //Process the next block from the start 00257 offset = 0; 00258 } 00259 else 00260 { 00261 //Skip the current chunk 00262 offset -= buffer->chunk[i].length; 00263 } 00264 } 00265 00266 //Send flag 00267 pppHdlcDriverWriteTxQueue(context, PPP_FLAG_CHAR); 00268 00269 //Start transferring data 00270 interface->uartDriver->startTx(); 00271 00272 //Check whether the TX queue is available for writing 00273 if(context->txBufferLen <= (PPP_TX_BUFFER_SIZE - 3006)) 00274 { 00275 //The transmitter can accept another packet 00276 osSetEvent(&interface->nicTxEvent); 00277 } 00278 00279 //Data successfully written 00280 return NO_ERROR; 00281 } 00282 00283 00284 /** 00285 * @brief Receive a packet 00286 * @param[in] interface Underlying network interface 00287 * @return Error code 00288 **/ 00289 00290 error_t pppHdlcDriverReceivePacket(NetInterface *interface) 00291 { 00292 size_t n; 00293 uint8_t c; 00294 bool_t escFlag; 00295 uint32_t accm; 00296 PppContext *context; 00297 00298 //Point to the PPP context 00299 context = interface->pppContext; 00300 //Retrieve ACCM 00301 accm = context->localConfig.accm; 00302 00303 //Length of the original PPP frame 00304 n = 0; 00305 //This flag tells whether the next character is escaped 00306 escFlag = FALSE; 00307 00308 //The receiver must reverse the octet stuffing procedure 00309 while(n < PPP_MAX_FRAME_SIZE && context->rxBufferLen > 0) 00310 { 00311 //Read a single character 00312 c = pppHdlcDriverReadRxQueue(context); 00313 00314 if(c < PPP_MASK_CHAR) 00315 { 00316 //Check whether the character is flagged 00317 if(accm & (1 << c)) 00318 { 00319 //The extra characters must be removed from the incoming data stream 00320 } 00321 else 00322 { 00323 //Copy current character 00324 context->frame[n++] = c; 00325 } 00326 } 00327 else if(c == PPP_ESC_CHAR) 00328 { 00329 //All occurrences of 0x7D indicate that the next character is escaped 00330 escFlag = TRUE; 00331 } 00332 else if(c == PPP_FLAG_CHAR) 00333 { 00334 //0x7E flag found 00335 break; 00336 } 00337 else if(escFlag) 00338 { 00339 //The character is XOR'ed with 0x20 00340 context->frame[n++] = c ^ PPP_MASK_CHAR; 00341 escFlag = FALSE; 00342 } 00343 else 00344 { 00345 //Copy current character 00346 context->frame[n++] = c; 00347 } 00348 } 00349 00350 //Check whether a valid PPP frame has been received 00351 if(n > 0) 00352 { 00353 //Debug message 00354 TRACE_DEBUG("PPP frame received (%" PRIuSIZE " bytes)...\r\n", n); 00355 TRACE_DEBUG_ARRAY(" ", context->frame, n); 00356 00357 //Pass the packet to the upper layer 00358 nicProcessPacket(interface, context->frame, n); 00359 } 00360 00361 //Successful read operation 00362 return NO_ERROR; 00363 } 00364 00365 00366 /** 00367 * @brief Configure multicast MAC address filtering 00368 * @param[in] interface Underlying network interface 00369 * @return Error code 00370 **/ 00371 00372 error_t pppHdlcDriverSetMulticastFilter(NetInterface *interface) 00373 { 00374 //Not implemented 00375 return NO_ERROR; 00376 } 00377 00378 00379 /** 00380 * @brief Send AT command 00381 * @param[in] interface Underlying network interface 00382 * @param[in] data NULL-terminated string that contains the AT command to be sent 00383 * @return Error code 00384 **/ 00385 00386 error_t pppHdlcDriverSendAtCommand(NetInterface *interface, const char_t *data) 00387 { 00388 size_t i; 00389 PppContext *context; 00390 00391 //Point to the PPP context 00392 context = interface->pppContext; 00393 00394 //Send AT command 00395 for(i = 0; data[i] != '\0' && i < 3006; i++) 00396 pppHdlcDriverWriteTxQueue(context, data[i]); 00397 00398 //Start transferring data 00399 interface->uartDriver->startTx(); 00400 00401 //Check whether the TX queue is available for writing 00402 if(context->txBufferLen <= (PPP_TX_BUFFER_SIZE - 3006)) 00403 { 00404 //The transmitter can accept another packet 00405 osSetEvent(&interface->nicTxEvent); 00406 } 00407 00408 //Data successfully written 00409 return NO_ERROR; 00410 } 00411 00412 00413 /** 00414 * @brief Wait for an incoming AT command 00415 * @param[in] interface Underlying network interface 00416 * @param[out] data Buffer where to store the incoming AT command 00417 * @param[in] size Size of the buffer, in bytes 00418 * @return Error code 00419 **/ 00420 00421 error_t pppHdlcDriverReceiveAtCommand(NetInterface *interface, char_t *data, size_t size) 00422 { 00423 uint_t i; 00424 uint_t k; 00425 uint_t n; 00426 bool_t valid; 00427 PppContext *context; 00428 00429 //Point to the PPP context 00430 context = interface->pppContext; 00431 00432 //Point to the first byte of the receive buffer 00433 k = context->rxReadIndex; 00434 //Number of characters pending in the receive buffer 00435 n = context->rxBufferLen; 00436 00437 //Loop through received data 00438 for(i = 0, valid = FALSE; i < n && !valid; i++) 00439 { 00440 //Read current character 00441 data[i] = context->rxBuffer[k]; 00442 00443 //Carriage return? 00444 if(data[i] == '\r' || data[i] == '\n') 00445 { 00446 data[i] = '\0'; 00447 valid = TRUE; 00448 } 00449 //Special processing of null-modem connections 00450 else if(i >= 5 && !memcmp(data + i - 5, "CLIENT", 6)) 00451 { 00452 data[i + 1] = '\0'; 00453 valid = TRUE; 00454 } 00455 else if(i >= 11 && !memcmp(data + i - 11, "CLIENTSERVER", 12)) 00456 { 00457 data[i + 1] = '\0'; 00458 valid = TRUE; 00459 } 00460 //Buffer full? 00461 else if(i == (size - 2)) 00462 { 00463 data[i + 1] = '\0'; 00464 valid = TRUE; 00465 } 00466 00467 //Increment index and wrap around if necessary 00468 if(++k >= PPP_RX_BUFFER_SIZE) 00469 k = 0; 00470 } 00471 00472 //Valid command received? 00473 if(valid) 00474 { 00475 //Advance read index 00476 context->rxReadIndex = (context->rxReadIndex + i) % PPP_RX_BUFFER_SIZE; 00477 00478 //Enter critical section 00479 __disable_irq(); 00480 //Update the length of the RX buffer 00481 context->rxBufferLen -= i; 00482 //Exit critical section 00483 __enable_irq(); 00484 00485 //Successful processing 00486 return NO_ERROR; 00487 } 00488 else 00489 { 00490 //data[i] = '\0'; 00491 //TRACE_INFO("PPP RX buffer residue (%d bytes)\r\n", i); 00492 //TRACE_INFO_ARRAY("# ", data, i); 00493 return ERROR_BUFFER_EMPTY; 00494 } 00495 } 00496 00497 00498 /** 00499 * @brief Purge TX buffer 00500 * @param[in] context Pointer to the PPP context 00501 * @return Error code 00502 **/ 00503 00504 error_t pppHdlcDriverPurgeTxBuffer(PppContext *context) 00505 { 00506 //Enter critical section 00507 __disable_irq(); 00508 00509 //Purge TX buffer 00510 context->txBufferLen = 0; 00511 context->txWriteIndex = 0; 00512 context->txReadIndex = 0; 00513 00514 //Exit critical section 00515 __enable_irq(); 00516 00517 //Successful operation 00518 return NO_ERROR; 00519 } 00520 00521 00522 /** 00523 * @brief Purge RX buffer 00524 * @param[in] context Pointer to the PPP context 00525 * @return Error code 00526 **/ 00527 00528 error_t pppHdlcDriverPurgeRxBuffer(PppContext *context) 00529 { 00530 //Enter critical section 00531 __disable_irq(); 00532 00533 //Purge RX buffer 00534 context->rxBufferLen = 0; 00535 context->rxWriteIndex = 0; 00536 context->rxReadIndex = 0; 00537 context->rxFrameCount = 0; 00538 00539 //Exit critical section 00540 __enable_irq(); 00541 00542 //Successful operation 00543 return NO_ERROR; 00544 } 00545 00546 00547 /** 00548 * @brief Write TX queue 00549 * @param[in] context Pointer to the PPP context 00550 * @param[in] c Character to be written 00551 **/ 00552 00553 void pppHdlcDriverWriteTxQueue(PppContext *context, uint8_t c) 00554 { 00555 //Enqueue the character 00556 context->txBuffer[context->txWriteIndex] = c; 00557 00558 //Increment index and wrap around if necessary 00559 if(++context->txWriteIndex >= PPP_TX_BUFFER_SIZE) 00560 context->txWriteIndex = 0; 00561 00562 //Enter critical section 00563 __disable_irq(); 00564 //Update the length of the queue 00565 context->txBufferLen++; 00566 //Exit critical section 00567 __enable_irq(); 00568 } 00569 00570 00571 /** 00572 * @brief Read RX queue 00573 * @param[in] context Pointer to the PPP context 00574 * @return Character read from the queue 00575 **/ 00576 00577 uint8_t pppHdlcDriverReadRxQueue(PppContext *context) 00578 { 00579 uint8_t c; 00580 00581 //Read a single character 00582 c = context->rxBuffer[context->rxReadIndex]; 00583 00584 //Increment index and wrap around if necessary 00585 if(++context->rxReadIndex >= PPP_RX_BUFFER_SIZE) 00586 context->rxReadIndex = 0; 00587 00588 //Enter critical section 00589 __disable_irq(); 00590 //Update the length of the queue 00591 context->rxBufferLen--; 00592 //Exit critical section 00593 __enable_irq(); 00594 00595 //Return the character that has been read 00596 return c; 00597 } 00598 00599 00600 /** 00601 * @brief Read TX queue 00602 * @param[in] interface Underlying network interface 00603 * @param[out] c Character read from the queue 00604 * @return TRUE if a context switch is required 00605 **/ 00606 00607 bool_t pppHdlcDriverReadTxQueue(NetInterface *interface, int_t *c) 00608 { 00609 bool_t flag; 00610 PppContext *context; 00611 00612 //Point to the PPP context 00613 context = interface->pppContext; 00614 //This flag will be set if a higher priority task must be woken 00615 flag = FALSE; 00616 00617 //Any data pending in the TX queue? 00618 if(context->txBufferLen > 0) 00619 { 00620 //Read a single character 00621 *c = context->txBuffer[context->txReadIndex]; 00622 00623 //Increment index and wrap around if necessary 00624 if(++context->txReadIndex >= PPP_TX_BUFFER_SIZE) 00625 context->txReadIndex = 0; 00626 00627 //Update the length of the queue 00628 context->txBufferLen--; 00629 00630 //Check whether the TX is available for writing 00631 if(context->txBufferLen == (PPP_TX_BUFFER_SIZE - 3006)) 00632 { 00633 flag = osSetEventFromIsr(&interface->nicTxEvent); 00634 } 00635 } 00636 else 00637 { 00638 //The TX queue is empty 00639 *c = EOF; 00640 } 00641 00642 //The return value tells whether a context switch is required 00643 return flag; 00644 } 00645 00646 00647 /** 00648 * @brief Write RX queue 00649 * @param[in] interface Underlying network interface 00650 * @param[in] c Character to be written 00651 * @return TRUE if a context switch is required 00652 **/ 00653 00654 bool_t pppHdlcDriverWriteRxQueue(NetInterface *interface, uint8_t c) 00655 { 00656 bool_t flag; 00657 PppContext *context; 00658 00659 //Point to the PPP context 00660 context = interface->pppContext; 00661 //This flag will be set if a higher priority task must be woken 00662 flag = FALSE; 00663 00664 //Make sure the RX queue is not full 00665 if(context->rxBufferLen < PPP_RX_BUFFER_SIZE) 00666 { 00667 //Enqueue the character 00668 context->rxBuffer[context->rxWriteIndex] = c; 00669 00670 //Increment index and wrap around if necessary 00671 if(++context->rxWriteIndex >= PPP_RX_BUFFER_SIZE) 00672 context->rxWriteIndex = 0; 00673 00674 //Update the length of the queue 00675 context->rxBufferLen++; 00676 00677 //Check PPP connection state 00678 if(interface->pppContext->pppPhase != PPP_PHASE_DEAD) 00679 { 00680 //0x7E flag found? 00681 if(c == PPP_FLAG_CHAR) 00682 { 00683 //Increment frame counter 00684 context->rxFrameCount++; 00685 00686 //A complete HDLC frame has been received 00687 interface->nicEvent = TRUE; 00688 //Notify the TCP/IP stack of the event 00689 flag = osSetEventFromIsr(&netEvent); 00690 } 00691 } 00692 } 00693 00694 //The return value tells whether a context switch is required 00695 return flag; 00696 } 00697 00698 #endif 00699 00700
Generated on Tue Jul 12 2022 17:10:15 by
