Dhcpv6StatusCode dhcpv6GetStatusCode(const uint8_t *options, size_t length) { uint16_t statusCode; Dhcpv6Option *option; Dhcpv6StatusCodeOption *statusCodeOption; //Search for the Status Code option option = dhcpv6GetOption(options, length, DHCPV6_OPTION_STATUS_CODE); //Check whether the option has been found if(option != NULL && ntohs(option->length) >= sizeof(Dhcpv6StatusCodeOption)) { //The option contains a status code and a status message statusCodeOption = (Dhcpv6StatusCodeOption *) option->value; //Convert the status code from network byte order statusCode = ntohs(statusCodeOption->statusCode); } else { //If the Status Code option does not appear in a message in which the option //could appear, the status of the message is assumed to be Success statusCode = DHCPV6_STATUS_SUCCESS; } //Return status code return (Dhcpv6StatusCode) statusCode; }
error_t dhcpv6ParseStatusCodeOption(const uint8_t *options, size_t length) { error_t error; uint16_t statusCode; Dhcpv6Option *option; Dhcpv6StatusCodeOption *statusCodeOption; //Search for the Status Code option option = dhcpv6GetOption(options, length, DHCPV6_OPTION_STATUS_CODE); //If the Status Code option does not appear in a message in which the option //could appear, the status of the message is assumed to be Success if(!option || ntohs(option->length) < sizeof(Dhcpv6StatusCodeOption)) return NO_ERROR; //The option contains a status code and a status message statusCodeOption = (Dhcpv6StatusCodeOption *) option->value; //Convert status code from network byte order statusCode = ntohs(statusCodeOption->statusCode); //Check the status code returned by the peer switch(statusCode) { //Success case DHCPV6_STATUS_SUCCESS: error = NO_ERROR; break; //Unspecified failure case DHCPV6_STATUS_UNSPEC_FAILURE: error = ERROR_FAILURE; break; //Server has no address available to assign to the IA case DHCPV6_STATUS_NO_ADDRS_AVAILABLE: error = ERROR_NO_ADDRESS; break; //Client record (binding) unavailable case DHCPV6_STATUS_NO_BINDING: error = ERROR_NO_BINDING; break; //The prefix for the address is not appropriate for //the link to which the client is attached case DHCPV6_STATUS_NOT_ON_LINK: error = ERROR_NOT_ON_LINK; break; //Sent by a server to a client to force the client to send //messages to the server using the multicast address case DHCPV6_STATUS_USE_MULTICAST: error = ERROR_USE_MULTICAST; break; //Any other failure... default: error = ERROR_FAILURE; break; } //Return the corresponding error return error; }
error_t dhcpv6ForwardRelayReplyMessage(Dhcpv6RelayCtx *context) { error_t error; uint_t i; uint32_t interfaceId; size_t inputMessageLen; size_t outputMessageLen; Dhcpv6RelayMessage *inputMessage; Dhcpv6Message *outputMessage; Dhcpv6Option *option; IpAddr ipAddr; uint16_t port; //Point to the buffer where to store the incoming DHCPv6 message inputMessage = (Dhcpv6RelayMessage *) context->buffer; //Read incoming message error = socketReceiveFrom(context->serverSocket, &ipAddr, &port, inputMessage, DHCPV6_MAX_MSG_SIZE, &inputMessageLen, 0); //Any error to report? if(error) return error; //Debug message TRACE_INFO("\r\nDHCPv6 message received on network-facing interface %s (%" PRIuSIZE " bytes)...\r\n", context->serverInterface->name, inputMessageLen); //Dump the contents of the message for debugging purpose dhcpv6DumpMessage(inputMessage, inputMessageLen); //Check the length of the DHCPv6 message if(inputMessageLen < sizeof(Dhcpv6RelayMessage)) return ERROR_INVALID_MESSAGE; //Inspect the message type and only forward Relay-Reply messages. //Other DHCPv6 message types must be silently discarded if(inputMessage->msgType != DHCPV6_MSG_TYPE_RELAY_REPL) return ERROR_INVALID_MESSAGE; //Get the length of the Options field inputMessageLen -= sizeof(Dhcpv6Message); //Check whether an Interface ID option is included in the Relay-Reply option = dhcpv6GetOption(inputMessage->options, inputMessageLen, DHCPV6_OPTION_INTERFACE_ID); //Failed to retrieve specified option? if(!option || ntohs(option->length) != sizeof(interfaceId)) return ERROR_INVALID_MESSAGE; //Read the Interface ID option contents memcpy(&interfaceId, option->value, sizeof(interfaceId)); //Convert the 32-bit integer from network byte order interfaceId = ntohl(interfaceId); //The Relay-Reply message must include a Relay Message option option = dhcpv6GetOption(inputMessage->options, inputMessageLen, DHCPV6_OPTION_RELAY_MSG); //Failed to retrieve specified option? if(!option || ntohs(option->length) < sizeof(Dhcpv6Message)) return ERROR_INVALID_MESSAGE; //Extract the message from the Relay Message option outputMessage = (Dhcpv6Message *) option->value; //Save the length of the message outputMessageLen = ntohs(option->length); //Loop through client-facing interfaces for(i = 0; i < context->clientInterfaceCount; i++) { //Check whether the current interface matches the Interface ID option if(context->clientInterface[i]->id == interfaceId) { //Debug message TRACE_INFO("Forwarding DHCPv6 message on client-facing interface %s (%" PRIuSIZE " bytes)...\r\n", context->clientInterface[i]->name, outputMessageLen); //Dump the contents of the message for debugging purpose dhcpv6DumpMessage(outputMessage, outputMessageLen); //Copy the peer-address into the destination IP address ipAddr.length = sizeof(Ipv6Addr); ipAddr.ipv6Addr = inputMessage->peerAddress; //Select the relevant port number to use if(outputMessage->msgType == DHCPV6_MSG_TYPE_RELAY_REPL) port = DHCPV6_SERVER_PORT; else port = DHCPV6_CLIENT_PORT; //Relay the DHCPv6 message to the client on the link //identified by the Interface ID option return socketSendTo(context->clientSocket[i], &ipAddr, port, outputMessage, outputMessageLen, NULL, 0); } } //Unknown interface identifier... return ERROR_INVALID_OPTION; }