Webserver+3d print
cyclone_tcp/ppp/ipcp.c
- Committer:
- Sergunb
- Date:
- 2017-02-04
- Revision:
- 0:8918a71cdbe9
File content as of revision 0:8918a71cdbe9:
/** * @file ipcp.c * @brief IPCP (PPP Internet Protocol Control Protocol) * * @section License * * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. * * This file is part of CycloneTCP Open. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * @author Oryx Embedded SARL (www.oryx-embedded.com) * @version 1.7.6 **/ //Switch to the appropriate trace level #define TRACE_LEVEL PPP_TRACE_LEVEL //Dependencies #include "core/net.h" #include "ipv4/ipv4.h" #include "ppp/ppp_fsm.h" #include "ppp/ppp_misc.h" #include "ppp/ppp_debug.h" #include "ppp/ipcp.h" #include "debug.h" //Check TCP/IP stack configuration #if (PPP_SUPPORT == ENABLED && IPV4_SUPPORT == ENABLED) /** * @brief IPCP FSM callbacks **/ const PppCallbacks ipcpCallbacks = { ipcpThisLayerUp, ipcpThisLayerDown, ipcpThisLayerStarted, ipcpThisLayerFinished, ipcpInitRestartCount, ipcpZeroRestartCount, ipcpSendConfigureReq, ipcpSendConfigureAck, ipcpSendConfigureNak, ipcpSendConfigureRej, ipcpSendTerminateReq, ipcpSendTerminateAck, ipcpSendCodeRej, NULL }; /** * @brief IPCP Open event * @param[in] context PPP context * @return Error code **/ error_t ipcpOpen(PppContext *context) { //Debug message TRACE_INFO("\r\nIPCP Open event\r\n"); //The link is administratively available for traffic pppOpenEvent(context, &context->ipcpFsm, &ipcpCallbacks); //The lower layer is ready to carry packets pppUpEvent(context, &context->ipcpFsm, &ipcpCallbacks); //Successful processing return NO_ERROR; } /** * @brief IPCP Close event * @param[in] context PPP context * @return Error code **/ error_t ipcpClose(PppContext *context) { //Debug message TRACE_INFO("\r\nIPCP Close event\r\n"); //The lower layer is no longer ready to carry packets pppDownEvent(context, &context->ipcpFsm, &ipcpCallbacks); //The link is no longer available for traffic pppCloseEvent(context, &context->ipcpFsm, &ipcpCallbacks); //Successful processing return NO_ERROR; } /** * @brief IPCP timer handler * * This routine must be periodically called by the TCP/IP stack to * manage retransmissions * * @param[in] context PPP context **/ void ipcpTick(PppContext *context) { //Check whether the restart timer is running if(context->ipcpFsm.state >= PPP_STATE_4_CLOSING && context->ipcpFsm.state <= PPP_STATE_8_ACK_SENT) { //Get current time systime_t time = osGetSystemTime(); //Check restart timer if((time - context->ipcpFsm.timestamp) >= PPP_RESTART_TIMER) { //Debug message TRACE_INFO("\r\nIPCP Timeout event\r\n"); //The restart timer is used to retransmit Configure-Request //and Terminate-Request packets pppTimeoutEvent(context, &context->ipcpFsm, &ipcpCallbacks); } } } /** * @brief Process an incoming IPCP packet * @param[in] context PPP context * @param[in] packet IPCP packet received from the peer * @param[in] length Length of the packet, in bytes **/ void ipcpProcessPacket(PppContext *context, const PppPacket *packet, size_t length) { //Ensure the length of the incoming IPCP packet is valid if(length < sizeof(PppPacket)) return; //Check the length field if(ntohs(packet->length) > length) return; if(ntohs(packet->length) < sizeof(PppPacket)) return; //Save the length of the IPCP packet length = ntohs(packet->length); //Debug message TRACE_INFO("IPCP packet received (%" PRIuSIZE " bytes)...\r\n", length); //Dump IPCP packet contents for debugging purpose pppDumpPacket(packet, length, PPP_PROTOCOL_IPCP); //Check IPCP code field switch(packet->code) { //Configure-Request packet? case PPP_CODE_CONFIGURE_REQ: //Process Configure-Request packet ipcpProcessConfigureReq(context, (PppConfigurePacket *) packet); break; //Configure-Ack packet? case PPP_CODE_CONFIGURE_ACK: //Process Configure-Ack packet ipcpProcessConfigureAck(context, (PppConfigurePacket *) packet); break; //Configure-Nak packet? case PPP_CODE_CONFIGURE_NAK: //Process Configure-Nak packet ipcpProcessConfigureNak(context, (PppConfigurePacket *) packet); break; //Configure-Reject packet? case PPP_CODE_CONFIGURE_REJ: //Process Configure-Reject packet ipcpProcessConfigureReject(context, (PppConfigurePacket *) packet); break; //Terminate-Request packet? case PPP_CODE_TERMINATE_REQ: //Process Terminate-Request packet ipcpProcessTerminateReq(context, (PppTerminatePacket *) packet); break; //Terminate-Ack packet? case PPP_CODE_TERMINATE_ACK: //Process Terminate-Ack packet ipcpProcessTerminateAck(context, (PppTerminatePacket *) packet); break; //Code-Reject packet? case PPP_CODE_CODE_REJ: //Process Code-Reject packet ipcpProcessCodeRej(context, (PppCodeRejPacket *) packet); break; //Unknown code field default: //The packet is un-interpretable ipcpProcessUnknownCode(context, packet); break; } } /** * @brief Process Configure-Request packet * @param[in] context PPP context * @param[in] configureReqPacket Packet received from the peer * @return Error code **/ error_t ipcpProcessConfigureReq(PppContext *context, const PppConfigurePacket *configureReqPacket) { error_t error; size_t length; bool_t notRecognizable; bool_t notAcceptable; PppOption *option; //Debug message TRACE_INFO("\r\nIPCP Receive-Configure-Request event\r\n"); //Initialize variables error = NO_ERROR; notRecognizable = FALSE; notAcceptable = FALSE; //Retrieve the length of the option list length = ntohs(configureReqPacket->length) - sizeof(PppConfigurePacket); //Point to the first option option = (PppOption *) configureReqPacket->options; //Parse configuration options while(length > 0) { //Parse current option error = ipcpParseOption(context, option, length, NULL); //Any error to report? if(error == ERROR_INVALID_TYPE) { //Option not recognizable notRecognizable = TRUE; //Catch error error = NO_ERROR; } else if(error == ERROR_INVALID_VALUE) { //Option not acceptable for configuration notAcceptable = TRUE; //Catch error error = NO_ERROR; } else if(error) { //Malformed Configure-Request packet break; } //Remaining bytes to process length -= option->length; //Jump to the next option option = (PppOption *) ((uint8_t *) option + option->length); } //Valid Configure-Request packet received from the peer? if(!error) { //Check flags if(notRecognizable) { //If some configuration options received in the Configure-Request are not //recognizable or not acceptable for negotiation, then the implementation //must transmit a Configure-Reject pppRcvConfigureReqEvent(context, &context->ipcpFsm, &ipcpCallbacks, configureReqPacket, PPP_CODE_CONFIGURE_REJ); } else if(notAcceptable) { //If all configuration options are recognizable, but some values are not //acceptable, then the implementation must transmit a Configure-Nak pppRcvConfigureReqEvent(context, &context->ipcpFsm, &ipcpCallbacks, configureReqPacket, PPP_CODE_CONFIGURE_NAK); } else { //If every configuration option received in the Configure-Request is //recognizable and all values are acceptable, then the implementation //must transmit a Configure-Ack pppRcvConfigureReqEvent(context, &context->ipcpFsm, &ipcpCallbacks, configureReqPacket, PPP_CODE_CONFIGURE_ACK); } } //Return status code return error; } /** * @brief Process Configure-Ack packet * @param[in] context PPP context * @param[in] configureAckPacket Packet received from the peer * @return Error code **/ error_t ipcpProcessConfigureAck(PppContext *context, const PppConfigurePacket *configureAckPacket) { //Debug message TRACE_INFO("\r\nIPCP Receive-Configure-Ack event\r\n"); //When a packet is received with an invalid Identifier field, the //packet is silently discarded without affecting the automaton if(configureAckPacket->identifier != context->ipcpFsm.identifier) return ERROR_WRONG_IDENTIFIER; //A valid Configure-Ack packet has been received from the peer pppRcvConfigureAckEvent(context, &context->ipcpFsm, &ipcpCallbacks); //Successful processing return NO_ERROR; } /** * @brief Process Configure-Nak packet * @param[in] context PPP context * @param[in] configureNakPacket Packet received from the peer * @return Error code **/ error_t ipcpProcessConfigureNak(PppContext *context, const PppConfigurePacket *configureNakPacket) { size_t length; PppOption *option; //Debug message TRACE_INFO("IPCP Receive-Configure-Nak event\r\n"); //When a packet is received with an invalid Identifier field, the //packet is silently discarded without affecting the automaton if(configureNakPacket->identifier != context->ipcpFsm.identifier) return ERROR_WRONG_IDENTIFIER; //Retrieve the length of the option list length = ntohs(configureNakPacket->length) - sizeof(PppConfigurePacket); //Point to the first option option = (PppOption *) configureNakPacket->options; //Parse configuration options while(length > 0) { //Check option length if(option->length < sizeof(PppOption)) return ERROR_INVALID_LENGTH; if(option->length > length) return ERROR_INVALID_LENGTH; //IP-Address option? if(option->type == IPCP_OPTION_IP_ADDRESS) { //Cast option IpcpIpAddressOption *ipAddressOption = (IpcpIpAddressOption *) option; //Check option length if(ipAddressOption->length != sizeof(IpcpIpAddressOption)) return ERROR_INVALID_LENGTH; //Save IP address context->localConfig.ipAddr = ipAddressOption->ipAddr; } //Primary-DNS-Server-Address option? else if(option->type == IPCP_OPTION_PRIMARY_DNS) { //Cast option IpcpPrimaryDnsOption *primaryDns = (IpcpPrimaryDnsOption *) option; //Check option length if(primaryDns->length != sizeof(IpcpPrimaryDnsOption)) return ERROR_INVALID_LENGTH; //Save primary DNS server address context->localConfig.primaryDns = primaryDns->ipAddr; } //Secondary-DNS-Server-Address option? else if(option->type == IPCP_OPTION_SECONDARY_DNS) { //Cast option IpcpSecondaryDnsOption *secondaryDns = (IpcpSecondaryDnsOption *) option; //Check option length if(secondaryDns->length != sizeof(IpcpSecondaryDnsOption)) return ERROR_INVALID_LENGTH; //Save secondary DNS server address context->localConfig.secondaryDns = secondaryDns->ipAddr; } //Remaining bytes to process length -= option->length; //Jump to the next option option = (PppOption *) ((uint8_t *) option + option->length); } //A valid Configure-Nak or Configure-Reject packet has been received from the peer pppRcvConfigureNakEvent(context, &context->ipcpFsm, &ipcpCallbacks); //Successful processing return NO_ERROR; } /** * @brief Process Configure-Reject packet * @param[in] context PPP context * @param[in] configureRejPacket Packet received from the peer * @return Error code **/ error_t ipcpProcessConfigureReject(PppContext *context, const PppConfigurePacket *configureRejPacket) { size_t length; PppOption *option; //Debug message TRACE_INFO("\r\nIPCP Receive-Configure-Reject event\r\n"); //When a packet is received with an invalid Identifier field, the //packet is silently discarded without affecting the automaton if(configureRejPacket->identifier != context->ipcpFsm.identifier) return ERROR_WRONG_IDENTIFIER; //Retrieve the length of the option list length = ntohs(configureRejPacket->length) - sizeof(PppConfigurePacket); //Point to the first option option = (PppOption *) configureRejPacket->options; //Parse configuration options while(length > 0) { //Check option length if(option->length < sizeof(PppOption)) return ERROR_INVALID_LENGTH; if(option->length > length) return ERROR_INVALID_LENGTH; //IP-Address option? if(option->type == IPCP_OPTION_IP_ADDRESS) { //The option is not recognized by the peer context->localConfig.ipAddrRejected = TRUE; } //Primary-DNS-Server-Address option? else if(option->type == IPCP_OPTION_PRIMARY_DNS) { //The option is not recognized by the peer context->localConfig.primaryDnsRejected = TRUE; } //Secondary-DNS-Server-Address option? else if(option->type == IPCP_OPTION_SECONDARY_DNS) { //The option is not recognized by the peer context->localConfig.secondaryDnsRejected = TRUE; } //Remaining bytes to process length -= option->length; //Jump to the next option option = (PppOption *) ((uint8_t *) option + option->length); } //A valid Configure-Nak or Configure-Reject packet has been received from the peer pppRcvConfigureNakEvent(context, &context->ipcpFsm, &ipcpCallbacks); //Successful processing return NO_ERROR; } /** * @brief Process Terminate-Request packet * @param[in] context PPP context * @param[in] terminateReqPacket Packet received from the peer * @return Error code **/ error_t ipcpProcessTerminateReq(PppContext *context, const PppTerminatePacket *terminateReqPacket) { //Debug message TRACE_INFO("\r\nIPCP Receive-Terminate-Request event\r\n"); //The Terminate-Request indicates the desire of the peer to close the connection pppRcvTerminateReqEvent(context, &context->ipcpFsm, &ipcpCallbacks, terminateReqPacket); //Successful processing return NO_ERROR; } /** * @brief Process Terminate-Ack packet * @param[in] context PPP context * @param[in] terminateAckPacket Packet received from the peer * @return Error code **/ error_t ipcpProcessTerminateAck(PppContext *context, const PppTerminatePacket *terminateAckPacket) { //Debug message TRACE_INFO("\r\nIPCP Receive-Terminate-Ack event\r\n"); //The Terminate-Ack packet is usually a response to a Terminate-Request //packet. This packet may also indicate that the peer is in Closed or //Stopped states, and serves to re-synchronize the link configuration pppRcvTerminateAckEvent(context, &context->ipcpFsm, &ipcpCallbacks); //Successful processing return NO_ERROR; } /** * @brief Process Code-Reject packet * @param[in] context PPP context * @param[in] codeRejPacket Packet received from the peer * @return Error code **/ error_t ipcpProcessCodeRej(PppContext *context, const PppCodeRejPacket *codeRejPacket) { size_t length; PppPacket *packet; //Debug message TRACE_INFO("\r\nIPCP Receive-Code-Reject event\r\n"); //Point to the rejected packet packet = (PppPacket *) codeRejPacket->rejectedPacket; //Retrieve the length of the rejected packet length = ntohs(codeRejPacket->length) - sizeof(PppCodeRejPacket); //Make sure the length of the rejected packet is valid if(length < sizeof(PppPacket)) return ERROR_INVALID_LENGTH; //Check whether the rejected value is acceptable or catastrophic if(packet->code < PPP_CODE_CONFIGURE_REQ || packet->code > PPP_CODE_CODE_REJ) { //The RXJ+ event arises when the rejected value is acceptable, such //as a Code-Reject of an extended code, or a Protocol-Reject of a //NCP. These are within the scope of normal operation pppRcvCodeRejEvent(context, &context->ipcpFsm, &ipcpCallbacks, TRUE); } else { //The RXJ- event arises when the rejected value is catastrophic, such //as a Code-Reject of Configure-Request! This event communicates an //unrecoverable error that terminates the connection pppRcvCodeRejEvent(context, &context->ipcpFsm, &ipcpCallbacks, FALSE); } //Successful processing return NO_ERROR; } /** * @brief Process packet with unknown code * @param[in] context PPP context * @param[in] packet Un-interpretable packet received from the peer * @return Error code **/ error_t ipcpProcessUnknownCode(PppContext *context, const PppPacket *packet) { //Debug message TRACE_INFO("\r\nIPCP Receive-Unknown-Code event\r\n"); //This event occurs when an un-interpretable packet is received from //the peer. A Code-Reject packet is sent in response pppRcvUnknownCodeEvent(context, &context->ipcpFsm, &ipcpCallbacks, packet); //Successful processing return NO_ERROR; } /** * @brief This-Layer-Up callback function * @param[in] context PPP context **/ void ipcpThisLayerUp(PppContext *context) { NetInterface *interface; //Debug message TRACE_INFO("IPCP This-Layer-Up callback\r\n"); //Debug message TRACE_INFO(" Local IP Addr = %s\r\n", ipv4AddrToString(context->localConfig.ipAddr, NULL)); TRACE_INFO(" Peer IP Addr = %s\r\n", ipv4AddrToString(context->peerConfig.ipAddr, NULL)); TRACE_INFO(" Primary DNS = %s\r\n", ipv4AddrToString(context->localConfig.primaryDns, NULL)); TRACE_INFO(" Secondary DNS = %s\r\n", ipv4AddrToString(context->localConfig.secondaryDns, NULL)); //Point to the underlying interface interface = context->interface; //Update IPv4 configuration interface->ipv4Context.addr = context->localConfig.ipAddr; interface->ipv4Context.addrState = IPV4_ADDR_STATE_VALID; interface->ipv4Context.defaultGateway = context->peerConfig.ipAddr; //Update the list of DNS servers interface->ipv4Context.dnsServerList[0] = context->localConfig.primaryDns; #if (IPV4_DNS_SERVER_LIST_SIZE >= 2) interface->ipv4Context.dnsServerList[1] = context->localConfig.secondaryDns; #endif //All the outgoing traffic will be routed to the other end of the link interface->ipv4Context.subnetMask = IPCP_DEFAULT_SUBNET_MASK; //Link is up interface->linkState = TRUE; //Disable interrupts interface->nicDriver->disableIrq(interface); //Process link state change event nicNotifyLinkChange(interface); //Re-enable interrupts interface->nicDriver->enableIrq(interface); } /** * @brief This-Layer-Down callback function * @param[in] context PPP context **/ void ipcpThisLayerDown(PppContext *context) { NetInterface *interface; //Debug message TRACE_INFO("IPCP This-Layer-Down callback\r\n"); //Point to the underlying interface interface = context->interface; //Link is up interface->linkState = FALSE; //Disable interrupts interface->nicDriver->disableIrq(interface); //Process link state change event nicNotifyLinkChange(interface); //Re-enable interrupts interface->nicDriver->enableIrq(interface); } /** * @brief This-Layer-Started callback function * @param[in] context PPP context **/ void ipcpThisLayerStarted(PppContext *context) { //Debug message TRACE_INFO("IPCP This-Layer-Started callback\r\n"); } /** * @brief This-Layer-Finished callback function * @param[in] context PPP context **/ void ipcpThisLayerFinished(PppContext *context) { //Debug message TRACE_INFO("IPCP This-Layer-Finished callback\r\n"); } /** * @brief Initialize-Restart-Count callback function * @param[in] context PPP context * @param[in] value Restart counter value **/ void ipcpInitRestartCount(PppContext *context, uint_t value) { //Debug message TRACE_INFO("IPCP Initialize-Restart-Count callback\r\n"); //Initialize restart counter context->ipcpFsm.restartCounter = value; } /** * @brief Zero-Restart-Count callback function * @param[in] context PPP context **/ void ipcpZeroRestartCount(PppContext *context) { //Debug message TRACE_INFO("IPCP Zero-Restart-Count callback\r\n"); //Zero restart counter context->ipcpFsm.restartCounter = 0; //The receiver of a Terminate-Request should wait for the peer to //disconnect, and must not disconnect until at least one Restart //time has passed after sending a Terminate-Ack context->ipcpFsm.timestamp = osGetSystemTime(); } /** * @brief Send-Configure-Request callback function * @param[in] context PPP context * @return Error code **/ error_t ipcpSendConfigureReq(PppContext *context) { error_t error; size_t length; size_t offset; NetBuffer *buffer; PppConfigurePacket *configureReqPacket; //Debug message TRACE_INFO("IPCP Send-Configure-Request callback\r\n"); //Allocate a buffer memory to hold the Configure-Request packet buffer = pppAllocBuffer(PPP_MAX_CONF_REQ_SIZE, &offset); //Failed to allocate memory? if(buffer == NULL) return ERROR_OUT_OF_MEMORY; //Point to the Configure-Request packet configureReqPacket = netBufferAt(buffer, offset); //Format packet header configureReqPacket->code = PPP_CODE_CONFIGURE_REQ; configureReqPacket->identifier = ++context->ipcpFsm.identifier; configureReqPacket->length = sizeof(PppConfigurePacket); //Make sure the IP-Address option has not been previously rejected if(!context->localConfig.ipAddrRejected) { //Add option pppAddOption(configureReqPacket, IPCP_OPTION_IP_ADDRESS, &context->localConfig.ipAddr, sizeof(Ipv4Addr)); } //Make sure the Primary-DNS-Server-Address option has not been //previously rejected if(!context->localConfig.primaryDnsRejected) { //Add option pppAddOption(configureReqPacket, IPCP_OPTION_PRIMARY_DNS, &context->localConfig.primaryDns, sizeof(Ipv4Addr)); } //Make sure the Secondary-DNS-Server-Address option has not been //previously rejected if(!context->localConfig.secondaryDnsRejected) { //Add option pppAddOption(configureReqPacket, IPCP_OPTION_SECONDARY_DNS, &context->localConfig.secondaryDns, sizeof(Ipv4Addr)); } //Save packet length length = configureReqPacket->length; //Convert length field to network byte order configureReqPacket->length = htons(length); //Adjust the length of the multi-part buffer netBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending Configure-Request packet (%" PRIuSIZE " bytes)...\r\n", length); //Dump packet contents for debugging purpose pppDumpPacket((PppPacket *) configureReqPacket, length, PPP_PROTOCOL_IPCP); //Send PPP frame error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_IPCP); //The restart counter is decremented each time a Configure-Request is sent if(context->ipcpFsm.restartCounter > 0) context->ipcpFsm.restartCounter--; //Save the time at which the packet was sent context->ipcpFsm.timestamp = osGetSystemTime(); //Free previously allocated memory block netBufferFree(buffer); //Return status code return error; } /** * @brief Send-Configure-Ack callback function * @param[in] context PPP context * @param[in] configureReqPacket Configure-Request packet received from the peer * @return Error code **/ error_t ipcpSendConfigureAck(PppContext *context, const PppConfigurePacket *configureReqPacket) { //Debug message TRACE_INFO("IPCP Send-Configure-Ack callback\r\n"); //Send Configure-Ack packet return pppSendConfigureAckNak(context, configureReqPacket, PPP_PROTOCOL_IPCP, PPP_CODE_CONFIGURE_ACK); } /** * @brief Send-Configure-Nak callback function * @param[in] context PPP context * @param[in] configureReqPacket Configure-Request packet received from the peer * @return Error code **/ error_t ipcpSendConfigureNak(PppContext *context, const PppConfigurePacket *configureReqPacket) { //Debug message TRACE_INFO("IPCP Send-Configure-Nak callback\r\n"); //Send Configure-Nak packet return pppSendConfigureAckNak(context, configureReqPacket, PPP_PROTOCOL_IPCP, PPP_CODE_CONFIGURE_NAK); } /** * @brief Send-Configure-Reject callback function * @param[in] context PPP context * @param[in] configureReqPacket Configure-Request packet received from the peer * @return Error code **/ error_t ipcpSendConfigureRej(PppContext *context, const PppConfigurePacket *configureReqPacket) { //Debug message TRACE_INFO("IPCP Send-Configure-Reject callback\r\n"); //Send Configure-Reject packet return pppSendConfigureAckNak(context, configureReqPacket, PPP_PROTOCOL_IPCP, PPP_CODE_CONFIGURE_REJ); } /** * @brief Send-Terminate-Request callback function * @param[in] context PPP context * @return Error code **/ error_t ipcpSendTerminateReq(PppContext *context) { error_t error; //Debug message TRACE_INFO("IPCP Send-Terminate-Request callback\r\n"); //On transmission, the Identifier field must be changed context->ipcpFsm.identifier++; //Send Terminate-Request packet error = pppSendTerminateReq(context, context->ipcpFsm.identifier, PPP_PROTOCOL_IPCP); //The restart counter is decremented each time a Terminate-Request is sent if(context->ipcpFsm.restartCounter > 0) context->ipcpFsm.restartCounter--; //Save the time at which the packet was sent context->ipcpFsm.timestamp = osGetSystemTime(); //Return status code return error; } /** * @brief Send-Terminate-Ack callback function * @param[in] context PPP context * @param[in] terminateReqPacket Terminate-Request packet received from the peer * @return Error code **/ error_t ipcpSendTerminateAck(PppContext *context, const PppTerminatePacket *terminateReqPacket) { uint8_t identifier; //Debug message TRACE_INFO("IPCP Send-Terminate-Ack callback\r\n"); //Check whether this Terminate-Ack acknowledges the reception of a //Terminate-Request packet if(terminateReqPacket != NULL) { //The Identifier field of the Terminate-Request is copied into the //Identifier field of the Terminate-Ack packet identifier = terminateReqPacket->identifier; } else { //This Terminate-Ack packet serves to synchronize the automatons identifier = ++context->ipcpFsm.identifier; } //Send Terminate-Ack packet return pppSendTerminateAck(context, identifier, PPP_PROTOCOL_IPCP); } /** * @brief Send-Code-Reject callback function * @param[in] context PPP context * @param[in] packet Un-interpretable packet received from the peer * @return Error code **/ error_t ipcpSendCodeRej(PppContext *context, const PppPacket *packet) { //Debug message TRACE_INFO("IPCP Send-Code-Reject callback\r\n"); //The Identifier field must be changed for each Code-Reject sent context->ipcpFsm.identifier++; //Send Code-Reject packet return pppSendCodeRej(context, packet, context->ipcpFsm.identifier, PPP_PROTOCOL_IPCP); } /** * @brief Parse IPCP configuration option * @param[in] context PPP context * @param[in] option Option to be checked * @param[in] inPacketLen Remaining bytes to process in the incoming packet * @param[out] outPacket Pointer to the Configure-Ack, Nak or Reject packet * @return Error code **/ error_t ipcpParseOption(PppContext *context, PppOption *option, size_t inPacketLen, PppConfigurePacket *outPacket) { error_t error; //Malformed IPCP packet? if(inPacketLen < sizeof(PppOption)) return ERROR_INVALID_LENGTH; //Check option length if(option->length < sizeof(PppOption)) return ERROR_INVALID_LENGTH; if(option->length > inPacketLen) return ERROR_INVALID_LENGTH; //Check option type switch(option->type) { case IPCP_OPTION_IP_ADDRESS: //Check IP-Address option error = ipcpParseIpAddressOption(context, (IpcpIpAddressOption *) option, outPacket); break; default: //If some configuration options received in the Configure-Request are not //recognizable or not acceptable for negotiation, then the implementation //must transmit a Configure-Reject if(outPacket->code == PPP_CODE_CONFIGURE_REJ) { //The options field of the Configure-Reject packet is filled //with the unrecognized options from the Configure-Request pppAddOption(outPacket, option->type, option->data, option->length - sizeof(PppOption)); } //The option is not acceptable for negotiation error = ERROR_INVALID_TYPE; break; } //Return status code return error; } /** * @brief Parse IP-Address option * @param[in] context PPP context * @param[in] option Option to be checked * @param[out] outPacket Pointer to the Configure-Nak or Configure-Reject packet * @return Error code **/ error_t ipcpParseIpAddressOption(PppContext *context, IpcpIpAddressOption *option, PppConfigurePacket *outPacket) { error_t error; //Check length field if(option->length == sizeof(IpcpIpAddressOption)) { //Check whether the option value is acceptable if(option->ipAddr != IPV4_UNSPECIFIED_ADDR) { //If every configuration option received in the Configure-Request is //recognizable and all values are acceptable, then the implementation //must transmit a Configure-Ack if(outPacket != NULL && outPacket->code == PPP_CODE_CONFIGURE_ACK) { //Save IP address context->peerConfig.ipAddr = option->ipAddr; //The options field of the Configure-Ack packet contains the //configuration options that the sender is acknowledging pppAddOption(outPacket, IPCP_OPTION_IP_ADDRESS, (void *) &option->ipAddr, option->length - sizeof(PppOption)); } //The value is acceptable error = NO_ERROR; } else { //If all configuration options are recognizable, but some values are not //acceptable, then the implementation must transmit a Configure-Nak if(outPacket != NULL && outPacket->code == PPP_CODE_CONFIGURE_NAK) { //The option must be modified to a value acceptable to the //Configure-Nak sender pppAddOption(outPacket, IPCP_OPTION_IP_ADDRESS, &context->peerConfig.ipAddr, sizeof(Ipv4Addr)); } //The value is not acceptable error = ERROR_INVALID_VALUE; } } else { //Invalid length field error = ERROR_INVALID_LENGTH; } //Return status code return error; } #endif