error_t pppSendEchoRep(PppContext *context, const PppEchoPacket *echoReqPacket, PppProtocol protocol) { error_t error; size_t length; size_t offset; NetBuffer *buffer; PppEchoPacket *echoRepPacket; //Retrieve the length of the Echo-Request packet length = ntohs(echoReqPacket->length); //Make sure the length is valid if(length < sizeof(PppEchoPacket)) return ERROR_INVALID_LENGTH; if(length > context->peerConfig.mru) return ERROR_INVALID_LENGTH; //Allocate a buffer memory to hold the Echo-Reply packet buffer = pppAllocBuffer(sizeof(PppEchoPacket), &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the Echo-Reply packet echoRepPacket = netBufferAt(buffer, offset); //Format packet header echoRepPacket->code = PPP_CODE_CODE_REJ; echoRepPacket->identifier = echoReqPacket->identifier; echoRepPacket->length = htons(length); echoRepPacket->magicNumber = context->localConfig.magicNumber; //The data field of the Echo-Request packet is copied into the data //field of the Echo-Reply packet error = netBufferAppend(buffer, echoReqPacket->data, length - sizeof(PppEchoPacket)); //Check status code if(!error) { //Debug message TRACE_INFO("Sending Echo-Reply packet (%" PRIuSIZE " bytes)...\r\n", length); //Send PPP frame error = pppSendFrame(context->interface, buffer, offset, protocol); } //Free previously allocated memory block netBufferFree(buffer); //Return status code return error; }
error_t pppSendProtocolRej(PppContext *context, uint8_t identifier, uint16_t protocol, const uint8_t *information, size_t length) { error_t error; size_t offset; NetBuffer *buffer; PppProtocolRejPacket *protocolRejPacket; //Calculate the length of the Protocol-Reject packet length += sizeof(PppProtocolRejPacket); //The Rejected-Information must be truncated to comply with //the peer's established MRU length = MIN(length, context->peerConfig.mru); //Allocate a buffer memory to hold the Protocol-Reject packet buffer = pppAllocBuffer(sizeof(PppProtocolRejPacket), &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the Protocol-Reject packet protocolRejPacket = netBufferAt(buffer, offset); //Format packet header protocolRejPacket->code = PPP_CODE_PROTOCOL_REJ; protocolRejPacket->identifier = identifier; protocolRejPacket->length = htons(length); protocolRejPacket->rejectedProtocol = htons(protocol); //The Rejected-Information field contains a copy of the //packet which is being rejected error = netBufferAppend(buffer, information, length - sizeof(PppProtocolRejPacket)); //Check status code if(!error) { //Debug message TRACE_INFO("Sending Protocol-Reject packet (%" PRIuSIZE " bytes)...\r\n", length); //Send PPP frame error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_LCP); } //Free previously allocated memory block netBufferFree(buffer); //Return status code return error; }
error_t chapSendResponse(PppContext *context, const uint8_t *value) { error_t error; size_t n; size_t length; size_t offset; NetBuffer *buffer; ChapResponsePacket *responsePacket; //Retrieve the length of the username n = strlen(context->username); //Calculate the length of the Response packet length = sizeof(ChapResponsePacket) + MD5_DIGEST_SIZE + n; //Allocate a buffer memory to hold the Response packet buffer = pppAllocBuffer(length, &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the Response packet responsePacket = netBufferAt(buffer, offset); //Format packet header responsePacket->code = CHAP_CODE_RESPONSE; responsePacket->identifier = context->chapFsm.peerIdentifier; responsePacket->length = htons(length); responsePacket->valueSize = MD5_DIGEST_SIZE; //Copy the Response value memcpy(responsePacket->value, value, MD5_DIGEST_SIZE); //The Name field is one or more octets representing the //identification of the system transmitting the packet memcpy(responsePacket->value + MD5_DIGEST_SIZE, context->username, n); //Debug message TRACE_INFO("Sending CHAP Response packet (%" PRIuSIZE " bytes)...\r\n", length); //Dump packet contents for debugging purpose pppDumpPacket((PppPacket *) responsePacket, length, PPP_PROTOCOL_CHAP); //Send PPP frame error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_CHAP); //Free previously allocated memory block netBufferFree(buffer); //Return status code return error; }
error_t pppSendTerminateAck(PppContext *context, uint8_t identifier, PppProtocol protocol) { error_t error; size_t length; size_t offset; NetBuffer *buffer; PppTerminatePacket *terminateAckPacket; //Length of the Terminate-Ack packet length = sizeof(PppTerminatePacket); //Allocate a buffer memory to hold the Terminate-Ack packet buffer = pppAllocBuffer(length, &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the Terminate-Ack packet terminateAckPacket = netBufferAt(buffer, offset); //Format packet header terminateAckPacket->code = PPP_CODE_TERMINATE_ACK; terminateAckPacket->identifier = identifier; terminateAckPacket->length = htons(length); //Debug message TRACE_INFO("Sending Terminate-Ack packet (%" PRIuSIZE " bytes)...\r\n", length); //Dump packet contents for debugging purpose pppDumpPacket((PppPacket *) terminateAckPacket, length, protocol); //Send PPP frame error = pppSendFrame(context->interface, buffer, offset, protocol); //Free previously allocated memory block netBufferFree(buffer); //Return status code return error; }
error_t chapSendFailure(PppContext *context) { error_t error; size_t length; size_t offset; NetBuffer *buffer; PppPacket *failurePacket; //Retrieve the length of the Failure packet length = sizeof(PppPacket); //Allocate a buffer memory to hold the Failure packet buffer = pppAllocBuffer(length, &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the Failure packet failurePacket = netBufferAt(buffer, offset); //Format packet header failurePacket->code = CHAP_CODE_FAILURE; failurePacket->identifier = context->chapFsm.localIdentifier; failurePacket->length = htons(length); //Debug message TRACE_INFO("Sending CHAP Failure packet (%" PRIuSIZE " bytes)...\r\n", length); //Dump packet contents for debugging purpose pppDumpPacket((PppPacket *) failurePacket, length, PPP_PROTOCOL_CHAP); //Send PPP frame error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_CHAP); //Free previously allocated memory block netBufferFree(buffer); //Return status code return error; }
error_t lcpSendConfigureReq(PppContext *context) { error_t error; size_t length; size_t offset; NetBuffer *buffer; PppConfigurePacket *configureReqPacket; //Debug message TRACE_INFO("LCP Send-Configure-Request callback\r\n"); //Calculate the maximum size of the Configure-Request packet length = sizeof(PppConfigurePacket) + sizeof(LcpMruOption) + sizeof(LcpAccmOption); //Allocate a buffer memory to hold the packet buffer = pppAllocBuffer(length, &offset); //Failed to allocate memory? if(!buffer) 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->lcpFsm.identifier; configureReqPacket->length = sizeof(PppConfigurePacket); //Make sure the Maximum-Receive-Unit option has not been previously rejected if(!context->localConfig.mruRejected) { //Convert MRU to network byte order uint16_t value = htons(context->localConfig.mru); //Add option pppAddOption(configureReqPacket, LCP_OPTION_MRU, &value, sizeof(uint16_t)); } //Make sure the Async-Control-Character-Map option has not been previously rejected if(!context->localConfig.accmRejected) { //Convert ACCM to network byte order uint32_t value = htonl(context->localConfig.accm); //Add option pppAddOption(configureReqPacket, LCP_OPTION_ACCM, &value, sizeof(uint32_t)); } //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_LCP); //Send PPP frame error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_LCP); //The restart counter is decremented each time a Configure-Request is sent if(context->lcpFsm.restartCounter > 0) context->lcpFsm.restartCounter--; //Save the time at which the packet was sent context->lcpFsm.timestamp = osGetSystemTime(); //Free previously allocated memory block netBufferFree(buffer); //Return status code return error; }
error_t pppSendConfigureAckNak(PppContext *context, const PppConfigurePacket *configureReqPacket, PppProtocol protocol, PppCode code) { error_t error; size_t length; size_t offset; NetBuffer *buffer; PppConfigurePacket *configureAckNakPacket; PppOption *option; //Initialize status code error = NO_ERROR; //Retrieve the length of the Configure-Request packet length = ntohs(configureReqPacket->length); //Allocate a buffer memory to hold the Configure-Ack, Nak or Reject packet buffer = pppAllocBuffer(length, &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the beginning of the packet configureAckNakPacket = netBufferAt(buffer, offset); //Format packet header configureAckNakPacket->code = code; configureAckNakPacket->identifier = configureReqPacket->identifier; configureAckNakPacket->length = sizeof(PppConfigurePacket); //Retrieve the length of the option list length -= sizeof(PppConfigurePacket); //Point to the first option option = (PppOption *) configureReqPacket->options; //Parse configuration options while(length > 0) { //LCP protocol? if(protocol == PPP_PROTOCOL_LCP) { //Parse LCP option lcpParseOption(context, option, length, configureAckNakPacket); } #if (IPV4_SUPPORT) //IPCP protocol? else if(protocol == PPP_PROTOCOL_IPCP) { //Parse IPCP option ipcpParseOption(context, option, length, configureAckNakPacket); } #endif //Remaining bytes to process length -= option->length; //Jump to the next option option = (PppOption *) ((uint8_t *) option + option->length); } //Adjust the length of the multi-part buffer netBufferSetLength(buffer, offset + configureAckNakPacket->length); //Convert length field to network byte order configureAckNakPacket->length = htons(configureAckNakPacket->length); //Debug message if(code == PPP_CODE_CONFIGURE_ACK) { TRACE_INFO("Sending Configure-Ack packet (%" PRIuSIZE " bytes)...\r\n", ntohs(configureAckNakPacket->length)); } else if(code == PPP_CODE_CONFIGURE_NAK) { TRACE_INFO("Sending Configure-Nak packet (%" PRIuSIZE " bytes)...\r\n", ntohs(configureAckNakPacket->length)); } else if(code == PPP_CODE_CONFIGURE_REJ) { TRACE_INFO("Sending Configure-Reject packet (%" PRIuSIZE " bytes)...\r\n", ntohs(configureAckNakPacket->length)); } //Dump packet contents for debugging purpose pppDumpPacket((PppPacket *) configureAckNakPacket, ntohs(configureAckNakPacket->length), protocol); //Send PPP frame error = pppSendFrame(context->interface, buffer, offset, protocol); //Free previously allocated memory block netBufferFree(buffer); //Return status code return error; }
error_t ipv4SendPacket(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, uint16_t fragId, uint16_t fragOffset, NetBuffer *buffer, size_t offset, uint8_t ttl) { error_t error; size_t length; Ipv4Header *packet; //Is there enough space for the IPv4 header? if(offset < sizeof(Ipv4Header)) return ERROR_INVALID_PARAMETER; //Make room for the header offset -= sizeof(Ipv4Header); //Calculate the size of the entire packet, including header and data length = netBufferGetLength(buffer) - offset; //Point to the IPv4 header packet = netBufferAt(buffer, offset); //Format IPv4 header packet->version = IPV4_VERSION; packet->headerLength = 5; packet->typeOfService = 0; packet->totalLength = htons(length); packet->identification = htons(fragId); packet->fragmentOffset = htons(fragOffset); packet->timeToLive = ttl; packet->protocol = pseudoHeader->protocol; packet->headerChecksum = 0; packet->srcAddr = pseudoHeader->srcAddr; packet->destAddr = pseudoHeader->destAddr; //Calculate IP header checksum packet->headerChecksum = ipCalcChecksumEx(buffer, offset, packet->headerLength * 4); //Ensure the source address is valid error = ipv4CheckSourceAddr(interface, pseudoHeader->srcAddr); //Invalid source address? if(error) return error; //Destination address is the unspecified address? if(pseudoHeader->destAddr == IPV4_UNSPECIFIED_ADDR) { //Destination address is not acceptable return ERROR_INVALID_ADDRESS; } //Destination address is the loopback address? else if(pseudoHeader->destAddr == IPV4_LOOPBACK_ADDR) { //Not yet implemented... return ERROR_NOT_IMPLEMENTED; } #if (ETH_SUPPORT == ENABLED) //Ethernet interface? if(interface->nicDriver->type == NIC_TYPE_ETHERNET) { Ipv4Addr destIpAddr; MacAddr destMacAddr; //Destination address is a broadcast address? if(ipv4IsBroadcastAddr(interface, pseudoHeader->destAddr)) { //Destination IPv4 address destIpAddr = pseudoHeader->destAddr; //Make use of the broadcast MAC address destMacAddr = MAC_BROADCAST_ADDR; //No error to report error = NO_ERROR; } //Destination address is a multicast address? else if(ipv4IsMulticastAddr(pseudoHeader->destAddr)) { //Destination IPv4 address destIpAddr = pseudoHeader->destAddr; //Map IPv4 multicast address to MAC-layer multicast address error = ipv4MapMulticastAddrToMac(pseudoHeader->destAddr, &destMacAddr); } //Destination host is in the local subnet? else if(ipv4IsInLocalSubnet(interface, pseudoHeader->destAddr)) { //Destination IPv4 address destIpAddr = pseudoHeader->destAddr; //Resolve host address before sending the packet error = arpResolve(interface, pseudoHeader->destAddr, &destMacAddr); } //Destination host is outside the local subnet? else { //Make sure the default gateway is properly set if(interface->ipv4Config.defaultGateway != IPV4_UNSPECIFIED_ADDR) { //Use the default gateway to forward the packet destIpAddr = interface->ipv4Config.defaultGateway; //Perform address resolution error = arpResolve(interface, interface->ipv4Config.defaultGateway, &destMacAddr); } else { //There is no route to the outside world... error = ERROR_NO_ROUTE; } } //Successful address resolution? if(!error) { //Debug message TRACE_INFO("Sending IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length); //Dump IP header contents for debugging purpose ipv4DumpHeader(packet); //Send Ethernet frame error = ethSendFrame(interface, &destMacAddr, buffer, offset, ETH_TYPE_IPV4); } //Address resolution is in progress? else if(error == ERROR_IN_PROGRESS) { //Debug message TRACE_INFO("Enqueuing IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length); //Dump IP header contents for debugging purpose ipv4DumpHeader(packet); //Enqueue packets waiting for address resolution error = arpEnqueuePacket(interface, destIpAddr, buffer, offset); } //Address resolution failed? else { //Debug message TRACE_WARNING("Cannot map IPv4 address to Ethernet address!\r\n"); } } else #endif #if (PPP_SUPPORT == ENABLED) //PPP interface? if(interface->nicDriver->type == NIC_TYPE_PPP) { //Debug message TRACE_INFO("Sending IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length); //Dump IP header contents for debugging purpose ipv4DumpHeader(packet); //Send PPP frame error = pppSendFrame(interface, buffer, offset, PPP_PROTOCOL_IP); } else #endif //Unknown interface type? { //Report an error error = ERROR_INVALID_INTERFACE; } //Return status code return error; }
error_t chapSendChallenge(PppContext *context) { error_t error; size_t n; size_t length; size_t offset; NetBuffer *buffer; ChapChallengePacket *challengePacket; //Retrieve the length of the username n = strlen(context->username); //Calculate the length of the Challenge packet length = sizeof(ChapChallengePacket) + MD5_DIGEST_SIZE + n; //Allocate a buffer memory to hold the Challenge packet buffer = pppAllocBuffer(length, &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the Challenge packet challengePacket = netBufferAt(buffer, offset); //Format packet header challengePacket->code = CHAP_CODE_CHALLENGE; challengePacket->identifier = ++context->chapFsm.localIdentifier; challengePacket->length = htons(length); challengePacket->valueSize = MD5_DIGEST_SIZE; //Make sure that the callback function has been registered if(context->settings.randCallback != NULL) { //Generate a random challenge value error = context->settings.randCallback( context->chapFsm.challenge, MD5_DIGEST_SIZE); } else { //Report an error error = ERROR_FAILURE; } //Check status code if(!error) { //Copy the challenge value memcpy(challengePacket->value, context->chapFsm.challenge, MD5_DIGEST_SIZE); //The Name field is one or more octets representing the //identification of the system transmitting the packet memcpy(challengePacket->value + MD5_DIGEST_SIZE, context->username, n); //Debug message TRACE_INFO("Sending CHAP Challenge packet (%" PRIuSIZE " bytes)...\r\n", length); //Dump packet contents for debugging purpose pppDumpPacket((PppPacket *) challengePacket, length, PPP_PROTOCOL_CHAP); //Send PPP frame error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_CHAP); //The restart counter is decremented each time a Challenge packet is sent if(context->chapFsm.restartCounter > 0) context->chapFsm.restartCounter--; //Save the time at which the packet was sent context->chapFsm.timestamp = osGetSystemTime(); } //Free previously allocated memory block netBufferFree(buffer); //Return status code return error; }