void tcpDiscardConnectionTask(void *param) { error_t error; size_t n; size_t byteCount; systime_t startTime; systime_t duration; DiscardServiceContext *context; //Get a pointer to the context context = (DiscardServiceContext *) param; //Get current time startTime = osGetSystemTime(); //Total number of bytes received byteCount = 0; //Main loop while(1) { //Throw away any received datagram... error = socketReceive(context->socket, context->buffer, DISCARD_BUFFER_SIZE, &n, 0); //Any error to report? if(error) break; //Total number of bytes received byteCount += n; } //Graceful shutdown socketShutdown(context->socket, SOCKET_SD_BOTH); //Compute total duration duration = osGetSystemTime() - startTime; //Avoid division by zero... if(!duration) duration = 1; //Debug message TRACE_INFO("Discard service: %" PRIuSIZE " bytes " "received in %" PRIu32 " ms (%" PRIu32 " kBps, %" PRIu32 " kbps)\r\n", byteCount, duration, byteCount / duration, (byteCount * 8) / duration); //Close socket socketClose(context->socket); //Release previously allocated memory osFreeMem(context); //Kill ourselves osDeleteTask(NULL); }
void ipv6FragTick(NetInterface *interface) { error_t error; uint_t i; systime_t time; Ipv6HoleDesc *hole; //Acquire exclusive access to the reassembly queue osAcquireMutex(&interface->ipv6FragQueueMutex); //Get current time time = osGetSystemTime(); //Loop through the reassembly queue for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++) { //Point to the current entry in the reassembly queue Ipv6FragDesc *frag = &interface->ipv6FragQueue[i]; //Make sure the entry is currently in use if(frag->buffer.chunkCount > 0) { //If the timer runs out, the partially-reassembled datagram must be //discarded and ICMPv6 Time Exceeded message sent to the source host if((time - frag->timestamp) >= IPV6_FRAG_TIME_TO_LIVE) { //Debug message TRACE_INFO("IPv6 fragment reassembly timeout...\r\n"); //Dump IP header contents for debugging purpose ipv6DumpHeader(frag->buffer.chunk[0].address); //Point to the first hole descriptor hole = ipv6FindHole(frag, frag->firstHole); //Make sure the fragment zero has been received //before sending an ICMPv6 message if(hole != NULL && hole->first > 0) { //Fix the size of the reconstructed datagram error = chunkedBufferSetLength((ChunkedBuffer *) &frag->buffer, frag->unfragPartLength + hole->first); //Check status code if(!error) { //Send an ICMPv6 Time Exceeded message icmpv6SendErrorMessage(interface, ICMPV6_TYPE_TIME_EXCEEDED, ICMPV6_CODE_REASSEMBLY_TIME_EXCEEDED, 0, (ChunkedBuffer *) &frag->buffer); } } //Drop the partially reconstructed datagram chunkedBufferSetLength((ChunkedBuffer *) &frag->buffer, 0); } } } //Release exclusive access to the reassembly queue osReleaseMutex(&interface->ipv6FragQueueMutex); }
error_t sntpSendRequest(SntpClientContext *context) { size_t length; NtpHeader *message; //Point to the buffer where to format the NTP message message = &context->message; //Clear NTP message memset(message, 0, sizeof(NtpHeader)); //Format NTP request message->vn = NTP_VERSION_3; message->mode = NTP_MODE_CLIENT; //Time at which the NTP request was sent context->t1 = osGetSystemTime(); //The Transmit Timestamp allows a simple calculation to determine the //propagation delay between the server and client and to align the system //clock generally within a few tens of milliseconds relative to the server message->transmitTimestamp.seconds = 0; message->transmitTimestamp.fraction = htonl(context->t1); //Length of the NTP request length = sizeof(NtpHeader); //Debug message TRACE_INFO("Sending NTP request message (%" PRIuSIZE " bytes)...\r\n", sizeof(NtpHeader)); //Dump NTP message sntpDumpMessage(message, length); //Send NTP request return socketSend(context->socket, message, length, NULL, 0); }
void chapTick(PppContext *context) { //Check whether the restart timer is running if(context->chapFsm.localState == CHAP_STATE_2_CHALLENGE_SENT) { //Get current time systime_t time = osGetSystemTime(); //Check restart timer if((time - context->chapFsm.timestamp) >= CHAP_RESTART_TIMER) { //Debug message TRACE_INFO("\r\nCHAP Timeout event\r\n"); //Check whether the restart counter is greater than zero if(context->chapFsm.restartCounter > 0) { //Retransmit the Challenge packet chapSendChallenge(context); } else { //Abort CHAP authentication context->chapFsm.localState = CHAP_STATE_0_INITIAL; //Authentication failed lcpClose(context); } } } }
error_t tlsSaveSession(const TlsContext *context, TlsSession *session) { //Check parameters if(context == NULL || session == NULL) return ERROR_INVALID_PARAMETER; //Invalid session parameters? if(!context->sessionIdLength || !context->cipherSuite) return ERROR_FAILURE; //Save session identifier memcpy(session->id, context->sessionId, context->sessionIdLength); session->idLength = context->sessionIdLength; //Get current time session->timestamp = osGetSystemTime(); //Negotiated cipher suite and compression method session->cipherSuite = context->cipherSuite; session->compressionMethod = context->compressionMethod; //Save master secret memcpy(session->masterSecret, context->masterSecret, 48); //Successful processing return NO_ERROR; }
error_t mib2GetSysUpTime(const MibObject *object, const uint8_t *oid, size_t oidLen, MibVariant *value, size_t *valueLen) { //Get object value value->timeTicks = osGetSystemTime() / 10; //Successful processing return NO_ERROR; }
void tcpTimerStart(TcpTimer *timer, systime_t delay) { //Start timer timer->startTime = osGetSystemTime(); timer->interval = delay; //The timer is now running... timer->running = TRUE; }
error_t sntpWaitForResponse(SntpClientContext *context, systime_t timeout) { error_t error; size_t length; systime_t elapsedTime; //Time elapsed since the NTP request was sent elapsedTime = 0; //Keep listening as long as the retransmission timeout has not been reached while(elapsedTime < timeout) { //Adjust receive timeout error = socketSetTimeout(context->socket, timeout - elapsedTime); //Any error to report? if(error) break; //Wait for a response from the NTP server error = socketReceive(context->socket, &context->message, sizeof(NtpHeader), &length, 0); //Any datagram received? if(!error) { //Time at which the response was received context->t4 = osGetSystemTime(); //Parse incoming datagram error = sntpParseResponse(context, &context->message, length); //Valid NTP response message? if(!error) return NO_ERROR; } //Compute the time elapsed since the NTP request was sent elapsedTime = osGetSystemTime() - context->t1; } //The timeout period elapsed return ERROR_TIMEOUT; }
void lcpZeroRestartCount(PppContext *context) { //Debug message TRACE_INFO("LCP Zero-Restart-Count callback\r\n"); //Zero restart counter context->lcpFsm.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->lcpFsm.timestamp = osGetSystemTime(); }
bool_t tcpTimerElapsed(TcpTimer *timer) { systime_t time; //Check whether the timer is running if(!timer->running) return FALSE; //Get current time time = osGetSystemTime(); //Check whether the specified time interval has elapsed if(timeCompare(time, timer->startTime + timer->interval) >= 0) return TRUE; else return FALSE; }
void lcpTick(PppContext *context) { //Check whether the restart timer is running if(context->lcpFsm.state >= PPP_STATE_4_CLOSING && context->lcpFsm.state <= PPP_STATE_8_ACK_SENT) { //Get current time systime_t time = osGetSystemTime(); //Check restart timer if((time - context->lcpFsm.timestamp) >= PPP_RESTART_TIMER) { //Debug message TRACE_INFO("\r\nLCP Timeout event\r\n"); //The restart timer is used to restransmit Configure-Request //and Terminate-Request packets pppTimeoutEvent(context, &context->lcpFsm, &lcpCallbacks); } } }
error_t lcpSendTerminateReq(PppContext *context) { error_t error; //Debug message TRACE_INFO("LCP Send-Terminate-Request callback\r\n"); //On transmission, the Identifier field must be changed context->lcpFsm.identifier++; //Send Terminate-Request packet error = pppSendTerminateReq(context, context->lcpFsm.identifier, PPP_PROTOCOL_LCP); //The restart counter is decremented each time a Terminate-Request is sent if(context->lcpFsm.restartCounter > 0) context->lcpFsm.restartCounter--; //Save the time at which the packet was sent context->lcpFsm.timestamp = osGetSystemTime(); //Return status code return error; }
error_t httpServerCgiCallback(HttpConnection *connection, const char_t *param) { static uint_t pageCounter = 0; uint_t length; MacAddr macAddr; #if (IPV4_SUPPORT == ENABLED) Ipv4Addr ipv4Addr; #endif #if (IPV6_SUPPORT == ENABLED) uint_t n; Ipv6Addr ipv6Addr; #endif //Underlying network interface NetInterface *interface = connection->socket->interface; //Check parameter name if(!strcasecmp(param, "PAGE_COUNTER")) { pageCounter++; sprintf(connection->buffer, "%u time%s", pageCounter, (pageCounter >= 2) ? "s" : ""); } else if(!strcasecmp(param, "BOARD_NAME")) { strcpy(connection->buffer, "SAM7SE-EK"); } else if(!strcasecmp(param, "SYSTEM_TIME")) { systime_t time = osGetSystemTime(); formatSystemTime(time, connection->buffer); } else if(!strcasecmp(param, "MAC_ADDR")) { netGetMacAddr(interface, &macAddr); macAddrToString(&macAddr, connection->buffer); } else if(!strcasecmp(param, "IPV4_ADDR")) { ipv4GetHostAddr(interface, &ipv4Addr); ipv4AddrToString(ipv4Addr, connection->buffer); } else if(!strcasecmp(param, "SUBNET_MASK")) { ipv4GetSubnetMask(interface, &ipv4Addr); ipv4AddrToString(ipv4Addr, connection->buffer); } else if(!strcasecmp(param, "DEFAULT_GATEWAY")) { ipv4GetDefaultGateway(interface, &ipv4Addr); ipv4AddrToString(ipv4Addr, connection->buffer); } else if(!strcasecmp(param, "IPV4_PRIMARY_DNS")) { ipv4GetDnsServer(interface, 0, &ipv4Addr); ipv4AddrToString(ipv4Addr, connection->buffer); } else if(!strcasecmp(param, "IPV4_SECONDARY_DNS")) { ipv4GetDnsServer(interface, 1, &ipv4Addr); ipv4AddrToString(ipv4Addr, connection->buffer); } #if (IPV6_SUPPORT == ENABLED) else if(!strcasecmp(param, "LINK_LOCAL_ADDR")) { ipv6GetLinkLocalAddr(interface, &ipv6Addr); ipv6AddrToString(&ipv6Addr, connection->buffer); } else if(!strcasecmp(param, "GLOBAL_ADDR")) { ipv6GetGlobalAddr(interface, 0, &ipv6Addr); ipv6AddrToString(&ipv6Addr, connection->buffer); } else if(!strcasecmp(param, "IPV6_PREFIX")) { ipv6GetPrefix(interface, 0, &ipv6Addr, &n); ipv6AddrToString(&ipv6Addr, connection->buffer); length = strlen(connection->buffer); sprintf(connection->buffer + length, "/%u", n); } else if(!strcasecmp(param, "ROUTER")) { ipv6GetDefaultRouter(interface, 0, &ipv6Addr); ipv6AddrToString(&ipv6Addr, connection->buffer); } else if(!strcasecmp(param, "IPV6_PRIMARY_DNS")) { ipv6GetDnsServer(interface, 0, &ipv6Addr); ipv6AddrToString(&ipv6Addr, connection->buffer); } else if(!strcasecmp(param, "IPV6_SECONDARY_DNS")) { ipv6GetDnsServer(interface, 1, &ipv6Addr); ipv6AddrToString(&ipv6Addr, connection->buffer); } #endif else { return ERROR_INVALID_TAG; } //Get the length of the resulting string length = strlen(connection->buffer); //Send the contents of the specified environment variable return httpWriteStream(connection, connection->buffer, length); }
error_t nbnsResolve(NetInterface *interface, const char_t *name, IpAddr *ipAddr) { error_t error; DnsCacheEntry *entry; #if (NET_RTOS_SUPPORT == ENABLED) systime_t delay; //Debug message TRACE_INFO("Resolving host name %s (NBNS resolver)...\r\n", name); #endif //Acquire exclusive access to the DNS cache osAcquireMutex(&dnsCacheMutex); //Search the DNS cache for the specified host name entry = dnsFindEntry(interface, name, HOST_TYPE_IPV4, HOST_NAME_RESOLVER_NBNS); //Check whether a matching entry has been found if(entry) { //Host name already resolved? if(entry->state == DNS_STATE_RESOLVED || entry->state == DNS_STATE_PERMANENT) { //Return the corresponding IP address *ipAddr = entry->ipAddr; //Successful host name resolution error = NO_ERROR; } else { //Host name resolution is in progress... error = ERROR_IN_PROGRESS; } } else { //If no entry exists, then create a new one entry = dnsCreateEntry(); //Record the host name whose IP address is unknown strcpy(entry->name, name); //Initialize DNS cache entry entry->type = HOST_TYPE_IPV4; entry->protocol = HOST_NAME_RESOLVER_NBNS; entry->interface = interface; //Initialize retransmission counter entry->retransmitCount = NBNS_CLIENT_MAX_RETRIES; //Send NBNS query error = nbnsSendQuery(entry); //NBNS message successfully sent? if(!error) { //Save the time at which the query message was sent entry->timestamp = osGetSystemTime(); //Set timeout value entry->timeout = NBNS_CLIENT_INIT_TIMEOUT; entry->maxTimeout = NBNS_CLIENT_MAX_TIMEOUT; //Decrement retransmission counter entry->retransmitCount--; //Switch state entry->state = DNS_STATE_IN_PROGRESS; //Host name resolution is in progress error = ERROR_IN_PROGRESS; } } //Release exclusive access to the DNS cache osReleaseMutex(&dnsCacheMutex); #if (NET_RTOS_SUPPORT == ENABLED) //Set default polling interval delay = DNS_CACHE_INIT_POLLING_INTERVAL; //Wait the host name resolution to complete while(error == ERROR_IN_PROGRESS) { //Wait until the next polling period osDelayTask(delay); //Acquire exclusive access to the DNS cache osAcquireMutex(&dnsCacheMutex); //Search the DNS cache for the specified host name entry = dnsFindEntry(interface, name, HOST_TYPE_IPV4, HOST_NAME_RESOLVER_NBNS); //Check whether a matching entry has been found if(entry) { //Host name successfully resolved? if(entry->state == DNS_STATE_RESOLVED) { //Return the corresponding IP address *ipAddr = entry->ipAddr; //Successful host name resolution error = NO_ERROR; } } else { //Host name resolution failed error = ERROR_FAILURE; } //Release exclusive access to the DNS cache osReleaseMutex(&dnsCacheMutex); //Backoff support for less aggressive polling delay = MIN(delay * 2, DNS_CACHE_MAX_POLLING_INTERVAL); } //Check status code if(error) { //Failed to resolve host name TRACE_INFO("Host name resolution failed!\r\n"); } else { //Successful host name resolution TRACE_INFO("Host name resolved to %s...\r\n", ipAddrToString(ipAddr, NULL)); } #endif //Return status code return error; }
void ndpProcessNeighborAdv(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader, const ChunkedBuffer *buffer, size_t offset, uint8_t hopLimit) { size_t length; NdpNeighborAdvMessage *message; NdpLinkLayerAddrOption *option; NdpCacheEntry *entry; //Retrieve the length of the message length = chunkedBufferGetLength(buffer) - offset; //Check the length of the Neighbor Advertisement message if(length < sizeof(NdpNeighborAdvMessage)) return; //Point to the beginning of the message message = chunkedBufferAt(buffer, offset); //Sanity check if(!message) return; //Debug message TRACE_INFO("Neighbor Advertisement message received (%" PRIuSIZE " bytes)...\r\n", length); //Dump message contents for debugging purpose ndpDumpNeighborAdvMessage(message); //The IPv6 Hop Limit field must have a value of 255 to ensure //that the packet has not been forwarded by a router if(hopLimit != NDP_HOP_LIMIT) return; //ICMPv6 Code must be 0 if(message->code) return; //Check whether the target address is tentative or matches //a unicast address assigned to the interface if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.linkLocalAddr) && interface->ipv6Config.linkLocalAddrState != IPV6_ADDR_STATE_INVALID) { //Debug message TRACE_WARNING("The address %s is a duplicate!\r\n", ipv6AddrToString(&interface->ipv6Config.linkLocalAddr, NULL)); //The address is a duplicate and should not be used interface->ipv6Config.linkLocalAddrDup = TRUE; //Exit immediately return; } else if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.globalAddr) && interface->ipv6Config.globalAddrState != IPV6_ADDR_STATE_INVALID) { //Debug message TRACE_WARNING("The address %s is a duplicate!\r\n", ipv6AddrToString(&interface->ipv6Config.globalAddr, NULL)); //The address is a duplicate and should not be used interface->ipv6Config.globalAddrDup = TRUE; //Exit immediately return; } //The target address must not be a multicast address if(ipv6IsMulticastAddr(&message->targetAddr)) { //Debug message TRACE_WARNING("Target address must not be a multicast address!\r\n"); //Exit immediately return; } //If the destination address is a multicast address //then the Solicited flag must be zero if(ipv6IsMulticastAddr(&pseudoHeader->destAddr) && message->s) { //Debug message TRACE_WARNING("Solicited flag must be zero!\r\n"); //Exit immediately return; } //Calculate the length of the Options field length -= sizeof(NdpNeighborSolMessage); //Search for the Target Link-Layer Address option option = ndpGetOption(message->options, length, NDP_OPT_TARGET_LINK_LAYER_ADDR); //Source Link-Layer Address option found? if(option && option->length == 1) { //Debug message TRACE_DEBUG(" Target Link-Layer Address = %s\r\n", macAddrToString(&option->linkLayerAddr, NULL)); //Acquire exclusive access to Neighbor cache osAcquireMutex(&interface->ndpCacheMutex); //Search the Neighbor cache for the specified target address entry = ndpFindEntry(interface, &message->targetAddr); //If no entry exists, the advertisement should be silently discarded if(entry) { //INCOMPLETE state? if(entry->state == NDP_STATE_INCOMPLETE) { //Record link-layer address entry->macAddr = option->linkLayerAddr; //Send all the packets that are pending for transmission ndpSendQueuedPackets(interface, entry); //Save current time entry->timestamp = osGetSystemTime(); //Solicited flag is set? if(message->s) { //Computing the random ReachableTime value entry->timeout = NDP_REACHABLE_TIME; //Switch to the REACHABLE state entry->state = NDP_STATE_REACHABLE; } //Solicited flag is cleared? else { //Enter the STALE state entry->state = NDP_STATE_STALE; } } //REACHABLE, STALE, DELAY or PROBE state? else { //Solicited flag is set and Override flag is cleared? if(message->s && !message->o) { //Same link-layer address than cached? if(macCompAddr(&entry->macAddr, &option->linkLayerAddr)) { //Save current time entry->timestamp = osGetSystemTime(); //Computing the random ReachableTime value entry->timeout = NDP_REACHABLE_TIME; //Switch to the REACHABLE state entry->state = NDP_STATE_REACHABLE; } //Different link-layer address than cached? else { //REACHABLE state? if(entry->state == NDP_STATE_REACHABLE) { //Save current time entry->timestamp = osGetSystemTime(); //Enter the STALE state entry->state = NDP_STATE_STALE; } } } //Both Solicited and Override flags are set? else if(message->s && message->o) { //Record link-layer address (if different) entry->macAddr = option->linkLayerAddr; //Save current time entry->timestamp = osGetSystemTime(); //Computing the random ReachableTime value entry->timeout = NDP_REACHABLE_TIME; //Switch to the REACHABLE state entry->state = NDP_STATE_REACHABLE; } //Solicited flag is cleared and Override flag is set? else if(!message->s && message->o) { //Different link-layer address than cached? if(!macCompAddr(&entry->macAddr, &option->linkLayerAddr)) { //Record link-layer address entry->macAddr = option->linkLayerAddr; //Save current time entry->timestamp = osGetSystemTime(); //Enter the STALE state entry->state = NDP_STATE_STALE; } } } } } //Source Link-Layer Address option not found? else { //Update content of IsRouter flag } //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); }
void ndpTick(NetInterface *interface) { uint_t i; systime_t time; NdpCacheEntry *entry; //Get current time time = osGetSystemTime(); //Acquire exclusive access to Neighbor cache osAcquireMutex(&interface->ndpCacheMutex); //Go through Neighbor cache for(i = 0; i < NDP_CACHE_SIZE; i++) { //Point to the current entry entry = &interface->ndpCache[i]; //INCOMPLETE state? if(entry->state == NDP_STATE_INCOMPLETE) { //The Neighbor Solicitation timed out? if((time - entry->timestamp) >= entry->timeout) { //Increment retransmission counter entry->retransmitCount++; //Check whether the maximum number of retransmissions has been exceeded if(entry->retransmitCount < NDP_MAX_MULTICAST_SOLICIT) { //Retransmit a multicast Neighbor Solicitation message ndpSendNeighborSol(interface, &entry->ipAddr); //Save the time at which the message was sent entry->timestamp = time; //Set timeout value entry->timeout = NDP_RETRANS_TIMER; } else { //Drop packets that are waiting for address resolution ndpFlushQueuedPackets(interface, entry); //The entry should be deleted since address resolution has failed entry->state = NDP_STATE_NONE; } } } //REACHABLE state? else if(entry->state == NDP_STATE_REACHABLE) { //Periodically time out Neighbor cache entries if((time - entry->timestamp) >= entry->timeout) { //Save current time entry->timestamp = osGetSystemTime(); //Enter STALE state entry->state = NDP_STATE_STALE; } } //DELAY state? else if(entry->state == NDP_STATE_DELAY) { //Wait for the specified delay before sending the first probe if((time - entry->timestamp) >= entry->timeout) { //Send a unicast Neighbor Solicitation message ndpSendNeighborSol(interface, &entry->ipAddr); //Save the time at which the message was sent entry->timestamp = time; //Set timeout value entry->timeout = NDP_RETRANS_TIMER; //Switch to the PROBE state entry->state = NDP_STATE_PROBE; } } //PROBE state? else if(entry->state == NDP_STATE_PROBE) { //The request timed out? if((time - entry->timestamp) >= entry->timeout) { //Increment retransmission counter entry->retransmitCount++; //Check whether the maximum number of retransmissions has been exceeded if(entry->retransmitCount < NDP_MAX_UNICAST_SOLICIT) { //Send a unicast Neighbor Solicitation message ndpSendNeighborSol(interface, &entry->ipAddr); //Save the time at which the packet was sent entry->timestamp = time; //Set timeout value entry->timeout = NDP_RETRANS_TIMER; } else { //The entry should be deleted since the host is not reachable anymore entry->state = NDP_STATE_NONE; } } } } //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); }
error_t httpVerifyNonce(HttpServerContext *context, const char_t *nonce, const char_t *nc) { #if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED) error_t error; uint_t i; uint32_t count; systime_t time; HttpNonceCacheEntry *entry; //Check parameters if(nonce == NULL || nc == NULL) return ERROR_INVALID_PARAMETER; //Convert the nonce count to integer count = strtoul(nc, NULL, 16); //Get current time time = osGetSystemTime(); //Acquire exclusive access to the nonce cache osAcquireMutex(&context->nonceCacheMutex); //Loop through nonce cache entries for(i = 0; i < HTTP_SERVER_NONCE_CACHE_SIZE; i++) { //Point to the current entry entry = &context->nonceCache[i]; //Check nonce value if(!strcasecmp(entry->nonce, nonce)) { //Make sure the nonce timestamp has not expired if((time - entry->timestamp) < HTTP_SERVER_NONCE_LIFETIME) { //Check nonce count to prevent replay attacks if(count >= entry->count) { //Update nonce count to the next expected value entry->count = count + 1; //We are done break; } } } } //Check whether the nonce is valid if(i < HTTP_SERVER_NONCE_CACHE_SIZE) error = NO_ERROR; else error = ERROR_NOT_FOUND; //Release exclusive access to the nonce cache osReleaseMutex(&context->nonceCacheMutex); //Return status code return error; #else //Not implemented return ERROR_NOT_IMPLEMENTED; #endif }
void tcpProcessSegment(NetInterface *interface, IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset) { uint_t i; size_t length; Socket *socket; Socket *passiveSocket; TcpHeader *segment; //Total number of segments received, including those received in error MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInSegs, 1); MIB2_INC_COUNTER64(mib2Base.tcpGroup.tcpHCInSegs, 1); //A TCP implementation must silently discard an incoming //segment that is addressed to a broadcast or multicast //address (see RFC 1122 4.2.3.10) #if (IPV4_SUPPORT == ENABLED) if(pseudoHeader->length == sizeof(Ipv4PseudoHeader)) { //Ensure the destination address is not a broadcast address if(ipv4IsBroadcastAddr(interface, pseudoHeader->ipv4Data.destAddr)) return; //Ensure the destination address is not a multicast address if(ipv4IsMulticastAddr(pseudoHeader->ipv4Data.destAddr)) return; } else #endif #if (IPV6_SUPPORT == ENABLED) if(pseudoHeader->length == sizeof(Ipv6PseudoHeader)) { //Ensure the destination address is not a multicast address if(ipv6IsMulticastAddr(&pseudoHeader->ipv6Data.destAddr)) return; } else #endif { //This should never occur... return; } //Retrieve the length of the TCP segment length = netBufferGetLength(buffer) - offset; //Point to the TCP header segment = netBufferAt(buffer, offset); //Sanity check if(segment == NULL) return; //Ensure the TCP header is valid if(length < sizeof(TcpHeader)) { //Debug message TRACE_WARNING("TCP segment length is invalid!\r\n"); //Total number of segments received in error MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1); //Exit immediately return; } //Check header length if(segment->dataOffset < 5 || (segment->dataOffset * 4) > length) { //Debug message TRACE_WARNING("TCP header length is invalid!\r\n"); //Total number of segments received in error MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1); //Exit immediately return; } //Verify TCP checksum if(ipCalcUpperLayerChecksumEx(pseudoHeader->data, pseudoHeader->length, buffer, offset, length) != 0x0000) { //Debug message TRACE_WARNING("Wrong TCP header checksum!\r\n"); //Total number of segments received in error MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1); //Exit immediately return; } //No matching socket in the LISTEN state for the moment passiveSocket = NULL; //Look through opened sockets for(i = 0; i < SOCKET_MAX_COUNT; i++) { //Point to the current socket socket = socketTable + i; //TCP socket found? if(socket->type != SOCKET_TYPE_STREAM) continue; //Check whether the socket is bound to a particular interface if(socket->interface && socket->interface != interface) continue; //Check destination port number if(socket->localPort != ntohs(segment->destPort)) continue; #if (IPV4_SUPPORT == ENABLED) //An IPv4 packet was received? if(pseudoHeader->length == sizeof(Ipv4PseudoHeader)) { //Destination IP address filtering if(socket->localIpAddr.length) { //An IPv4 address is expected if(socket->localIpAddr.length != sizeof(Ipv4Addr)) continue; //Filter out non-matching addresses if(socket->localIpAddr.ipv4Addr != pseudoHeader->ipv4Data.destAddr) continue; } //Source IP address filtering if(socket->remoteIpAddr.length) { //An IPv4 address is expected if(socket->remoteIpAddr.length != sizeof(Ipv4Addr)) continue; //Filter out non-matching addresses if(socket->remoteIpAddr.ipv4Addr != pseudoHeader->ipv4Data.srcAddr) continue; } } else #endif #if (IPV6_SUPPORT == ENABLED) //An IPv6 packet was received? if(pseudoHeader->length == sizeof(Ipv6PseudoHeader)) { //Destination IP address filtering if(socket->localIpAddr.length) { //An IPv6 address is expected if(socket->localIpAddr.length != sizeof(Ipv6Addr)) continue; //Filter out non-matching addresses if(!ipv6CompAddr(&socket->localIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr)) continue; } //Source IP address filtering if(socket->remoteIpAddr.length) { //An IPv6 address is expected if(socket->remoteIpAddr.length != sizeof(Ipv6Addr)) continue; //Filter out non-matching addresses if(!ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr)) continue; } } else #endif //An invalid packet was received? { //This should never occur... continue; } //Keep track of the first matching socket in the LISTEN state if(socket->state == TCP_STATE_LISTEN && !passiveSocket) passiveSocket = socket; //Source port filtering if(socket->remotePort != ntohs(segment->srcPort)) continue; //A matching socket has been found break; } //If no matching socket has been found then try to //use the first matching socket in the LISTEN state if(i >= SOCKET_MAX_COUNT) socket = passiveSocket; //Offset to the first data byte offset += segment->dataOffset * 4; //Calculate the length of the data length -= segment->dataOffset * 4; //Debug message TRACE_DEBUG("%s: TCP segment received (%" PRIuSIZE " data bytes)...\r\n", formatSystemTime(osGetSystemTime(), NULL), length); //Dump TCP header contents for debugging purpose if(!socket) tcpDumpHeader(segment, length, 0, 0); else tcpDumpHeader(segment, length, socket->irs, socket->iss); //Convert from network byte order to host byte order segment->srcPort = ntohs(segment->srcPort); segment->destPort = ntohs(segment->destPort); segment->seqNum = ntohl(segment->seqNum); segment->ackNum = ntohl(segment->ackNum); segment->window = ntohs(segment->window); segment->urgentPointer = ntohs(segment->urgentPointer); //Specified port is unreachable? if(!socket) { //An incoming segment not containing a RST causes //a reset to be sent in response if(!(segment->flags & TCP_FLAG_RST)) tcpSendResetSegment(interface, pseudoHeader, segment, length); //Return immediately return; } //Check current state switch(socket->state) { //Process CLOSED state case TCP_STATE_CLOSED: //This is the default state that each connection starts in before //the process of establishing it begins tcpStateClosed(interface, pseudoHeader, segment, length); break; //Process LISTEN state case TCP_STATE_LISTEN: //A device (normally a server) is waiting to receive a synchronize (SYN) //message from a client. It has not yet sent its own SYN message tcpStateListen(socket, interface, pseudoHeader, segment, length); break; //Process SYN_SENT state case TCP_STATE_SYN_SENT: //The device (normally a client) has sent a synchronize (SYN) message and //is waiting for a matching SYN from the other device (usually a server) tcpStateSynSent(socket, segment, length); break; //Process SYN_RECEIVED state case TCP_STATE_SYN_RECEIVED: //The device has both received a SYN from its partner and sent its own SYN. //It is now waiting for an ACK to its SYN to finish connection setup tcpStateSynReceived(socket, segment, buffer, offset, length); break; //Process ESTABLISHED state case TCP_STATE_ESTABLISHED: //Data can be exchanged freely once both devices in the connection enter //this state. This will continue until the connection is closed tcpStateEstablished(socket, segment, buffer, offset, length); break; //Process CLOSE_WAIT state case TCP_STATE_CLOSE_WAIT: //The device has received a close request (FIN) from the other device. It //must now wait for the application to acknowledge this request and //generate a matching request tcpStateCloseWait(socket, segment, length); break; //Process LAST_ACK state case TCP_STATE_LAST_ACK: //A device that has already received a close request and acknowledged it, //has sent its own FIN and is waiting for an ACK to this request tcpStateLastAck(socket, segment, length); break; //Process FIN_WAIT_1 state case TCP_STATE_FIN_WAIT_1: //A device in this state is waiting for an ACK for a FIN it has sent, or //is waiting for a connection termination request from the other device tcpStateFinWait1(socket, segment, buffer, offset, length); break; //Process FIN_WAIT_2 state case TCP_STATE_FIN_WAIT_2: //A device in this state has received an ACK for its request to terminate the //connection and is now waiting for a matching FIN from the other device tcpStateFinWait2(socket, segment, buffer, offset, length); break; //Process CLOSING state case TCP_STATE_CLOSING: //The device has received a FIN from the other device and sent an ACK for //it, but not yet received an ACK for its own FIN message tcpStateClosing(socket, segment, length); break; //Process TIME_WAIT state case TCP_STATE_TIME_WAIT: //The device has now received a FIN from the other device and acknowledged //it, and sent its own FIN and received an ACK for it. We are done, except //for waiting to ensure the ACK is received and prevent potential overlap //with new connections tcpStateTimeWait(socket, segment, length); break; //Invalid state... default: //Back to the CLOSED state tcpChangeState(socket, TCP_STATE_CLOSED); //Silently discard incoming packet break; } }
error_t httpServerCgiCallback(HttpConnection *connection, const char_t *param) { static uint_t pageCounter = 0; uint_t length; //Underlying network interface NetInterface *interface = connection->socket->interface; //Check parameter name if(!strcasecmp(param, "PAGE_COUNTER")) { pageCounter++; sprintf(connection->buffer, "%u time%s", pageCounter, (pageCounter >= 2) ? "s" : ""); } else if(!strcasecmp(param, "BOARD_NAME")) { strcpy(connection->buffer, "STM32F4-Discovery"); } else if(!strcasecmp(param, "SYSTEM_TIME")) { systime_t time = osGetSystemTime(); formatSystemTime(time, connection->buffer); } else if(!strcasecmp(param, "MAC_ADDR")) { macAddrToString(&interface->macAddr, connection->buffer); } else if(!strcasecmp(param, "IPV4_ADDR")) { ipv4AddrToString(interface->ipv4Config.addr, connection->buffer); } else if(!strcasecmp(param, "SUBNET_MASK")) { ipv4AddrToString(interface->ipv4Config.subnetMask, connection->buffer); } else if(!strcasecmp(param, "DEFAULT_GATEWAY")) { ipv4AddrToString(interface->ipv4Config.defaultGateway, connection->buffer); } else if(!strcasecmp(param, "IPV4_PRIMARY_DNS")) { ipv4AddrToString(interface->ipv4Config.dnsServer[0], connection->buffer); } else if(!strcasecmp(param, "IPV4_SECONDARY_DNS")) { ipv4AddrToString(interface->ipv4Config.dnsServer[1], connection->buffer); } #if (IPV6_SUPPORT == ENABLED) else if(!strcasecmp(param, "LINK_LOCAL_ADDR")) { ipv6AddrToString(&interface->ipv6Config.linkLocalAddr, connection->buffer); } else if(!strcasecmp(param, "GLOBAL_ADDR")) { ipv6AddrToString(&interface->ipv6Config.globalAddr, connection->buffer); } else if(!strcasecmp(param, "IPV6_PREFIX")) { ipv6AddrToString(&interface->ipv6Config.prefix, connection->buffer); length = strlen(connection->buffer); sprintf(connection->buffer + length, "/%u", interface->ipv6Config.prefixLength); } else if(!strcasecmp(param, "ROUTER")) { ipv6AddrToString(&interface->ipv6Config.router, connection->buffer); } else if(!strcasecmp(param, "IPV6_PRIMARY_DNS")) { ipv6AddrToString(&interface->ipv6Config.dnsServer[0], connection->buffer); } else if(!strcasecmp(param, "IPV6_SECONDARY_DNS")) { ipv6AddrToString(&interface->ipv6Config.dnsServer[1], connection->buffer); } #endif else { return ERROR_INVALID_TAG; } //Get the length of the resulting string length = strlen(connection->buffer); //Send the contents of the specified environment variable return httpWriteStream(connection, connection->buffer, length); }
void mdnsTick(NetInterface *interface) { error_t error; systime_t time; MdnsContext *context; //Get current time time = osGetSystemTime(); //Point to the mDNS context context = &interface->mdnsContext; //Check current state if(context->state == MDNS_STATE_INIT) { //Make sure that the link is up if(interface->linkState) { #if (IPV4_SUPPORT == ENABLED) //Check whether the IPv4 host address is valid if(interface->ipv4Config.addrState == IPV4_ADDR_STATE_VALID) context->state = MDNS_STATE_PROBING; #endif #if (IPV6_SUPPORT == ENABLED) //Check whether the IPv6 link-local address is valid if(interface->ipv6Config.linkLocalAddrState == IPV6_ADDR_STATE_PREFERRED) context->state = MDNS_STATE_PROBING; #endif //Start probing? if(context->state == MDNS_STATE_PROBING) { //Clear conflict flag context->conflict = FALSE; //Set time stamp context->timestamp = time; //Initial random delay context->timeout = netGetRandRange(0, MDNS_INIT_DELAY); //Reset probe counter context->counter = 0; } } } else if(context->state == MDNS_STATE_PROBING) { //Check current time if((time - context->timestamp) >= context->timeout) { //Any conflict detected? if(context->conflict) { //Programmatically change the host name error = mdnsGenerateHostname(interface); //Failed to change host name? if(error) { //Report an error context->state = MDNS_STATE_ERROR; } else { //Restart probing context->state = MDNS_STATE_INIT; } } //Probing is on-going? else if(context->counter < MDNS_PROBE_NUM) { //Send probe packet mdnsSendProbe(interface); //Save the time at which the packet was sent context->timestamp = time; //Time interval between subsequent probe packets context->timeout = MDNS_PROBE_DELAY; //Increment packet counter context->counter++; } else { //Set time stamp context->timestamp = time; //Reset timeout value context->timeout = 0; //Reset probe counter context->counter = 0; //Move to the next step (announcing) context->state = MDNS_STATE_ANNOUNCING; } } } else if(context->state == MDNS_STATE_ANNOUNCING) { //Check current time if((time - context->timestamp) >= context->timeout) { //Send announcement packet mdnsSendAnnouncement(interface); //Save the time at which the packet was sent context->timestamp = time; //Time interval between subsequent announcement packets context->timeout = MDNS_ANNOUNCE_DELAY; //Increment packet counter context->counter++; //Announcing is complete? if(context->counter >= MDNS_ANNOUNCE_NUM) { //Probing and announcing steps are complete context->state = MDNS_STATE_DONE; } } } else if(context->state == MDNS_STATE_DONE) { if(interface->nicDriver->type == NIC_TYPE_ETHERNET) { //Any conflict detected? if(context->conflict) { //Programmatically change the host name error = mdnsGenerateHostname(interface); //Failed to change host name? if(error) { //Report an error context->state = MDNS_STATE_ERROR; } else { //Restart probing context->state = MDNS_STATE_INIT; } } } } }
void tcpTick(void) { error_t error; uint_t i; uint_t n; uint_t u; //Enter critical section osAcquireMutex(&socketMutex); //Loop through opened sockets for(i = 0; i < SOCKET_MAX_COUNT; i++) { //Shortcut to the current socket Socket *socket = socketTable + i; //Check socket type if(socket->type != SOCKET_TYPE_STREAM) continue; //Check the current state of the TCP state machine if(socket->state == TCP_STATE_CLOSED) continue; //Is there any packet in the retransmission queue? if(socket->retransmitQueue != NULL) { //Retransmission timeout? if(tcpTimerElapsed(&socket->retransmitTimer)) { //When a TCP sender detects segment loss using the retransmission //timer and the given segment has not yet been resent by way of //the retransmission timer, the value of ssthresh must be updated if(!socket->retransmitCount) { //Amount of data that has been sent but not yet acknowledged uint_t flightSize = socket->sndNxt - socket->sndUna; //Adjust ssthresh value socket->ssthresh = MAX(flightSize / 2, 2 * socket->mss); } //Furthermore, upon a timeout cwnd must be set to no more than //the loss window, LW, which equals 1 full-sized segment socket->cwnd = MIN(TCP_LOSS_WINDOW * socket->mss, socket->txBufferSize); //Make sure the maximum number of retransmissions has not been reached if(socket->retransmitCount < TCP_MAX_RETRIES) { //Debug message TRACE_INFO("%s: TCP segment retransmission #%u (%u data bytes)...\r\n", formatSystemTime(osGetSystemTime(), NULL), socket->retransmitCount + 1, socket->retransmitQueue->length); //Retransmit the earliest segment that has not been //acknowledged by the TCP receiver tcpRetransmitSegment(socket); //Use exponential back-off algorithm to calculate the new RTO socket->rto = MIN(socket->rto * 2, TCP_MAX_RTO); //Restart retransmission timer tcpTimerStart(&socket->retransmitTimer, socket->rto); //Increment retransmission counter socket->retransmitCount++; } else { //The maximum number of retransmissions has been exceeded tcpChangeState(socket, TCP_STATE_CLOSED); //Turn off the retransmission timer tcpTimerStop(&socket->retransmitTimer); } //TCP must use Karn's algorithm for taking RTT samples. That is, RTT //samples must not be made using segments that were retransmitted socket->rttBusy = FALSE; } } //Check the current state of the TCP state machine if(socket->state == TCP_STATE_CLOSED) continue; //The persist timer is used when the remote host advertises //a window size of zero if(!socket->sndWnd && socket->wndProbeInterval) { //Time to send a new probe? if(tcpTimerElapsed(&socket->persistTimer)) { //Make sure the maximum number of retransmissions has not been reached if(socket->wndProbeCount < TCP_MAX_RETRIES) { //Debug message TRACE_INFO("%s: TCP zero window probe #%u...\r\n", formatSystemTime(osGetSystemTime(), NULL), socket->wndProbeCount + 1); //Zero window probes usually have the sequence number one less than expected tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt - 1, socket->rcvNxt, 0, FALSE); //The interval between successive probes should be increased exponentially socket->wndProbeInterval = MIN(socket->wndProbeInterval * 2, TCP_MAX_PROBE_INTERVAL); //Restart the persist timer tcpTimerStart(&socket->persistTimer, socket->wndProbeInterval); //Increment window probe counter socket->wndProbeCount++; } else { //Enter CLOSED state tcpChangeState(socket, TCP_STATE_CLOSED); } } } //To avoid a deadlock, it is necessary to have a timeout to force //transmission of data, overriding the SWS avoidance algorithm. In //practice, this timeout should seldom occur (see RFC 1122 4.2.3.4) if(socket->state == TCP_STATE_ESTABLISHED || socket->state == TCP_STATE_CLOSE_WAIT) { //The override timeout occurred? if(socket->sndUser && tcpTimerElapsed(&socket->overrideTimer)) { //The amount of data that can be sent at any given time is //limited by the receiver window and the congestion window n = MIN(socket->sndWnd, socket->cwnd); n = MIN(n, socket->txBufferSize); //Retrieve the size of the usable window u = n - (socket->sndNxt - socket->sndUna); //Send as much data as possible while(socket->sndUser > 0) { //The usable window size may become zero or negative, //preventing packet transmission if((int_t) u <= 0) break; //Calculate the number of bytes to send at a time n = MIN(u, socket->sndUser); n = MIN(n, socket->mss); //Send TCP segment error = tcpSendSegment(socket, TCP_FLAG_PSH | TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, n, TRUE); //Failed to send TCP segment? if(error) break; //Advance SND.NXT pointer socket->sndNxt += n; //Adjust the number of bytes buffered but not yet sent socket->sndUser -= n; } //Check whether the transmitter can accept more data tcpUpdateEvents(socket); //Restart override timer if necessary if(socket->sndUser > 0) tcpTimerStart(&socket->overrideTimer, TCP_OVERRIDE_TIMEOUT); } } //The FIN-WAIT-2 timer prevents the connection //from staying in the FIN-WAIT-2 state forever if(socket->state == TCP_STATE_FIN_WAIT_2) { //Maximum FIN-WAIT-2 time has elapsed? if(tcpTimerElapsed(&socket->finWait2Timer)) { //Debug message TRACE_WARNING("TCP FIN-WAIT-2 timer elapsed...\r\n"); //Enter CLOSED state tcpChangeState(socket, TCP_STATE_CLOSED); } } //TIME-WAIT timer if(socket->state == TCP_STATE_TIME_WAIT) { //2MSL time has elapsed? if(tcpTimerElapsed(&socket->timeWaitTimer)) { //Debug message TRACE_WARNING("TCP 2MSL timer elapsed (socket %u)...\r\n", i); //Enter CLOSED state tcpChangeState(socket, TCP_STATE_CLOSED); //Dispose the socket if the user does not have the ownership anymore if(!socket->ownedFlag) { //Delete the TCB tcpDeleteControlBlock(socket); //Mark the socket as closed socket->type = SOCKET_TYPE_UNUSED; } } } } //Leave critical section osReleaseMutex(&socketMutex); }
Ipv6FragDesc *ipv6SearchFragQueue(NetInterface *interface, Ipv6Header *packet, Ipv6FragmentHeader *header) { error_t error; uint_t i; Ipv6Header *datagram; Ipv6FragDesc *frag; Ipv6HoleDesc *hole; //Search for a matching IP datagram being reassembled for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++) { //Point to the current entry in the reassembly queue frag = &interface->ipv6FragQueue[i]; //Check whether the current entry is used? if(frag->buffer.chunkCount > 0) { //Point to the corresponding datagram datagram = chunkedBufferAt((ChunkedBuffer *) &frag->buffer, 0); //Check source and destination addresses if(!ipv6CompAddr(&datagram->srcAddr, &packet->srcAddr)) continue; if(!ipv6CompAddr(&datagram->destAddr, &packet->destAddr)) continue; //Compare fragment identification fields if(frag->identification != header->identification) continue; //A matching entry has been found in the reassembly queue return frag; } } //If the current packet does not match an existing entry //in the reassembly queue, then create a new entry for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++) { //Point to the current entry in the reassembly queue frag = &interface->ipv6FragQueue[i]; //The current entry is free? if(!frag->buffer.chunkCount) { //Number of chunks that comprise the reassembly buffer frag->buffer.maxChunkCount = arraysize(frag->buffer.chunk); //Allocate sufficient memory to hold the IPv6 header and //the first hole descriptor error = chunkedBufferSetLength((ChunkedBuffer *) &frag->buffer, MEM_POOL_BUFFER_SIZE + sizeof(Ipv6HoleDesc)); //Failed to allocate memory? if(error) { //Clean up side effects chunkedBufferSetLength((ChunkedBuffer *) &frag->buffer, 0); //Exit immediately return NULL; } //Initial length of the reconstructed datagram frag->unfragPartLength = sizeof(Ipv6Header); frag->fragPartLength = 0; //Fix the length of the first chunk frag->buffer.chunk[0].length = frag->unfragPartLength; //Copy IPv6 header from the incoming fragment chunkedBufferWrite((ChunkedBuffer *) &frag->buffer, 0, packet, frag->unfragPartLength); //Save current time frag->timestamp = osGetSystemTime(); //Record fragment identification field frag->identification = header->identification; //Create a new entry in the hole descriptor list frag->firstHole = 0; //Point to first hole descriptor hole = ipv6FindHole(frag, frag->firstHole); //The entry describes the datagram as being completely missing hole->first = 0; hole->last = IPV6_INFINITY; hole->next = IPV6_INFINITY; //Dump hole descriptor list ipv6DumpHoleList(frag); //Return the matching fragment descriptor return frag; } } //The reassembly queue is full return NULL; }
error_t httpGenerateNonce(HttpServerContext *context, char_t *output, size_t *length) { #if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED) error_t error; uint_t i; HttpNonceCacheEntry *entry; HttpNonceCacheEntry *oldestEntry; uint8_t nonce[HTTP_SERVER_NONCE_SIZE]; //Acquire exclusive access to the nonce cache osAcquireMutex(&context->nonceCacheMutex); //Keep track of the oldest entry oldestEntry = &context->nonceCache[0]; //Loop through nonce cache entries for(i = 0; i < HTTP_SERVER_NONCE_CACHE_SIZE; i++) { //Point to the current entry entry = &context->nonceCache[i]; //Check whether the entry is currently in used or not if(!entry->count) break; //Keep track of the oldest entry in the table if(timeCompare(entry->timestamp, oldestEntry->timestamp) < 0) oldestEntry = entry; } //The oldest entry is removed whenever the table runs out of space if(i >= HTTP_SERVER_NONCE_CACHE_SIZE) entry = oldestEntry; //Generate a new nonce error = context->settings.prngAlgo->read(context->settings.prngContext, nonce, HTTP_SERVER_NONCE_SIZE); //Check status code if(!error) { //Convert the byte array to hex string httpConvertArrayToHexString(nonce, HTTP_SERVER_NONCE_SIZE, entry->nonce); //Clear nonce count entry->count = 1; //Save the time at which the nonce was generated entry->timestamp = osGetSystemTime(); //Copy the nonce to the output buffer strcpy(output, entry->nonce); //Return the length of the nonce excluding the NULL character *length = HTTP_SERVER_NONCE_SIZE * 2; } else { //Random number generation failed memset(entry, 0, sizeof(HttpNonceCacheEntry)); } //Release exclusive access to the nonce cache osReleaseMutex(&context->nonceCacheMutex); //Return status code return error; #else //Not implemented return ERROR_NOT_IMPLEMENTED; #endif }
void slaacProcessRouterAdv(SlaacContext *context, const Ipv6Addr *srcAddr, NdpRouterAdvMessage *message, size_t length) { uint_t i; uint_t n; NdpPrefixInfoOption *prefixInfoOption; NdpRdnssOption *rdnssOption; Eui64 interfaceId; Ipv6Addr globalAddr; //Check current state if(context->state != SLAAC_STATE_ROUTER_SOLICIT) return; //Save router address ipv6SetRouter(context->interface, srcAddr); //Calculate the length of the Options field length -= sizeof(NdpRouterAdvMessage); //Search for the Prefix Information option prefixInfoOption = ndpGetOption(message->options, length, NDP_OPT_PREFIX_INFORMATION); //Prefix Information option not found? if(prefixInfoOption == NULL || prefixInfoOption->length != 4) return; //If the Autonomous flag is not set, silently ignore the Prefix //Information option if(!prefixInfoOption->a) return; //If the prefix is the link-local prefix, silently ignore the //Prefix Information option if(ipv6CompPrefix(&prefixInfoOption->prefix, &IPV6_LINK_LOCAL_ADDR_PREFIX, 64)) return; //If the preferred lifetime is greater than the valid lifetime, //silently ignore the Prefix Information option if(prefixInfoOption->preferredLifetime > prefixInfoOption->validLifetime) return; //If the sum of the prefix length and interface identifier length does //not equal 128 bits, the Prefix Information option must be ignored if(prefixInfoOption->prefixLength != 64) return; //Save IPv6 prefix ipv6SetPrefix(context->interface, &prefixInfoOption->prefix, prefixInfoOption->prefixLength); //Generate the 64-bit interface identifier macAddrToEui64(&context->interface->macAddr, &interfaceId); //Form an address by combining the advertised prefix //with the interface identifier globalAddr.w[0] = prefixInfoOption->prefix.w[0]; globalAddr.w[1] = prefixInfoOption->prefix.w[1]; globalAddr.w[2] = prefixInfoOption->prefix.w[2]; globalAddr.w[3] = prefixInfoOption->prefix.w[3]; globalAddr.w[4] = interfaceId.w[0]; globalAddr.w[5] = interfaceId.w[1]; globalAddr.w[6] = interfaceId.w[2]; globalAddr.w[7] = interfaceId.w[3]; //Use the global address as a tentative address ipv6SetGlobalAddr(context->interface, &globalAddr, IPV6_ADDR_STATE_TENTATIVE); //Use the DNS servers provided by the router? if(!context->manualDnsConfig) { //Search for the Recursive DNS Server (RDNSS) option rdnssOption = ndpGetOption(message->options, length, NDP_OPT_RECURSIVE_DNS_SERVER); //RDNSS option found? if(rdnssOption != NULL && rdnssOption->length >= 1) { //Retrieve the number of addresses n = (rdnssOption->length - 1) / 2; //Save DNS servers for(i = 0; i < n; i++) ipv6SetDnsServer(context->interface, i, &rdnssOption->address[i]); } } //Set time stamp context->timestamp = osGetSystemTime(); //Reset timeout value context->timeout = 0; //Reset retransmission counter context->retransmitCount = 0; //Verify the uniqueness of the global address context->state = SLAAC_STATE_GLOBAL_ADDR_DAD; }
error_t ndpResolve(NetInterface *interface, const Ipv6Addr *ipAddr, MacAddr *macAddr) { NdpCacheEntry *entry; //Acquire exclusive access to Neighbor cache osAcquireMutex(&interface->ndpCacheMutex); //Search the ndpCacheMutex cache for the specified IPv6 address entry = ndpFindEntry(interface, ipAddr); //Check whether a matching entry has been found if(entry) { //Check the state of the Neighbor cache entry if(entry->state == NDP_STATE_INCOMPLETE) { //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); //The address resolution is already in progress return ERROR_IN_PROGRESS; } else if(entry->state == NDP_STATE_STALE) { //Copy the MAC address associated with the specified IPv6 address *macAddr = entry->macAddr; //Start delay timer entry->timestamp = osGetSystemTime(); //Delay before sending the first probe entry->timeout = NDP_DELAY_FIRST_PROBE_TIME; //Switch to the DELAY state entry->state = NDP_STATE_DELAY; //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); //Successful address resolution return NO_ERROR; } else { //Copy the MAC address associated with the specified IPv6 address *macAddr = entry->macAddr; //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); //Successful address resolution return NO_ERROR; } } //If no entry exists, then create a new one entry = ndpCreateEntry(interface); //Any error to report? if(!entry) { //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); //Report an error to the calling function return ERROR_OUT_OF_RESOURCES; } //Record the IPv6 address whose MAC address is unknown entry->ipAddr = *ipAddr; entry->macAddr = MAC_UNSPECIFIED_ADDR; //Reset retransmission counter entry->retransmitCount = 0; //No packet are pending in the transmit queue entry->queueSize = 0; //Send a multicast Neighbor Solicitation message ndpSendNeighborSol(interface, ipAddr); //Save the time at which the message was sent entry->timestamp = osGetSystemTime(); //Set timeout value entry->timeout = NDP_RETRANS_TIMER; //Enter INCOMPLETE state entry->state = NDP_STATE_INCOMPLETE; //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); //The address resolution is in progress return ERROR_IN_PROGRESS; }
void dnsTick(void) { error_t error; uint_t i; systime_t time; DnsCacheEntry *entry; //Get current time time = osGetSystemTime(); //Acquire exclusive access to the DNS cache osAcquireMutex(&dnsCacheMutex); //Go through DNS cache for(i = 0; i < DNS_CACHE_SIZE; i++) { //Point to the current entry entry = &dnsCache[i]; //Name resolution in progress? if(entry->state == DNS_STATE_IN_PROGRESS) { //The request timed out? if(timeCompare(time, entry->timestamp + entry->timeout) >= 0) { //Check whether the maximum number of retransmissions has been exceeded if(entry->retransmitCount > 0) { #if (DNS_CLIENT_SUPPORT == ENABLED) //DNS resolver? if(entry->protocol == HOST_NAME_RESOLVER_DNS) { //Retransmit DNS query error = dnsSendQuery(entry); } else #endif #if (MDNS_CLIENT_SUPPORT == ENABLED) //mDNS resolver? if(entry->protocol == HOST_NAME_RESOLVER_MDNS) { //Retransmit mDNS query error = mdnsSendQuery(entry); } else #endif #if (NBNS_CLIENT_SUPPORT == ENABLED && IPV4_SUPPORT == ENABLED) //NetBIOS Name Service resolver? if(entry->protocol == HOST_NAME_RESOLVER_NBNS) { //Retransmit NBNS query error = nbnsSendQuery(entry); } else #endif //Unknown protocol? { error = ERROR_FAILURE; } //Query message successfully sent? if(!error) { //Save the time at which the query message was sent entry->timestamp = time; //The timeout value is doubled for each subsequent retransmission entry->timeout = MIN(entry->timeout * 2, entry->maxTimeout); //Decrement retransmission counter entry->retransmitCount--; } else { //The entry should be deleted since name resolution has failed dnsDeleteEntry(entry); } } #if (DNS_CLIENT_SUPPORT == ENABLED) //DNS resolver? else if(entry->protocol == HOST_NAME_RESOLVER_DNS) { //Select the next DNS server entry->dnsServerNum++; //Initialize retransmission counter entry->retransmitCount = DNS_CLIENT_MAX_RETRIES; //Send DNS query error = dnsSendQuery(entry); //DNS message successfully sent? if(!error) { //Save the time at which the query message was sent entry->timestamp = time; //Set timeout value entry->timeout = DNS_CLIENT_INIT_TIMEOUT; //Decrement retransmission counter entry->retransmitCount--; } else { //The entry should be deleted since name resolution has failed dnsDeleteEntry(entry); } } #endif else { //The maximum number of retransmissions has been exceeded dnsDeleteEntry(entry); } } } //Name successfully resolved? else if(entry->state == DNS_STATE_RESOLVED) { //Check the lifetime of the current DNS cache entry if(timeCompare(time, entry->timestamp + entry->timeout) >= 0) { //Periodically time out DNS cache entries dnsDeleteEntry(entry); } } } //Release exclusive access to the DNS cache osReleaseMutex(&dnsCacheMutex); }
void ndpProcessNeighborSol(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader, const ChunkedBuffer *buffer, size_t offset, uint8_t hopLimit) { size_t length; NdpNeighborSolMessage *message; NdpLinkLayerAddrOption *option; NdpCacheEntry *entry; //Retrieve the length of the message length = chunkedBufferGetLength(buffer) - offset; //Check the length of the Neighbor Solicitation message if(length < sizeof(NdpNeighborSolMessage)) return; //Point to the beginning of the message message = chunkedBufferAt(buffer, offset); //Sanity check if(!message) return; //Debug message TRACE_INFO("Neighbor Solicitation message received (%" PRIuSIZE " bytes)...\r\n", length); //Dump message contents for debugging purpose ndpDumpNeighborSolMessage(message); //The IPv6 Hop Limit field must have a value of 255 to ensure //that the packet has not been forwarded by a router if(hopLimit != NDP_HOP_LIMIT) return; //ICMPv6 Code must be 0 if(message->code) return; //The target address must a valid unicast address assigned to the interface //or a tentative address on which DAD is being performed if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.linkLocalAddr)) { //Check whether the target address is tentative if(interface->ipv6Config.linkLocalAddrState == IPV6_ADDR_STATE_TENTATIVE) { //If the source address of the Neighbor Solicitation is the unspecified //address, the solicitation is from a node performing Duplicate Address //Detection if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR)) { //Debug message TRACE_WARNING("The tentative address %s is a duplicate!\r\n", ipv6AddrToString(&interface->ipv6Config.linkLocalAddr, NULL)); //The tentative address is a duplicate and should not be used interface->ipv6Config.linkLocalAddrDup = TRUE; } //In all cases, a node must not respond to a Neighbor Solicitation //for a tentative address return; } } else if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.globalAddr)) { //Check whether the target address is tentative if(interface->ipv6Config.globalAddrState == IPV6_ADDR_STATE_TENTATIVE) { //If the source address of the Neighbor Solicitation is the unspecified //address, the solicitation is from a node performing Duplicate Address //Detection if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR)) { //Debug message TRACE_WARNING("The tentative address %s is a duplicate!\r\n", ipv6AddrToString(&interface->ipv6Config.globalAddr, NULL)); //The tentative address is a duplicate and should not be used interface->ipv6Config.globalAddrDup = TRUE; } //In all cases, a node must not respond to a Neighbor Solicitation //for a tentative address return; } } else { //Debug message TRACE_WARNING("Wrong target address!\r\n"); //Exit immediately return; } //If the IP source address is the unspecified address, the IP //destination address must be a solicited-node multicast address if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR) && !ipv6IsSolicitedNodeAddr(&pseudoHeader->destAddr)) { //Debug message TRACE_WARNING("Destination address must be a solicited-node address!\r\n"); //Exit immediately return; } //Calculate the length of the Options field length -= sizeof(NdpNeighborSolMessage); //Search for the Source Link-Layer Address option option = ndpGetOption(message->options, length, NDP_OPT_SOURCE_LINK_LAYER_ADDR); //Source Link-Layer Address option found? if(option && option->length == 1) { //Debug message TRACE_DEBUG(" Source Link-Layer Address = %s\r\n", macAddrToString(&option->linkLayerAddr, NULL)); //If the Source Address is not the unspecified address, then the Neighbor //cache should be updated for the IP source address of the solicitation if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR)) return; //Acquire exclusive access to Neighbor cache osAcquireMutex(&interface->ndpCacheMutex); //Search the Neighbor cache for the source address of the solicitation entry = ndpFindEntry(interface, &pseudoHeader->srcAddr); //No matching entry has been found? if(!entry) { //Create an entry entry = ndpCreateEntry(interface); //Neighbor cache entry successfully created? if(entry) { //Record the IPv6 and the corresponding MAC address entry->ipAddr = pseudoHeader->srcAddr; entry->macAddr = option->linkLayerAddr; //Save current time entry->timestamp = osGetSystemTime(); //Enter the STALE state entry->state = NDP_STATE_STALE; } } else { //INCOMPLETE state? if(entry->state == NDP_STATE_INCOMPLETE) { //Record link-layer address entry->macAddr = option->linkLayerAddr; //Send all the packets that are pending for transmission ndpSendQueuedPackets(interface, entry); //Save current time entry->timestamp = osGetSystemTime(); //Enter the STALE state entry->state = NDP_STATE_STALE; } //REACHABLE, STALE, DELAY or PROBE state? else { //Different link-layer address than cached? if(!macCompAddr(&entry->macAddr, &option->linkLayerAddr)) { //Update link-layer address entry->macAddr = option->linkLayerAddr; //Save current time entry->timestamp = osGetSystemTime(); //Enter the STALE state entry->state = NDP_STATE_STALE; } } } //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); } //Source Link-Layer Address option not found? else { //This option must be included in multicast solicitations if(ipv6IsMulticastAddr(&pseudoHeader->destAddr)) { //Debug message TRACE_WARNING("The Source Link-Layer Address must be included!\r\n"); //Exit immediately return; } } //After any updates to the Neighbor cache, the node sends a Neighbor //Advertisement response as described in RFC 4861 7.2.4 ndpSendNeighborAdv(interface, &message->targetAddr, &pseudoHeader->srcAddr); }
void nbnsProcessResponse(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const NbnsHeader *message, size_t length) { uint_t i; size_t pos; DnsCacheEntry *entry; DnsResourceRecord *resourceRecord; NbnsAddrEntry *addrEntry; //The NBNS response shall contain one answer if(ntohs(message->qdcount) != 0 && ntohs(message->ancount) != 1) return; //Parse NetBIOS name pos = nbnsParseName(message, length, sizeof(DnsHeader), NULL); //Invalid name? if(!pos) return; //Point to the associated resource record resourceRecord = DNS_GET_RESOURCE_RECORD(message, pos); //Point to the resource data pos += sizeof(DnsResourceRecord); //Make sure the resource record is valid if(pos > length) return; if((pos + ntohs(resourceRecord->rdlength)) > length) return; //Check the class and the type of the resource record if(ntohs(resourceRecord->rclass) != DNS_RR_CLASS_IN) return; if(ntohs(resourceRecord->rtype) != DNS_RR_TYPE_NB) return; //Verify the length of the data field if(ntohs(resourceRecord->rdlength) < sizeof(NbnsAddrEntry)) return; //Acquire exclusive access to the DNS cache osAcquireMutex(&dnsCacheMutex); //Loop through DNS cache entries for(i = 0; i < DNS_CACHE_SIZE; i++) { //Point to the current entry entry = &dnsCache[i]; //NBNS name resolution in progress? if(entry->state == DNS_STATE_IN_PROGRESS && entry->protocol == HOST_NAME_RESOLVER_NBNS && entry->type == HOST_TYPE_IPV4) { //Compare identifiers if(entry->id == ntohs(message->id)) { //Compare NetBIOS names if(nbnsCompareName(message, length, sizeof(DnsHeader), entry->name)) { //Point to the address entry array addrEntry = (NbnsAddrEntry *) resourceRecord->rdata; //Copy the IPv4 address entry->ipAddr.length = sizeof(Ipv4Addr); entry->ipAddr.ipv4Addr = addrEntry->addr; //Save current time entry->timestamp = osGetSystemTime(); //Save TTL value entry->timeout = ntohl(resourceRecord->ttl) * 1000; //Limit the lifetime of the NBNS cache entries entry->timeout = MIN(entry->timeout, NBNS_MAX_LIFETIME); //Host name successfully resolved entry->state = DNS_STATE_RESOLVED; } } } } //Release exclusive access to the DNS cache osReleaseMutex(&dnsCacheMutex); }
void slaacTick(SlaacContext *context) { systime_t time; //Get current time time = osGetSystemTime(); //Enter critical section osAcquireMutex(&context->mutex); //Check current state if(context->state == SLAAC_STATE_INIT) { //Check link state if(context->running && context->interface->linkState) { Eui64 interfaceId; Ipv6Addr linkLocalAddr; //Generate the 64-bit interface identifier macAddrToEui64(&context->interface->macAddr, &interfaceId); //A link-local address is formed by combining the well-known //link-local prefix fe80::0 with the interface identifier linkLocalAddr.w[0] = htons(0xFE80); linkLocalAddr.w[1] = htons(0x0000); linkLocalAddr.w[2] = htons(0x0000); linkLocalAddr.w[3] = htons(0x0000); linkLocalAddr.w[4] = interfaceId.w[0]; linkLocalAddr.w[5] = interfaceId.w[1]; linkLocalAddr.w[6] = interfaceId.w[2]; linkLocalAddr.w[7] = interfaceId.w[3]; //Use the link-local address as a tentative address ipv6SetLinkLocalAddr(context->interface, &linkLocalAddr, IPV6_ADDR_STATE_TENTATIVE); //Set time stamp context->timestamp = time; //Reset timeout value context->timeout = 0; //Reset retransmission counter context->retransmitCount = 0; //Verify the uniqueness of the link-local address context->state = SLAAC_STATE_LINK_LOCAL_ADDR_DAD; } } else if(context->state == SLAAC_STATE_LINK_LOCAL_ADDR_DAD) { //Check current time if((time - context->timestamp) >= context->timeout) { //Duplicate Address Detection failed? if(context->interface->ipv6Config.linkLocalAddrDup) { //A tentative address that is determined to be a duplicate //must not be assigned to an interface ipv6SetLinkLocalAddr(context->interface, &IPV6_UNSPECIFIED_ADDR, IPV6_ADDR_STATE_INVALID); //Address autoconfiguration failed context->state = SLAAC_STATE_ERROR; //Dump current IPv6 configuration for debugging purpose slaacDumpConfig(context); } #if (NDP_DUP_ADDR_DETECT_TRANSMITS > 0) //Duplicate Address Detection is on-going? else if(context->retransmitCount < NDP_DUP_ADDR_DETECT_TRANSMITS) { //Send Neighbor Solicitation message ndpSendNeighborSol(context->interface, &context->interface->ipv6Config.linkLocalAddr); //Save the time at which the message was sent context->timestamp = time; //Set timeout value context->timeout = NDP_RETRANS_TIMER; //Increment retransmission counter context->retransmitCount++; } #endif //Duplicate Address Detection is complete? else { //The use of the link-local address is now unrestricted context->interface->ipv6Config.linkLocalAddrState = IPV6_ADDR_STATE_PREFERRED; //Set time stamp context->timestamp = time; //Delay before transmitting the first Router Solicitation message context->timeout = tcpIpStackGetRandRange(0, NDP_MAX_RTR_SOLICITATION_DELAY); //Reset retransmission counter context->retransmitCount = 0; //To obtain an advertisement quickly, a host sends out Router Solicitations context->state = SLAAC_STATE_ROUTER_SOLICIT; } } } else if(context->state == SLAAC_STATE_ROUTER_SOLICIT) { //Check current time if((time - context->timestamp) >= context->timeout) { //Check retransmission counter if(context->retransmitCount < NDP_MAX_RTR_SOLICITATIONS) { //Send Router Solicitation message ndpSendRouterSol(context->interface); //Save the time at which the message was sent context->timestamp = time; //Set timeout value context->timeout = NDP_RTR_SOLICITATION_INTERVAL; //Increment retransmission counter context->retransmitCount++; } else { //A link has no routers if no Router Advertisements are received //after having sent a small number of Router Solicitations context->state = SLAAC_STATE_ERROR; //Dump current IPv6 configuration for debugging purpose slaacDumpConfig(context); } } } else if(context->state == SLAAC_STATE_GLOBAL_ADDR_DAD) { //Check current time if((time - context->timestamp) >= context->timeout) { //Duplicate Address Detection failed? if(context->interface->ipv6Config.globalAddrDup) { //A tentative address that is determined to be a duplicate //must not be assigned to an interface ipv6SetGlobalAddr(context->interface, &IPV6_UNSPECIFIED_ADDR, IPV6_ADDR_STATE_INVALID); //Address autoconfiguration failed context->state = SLAAC_STATE_ERROR; //Dump current IPv6 configuration for debugging purpose slaacDumpConfig(context); } #if (NDP_DUP_ADDR_DETECT_TRANSMITS > 0) //Duplicate Address Detection is on-going? else if(context->retransmitCount < NDP_DUP_ADDR_DETECT_TRANSMITS) { //Send Neighbor Solicitation message ndpSendNeighborSol(context->interface, &context->interface->ipv6Config.globalAddr); //Save the time at which the message was sent context->timestamp = time; //Set timeout value context->timeout = NDP_RETRANS_TIMER; //Increment retransmission counter context->retransmitCount++; } #endif //Duplicate Address Detection is complete? else { //The use of the global address is now unrestricted context->interface->ipv6Config.globalAddrState = IPV6_ADDR_STATE_PREFERRED; //Successful address autoconfiguration context->state = SLAAC_STATE_CONFIGURED; //Dump current IPv6 configuration for debugging purpose slaacDumpConfig(context); } } } //Leave critical section osReleaseMutex(&context->mutex); }
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; }