error_t rawSocketReceiveEthPacket(Socket *socket, void *data, size_t size, size_t *received, uint_t flags) { SocketQueueItem *queueItem; //The SOCKET_FLAG_DONT_WAIT enables non-blocking operation if(!(flags & SOCKET_FLAG_DONT_WAIT)) { //The receive queue is empty? if(!socket->receiveQueue) { //Set the events the application is interested in socket->eventMask = SOCKET_EVENT_RX_READY; //Reset the event object osResetEvent(&socket->event); //Leave critical section osReleaseMutex(&socketMutex); //Wait until an event is triggered osWaitForEvent(&socket->event, socket->timeout); //Enter critical section osAcquireMutex(&socketMutex); } } //Check whether the read operation timed out if(!socket->receiveQueue) { //No data can be read *received = 0; //Report a timeout error return ERROR_TIMEOUT; } //Point to the first item in the receive queue queueItem = socket->receiveQueue; //Copy data to user buffer *received = netBufferRead(data, queueItem->buffer, queueItem->offset, size); //If the SOCKET_FLAG_PEEK flag is set, the data is copied //into the buffer but is not removed from the input queue if(!(flags & SOCKET_FLAG_PEEK)) { //Remove the item from the receive queue socket->receiveQueue = queueItem->next; //Deallocate memory buffer netBufferFree(queueItem->buffer); } //Update the state of events rawSocketUpdateEvents(socket); //Successful read operation return NO_ERROR; }
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 udpSendDatagram(Socket *socket, const IpAddr *destIpAddr, uint16_t destPort, const void *data, size_t length, size_t *written) { error_t error; size_t offset; NetBuffer *buffer; //Allocate a memory buffer to hold the UDP datagram buffer = udpAllocBuffer(0, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Copy data payload error = netBufferAppend(buffer, data, length); //Successful processing? if(!error) { //Send UDP datagram error = udpSendDatagramEx(socket->interface, socket->localPort, destIpAddr, destPort, buffer, offset, socket->ttl); } //Successful processing? if(!error) { //Total number of data bytes successfully transmitted if(written != NULL) *written = length; } //Free previously allocated memory netBufferFree(buffer); //Return status code return error; }
error_t rawSocketSendEthPacket(Socket *socket, const void *data, size_t length, size_t *written) { error_t error; uint32_t crc; NetBuffer *buffer; NetInterface *interface; //Select the relevant network interface if(!socket->interface) interface = netGetDefaultInterface(); else interface = socket->interface; //Allocate a buffer memory to hold the raw Ethernet packet buffer = netBufferAlloc(0); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Copy the raw data error = netBufferAppend(buffer, data, length); //Successful processing? if(!error) { //Automatic padding not supported by hardware? if(!interface->nicDriver->autoPadding) { //The host controller should manually add padding //to the packet before transmitting it if(length < (ETH_MIN_FRAME_SIZE - ETH_CRC_SIZE)) { //Add padding as necessary size_t n = (ETH_MIN_FRAME_SIZE - ETH_CRC_SIZE) - length; //Append padding bytes error = netBufferAppend(buffer, ethPadding, n); //Any error to report? if(error) return error; //Adjust frame length length += n; } } //CRC generation not supported by hardware? if(!interface->nicDriver->autoCrcGen) { //Compute CRC over the header and payload crc = ethCalcCrcEx(buffer, 0, length); //Convert from host byte order to little-endian byte order crc = htole32(crc); //Append the calculated CRC value error = netBufferAppend(buffer, &crc, sizeof(crc)); //Any error to report? if(error) return error; //Adjust frame length length += sizeof(crc); } //Debug message TRACE_DEBUG("Sending raw Ethernet frame (%" PRIuSIZE " bytes)...\r\n", length); //Send the resulting packet over the specified link error = nicSendPacket(interface, buffer, 0); } //Successful processing? if(!error) { //Total number of bytes successfully transmitted if(written != NULL) *written = length; } //Free previously allocated memory block netBufferFree(buffer); //Return status code return error; }
error_t rawSocketSendIpPacket(Socket *socket, const IpAddr *destIpAddr, const void *data, size_t length, size_t *written) { error_t error; size_t offset; uint_t timeToLive; NetBuffer *buffer; NetInterface *interface; IpPseudoHeader pseudoHeader; //The socket may be bound to a particular network interface interface = socket->interface; //Allocate a buffer memory to hold the raw IP datagram buffer = ipAllocBuffer(0, &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Start of exception handling block do { //Copy the raw data error = netBufferAppend(buffer, data, length); //Any error to report? if(error) break; #if (IPV4_SUPPORT == ENABLED) //Destination address is an IPv4 address? if(destIpAddr->length == sizeof(Ipv4Addr)) { Ipv4Addr srcIpAddr; //Select the source IPv4 address and the relevant network interface //to use when sending data to the specified destination host error = ipv4SelectSourceAddr(&interface, destIpAddr->ipv4Addr, &srcIpAddr); //Any error to report? if(error) break; //Format IPv4 pseudo header pseudoHeader.length = sizeof(Ipv4PseudoHeader); pseudoHeader.ipv4Data.srcAddr = srcIpAddr; pseudoHeader.ipv4Data.destAddr = destIpAddr->ipv4Addr; pseudoHeader.ipv4Data.reserved = 0; pseudoHeader.ipv4Data.protocol = socket->protocol; pseudoHeader.ipv4Data.length = htons(length); //Set TTL value timeToLive = IPV4_DEFAULT_TTL; } else #endif #if (IPV6_SUPPORT == ENABLED) //Destination address is an IPv6 address? if(destIpAddr->length == sizeof(Ipv6Addr)) { //Select the source IPv6 address and the relevant network interface //to use when sending data to the specified destination host error = ipv6SelectSourceAddr(&interface, &destIpAddr->ipv6Addr, &pseudoHeader.ipv6Data.srcAddr); //Any error to report? if(error) break; //Format IPv6 pseudo header pseudoHeader.length = sizeof(Ipv6PseudoHeader); pseudoHeader.ipv6Data.destAddr = destIpAddr->ipv6Addr; pseudoHeader.ipv6Data.length = htonl(length); pseudoHeader.ipv6Data.reserved = 0; pseudoHeader.ipv6Data.nextHeader = socket->protocol; //Set Hop Limit value timeToLive = IPV6_DEFAULT_HOP_LIMIT; } else #endif //Invalid destination address? { //An internal error has occurred error = ERROR_FAILURE; //Exit immediately break; } //Send raw IP datagram error = ipSendDatagram(interface, &pseudoHeader, buffer, offset, timeToLive); //Failed to send data? if(error) break; //Total number of bytes successfully transmitted if(written != NULL) *written = length; //End of exception handling block } while(0); //Free previously allocated memory block netBufferFree(buffer); //Return status code return error; }
error_t mdnsSendAnnouncement(NetInterface *interface) { error_t error; size_t length; size_t offset; NetBuffer *buffer; DnsHeader *message; IpAddr destIpAddr; //Initialize error code error = NO_ERROR; //Allocate a memory buffer to hold the mDNS query message buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the mDNS header message = netBufferAt(buffer, offset); //Format mDNS query message message->id = 0; message->qr = 1; message->opcode = DNS_OPCODE_QUERY; message->aa = 1; message->tc = 0; message->rd = 0; message->ra = 0; message->z = 0; message->rcode = DNS_RCODE_NO_ERROR; //Multicast DNS responses must not contain any questions message->qdcount = 0; message->ancount = 0; message->nscount = 0; message->arcount = 0; //Length of the mDNS query message length = sizeof(DnsHeader); //Start of exception handling block do { //Format A resource record error = mdnsAddIpv4ResourceRecord(interface, message, &length, TRUE); //Any error to report? if(error) break; //Format AAAA resource record error = mdnsAddIpv6ResourceRecord(interface, message, &length, TRUE); //Any error to report? if(error) break; //Convert 16-bit value to network byte order message->ancount = htons(message->ancount); //Adjust the length of the multi-part buffer netBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending mDNS announcement (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage(message, length); #if (IPV4_SUPPORT == ENABLED) //Select the relevant multicast address (224.0.0.251) destIpAddr.length = sizeof(Ipv4Addr); destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR; //All multicast DNS queries should be sent with an IP TTL set to 255 error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr, MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL); //Any error to report? if(error)break; #endif #if (IPV6_SUPPORT == ENABLED) //Select the relevant multicast address (ff02::fb) destIpAddr.length = sizeof(Ipv6Addr); destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR; //All multicast DNS queries should be sent with an IP TTL set to 255 error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr, MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL); //Any error to report? if(error)break; #endif //End of exception handling block } while(0); //Free previously allocated memory netBufferFree(buffer); //Return status code return error; }
error_t mdnsSendProbe(NetInterface *interface) { error_t error; size_t length; size_t offset; NetBuffer *buffer; DnsHeader *message; DnsQuestion *dnsQuestion; IpAddr destIpAddr; //Initialize error code error = NO_ERROR; //Allocate a memory buffer to hold the mDNS query message buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the mDNS header message = netBufferAt(buffer, offset); //Format mDNS query message message->id = 0; message->qr = 0; message->opcode = DNS_OPCODE_QUERY; message->aa = 0; message->tc = 0; message->rd = 0; message->ra = 0; message->z = 0; message->rcode = DNS_RCODE_NO_ERROR; //The mDNS query contains one question message->qdcount = HTONS(1); message->ancount = 0; message->nscount = 0; message->arcount = 0; //Length of the mDNS query message length = sizeof(DnsHeader); //Encode the host name using the DNS name notation length += mdnsEncodeName(interface->hostname, "", ".local", (uint8_t *) message + length); //Point to the corresponding question structure dnsQuestion = DNS_GET_QUESTION(message, length); //Fill in question structure dnsQuestion->qtype = HTONS(DNS_RR_TYPE_ANY); dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN); //Update the length of the mDNS query message length += sizeof(DnsQuestion); //Adjust the length of the multi-part buffer netBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending mDNS probe (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage(message, length); #if (IPV4_SUPPORT == ENABLED) //Check status code if(!error) { //Select the relevant multicast address (224.0.0.251) destIpAddr.length = sizeof(Ipv4Addr); destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR; //All multicast DNS queries should be sent with an IP TTL set to 255 error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr, MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL); } #endif #if (IPV6_SUPPORT == ENABLED) //Check status code if(!error) { //Select the relevant multicast address (ff02::fb) destIpAddr.length = sizeof(Ipv6Addr); destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR; //All multicast DNS queries should be sent with an IP TTL set to 255 error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr, MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL); } #endif //Free previously allocated memory netBufferFree(buffer); //Return status code return error; }
void mdnsProcessQuery(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const DnsHeader *query, size_t queryLen) { error_t error; uint_t i; size_t pos; size_t offset; size_t responseLen; DnsHeader *response; NetBuffer *buffer; //Check the state of the mDNS responder if(interface->mdnsContext.state != MDNS_STATE_DONE) return; //Initialize error code error = NO_ERROR; //This buffer will hold the mDNS response, if any buffer = NULL; //Point to the first question pos = sizeof(DnsHeader); //Parse question section for(i = 0; i < ntohs(query->qdcount); i++) { size_t n; uint16_t qclass; uint16_t qtype; DnsQuestion *question; //Parse domain name n = dnsParseName(query, queryLen, pos, NULL, 0); //Invalid name? if(!n) break; //Malformed mDNS message? if((n + sizeof(DnsQuestion)) > queryLen) break; //Point to the corresponding entry question = DNS_GET_QUESTION(query, n); //Convert the query class to host byte order qclass = ntohs(question->qclass); //Discard QU flag qclass &= ~MDNS_QCLASS_QU; //Convert the query type to host byte order qtype = ntohs(question->qtype); //Check the class of the query if(qclass == DNS_RR_CLASS_IN || qclass == DNS_RR_CLASS_ANY) { #if (DNS_SD_SUPPORT == ENABLED) //PTR query? if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY) { uint_t j; //Service type enumeration meta-query received? if(mdnsCompareName(query, queryLen, pos, "", "_services._dns-sd._udp", ".local", 0)) { //Any registered services? if(interface->numServices > 0 && interface->instanceName != NULL) { //Create a mDNS response message only if necessary if(!buffer) { //Allocate the mDNS response message buffer = mdnsCreateResponse(query->id, &offset, &response, &responseLen); //Failed to allocate memory? if(!buffer) break; } //Loop through registered services for(j = 0; j < interface->numServices; j++) { //Format PTR resource record error = dnsSdAddPtrResourceRecord(interface, &interface->services[j], TRUE, response, &responseLen); //Any error to report? if(error) break; } //Propagate exception if necessary... if(error) break; } } else { //Loop through registered services for(j = 0; j < interface->numServices; j++) { //Compare service name if(mdnsCompareName(query, queryLen, pos, "", interface->services[j].name, ".local", 0)) { //The current service name matches a registered service break; } } //Any matching service name? if(j < interface->numServices && interface->instanceName != NULL) { //Create a mDNS response message only if necessary if(!buffer) { //Allocate the mDNS response message buffer = mdnsCreateResponse(query->id, &offset, &response, &responseLen); //Failed to allocate memory? if(!buffer) break; } //Format PTR resource record error = dnsSdAddPtrResourceRecord(interface, &interface->services[j], FALSE, response, &responseLen); //Any error to report? if(error) break; //Format TXT resource record error = dnsSdAddTxtResourceRecord(interface, &interface->services[j], response, &responseLen); //Any error to report? if(error) break; //Format SRV resource record error = dnsSdAddSrvResourceRecord(interface, &interface->services[j], response, &responseLen); //Any error to report? if(error) break; //Format A resource record error = mdnsAddIpv4ResourceRecord(interface, response, &responseLen, FALSE); //Any error to report? if(error) break; //Format AAAA resource record error = mdnsAddIpv6ResourceRecord(interface, response, &responseLen, FALSE); //Any error to report? if(error) break; } } } //SRV or TXT query? else if(qtype == DNS_RR_TYPE_SRV || qtype == DNS_RR_TYPE_TXT) { uint_t j; //Loop through registered services for(j = 0; j < interface->numServices; j++) { //Compare service name if(mdnsCompareName(query, queryLen, pos, interface->instanceName, interface->services[j].name, ".local", 0)) { //The current service name matches a registered service break; } } //Any matching service name? if(j < interface->numServices && interface->instanceName != NULL) { //Create a mDNS response message only if necessary if(!buffer) { //Allocate the mDNS response message buffer = mdnsCreateResponse(query->id, &offset, &response, &responseLen); //Failed to allocate memory? if(!buffer) break; } //Check query type? if(qtype == DNS_RR_TYPE_TXT) { //Format TXT resource record error = dnsSdAddTxtResourceRecord(interface, &interface->services[j], response, &responseLen); //Any error to report? if(error) break; } else if(qtype == DNS_RR_TYPE_SRV) { //Format SRV resource record error = dnsSdAddSrvResourceRecord(interface, &interface->services[j], response, &responseLen); //Any error to report? if(error) break; //Format A resource record error = mdnsAddIpv4ResourceRecord(interface, response, &responseLen, FALSE); //Any error to report? if(error) break; //Format AAAA resource record error = mdnsAddIpv6ResourceRecord(interface, response, &responseLen, FALSE); //Any error to report? if(error) break; } } } #endif #if (IPV4_SUPPORT == ENABLED) //A query? #if (DNS_SD_SUPPORT == ENABLED) if(qtype == DNS_RR_TYPE_A) #else if(qtype == DNS_RR_TYPE_A || qtype == DNS_RR_TYPE_ANY) #endif { //Compare domain name if(mdnsCompareName(query, queryLen, pos, interface->hostname, "", ".local", 0)) { //Create a mDNS response message only if necessary if(!buffer) { //Allocate the mDNS response message buffer = mdnsCreateResponse(query->id, &offset, &response, &responseLen); //Failed to allocate memory? if(!buffer) break; } //Format A resource record error = mdnsAddIpv4ResourceRecord(interface, response, &responseLen, FALSE); //Any error to report? if(error) break; } } #endif #if (IPV6_SUPPORT == ENABLED) //AAAA query? #if (DNS_SD_SUPPORT == ENABLED) if(qtype == DNS_RR_TYPE_AAAA) #else if(qtype == DNS_RR_TYPE_AAAA || qtype == DNS_RR_TYPE_ANY) #endif { //Compare domain name if(mdnsCompareName(query, queryLen, pos, interface->hostname, "", ".local", 0)) { //Create a mDNS response message only if necessary if(!buffer) { //Allocate the mDNS response message buffer = mdnsCreateResponse(query->id, &offset, &response, &responseLen); //Failed to allocate memory? if(!buffer) break; } //Format AAAA resource record error = mdnsAddIpv6ResourceRecord(interface, response, &responseLen, FALSE); //Any error to report? if(error) break; } } #endif } //Point to the next question pos = n + sizeof(DnsQuestion); } //Any response to send? if(buffer != NULL) { //Check status code if(!error) { //Send mDNS response message mdnsSendResponse(interface, pseudoHeader, udpHeader, buffer, offset, responseLen); } //Free previously allocated memory netBufferFree(buffer); } }
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; }
error_t dnsSendQuery(DnsCacheEntry *entry) { error_t error; size_t length; size_t offset; NetBuffer *buffer; DnsHeader *message; DnsQuestion *dnsQuestion; IpAddr destIpAddr; #if (IPV4_SUPPORT == ENABLED) //An IPv4 address is expected? if(entry->type == HOST_TYPE_IPV4) { //Select the relevant DNS server destIpAddr.length = sizeof(Ipv4Addr); ipv4GetDnsServer(entry->interface, entry->dnsServerNum, &destIpAddr.ipv4Addr); //Make sure the IP address is valid if(destIpAddr.ipv4Addr == IPV4_UNSPECIFIED_ADDR) return ERROR_NO_DNS_SERVER; } else #endif #if (IPV6_SUPPORT == ENABLED) //An IPv6 address is expected? if(entry->type == HOST_TYPE_IPV6) { //Select the relevant DNS server destIpAddr.length = sizeof(Ipv6Addr); ipv6GetDnsServer(entry->interface, entry->dnsServerNum, &destIpAddr.ipv6Addr); //Make sure the IP address is valid if(ipv6CompAddr(&destIpAddr.ipv6Addr, &IPV6_UNSPECIFIED_ADDR)) return ERROR_NO_DNS_SERVER; } else #endif //Invalid host type? { //Report an error return ERROR_INVALID_PARAMETER; } //Allocate a memory buffer to hold the DNS query message buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the DNS header message = netBufferAt(buffer, offset); //Format DNS query message message->id = htons(entry->id); message->qr = 0; message->opcode = DNS_OPCODE_QUERY; message->aa = 0; message->tc = 0; message->rd = 1; message->ra = 0; message->z = 0; message->rcode = DNS_RCODE_NO_ERROR; //The DNS query contains one question message->qdcount = HTONS(1); message->ancount = 0; message->nscount = 0; message->arcount = 0; //Length of the DNS query message length = sizeof(DnsHeader); //Encode the host name using the DNS name notation length += dnsEncodeName(entry->name, message->questions); //Point to the corresponding question structure dnsQuestion = DNS_GET_QUESTION(message, length); #if (IPV4_SUPPORT == ENABLED) //An IPv4 address is expected? if(entry->type == HOST_TYPE_IPV4) { //Fill in question structure dnsQuestion->qtype = HTONS(DNS_RR_TYPE_A); dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN); } #endif #if (IPV6_SUPPORT == ENABLED) //An IPv6 address is expected? if(entry->type == HOST_TYPE_IPV6) { //Fill in question structure dnsQuestion->qtype = HTONS(DNS_RR_TYPE_AAAA); dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN); } #endif //Update the length of the DNS query message length += sizeof(DnsQuestion); //Adjust the length of the multi-part buffer netBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending DNS message (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage(message, length); //Send DNS query message error = udpSendDatagramEx(entry->interface, entry->port, &destIpAddr, DNS_PORT, buffer, offset, 0); //Free previously allocated memory 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 nbnsSendQuery(DnsCacheEntry *entry) { error_t error; size_t length; size_t offset; NetBuffer *buffer; NbnsHeader *message; DnsQuestion *dnsQuestion; IpAddr destIpAddr; //Allocate a memory buffer to hold the NBNS query message buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the NBNS header message = netBufferAt(buffer, offset); //Format NBNS query message message->id = htons(entry->id); message->qr = 0; message->opcode = DNS_OPCODE_QUERY; message->aa = 0; message->tc = 0; message->rd = 0; message->ra = 0; message->z = 0; message->b = 1; message->rcode = DNS_RCODE_NO_ERROR; //The NBNS query contains one question message->qdcount = HTONS(1); message->ancount = 0; message->nscount = 0; message->arcount = 0; //Length of the NBNS query message length = sizeof(DnsHeader); //Encode the NetBIOS name length += nbnsEncodeName(entry->name, message->questions); //Point to the corresponding question structure dnsQuestion = DNS_GET_QUESTION(message, length); //Fill in question structure dnsQuestion->qtype = HTONS(DNS_RR_TYPE_NB); dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN); //Update the length of the NBNS query message length += sizeof(DnsQuestion); //Adjust the length of the multi-part buffer netBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending NBNS message (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage((DnsHeader *) message, length); //The destination address is the broadcast address destIpAddr.length = sizeof(Ipv4Addr); ipv4GetBroadcastAddr(entry->interface, &destIpAddr.ipv4Addr); //A request packet is always sent to the well known port 137 error = udpSendDatagramEx(entry->interface, NBNS_PORT, &destIpAddr, NBNS_PORT, buffer, offset, IPV4_DEFAULT_TTL); //Free previously allocated memory 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 ipv4FragmentDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, uint16_t id, const NetBuffer *payload, size_t payloadOffset, uint8_t timeToLive) { error_t error; size_t offset; size_t length; size_t payloadLength; size_t fragmentOffset; size_t maxFragmentSize; NetBuffer *fragment; //Retrieve the length of the payload payloadLength = netBufferGetLength(payload) - payloadOffset; //Allocate a memory buffer to hold IP fragments fragment = ipAllocBuffer(0, &fragmentOffset); //Failed to allocate memory? if(!fragment) return ERROR_OUT_OF_MEMORY; //Maximum payload size for fragmented packets maxFragmentSize = interface->ipv4Config.mtu - sizeof(Ipv4Header); //The size shall be a multiple of 8-byte blocks maxFragmentSize -= (maxFragmentSize % 8); //Split the payload into multiple IP fragments for(offset = 0; offset < payloadLength; offset += length) { //Flush the contents of the fragment error = netBufferSetLength(fragment, fragmentOffset); //Sanity check if(error) break; //Process the last fragment? if((payloadLength - offset) <= maxFragmentSize) { //Size of the current fragment length = payloadLength - offset; //Copy fragment data netBufferConcat(fragment, payload, payloadOffset + offset, length); //Do not set the MF flag for the last fragment error = ipv4SendPacket(interface, pseudoHeader, id, offset / 8, fragment, fragmentOffset, timeToLive); } else { //Size of the current fragment (must be a multiple of 8-byte blocks) length = maxFragmentSize; //Copy fragment data netBufferConcat(fragment, payload, payloadOffset + offset, length); //Fragmented packets must have the MF flag set error = ipv4SendPacket(interface, pseudoHeader, id, IPV4_FLAG_MF | (offset / 8), fragment, fragmentOffset, timeToLive); } //Failed to send current IP packet? if(error) break; } //Free previously allocated memory netBufferFree(fragment); //Return status code return error; }