Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ipv6cp.c Source File

ipv6cp.c

Go to the documentation of this file.
00001 /**
00002  * @file ipv6cp.c
00003  * @brief IPV6CP (PPP IPv6 Control 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 "ipv6/ipv6.h"
00035 #include "ipv6/ipv6_misc.h"
00036 #include "ppp/ppp_fsm.h"
00037 #include "ppp/ppp_misc.h"
00038 #include "ppp/ppp_debug.h"
00039 #include "ppp/ipv6cp.h"
00040 #include "debug.h"
00041 
00042 //Check TCP/IP stack configuration
00043 #if (PPP_SUPPORT == ENABLED && IPV6_SUPPORT == ENABLED)
00044 
00045 
00046 /**
00047  * @brief IPV6CP FSM callbacks
00048  **/
00049 
00050 const PppCallbacks ipv6cpCallbacks =
00051 {
00052    ipv6cpThisLayerUp,
00053    ipv6cpThisLayerDown,
00054    ipv6cpThisLayerStarted,
00055    ipv6cpThisLayerFinished,
00056    ipv6cpInitRestartCount,
00057    ipv6cpZeroRestartCount,
00058    ipv6cpSendConfigureReq,
00059    ipv6cpSendConfigureAck,
00060    ipv6cpSendConfigureNak,
00061    ipv6cpSendConfigureRej,
00062    ipv6cpSendTerminateReq,
00063    ipv6cpSendTerminateAck,
00064    ipv6cpSendCodeRej,
00065    NULL
00066 };
00067 
00068 
00069 /**
00070  * @brief IPV6CP Open event
00071  * @param[in] context PPP context
00072  * @return Error code
00073  **/
00074 
00075 error_t ipv6cpOpen(PppContext *context)
00076 {
00077    //Debug message
00078    TRACE_INFO("\r\nIPV6CP Open event\r\n");
00079 
00080    //The link is administratively available for traffic
00081    pppOpenEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks);
00082    //The lower layer is ready to carry packets
00083    pppUpEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks);
00084 
00085    //Successful processing
00086    return NO_ERROR;
00087 }
00088 
00089 
00090 /**
00091  * @brief IPV6CP Close event
00092  * @param[in] context PPP context
00093  * @return Error code
00094  **/
00095 
00096 error_t ipv6cpClose(PppContext *context)
00097 {
00098    //Debug message
00099    TRACE_INFO("\r\nIPV6CP Close event\r\n");
00100 
00101    //The lower layer is no longer ready to carry packets
00102    pppDownEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks);
00103    //The link is no longer available for traffic
00104    pppCloseEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks);
00105 
00106    //Successful processing
00107    return NO_ERROR;
00108 }
00109 
00110 
00111 /**
00112  * @brief IPV6CP timer handler
00113  *
00114  * This routine must be periodically called by the TCP/IP stack to
00115  * manage retransmissions
00116  *
00117  * @param[in] context PPP context
00118  **/
00119 
00120 void ipv6cpTick(PppContext *context)
00121 {
00122    //Check whether the restart timer is running
00123    if(context->ipv6cpFsm.state >= PPP_STATE_4_CLOSING &&
00124       context->ipv6cpFsm.state <= PPP_STATE_8_ACK_SENT)
00125    {
00126       //Get current time
00127       systime_t time = osGetSystemTime();
00128 
00129       //Check restart timer
00130       if((time - context->ipv6cpFsm.timestamp) >= PPP_RESTART_TIMER)
00131       {
00132          //Debug message
00133          TRACE_INFO("\r\nIPV6CP Timeout event\r\n");
00134 
00135          //The restart timer is used to retransmit Configure-Request
00136          //and Terminate-Request packets
00137          pppTimeoutEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks);
00138       }
00139    }
00140 }
00141 
00142 
00143 /**
00144  * @brief Process an incoming IPV6CP packet
00145  * @param[in] context PPP context
00146  * @param[in]  packet IPV6CP packet received from the peer
00147  * @param[in] length Length of the packet, in bytes
00148  **/
00149 
00150 void ipv6cpProcessPacket(PppContext *context, const PppPacket *packet, size_t length)
00151 {
00152    //Ensure the length of the incoming IPV6CP packet is valid
00153    if(length < sizeof(PppPacket))
00154       return;
00155 
00156    //Check the length field
00157    if(ntohs(packet->length) > length)
00158       return;
00159    if(ntohs(packet->length) < sizeof(PppPacket))
00160       return;
00161 
00162    //Save the length of the IPV6CP packet
00163    length = ntohs(packet->length);
00164 
00165    //Debug message
00166    TRACE_INFO("IPV6CP packet received (%" PRIuSIZE " bytes)...\r\n", length);
00167    //Dump IPV6CP packet contents for debugging purpose
00168    pppDumpPacket(packet, length, PPP_PROTOCOL_IPV6CP);
00169 
00170    //Check IPV6CP code field
00171    switch(packet->code)
00172    {
00173    //Configure-Request packet?
00174    case PPP_CODE_CONFIGURE_REQ:
00175       //Process Configure-Request packet
00176       ipv6cpProcessConfigureReq(context, (PppConfigurePacket *) packet);
00177       break;
00178    //Configure-Ack packet?
00179    case PPP_CODE_CONFIGURE_ACK:
00180       //Process Configure-Ack packet
00181       ipv6cpProcessConfigureAck(context, (PppConfigurePacket *) packet);
00182       break;
00183    //Configure-Nak packet?
00184    case PPP_CODE_CONFIGURE_NAK:
00185       //Process Configure-Nak packet
00186       ipv6cpProcessConfigureNak(context, (PppConfigurePacket *) packet);
00187       break;
00188    //Configure-Reject packet?
00189    case PPP_CODE_CONFIGURE_REJ:
00190       //Process Configure-Reject packet
00191       ipv6cpProcessConfigureReject(context, (PppConfigurePacket *) packet);
00192       break;
00193    //Terminate-Request packet?
00194    case PPP_CODE_TERMINATE_REQ:
00195       //Process Terminate-Request packet
00196       ipv6cpProcessTerminateReq(context, (PppTerminatePacket *) packet);
00197       break;
00198    //Terminate-Ack packet?
00199    case PPP_CODE_TERMINATE_ACK:
00200       //Process Terminate-Ack packet
00201       ipv6cpProcessTerminateAck(context, (PppTerminatePacket *) packet);
00202       break;
00203    //Code-Reject packet?
00204    case PPP_CODE_CODE_REJ:
00205       //Process Code-Reject packet
00206       ipv6cpProcessCodeRej(context, (PppCodeRejPacket *) packet);
00207       break;
00208    //Unknown code field
00209    default:
00210       //The packet is un-interpretable
00211       ipv6cpProcessUnknownCode(context, packet);
00212       break;
00213    }
00214 }
00215 
00216 
00217 /**
00218  * @brief Process Configure-Request packet
00219  * @param[in] context PPP context
00220  * @param[in] configureReqPacket Packet received from the peer
00221  * @return Error code
00222  **/
00223 
00224 error_t ipv6cpProcessConfigureReq(PppContext *context,
00225    const PppConfigurePacket *configureReqPacket)
00226 {
00227    error_t error;
00228    size_t length;
00229    bool_t notRecognizable;
00230    bool_t notAcceptable;
00231    PppOption *option;
00232 
00233    //Debug message
00234    TRACE_INFO("\r\nIPV6CP Receive-Configure-Request event\r\n");
00235 
00236    //Initialize variables
00237    error = NO_ERROR;
00238    notRecognizable = FALSE;
00239    notAcceptable = FALSE;
00240 
00241    //Retrieve the length of the option list
00242    length = ntohs(configureReqPacket->length) - sizeof(PppConfigurePacket);
00243    //Point to the first option
00244    option = (PppOption *) configureReqPacket->options;
00245 
00246    //Parse configuration options
00247    while(length > 0)
00248    {
00249       //Parse current option
00250       error = ipv6cpParseOption(context, option, length, NULL);
00251 
00252       //Any error to report?
00253       if(error == ERROR_INVALID_TYPE)
00254       {
00255          //Option not recognizable
00256          notRecognizable = TRUE;
00257          //Catch error
00258          error = NO_ERROR;
00259       }
00260       else if(error == ERROR_INVALID_VALUE)
00261       {
00262          //Option not acceptable for configuration
00263          notAcceptable = TRUE;
00264          //Catch error
00265          error = NO_ERROR;
00266       }
00267       else if(error)
00268       {
00269          //Malformed Configure-Request packet
00270          break;
00271       }
00272 
00273       //Remaining bytes to process
00274       length -= option->length;
00275       //Jump to the next option
00276       option = (PppOption *) ((uint8_t *) option + option->length);
00277    }
00278 
00279    //Valid Configure-Request packet received from the peer?
00280    if(!error)
00281    {
00282       //Check flags
00283       if(notRecognizable)
00284       {
00285          //If some configuration options received in the Configure-Request are not
00286          //recognizable or not acceptable for negotiation, then the implementation
00287          //must transmit a Configure-Reject
00288          pppRcvConfigureReqEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks,
00289             configureReqPacket, PPP_CODE_CONFIGURE_REJ);
00290       }
00291       else if(notAcceptable)
00292       {
00293          //If all configuration options are recognizable, but some values are not
00294          //acceptable, then the implementation must transmit a Configure-Nak
00295          pppRcvConfigureReqEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks,
00296             configureReqPacket, PPP_CODE_CONFIGURE_NAK);
00297       }
00298       else
00299       {
00300          //If every configuration option received in the Configure-Request is
00301          //recognizable and all values are acceptable, then the implementation
00302          //must transmit a Configure-Ack
00303          pppRcvConfigureReqEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks,
00304             configureReqPacket, PPP_CODE_CONFIGURE_ACK);
00305       }
00306    }
00307 
00308    //Return status code
00309    return error;
00310 }
00311 
00312 
00313 /**
00314  * @brief Process Configure-Ack packet
00315  * @param[in] context PPP context
00316  * @param[in] configureAckPacket Packet received from the peer
00317  * @return Error code
00318  **/
00319 
00320 error_t ipv6cpProcessConfigureAck(PppContext *context,
00321    const PppConfigurePacket *configureAckPacket)
00322 {
00323    //Debug message
00324    TRACE_INFO("\r\nIPV6CP Receive-Configure-Ack event\r\n");
00325 
00326    //When a packet is received with an invalid Identifier field, the
00327    //packet is silently discarded without affecting the automaton
00328    if(configureAckPacket->identifier != context->ipv6cpFsm.identifier)
00329       return ERROR_WRONG_IDENTIFIER;
00330 
00331    //A valid Configure-Ack packet has been received from the peer
00332    pppRcvConfigureAckEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks);
00333 
00334    //Successful processing
00335    return NO_ERROR;
00336 }
00337 
00338 
00339 /**
00340  * @brief Process Configure-Nak packet
00341  * @param[in] context PPP context
00342  * @param[in] configureNakPacket Packet received from the peer
00343  * @return Error code
00344  **/
00345 
00346 error_t ipv6cpProcessConfigureNak(PppContext *context,
00347    const PppConfigurePacket *configureNakPacket)
00348 {
00349    size_t length;
00350    PppOption *option;
00351 
00352    //Debug message
00353    TRACE_INFO("IPV6CP Receive-Configure-Nak event\r\n");
00354 
00355    //When a packet is received with an invalid Identifier field, the
00356    //packet is silently discarded without affecting the automaton
00357    if(configureNakPacket->identifier != context->ipv6cpFsm.identifier)
00358       return ERROR_WRONG_IDENTIFIER;
00359 
00360    //Retrieve the length of the option list
00361    length = ntohs(configureNakPacket->length) - sizeof(PppConfigurePacket);
00362    //Point to the first option
00363    option = (PppOption *) configureNakPacket->options;
00364 
00365    //Parse configuration options
00366    while(length > 0)
00367    {
00368       //Check option length
00369       if(option->length < sizeof(PppOption))
00370          return ERROR_INVALID_LENGTH;
00371       if(option->length > length)
00372          return ERROR_INVALID_LENGTH;
00373 
00374       //Interface-Identifier option?
00375       if(option->type == IPV6CP_OPTION_INTERFACE_ID)
00376       {
00377          //Cast option
00378          Ipv6cpInterfaceIdOption *interfaceIdOption = (Ipv6cpInterfaceIdOption *) option;
00379 
00380          //Check option length
00381          if(interfaceIdOption->length != sizeof(Ipv6cpInterfaceIdOption))
00382             return ERROR_INVALID_LENGTH;
00383 
00384          //Save interface identifier
00385          context->localConfig.interfaceId = interfaceIdOption->interfaceId;
00386       }
00387 
00388       //Remaining bytes to process
00389       length -= option->length;
00390       //Jump to the next option
00391       option = (PppOption *) ((uint8_t *) option + option->length);
00392    }
00393 
00394    //A valid Configure-Nak or Configure-Reject packet has been received from the peer
00395    pppRcvConfigureNakEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks);
00396 
00397    //Successful processing
00398    return NO_ERROR;
00399 }
00400 
00401 
00402 /**
00403  * @brief Process Configure-Reject packet
00404  * @param[in] context PPP context
00405  * @param[in] configureRejPacket Packet received from the peer
00406  * @return Error code
00407  **/
00408 
00409 error_t ipv6cpProcessConfigureReject(PppContext *context,
00410    const PppConfigurePacket *configureRejPacket)
00411 {
00412    size_t length;
00413    PppOption *option;
00414 
00415    //Debug message
00416    TRACE_INFO("\r\nIPV6CP Receive-Configure-Reject event\r\n");
00417 
00418    //When a packet is received with an invalid Identifier field, the
00419    //packet is silently discarded without affecting the automaton
00420    if(configureRejPacket->identifier != context->ipv6cpFsm.identifier)
00421       return ERROR_WRONG_IDENTIFIER;
00422 
00423    //Retrieve the length of the option list
00424    length = ntohs(configureRejPacket->length) - sizeof(PppConfigurePacket);
00425    //Point to the first option
00426    option = (PppOption *) configureRejPacket->options;
00427 
00428    //Parse configuration options
00429    while(length > 0)
00430    {
00431       //Check option length
00432       if(option->length < sizeof(PppOption))
00433          return ERROR_INVALID_LENGTH;
00434       if(option->length > length)
00435          return ERROR_INVALID_LENGTH;
00436 
00437       //Interface-Identifier option?
00438       if(option->type == IPV6CP_OPTION_INTERFACE_ID)
00439       {
00440          //The option is not recognized by the peer
00441          context->localConfig.interfaceIdRejected = TRUE;
00442       }
00443 
00444       //Remaining bytes to process
00445       length -= option->length;
00446       //Jump to the next option
00447       option = (PppOption *) ((uint8_t *) option + option->length);
00448    }
00449 
00450    //A valid Configure-Nak or Configure-Reject packet has been received from the peer
00451    pppRcvConfigureNakEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks);
00452 
00453    //Successful processing
00454    return NO_ERROR;
00455 }
00456 
00457 
00458 /**
00459  * @brief Process Terminate-Request packet
00460  * @param[in] context PPP context
00461  * @param[in] terminateReqPacket Packet received from the peer
00462  * @return Error code
00463  **/
00464 
00465 error_t ipv6cpProcessTerminateReq(PppContext *context,
00466    const PppTerminatePacket *terminateReqPacket)
00467 {
00468    //Debug message
00469    TRACE_INFO("\r\nIPV6CP Receive-Terminate-Request event\r\n");
00470 
00471    //The Terminate-Request indicates the desire of the peer to close the connection
00472    pppRcvTerminateReqEvent(context, &context->ipv6cpFsm,
00473       &ipv6cpCallbacks, terminateReqPacket);
00474 
00475    //Successful processing
00476    return NO_ERROR;
00477 }
00478 
00479 
00480 /**
00481  * @brief Process Terminate-Ack packet
00482  * @param[in] context PPP context
00483  * @param[in] terminateAckPacket Packet received from the peer
00484  * @return Error code
00485  **/
00486 
00487 error_t ipv6cpProcessTerminateAck(PppContext *context,
00488    const PppTerminatePacket *terminateAckPacket)
00489 {
00490    //Debug message
00491    TRACE_INFO("\r\nIPV6CP Receive-Terminate-Ack event\r\n");
00492 
00493    //The Terminate-Ack packet is usually a response to a Terminate-Request
00494    //packet. This packet may also indicate that the peer is in Closed or
00495    //Stopped states, and serves to re-synchronize the link configuration
00496    pppRcvTerminateAckEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks);
00497 
00498    //Successful processing
00499    return NO_ERROR;
00500 }
00501 
00502 
00503 /**
00504  * @brief Process Code-Reject packet
00505  * @param[in] context PPP context
00506  * @param[in] codeRejPacket Packet received from the peer
00507  * @return Error code
00508  **/
00509 
00510 error_t ipv6cpProcessCodeRej(PppContext *context,
00511    const PppCodeRejPacket *codeRejPacket)
00512 {
00513    size_t length;
00514    PppPacket *packet;
00515 
00516    //Debug message
00517    TRACE_INFO("\r\nIPV6CP Receive-Code-Reject event\r\n");
00518 
00519    //Point to the rejected packet
00520    packet = (PppPacket *) codeRejPacket->rejectedPacket;
00521    //Retrieve the length of the rejected packet
00522    length = ntohs(codeRejPacket->length) - sizeof(PppCodeRejPacket);
00523 
00524    //Make sure the length of the rejected packet is valid
00525    if(length < sizeof(PppPacket))
00526       return ERROR_INVALID_LENGTH;
00527 
00528    //Check whether the rejected value is acceptable or catastrophic
00529    if(packet->code < PPP_CODE_CONFIGURE_REQ ||
00530       packet->code > PPP_CODE_CODE_REJ)
00531    {
00532       //The RXJ+ event arises when the rejected value is acceptable, such
00533       //as a Code-Reject of an extended code, or a Protocol-Reject of a
00534       //NCP. These are within the scope of normal operation
00535       pppRcvCodeRejEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks, TRUE);
00536    }
00537    else
00538    {
00539       //The RXJ- event arises when the rejected value is catastrophic, such
00540       //as a Code-Reject of Configure-Request! This event communicates an
00541       //unrecoverable error that terminates the connection
00542       pppRcvCodeRejEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks, FALSE);
00543    }
00544 
00545    //Successful processing
00546    return NO_ERROR;
00547 }
00548 
00549 
00550 /**
00551  * @brief Process packet with unknown code
00552  * @param[in] context PPP context
00553  * @param[in] packet Un-interpretable packet received from the peer
00554  * @return Error code
00555  **/
00556 
00557 error_t ipv6cpProcessUnknownCode(PppContext *context,
00558    const PppPacket *packet)
00559 {
00560    //Debug message
00561    TRACE_INFO("\r\nIPV6CP Receive-Unknown-Code event\r\n");
00562 
00563    //This event occurs when an un-interpretable packet is received from
00564    //the peer. A Code-Reject packet is sent in response
00565    pppRcvUnknownCodeEvent(context, &context->ipv6cpFsm, &ipv6cpCallbacks, packet);
00566 
00567    //Successful processing
00568    return NO_ERROR;
00569 }
00570 
00571 
00572 /**
00573  * @brief This-Layer-Up callback function
00574  * @param[in] context PPP context
00575  **/
00576 
00577 void ipv6cpThisLayerUp(PppContext *context)
00578 {
00579    NetInterface *interface;
00580    Ipv6Addr ipAddr;
00581 
00582    //Debug message
00583    TRACE_INFO("IPV6CP This-Layer-Up callback\r\n");
00584 
00585    //Debug message
00586    TRACE_INFO("  Local Interface Id = %s\r\n",
00587       eui64AddrToString(&context->localConfig.interfaceId, NULL));
00588    TRACE_INFO("  Peer Interface Id = %s\r\n",
00589       eui64AddrToString(&context->peerConfig.interfaceId, NULL));
00590 
00591    //Point to the underlying interface
00592    interface = context->interface;
00593 
00594    //Generate an IPv6 address from the local interface identifier
00595    ipv6GenerateLinkLocalAddr(&context->localConfig.interfaceId, &ipAddr);
00596 
00597    //Update IPv6 configuration
00598    ipv6SetAddr(interface, 0, &ipAddr, IPV6_ADDR_STATE_PREFERRED,
00599       NDP_INFINITE_LIFETIME, NDP_INFINITE_LIFETIME, TRUE);
00600 
00601    //Generate an IPv6 address from the remote interface identifier
00602    ipv6GenerateLinkLocalAddr(&context->peerConfig.interfaceId, &ipAddr);
00603 
00604    //Update IPv6 configuration
00605    interface->ipv6Context.routerList[0].addr = ipAddr;
00606    interface->ipv6Context.routerList[0].permanent = TRUE;
00607 
00608    //Link is up
00609    interface->linkState = TRUE;
00610 
00611    //Disable interrupts
00612    interface->nicDriver->disableIrq(interface);
00613    //Process link state change event
00614    nicNotifyLinkChange(interface);
00615    //Re-enable interrupts
00616    interface->nicDriver->enableIrq(interface);
00617 }
00618 
00619 
00620 /**
00621  * @brief This-Layer-Down callback function
00622  * @param[in] context PPP context
00623  **/
00624 
00625 void ipv6cpThisLayerDown(PppContext *context)
00626 {
00627    NetInterface *interface;
00628 
00629    //Debug message
00630    TRACE_INFO("IPV6CP This-Layer-Down callback\r\n");
00631 
00632    //Point to the underlying interface
00633    interface = context->interface;
00634 
00635    //Link is up
00636    interface->linkState = FALSE;
00637 
00638    //Disable interrupts
00639    interface->nicDriver->disableIrq(interface);
00640    //Process link state change event
00641    nicNotifyLinkChange(interface);
00642    //Re-enable interrupts
00643    interface->nicDriver->enableIrq(interface);
00644 }
00645 
00646 
00647 /**
00648  * @brief This-Layer-Started callback function
00649  * @param[in] context PPP context
00650  **/
00651 
00652 void ipv6cpThisLayerStarted(PppContext *context)
00653 {
00654    //Debug message
00655    TRACE_INFO("IPV6CP This-Layer-Started callback\r\n");
00656 }
00657 
00658 
00659 /**
00660  * @brief This-Layer-Finished callback function
00661  * @param[in] context PPP context
00662  **/
00663 
00664 void ipv6cpThisLayerFinished(PppContext *context)
00665 {
00666    //Debug message
00667    TRACE_INFO("IPV6CP This-Layer-Finished callback\r\n");
00668 }
00669 
00670 
00671 /**
00672  * @brief Initialize-Restart-Count callback function
00673  * @param[in] context PPP context
00674  * @param[in] value Restart counter value
00675  **/
00676 
00677 void ipv6cpInitRestartCount(PppContext *context, uint_t value)
00678 {
00679    //Debug message
00680    TRACE_INFO("IPV6CP Initialize-Restart-Count callback\r\n");
00681 
00682    //Initialize restart counter
00683    context->ipv6cpFsm.restartCounter = value;
00684 }
00685 
00686 
00687 /**
00688  * @brief Zero-Restart-Count callback function
00689  * @param[in] context PPP context
00690  **/
00691 
00692 void ipv6cpZeroRestartCount(PppContext *context)
00693 {
00694    //Debug message
00695    TRACE_INFO("IPV6CP Zero-Restart-Count callback\r\n");
00696 
00697    //Zero restart counter
00698    context->ipv6cpFsm.restartCounter = 0;
00699 
00700    //The receiver of a Terminate-Request should wait for the peer to
00701    //disconnect, and must not disconnect until at least one Restart
00702    //time has passed after sending a Terminate-Ack
00703    context->ipv6cpFsm.timestamp = osGetSystemTime();
00704 }
00705 
00706 
00707 /**
00708  * @brief Send-Configure-Request callback function
00709  * @param[in] context PPP context
00710  * @return Error code
00711  **/
00712 
00713 error_t ipv6cpSendConfigureReq(PppContext *context)
00714 {
00715    error_t error;
00716    size_t length;
00717    size_t offset;
00718    NetBuffer *buffer;
00719    PppConfigurePacket *configureReqPacket;
00720 
00721    //Debug message
00722    TRACE_INFO("IPV6CP Send-Configure-Request callback\r\n");
00723 
00724    //Allocate a buffer memory to hold the Configure-Request packet
00725    buffer = pppAllocBuffer(PPP_MAX_CONF_REQ_SIZE, &offset);
00726    //Failed to allocate memory?
00727    if(buffer == NULL)
00728       return ERROR_OUT_OF_MEMORY;
00729 
00730    //Point to the Configure-Request packet
00731    configureReqPacket = netBufferAt(buffer, offset);
00732 
00733    //Format packet header
00734    configureReqPacket->code = PPP_CODE_CONFIGURE_REQ;
00735    configureReqPacket->identifier = ++context->ipv6cpFsm.identifier;
00736    configureReqPacket->length = sizeof(PppConfigurePacket);
00737 
00738    //Make sure the Interface-Identifier option has not been previously rejected
00739    if(!context->localConfig.interfaceIdRejected)
00740    {
00741       //Add option
00742       pppAddOption(configureReqPacket, IPV6CP_OPTION_INTERFACE_ID,
00743          &context->localConfig.interfaceId, sizeof(Eui64));
00744    }
00745 
00746    //Save packet length
00747    length = configureReqPacket->length;
00748    //Convert length field to network byte order
00749    configureReqPacket->length = htons(length);
00750 
00751    //Adjust the length of the multi-part buffer
00752    netBufferSetLength(buffer, offset + length);
00753 
00754    //Debug message
00755    TRACE_INFO("Sending Configure-Request packet (%" PRIuSIZE " bytes)...\r\n", length);
00756    //Dump packet contents for debugging purpose
00757    pppDumpPacket((PppPacket *) configureReqPacket, length, PPP_PROTOCOL_IPV6CP);
00758 
00759    //Send PPP frame
00760    error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_IPV6CP);
00761 
00762    //The restart counter is decremented each time a Configure-Request is sent
00763    if(context->ipv6cpFsm.restartCounter > 0)
00764       context->ipv6cpFsm.restartCounter--;
00765 
00766    //Save the time at which the packet was sent
00767    context->ipv6cpFsm.timestamp = osGetSystemTime();
00768 
00769    //Free previously allocated memory block
00770    netBufferFree(buffer);
00771    //Return status code
00772    return error;
00773 }
00774 
00775 
00776 /**
00777  * @brief Send-Configure-Ack callback function
00778  * @param[in] context PPP context
00779  * @param[in] configureReqPacket Configure-Request packet received from the peer
00780  * @return Error code
00781  **/
00782 
00783 error_t ipv6cpSendConfigureAck(PppContext *context,
00784    const PppConfigurePacket *configureReqPacket)
00785 {
00786    //Debug message
00787    TRACE_INFO("IPV6CP Send-Configure-Ack callback\r\n");
00788 
00789    //Send Configure-Ack packet
00790    return pppSendConfigureAckNak(context, configureReqPacket,
00791       PPP_PROTOCOL_IPV6CP, PPP_CODE_CONFIGURE_ACK);
00792 }
00793 
00794 
00795 /**
00796  * @brief Send-Configure-Nak callback function
00797  * @param[in] context PPP context
00798  * @param[in] configureReqPacket Configure-Request packet received from the peer
00799  * @return Error code
00800  **/
00801 
00802 error_t ipv6cpSendConfigureNak(PppContext *context,
00803    const PppConfigurePacket *configureReqPacket)
00804 {
00805    //Debug message
00806    TRACE_INFO("IPV6CP Send-Configure-Nak callback\r\n");
00807 
00808    //Send Configure-Nak packet
00809    return pppSendConfigureAckNak(context, configureReqPacket,
00810       PPP_PROTOCOL_IPV6CP, PPP_CODE_CONFIGURE_NAK);
00811 }
00812 
00813 
00814 /**
00815  * @brief Send-Configure-Reject callback function
00816  * @param[in] context PPP context
00817  * @param[in] configureReqPacket Configure-Request packet received from the peer
00818  * @return Error code
00819  **/
00820 
00821 error_t ipv6cpSendConfigureRej(PppContext *context,
00822    const PppConfigurePacket *configureReqPacket)
00823 {
00824    //Debug message
00825    TRACE_INFO("IPV6CP Send-Configure-Reject callback\r\n");
00826 
00827    //Send Configure-Reject packet
00828    return pppSendConfigureAckNak(context, configureReqPacket,
00829       PPP_PROTOCOL_IPV6CP, PPP_CODE_CONFIGURE_REJ);
00830 }
00831 
00832 
00833 /**
00834  * @brief Send-Terminate-Request callback function
00835  * @param[in] context PPP context
00836  * @return Error code
00837  **/
00838 
00839 error_t ipv6cpSendTerminateReq(PppContext *context)
00840 {
00841    error_t error;
00842 
00843    //Debug message
00844    TRACE_INFO("IPV6CP Send-Terminate-Request callback\r\n");
00845 
00846    //On transmission, the Identifier field must be changed
00847    context->ipv6cpFsm.identifier++;
00848 
00849    //Send Terminate-Request packet
00850    error = pppSendTerminateReq(context, context->ipv6cpFsm.identifier, PPP_PROTOCOL_IPV6CP);
00851 
00852    //The restart counter is decremented each time a Terminate-Request is sent
00853    if(context->ipv6cpFsm.restartCounter > 0)
00854       context->ipv6cpFsm.restartCounter--;
00855 
00856    //Save the time at which the packet was sent
00857    context->ipv6cpFsm.timestamp = osGetSystemTime();
00858 
00859    //Return status code
00860    return error;
00861 }
00862 
00863 
00864 /**
00865  * @brief Send-Terminate-Ack callback function
00866  * @param[in] context PPP context
00867  * @param[in] terminateReqPacket Terminate-Request packet received from the peer
00868  * @return Error code
00869  **/
00870 
00871 error_t ipv6cpSendTerminateAck(PppContext *context,
00872    const PppTerminatePacket *terminateReqPacket)
00873 {
00874    uint8_t identifier;
00875 
00876    //Debug message
00877    TRACE_INFO("IPV6CP Send-Terminate-Ack callback\r\n");
00878 
00879    //Check whether this Terminate-Ack acknowledges the reception of a
00880    //Terminate-Request packet
00881    if(terminateReqPacket != NULL)
00882    {
00883       //The Identifier field of the Terminate-Request is copied into the
00884       //Identifier field of the Terminate-Ack packet
00885       identifier = terminateReqPacket->identifier;
00886    }
00887    else
00888    {
00889       //This Terminate-Ack packet serves to synchronize the automatons
00890       identifier = ++context->ipv6cpFsm.identifier;
00891    }
00892 
00893    //Send Terminate-Ack packet
00894    return pppSendTerminateAck(context, identifier, PPP_PROTOCOL_IPV6CP);
00895 }
00896 
00897 
00898 /**
00899  * @brief Send-Code-Reject callback function
00900  * @param[in] context PPP context
00901  * @param[in] packet Un-interpretable packet received from the peer
00902  * @return Error code
00903  **/
00904 
00905 error_t ipv6cpSendCodeRej(PppContext *context, const PppPacket *packet)
00906 {
00907    //Debug message
00908    TRACE_INFO("IPV6CP Send-Code-Reject callback\r\n");
00909 
00910    //The Identifier field must be changed for each Code-Reject sent
00911    context->ipv6cpFsm.identifier++;
00912 
00913    //Send Code-Reject packet
00914    return pppSendCodeRej(context, packet, context->ipv6cpFsm.identifier, PPP_PROTOCOL_IPV6CP);
00915 }
00916 
00917 
00918 /**
00919  * @brief Parse IPV6CP configuration option
00920  * @param[in] context PPP context
00921  * @param[in] option Option to be checked
00922  * @param[in] inPacketLen Remaining bytes to process in the incoming packet
00923  * @param[out] outPacket Pointer to the Configure-Ack, Nak or Reject packet
00924  * @return Error code
00925  **/
00926 
00927 error_t ipv6cpParseOption(PppContext *context, PppOption *option,
00928    size_t inPacketLen, PppConfigurePacket *outPacket)
00929 {
00930    error_t error;
00931 
00932    //Malformed IPV6CP packet?
00933    if(inPacketLen < sizeof(PppOption))
00934       return ERROR_INVALID_LENGTH;
00935 
00936    //Check option length
00937    if(option->length < sizeof(PppOption))
00938       return ERROR_INVALID_LENGTH;
00939    if(option->length > inPacketLen)
00940       return ERROR_INVALID_LENGTH;
00941 
00942    //Check option type
00943    switch(option->type)
00944    {
00945    case IPV6CP_OPTION_INTERFACE_ID:
00946       //Check Interface-Identifier option
00947       error = ipv6cpParseInterfaceIdOption(context, (Ipv6cpInterfaceIdOption *) option, outPacket);
00948       break;
00949    default:
00950       //If some configuration options received in the Configure-Request are not
00951       //recognizable or not acceptable for negotiation, then the implementation
00952       //must transmit a Configure-Reject
00953       if(outPacket->code == PPP_CODE_CONFIGURE_REJ)
00954       {
00955          //The options field of the Configure-Reject packet is filled
00956          //with the unrecognized options from the Configure-Request
00957          pppAddOption(outPacket, option->type, option->data,
00958             option->length - sizeof(PppOption));
00959       }
00960 
00961       //The option is not acceptable for negotiation
00962       error = ERROR_INVALID_TYPE;
00963       break;
00964    }
00965 
00966    //Return status code
00967    return error;
00968 }
00969 
00970 
00971 /**
00972  * @brief Parse Interface-Identifier option
00973  * @param[in] context PPP context
00974  * @param[in] option Option to be checked
00975  * @param[out] outPacket Pointer to the Configure-Nak or Configure-Reject packet
00976  * @return Error code
00977  **/
00978 
00979 error_t ipv6cpParseInterfaceIdOption(PppContext *context,
00980    Ipv6cpInterfaceIdOption *option, PppConfigurePacket *outPacket)
00981 {
00982    error_t error;
00983 
00984    //Check length field
00985    if(option->length == sizeof(Ipv6cpInterfaceIdOption))
00986    {
00987       //Check whether the option value is acceptable
00988       if(!eui64CompAddr(&option->interfaceId, &EUI64_UNSPECIFIED_ADDR))
00989       {
00990          //If every configuration option received in the Configure-Request is
00991          //recognizable and all values are acceptable, then the implementation
00992          //must transmit a Configure-Ack
00993          if(outPacket != NULL && outPacket->code == PPP_CODE_CONFIGURE_ACK)
00994          {
00995             //Save interface identifier
00996             context->peerConfig.interfaceId = option->interfaceId;
00997 
00998             //The options field of the Configure-Ack packet contains the
00999             //configuration options that the sender is acknowledging
01000             pppAddOption(outPacket, IPV6CP_OPTION_INTERFACE_ID,
01001                &option->interfaceId, option->length - sizeof(PppOption));
01002          }
01003 
01004          //The value is acceptable
01005          error = NO_ERROR;
01006       }
01007       else
01008       {
01009          //If all configuration options are recognizable, but some values are not
01010          //acceptable, then the implementation must transmit a Configure-Nak
01011          if(outPacket != NULL && outPacket->code == PPP_CODE_CONFIGURE_NAK)
01012          {
01013             //The option must be modified to a value acceptable to the
01014             //Configure-Nak sender
01015             pppAddOption(outPacket, IPV6CP_OPTION_INTERFACE_ID,
01016                &context->peerConfig.interfaceId, sizeof(Eui64));
01017          }
01018 
01019          //The value is not acceptable
01020          error = ERROR_INVALID_VALUE;
01021       }
01022    }
01023    else
01024    {
01025       //Invalid length field
01026       error = ERROR_INVALID_LENGTH;
01027    }
01028 
01029    //Return status code
01030    return error;
01031 }
01032 
01033 #endif
01034