Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ppp_hdlc.c Source File

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