error_t udpInvokeRxCallback(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *header, const ChunkedBuffer *buffer, size_t offset) { uint_t i; void *params; UdpRxCallbackDesc *entry; //This flag tells whether a matching entry has been found bool_t found = FALSE; //Acquire exclusive access to the callback table osMutexAcquire(udpCallbackMutex); //Loop through the table for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++) { //Point to the current entry entry = &udpCallbackTable[i]; //Check whether the entry is currently in used if(entry->callback != NULL) { //Bound to a particular interface? if(entry->interface == NULL || entry->interface == interface) { //Does the specified port number match the current entry? if(entry->port == ntohs(header->destPort)) { //Retrieve callback parameters params = entry->params; //Release mutex to prevent any deadlock if(params == NULL) osMutexRelease(udpCallbackMutex); //Invoke user callback function entry->callback(interface, pseudoHeader, header, buffer, offset, params); //Acquire mutex if(params == NULL) osMutexAcquire(udpCallbackMutex); //A matching entry was found found = TRUE; } } } } //Release exclusive access to the callback table osMutexRelease(udpCallbackMutex); //Return status code return found ? NO_ERROR : ERROR_PORT_UNREACHABLE; }
error_t udpReceiveDatagram(Socket *socket, IpAddr *srcIpAddr, uint16_t *srcPort, IpAddr *destIpAddr, void *data, size_t size, size_t *received, uint_t flags) { SocketQueueItem *queueItem; //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 osEventReset(socket->event); //Leave critical section osMutexRelease(socketMutex); //Wait until an event is triggered osEventWait(socket->event, socket->timeout); //Enter critical section osMutexAcquire(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 = chunkedBufferRead(data, queueItem->buffer, queueItem->offset, size); //Save the source IP address if(srcIpAddr) *srcIpAddr = queueItem->srcIpAddr; //Save the source port number if(srcPort) *srcPort = queueItem->srcPort; //Save the destination IP address if(destIpAddr) *destIpAddr = queueItem->destIpAddr; //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 chunkedBufferFree(queueItem->buffer); } //Update the state of events udpUpdateEvents(socket); //Successful read operation return NO_ERROR; }
void memPoolFree(void *p) { //Use fixed-size blocks allocation? #if (MEM_POOL_SUPPORT == ENABLED) uint_t i; //Acquire exclusive access to the memory pool osMutexAcquire(memPoolMutex); //Loop through allocation table for(i = 0; i < MEM_POOL_BUFFER_COUNT; i++) { if(memPool[i] == p) { //Mark the current block as free memPoolAllocTable[i] = FALSE; //Exit immediately break; } } //Release exclusive access to the memory pool osMutexRelease(memPoolMutex); #else //Release memory block osMemFree(p); #endif }
void tcpIpStackRxTask(void *param) { //Point to the structure describing the network interface NetInterface *interface = (NetInterface *) param; //Main loop while(1) { //Receive notifications when a Ethernet frame has been received, //or the link status has changed osEventWait(interface->nicRxEvent, INFINITE_DELAY); //Get exclusive access to the device osMutexAcquire(interface->nicDriverMutex); //Disable Ethernet controller interrupts interface->nicDriver->disableIrq(interface); //Handle incoming packets and link state changes interface->nicDriver->rxEventHandler(interface); //Re-enable Ethernet controller interrupts interface->nicDriver->enableIrq(interface); //Release exclusive access to the device osMutexRelease(interface->nicDriverMutex); } }
void ipv6FragTick(NetInterface *interface) { error_t error; uint_t i; time_t time; Ipv6HoleDesc *hole; //Acquire exclusive access to the reassembly queue osMutexAcquire(interface->ipv6FragQueueMutex); //Get current time time = osGetTickCount(); //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 osMutexRelease(interface->ipv6FragQueueMutex); }
void mldProcessListenerReport(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader, const ChunkedBuffer *buffer, size_t offset, uint8_t hopLimit) { uint_t i; size_t length; MldMessage *message; Ipv6FilterEntry *entry; //Retrieve the length of the MLD message length = chunkedBufferGetLength(buffer) - offset; //The message must be at least 24 octets long if(length < sizeof(MldMessage)) return; //Point to the beginning of the MLD message message = chunkedBufferAt(buffer, offset); //Sanity check if(!message) return; //Debug message TRACE_INFO("MLD message received (%" PRIuSIZE " bytes)...\r\n", length); //Dump message contents for debugging purpose mldDumpMessage(message); //Make sure the source address of the message is a valid link-local address if(!ipv6IsLinkLocalUnicastAddr(&pseudoHeader->srcAddr)) return; //Check the Hop Limit field if(hopLimit != MLD_HOP_LIMIT) return; //Acquire exclusive access to the IPv6 filter table osMutexAcquire(interface->ipv6FilterMutex); //Loop through filter table entries for(i = 0; i < interface->ipv6FilterSize; i++) { //Point to the current entry entry = &interface->ipv6Filter[i]; //Report messages are ignored for multicast addresses //in the Non-Listener or Idle Listener state if(entry->state == MLD_STATE_DELAYING_LISTENER) { //The Multicast Listener Report message matches the current entry? if(ipv6CompAddr(&message->multicastAddr, &entry->addr)) { //Clear flag entry->flag = FALSE; //Switch to the Idle Listener state entry->state = MLD_STATE_IDLE_LISTENER; } } } //Release exclusive access to the IPv6 filter table osMutexRelease(interface->ipv6FilterMutex); }
void *memPoolAlloc(size_t size) { #if (MEM_POOL_SUPPORT == ENABLED) uint_t i; #endif //Pointer to the allocated memory block void *p = NULL; //Debug message TRACE_DEBUG("Allocating %" PRIuSIZE " bytes...\r\n", size); //Use fixed-size blocks allocation? #if (MEM_POOL_SUPPORT == ENABLED) //Acquire exclusive access to the memory pool osMutexAcquire(memPoolMutex); //Enforce block size if(size <= MEM_POOL_BUFFER_SIZE) { //Loop through allocation table for(i = 0; i < MEM_POOL_BUFFER_COUNT; i++) { //Check whether the current block is free if(!memPoolAllocTable[i]) { //Mark the current entry as used memPoolAllocTable[i] = TRUE; //Point to the corresponding memory block p = memPool[i]; //Update statistics memPoolCurrentUsage++; //Maximum number of buffers that have been allocated so far memPoolMaxUsage = max(memPoolCurrentUsage, memPoolMaxUsage); //Exit immediately break; } } } //Release exclusive access to the memory pool osMutexRelease(memPoolMutex); #else //Allocate a memory block p = osMemAlloc(size); #endif //Failed to allocate memory? if(!p) { //Debug message TRACE_WARNING("Memory allocation failed!\r\n"); } //Return a pointer to the allocated memory block return p; }
void eventOS_scheduler_mutex_wait(void) { osMutexAcquire(event_mutex_id, osWaitForever); if (0 == owner_count) { event_mutex_owner_id = osThreadGetId(); } owner_count++; }
void mldLinkChangeEvent(NetInterface *interface) { uint_t i; systime_t time; Ipv6FilterEntry *entry; //Get current time time = osGetTickCount(); //Acquire exclusive access to the IPv6 filter table osMutexAcquire(interface->ipv6FilterMutex); //Link up event? if(interface->linkState) { //Loop through filter table entries for(i = 0; i < interface->ipv6FilterSize; i++) { //Point to the current entry entry = &interface->ipv6Filter[i]; //The link-scope all-nodes address (FF02::1) is handled as a special //case. The host starts in Idle Listener state for that address on //every interface and never transitions to another state if(ipv6CompAddr(&entry->addr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR)) continue; //Send an unsolicited Multicast Listener Report message for that group mldSendListenerReport(interface, &entry->addr); //Set flag entry->flag = TRUE; //Start timer entry->timer = time + MLD_UNSOLICITED_REPORT_INTERVAL; //Enter the Delaying Listener state entry->state = MLD_STATE_DELAYING_LISTENER; } } //Link down event? else { //Loop through filter table entries for(i = 0; i < interface->ipv6FilterSize; i++) { //Point to the current entry entry = &interface->ipv6Filter[i]; //Clear flag entry->flag = FALSE; //Enter the Idle Listener state entry->state = MLD_STATE_IDLE_LISTENER; } } //Release exclusive access to the IPv6 filter table osMutexRelease(interface->ipv6FilterMutex); }
error_t ipv4LeaveMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr) { uint_t i; uint_t j; MacAddr macAddr; //Ensure the specified IPv4 address is a multicast address if(!ipv4IsMulticastAddr(groupAddr)) return ERROR_INVALID_ADDRESS; //Acquire exclusive access to the IPv4 filter table osMutexAcquire(interface->ipv4FilterMutex); //Loop through filter table entries for(i = 0; i < interface->ipv4FilterSize; i++) { //Specified IPv4 address found? if(interface->ipv4Filter[i].addr == groupAddr) { //Decrement the reference count interface->ipv4Filter[i].refCount--; //Remove the entry if the reference count drops to zero if(interface->ipv4Filter[i].refCount < 1) { #if (IGMP_SUPPORT == ENABLED) //Report group membership termination igmpLeaveGroup(interface, &interface->ipv4Filter[i]); #endif //Map the multicast IPv4 address to a MAC-layer address ipv4MapMulticastAddrToMac(groupAddr, &macAddr); //Drop the corresponding address from the MAC filter table ethDropMulticastAddr(interface, &macAddr); //Adjust the size of the IPv4 filter table interface->ipv4FilterSize--; //Remove the corresponding entry for(j = i; j < interface->ipv4FilterSize; j++) interface->ipv4Filter[j] = interface->ipv4Filter[j + 1]; } //Release exclusive access to the IPv4 filter table osMutexRelease(interface->ipv4FilterMutex); //No error to report return NO_ERROR; } } //Release exclusive access to the IPv4 filter table osMutexRelease(interface->ipv4FilterMutex); //The specified IPv4 address does not exist return ERROR_FAILURE; }
TcpState tcpGetState(Socket *socket) { TcpState state; //Enter critical section osMutexAcquire(socketMutex); //Get TCP FSM current state state = socket->state; //Leave critical section osMutexRelease(socketMutex); //Return current state return state; }
void ipv6FlushFragQueue(NetInterface *interface) { uint_t i; //Acquire exclusive access to the reassembly queue osMutexAcquire(interface->ipv6FragQueueMutex); //Loop through the reassembly queue for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++) { //Drop any partially reconstructed datagram chunkedBufferSetLength((ChunkedBuffer *) &interface->ipv6FragQueue[i].buffer, 0); } //Release exclusive access to the reassembly queue osMutexRelease(interface->ipv6FragQueueMutex); }
error_t icecastClientReadMetadata(IcecastClientContext *context, char_t *metadata, size_t size, size_t *length) { //Ensure the parameters are valid if(!context || !metadata) return ERROR_INVALID_PARAMETER; //Enter critical section osMutexAcquire(context->mutex); //Limit the number of data to read *length = min(size, context->metadataLength); //Save metadata information memcpy(metadata, context->metadata, *length); //Leave critical section osMutexRelease(context->mutex); //Successful read operation return NO_ERROR; }
void mldTick(NetInterface *interface) { uint_t i; systime_t time; Ipv6FilterEntry *entry; //Get current time time = osGetTickCount(); //Acquire exclusive access to the IPv6 filter table osMutexAcquire(interface->ipv6FilterMutex); //Loop through filter table entries for(i = 0; i < interface->ipv6FilterSize; i++) { //Point to the current entry entry = &interface->ipv6Filter[i]; //Delaying Listener state? if(entry->state == MLD_STATE_DELAYING_LISTENER) { //Timer expired? if(timeCompare(time, entry->timer) >= 0) { //Send a Multicast Listener Report message mldSendListenerReport(interface, &entry->addr); //Set flag entry->flag = TRUE; //Switch to the Idle Listener state entry->state = MLD_STATE_IDLE_LISTENER; } } } //Release exclusive access to the IPv6 filter table osMutexRelease(interface->ipv6FilterMutex); }
error_t udpAttachRxCallback(NetInterface *interface, uint16_t port, UdpRxCallback callback, void *params) { uint_t i; UdpRxCallbackDesc *entry; //Acquire exclusive access to the callback table osMutexAcquire(udpCallbackMutex); //Loop through the table for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++) { //Point to the current entry entry = &udpCallbackTable[i]; //Check whether the entry is currently in used if(entry->callback == NULL) { //Create a new entry entry->interface = interface; entry->port = port; entry->callback = callback; entry->params = params; //We are done break; } } //Release exclusive access to the callback table osMutexRelease(udpCallbackMutex); //Failed to attach the specified user callback? if(i >= UDP_CALLBACK_TABLE_SIZE) return ERROR_OUT_OF_RESOURCES; //Successful processing return NO_ERROR; }
void arpFlushCache(NetInterface *interface) { uint_t i; ArpCacheEntry *entry; //Acquire exclusive access to ARP cache osMutexAcquire(interface->arpCacheMutex); //Loop through ARP cache entries for(i = 0; i < ARP_CACHE_SIZE; i++) { //Point to the current entry entry = &interface->arpCache[i]; //Drop packets that are waiting for address resolution arpFlushQueuedPackets(interface, entry); //Release ARP entry entry->state = ARP_STATE_NONE; } //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); }
error_t udpDetachRxCallback(NetInterface *interface, uint16_t port) { uint_t i; UdpRxCallbackDesc *entry; //This flag tells whether an entry has been found bool_t found = FALSE; //Acquire exclusive access to the callback table osMutexAcquire(udpCallbackMutex); //Loop through the table for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++) { //Point to the current entry entry = &udpCallbackTable[i]; //Check whether the entry is currently in used if(entry->callback != NULL) { //Does the specified port number match the current entry? if(entry->port == port && entry->interface == interface) { //Unregister user callback entry->callback = NULL; //A matching entry was found found = TRUE; } } } //Release exclusive access to the callback table osMutexRelease(udpCallbackMutex); //Check whether the specified callback has been successfully unregistered return found ? NO_ERROR : ERROR_FAILURE; }
void arpProcessReply(NetInterface *interface, ArpPacket *arpReply) { ArpCacheEntry *entry; //Debug message TRACE_INFO("ARP Reply received...\r\n"); //Check sender protocol address if(arpReply->spa == IPV4_UNSPECIFIED_ADDR) return; if(ipv4IsMulticastAddr(arpReply->spa)) return; if(ipv4IsBroadcastAddr(interface, arpReply->spa)) return; //Check sender hardware address if(macCompAddr(&arpReply->sha, &MAC_UNSPECIFIED_ADDR)) return; if(macCompAddr(&arpReply->sha, &MAC_BROADCAST_ADDR)) return; //Acquire exclusive access to ARP cache osMutexAcquire(interface->arpCacheMutex); //Search the ARP cache for the specified IPv4 address entry = arpFindEntry(interface, arpReply->spa); //A matching ARP entry has been found if(entry) { //Check current state if(entry->state == ARP_STATE_INCOMPLETE) { //Record the corresponding MAC address entry->macAddr = arpReply->sha; //Send all the packets that are pending for transmission arpSendQueuedPackets(interface, entry); //Save current time entry->timestamp = osGetTickCount(); //The validity of the ARP entry is limited in time entry->timeout = ARP_REACHABLE_TIME; //Switch to the REACHABLE state entry->state = ARP_STATE_REACHABLE; } else if(entry->state == ARP_STATE_REACHABLE) { //Different link-layer address than cached? if(!macCompAddr(&arpReply->sha, &entry->macAddr)) { //Enter STALE state entry->state = ARP_STATE_STALE; } } else if(entry->state == ARP_STATE_PROBE) { //Record IPv4/MAC address pair entry->ipAddr = arpReply->spa; entry->macAddr = arpReply->sha; //Save current time entry->timestamp = osGetTickCount(); //The validity of the ARP entry is limited in time entry->timeout = ARP_REACHABLE_TIME; //Switch to the REACHABLE state entry->state = ARP_STATE_REACHABLE; } } //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); }
void arpTick(NetInterface *interface) { uint_t i; time_t time; ArpCacheEntry *entry; //Get current time time = osGetTickCount(); //Acquire exclusive access to ARP cache osMutexAcquire(interface->arpCacheMutex); //Go through ARP cache for(i = 0; i < ARP_CACHE_SIZE; i++) { //Point to the current entry entry = &interface->arpCache[i]; //INCOMPLETE state? if(entry->state == ARP_STATE_INCOMPLETE) { //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 < ARP_MAX_REQUESTS) { //Retransmit ARP request arpSendRequest(interface, interface->ipv4Config.addr, entry->ipAddr, &MAC_BROADCAST_ADDR); //Save the time at which the packet was sent entry->timestamp = time; //Set timeout value entry->timeout = ARP_REQUEST_TIMEOUT; } else { //Drop packets that are waiting for address resolution arpFlushQueuedPackets(interface, entry); //The entry should be deleted since address resolution has failed entry->state = ARP_STATE_NONE; } } } //REACHABLE state? else if(entry->state == ARP_STATE_REACHABLE) { //Periodically time out ARP cache entries if((time - entry->timestamp) >= entry->timeout) { //Save current time entry->timestamp = osGetTickCount(); //Enter STALE state entry->state = ARP_STATE_STALE; } } //DELAY state? else if(entry->state == ARP_STATE_DELAY) { //Wait for the specified delay before sending the first probe if((time - entry->timestamp) >= entry->timeout) { //Send a point-to-point ARP request to the host arpSendRequest(interface, interface->ipv4Config.addr, entry->ipAddr, &entry->macAddr); //Save the time at which the packet was sent entry->timestamp = time; //Set timeout value entry->timeout = ARP_PROBE_TIMEOUT; //Switch to the PROBE state entry->state = ARP_STATE_PROBE; } } //PROBE state? else if(entry->state == ARP_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 < ARP_MAX_PROBES) { //Send a point-to-point ARP request to the host arpSendRequest(interface, interface->ipv4Config.addr, entry->ipAddr, &entry->macAddr); //Save the time at which the packet was sent entry->timestamp = time; //Set timeout value entry->timeout = ARP_PROBE_TIMEOUT; } else { //The entry should be deleted since the host is not reachable anymore entry->state = ARP_STATE_NONE; } } } } //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); }
error_t arpEnqueuePacket(NetInterface *interface, Ipv4Addr ipAddr, ChunkedBuffer *buffer, size_t offset) { error_t error; uint_t i; size_t length; ArpCacheEntry *entry; //Retrieve the length of the multi-part buffer length = chunkedBufferGetLength(buffer); //Acquire exclusive access to ARP cache osMutexAcquire(interface->arpCacheMutex); //Search the ARP cache for the specified Ipv4 address entry = arpFindEntry(interface, ipAddr); //No matching entry in ARP cache? if(!entry) { //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //Report an error to the calling function return ERROR_FAILURE; } //Check current state if(entry->state == ARP_STATE_INCOMPLETE) { //Check whether the packet queue is full if(entry->queueSize >= ARP_MAX_PENDING_PACKETS) { //When the queue overflows, the new arrival should replace the oldest entry chunkedBufferFree(entry->queue[0].buffer); //Make room for the new packet for(i = 1; i < ARP_MAX_PENDING_PACKETS; i++) entry->queue[i - 1] = entry->queue[i]; //Adjust the number of pending packets entry->queueSize--; } //Index of the entry to be filled in i = entry->queueSize; //Allocate a memory buffer to store the packet entry->queue[i].buffer = chunkedBufferAlloc(length); //Failed to allocate memory? if(!entry->queue[i].buffer) { //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //Report an error to the calling function return ERROR_OUT_OF_MEMORY; } //Copy packet contents chunkedBufferCopy(entry->queue[i].buffer, 0, buffer, 0, length); //Offset to the first byte of the IPv4 header entry->queue[i].offset = offset; //Increment the number of queued packets entry->queueSize++; //The packet was successfully enqueued error = NO_ERROR; } else { //Send immediately the packet since the address is already resolved error = ethSendFrame(interface, &entry->macAddr, buffer, offset, ETH_TYPE_IPV4); } //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //Return status code return error; }
error_t arpResolve(NetInterface *interface, Ipv4Addr ipAddr, MacAddr *macAddr) { ArpCacheEntry *entry; //Acquire exclusive access to ARP cache osMutexAcquire(interface->arpCacheMutex); //Search the ARP cache for the specified IPv4 address entry = arpFindEntry(interface, ipAddr); //Check whether a matching entry has been found if(entry) { //Check the state of the ARP entry if(entry->state == ARP_STATE_INCOMPLETE) { //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //The address resolution is already in progress return ERROR_IN_PROGRESS; } else if(entry->state == ARP_STATE_STALE) { //Copy the MAC address associated with the specified IPv4 address *macAddr = entry->macAddr; //Start delay timer entry->timestamp = osGetTickCount(); //Delay before sending the first probe entry->timeout = ARP_DELAY_FIRST_PROBE_TIME; //Switch to the DELAY state entry->state = ARP_STATE_DELAY; //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //Successful address resolution return NO_ERROR; } else { //Copy the MAC address associated with the specified IPv4 address *macAddr = entry->macAddr; //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //Successful address resolution return NO_ERROR; } } //If no entry exists, then create a new one entry = arpCreateEntry(interface); //Any error to report? if(!entry) { //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //Report an error to the calling function return ERROR_OUT_OF_RESOURCES; } //Record the IPv4 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 an ARP request arpSendRequest(interface, interface->ipv4Config.addr, entry->ipAddr, &MAC_BROADCAST_ADDR); //Save the time at which the packet was sent entry->timestamp = osGetTickCount(); //Set timeout value entry->timeout = ARP_REQUEST_TIMEOUT; //Enter INCOMPLETE state entry->state = ARP_STATE_INCOMPLETE; //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //The address resolution is in progress return ERROR_IN_PROGRESS; }
void mldProcessListenerQuery(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader, const ChunkedBuffer *buffer, size_t offset, uint8_t hopLimit) { uint_t i; size_t length; systime_t time; systime_t maxRespDelay; MldMessage *message; Ipv6FilterEntry *entry; //Retrieve the length of the MLD message length = chunkedBufferGetLength(buffer) - offset; //The message must be at least 24 octets long if(length < sizeof(MldMessage)) return; //Point to the beginning of the MLD message message = chunkedBufferAt(buffer, offset); //Sanity check if(!message) return; //Debug message TRACE_INFO("MLD message received (%" PRIuSIZE " bytes)...\r\n", length); //Dump message contents for debugging purpose mldDumpMessage(message); //Make sure the source address of the message is a valid link-local address if(!ipv6IsLinkLocalUnicastAddr(&pseudoHeader->srcAddr)) return; //Check the Hop Limit field if(hopLimit != MLD_HOP_LIMIT) return; //Get current time time = osGetTickCount(); //The Max Resp Delay field specifies the maximum time allowed //before sending a responding report maxRespDelay = message->maxRespDelay * 10; //Acquire exclusive access to the IPv6 filter table osMutexAcquire(interface->ipv6FilterMutex); //Loop through filter table entries for(i = 0; i < interface->ipv6FilterSize; i++) { //Point to the current entry entry = &interface->ipv6Filter[i]; //The link-scope all-nodes address (FF02::1) is handled as a special //case. The host starts in Idle Listener state for that address on //every interface and never transitions to another state if(ipv6CompAddr(&entry->addr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR)) continue; //A General Query is used to learn which multicast addresses have listeners //on an attached link. A Multicast-Address-Specific Query is used to learn //if a particular multicast address has any listeners on an attached link if(ipv6CompAddr(&message->multicastAddr, &IPV6_UNSPECIFIED_ADDR) || ipv6CompAddr(&message->multicastAddr, &entry->addr)) { //Delaying Listener state? if(entry->state == MLD_STATE_DELAYING_LISTENER) { //The timer has not yet expired? if(timeCompare(time, entry->timer) < 0) { //If a timer for the address is already running, it is reset to //the new random value only if the requested Max Response Delay //is less than the remaining value of the running timer if(maxRespDelay < (entry->timer - time)) { //Restart delay timer entry->timer = time + mldRand(maxRespDelay); } } } //Idle Listener state? else if(entry->state == MLD_STATE_IDLE_LISTENER) { //Switch to the Delaying Listener state entry->state = MLD_STATE_DELAYING_LISTENER; //Delay the response by a random amount of time entry->timer = time + mldRand(maxRespDelay); } } } //Release exclusive access to the IPv6 filter table osMutexRelease(interface->ipv6FilterMutex); }
void __rtos_env_lock(struct _reent *_r) { osMutexAcquire(env_mutex_id, osWaitForever); }
error_t dnsResolve(NetInterface *interface, const char_t *name, HostType type, IpAddr *ipAddr) { error_t error; systime_t delay; DnsCacheEntry *entry; //Debug message TRACE_INFO("Resolving host name %s (DNS resolver)...\r\n", name); //Acquire exclusive access to the DNS cache osMutexAcquire(dnsCacheMutex); //Search the DNS cache for the specified host name entry = dnsFindEntry(interface, name, type, HOST_NAME_RESOLVER_DNS); //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 = type; entry->protocol = HOST_NAME_RESOLVER_DNS; entry->interface = interface; //Select primary DNS server entry->dnsServerNum = 0; //Get an ephemeral port number entry->port = socketGetEphemeralPort(); //An identifier is used by the DNS client to match replies //with corresponding requests entry->id = tcpIpStackGetRand(); //Callback function to be called when a DNS response is received error = udpAttachRxCallback(interface, entry->port, dnsProcessResponse, NULL); //Check status code if(!error) { //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 = osGetTickCount(); //Set timeout value entry->timeout = DNS_CLIENT_INIT_TIMEOUT; entry->maxTimeout = DNS_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; } else { //Unregister callback function udpDetachRxCallback(interface, entry->port); } } } //Release exclusive access to the DNS cache osMutexRelease(dnsCacheMutex); //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 osDelay(delay); //Acquire exclusive access to the DNS cache osMutexAcquire(dnsCacheMutex); //Search the DNS cache for the specified host name entry = dnsFindEntry(interface, name, type, HOST_NAME_RESOLVER_DNS); //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 osMutexRelease(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)); } //Return status code return error; }
void __iar_file_Mtxlock(__iar_Rmtx *mutex) /* Lock a file lock */ { osMutexAcquire(*(osMutexId_t *)*mutex, osWaitForever); }
void __rtos_malloc_lock(struct _reent *_r) { osMutexAcquire(malloc_mutex_id, osWaitForever); }
void __iar_system_Mtxlock(__iar_Rmtx *mutex) /* Lock a system lock */ { osMutexAcquire(*(osMutexId_t *)*mutex, osWaitForever); }
error_t udpProcessDatagram(NetInterface *interface, IpPseudoHeader *pseudoHeader, const ChunkedBuffer *buffer, size_t offset) { error_t error; uint_t i; size_t length; UdpHeader *header; Socket *socket; SocketQueueItem *queueItem; ChunkedBuffer *p; //Retrieve the length of the UDP datagram length = chunkedBufferGetLength(buffer) - offset; //Ensure the UDP header is valid if(length < sizeof(UdpHeader)) { //Debug message TRACE_WARNING("UDP datagram length is invalid!\r\n"); //Report an error return ERROR_INVALID_HEADER; } //Point to the UDP header header = chunkedBufferAt(buffer, offset); //Sanity check if(!header) return ERROR_FAILURE; //Debug message TRACE_INFO("UDP datagram received (%" PRIuSIZE " bytes)...\r\n", length); //Dump UDP header contents for debugging purpose udpDumpHeader(header); //When UDP runs over IPv6, the checksum is mandatory if(header->checksum || pseudoHeader->length == sizeof(Ipv6PseudoHeader)) { //Verify UDP checksum if(ipCalcUpperLayerChecksumEx(pseudoHeader->data, pseudoHeader->length, buffer, offset, length) != 0xFFFF) { //Debug message TRACE_WARNING("Wrong UDP header checksum!\r\n"); //Report an error return ERROR_WRONG_CHECKSUM; } } //Enter critical section osMutexAcquire(socketMutex); //Loop through opened sockets for(i = 0; i < SOCKET_MAX_COUNT; i++) { //Point to the current socket socket = socketTable + i; //UDP socket found? if(socket->type != SOCKET_TYPE_DGRAM) 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(header->destPort)) continue; //Source port number filtering if(socket->remotePort && socket->remotePort != ntohs(header->srcPort)) 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; } //The current socket meets all the criteria break; } //Point to the payload offset += sizeof(UdpHeader); length -= sizeof(UdpHeader); //No matching socket found? if(i >= SOCKET_MAX_COUNT) { //Leave critical section osMutexRelease(socketMutex); //Invoke user callback, if any error = udpInvokeRxCallback(interface, pseudoHeader, header, buffer, offset); //Return status code return error; } //Empty receive queue? if(!socket->receiveQueue) { //Allocate a memory buffer to hold the data and the associated descriptor p = chunkedBufferAlloc(sizeof(SocketQueueItem) + length); //Successful memory allocation? if(p != NULL) { //Point to the newly created item queueItem = chunkedBufferAt(p, 0); queueItem->buffer = p; //Add the newly created item to the queue socket->receiveQueue = queueItem; } else { //Memory allocation failed queueItem = NULL; } } else { //Point to the very first item queueItem = socket->receiveQueue; //Reach the last item in the receive queue for(i = 1; queueItem->next; i++) queueItem = queueItem->next; //Make sure the receive queue is not full if(i >= UDP_RX_QUEUE_SIZE) { //Leave critical section osMutexRelease(socketMutex); //Notify the calling function that the queue is full return ERROR_RECEIVE_QUEUE_FULL; } //Allocate a memory buffer to hold the data and the associated descriptor p = chunkedBufferAlloc(sizeof(SocketQueueItem) + length); //Successful memory allocation? if(p != NULL) { //Add the newly created item to the queue queueItem->next = chunkedBufferAt(p, 0); //Point to the newly created item queueItem = queueItem->next; queueItem->buffer = p; } else { //Memory allocation failed queueItem = NULL; } } //Failed to allocate memory? if(!queueItem) { //Leave critical section osMutexRelease(socketMutex); //Return error code return ERROR_OUT_OF_MEMORY; } //Initialize next field queueItem->next = NULL; //Record the source port number queueItem->srcPort = ntohs(header->srcPort); #if (IPV4_SUPPORT == ENABLED) //IPv4 remote address? if(pseudoHeader->length == sizeof(Ipv4PseudoHeader)) { //Save the source IPv4 address queueItem->srcIpAddr.length = sizeof(Ipv4Addr); queueItem->srcIpAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr; //Save the destination IPv4 address queueItem->destIpAddr.length = sizeof(Ipv4Addr); queueItem->destIpAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr; } #endif #if (IPV6_SUPPORT == ENABLED) //IPv6 remote address? if(pseudoHeader->length == sizeof(Ipv6PseudoHeader)) { //Save the source IPv6 address queueItem->srcIpAddr.length = sizeof(Ipv6Addr); queueItem->srcIpAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr; //Save the destination IPv6 address queueItem->destIpAddr.length = sizeof(Ipv6Addr); queueItem->destIpAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr; } #endif //Offset to the payload queueItem->offset = sizeof(SocketQueueItem); //Copy the payload chunkedBufferCopy(queueItem->buffer, queueItem->offset, buffer, offset, length); //Notify user that data is available udpUpdateEvents(socket); //Leave critical section osMutexRelease(socketMutex); //Successful processing return NO_ERROR; }
error_t ipv4JoinMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr) { error_t error; uint_t i; MacAddr macAddr; //Ensure the specified IPv4 address is a multicast address if(!ipv4IsMulticastAddr(groupAddr)) return ERROR_INVALID_ADDRESS; //Acquire exclusive access to the IPv4 filter table osMutexAcquire(interface->ipv4FilterMutex); //Loop through filter table entries for(i = 0; i < interface->ipv4FilterSize; i++) { //Check whether the table already contains the specified IPv4 address if(interface->ipv4Filter[i].addr == groupAddr) { //Increment the reference count interface->ipv4Filter[i].refCount++; //Release exclusive access to the IPv4 filter table osMutexRelease(interface->ipv4FilterMutex); //No error to report return NO_ERROR; } } //The IPv4 filter table is full ? if(i >= IPV4_FILTER_MAX_SIZE) { //Release exclusive access to the IPv4 filter table osMutexRelease(interface->ipv4FilterMutex); //A new entry cannot be added return ERROR_FAILURE; } //Map the multicast IPv4 address to a MAC-layer address ipv4MapMulticastAddrToMac(groupAddr, &macAddr); //Add the corresponding address to the MAC filter table error = ethAcceptMulticastAddr(interface, &macAddr); //Ensure the MAC filter table was successfully updated if(!error) { //Now we can safely add a new entry to the table interface->ipv4Filter[i].addr = groupAddr; //Initialize the reference count interface->ipv4Filter[i].refCount = 1; //Adjust the size of the IPv4 filter table interface->ipv4FilterSize++; #if (IGMP_SUPPORT == ENABLED) //Report multicast group membership to the router igmpJoinGroup(interface, &interface->ipv4Filter[i]); #endif } //Release exclusive access to the IPv4 filter table osMutexRelease(interface->ipv4FilterMutex); //Return status code return error; }
void dnsProcessResponse(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const ChunkedBuffer *buffer, size_t offset, void *params) { uint_t i; uint_t j; size_t n; size_t pos; size_t length; DnsHeader *message; DnsQuestion *question; DnsResourceRecord *resourceRecord; DnsCacheEntry *entry; //Retrieve the length of the DNS message length = chunkedBufferGetLength(buffer) - offset; //Ensure the DNS message is valid if(length < sizeof(DnsHeader)) return; if(length > DNS_MESSAGE_MAX_SIZE) return; //Point to the DNS message header message = chunkedBufferAt(buffer, offset); //Sanity check if(!message) return; //Debug message TRACE_INFO("DNS message received (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage(message, length); //Acquire exclusive access to the DNS cache osMutexAcquire(dnsCacheMutex); //Loop through DNS cache entries for(i = 0; i < DNS_CACHE_SIZE; i++) { //Point to the current entry entry = &dnsCache[i]; //DNS name resolution in progress? if(entry->state == DNS_STATE_IN_PROGRESS && entry->protocol == HOST_NAME_RESOLVER_DNS) { //Check destination port number if(entry->port == ntohs(udpHeader->destPort)) { //Compare identifier against expected one if(ntohs(message->id) != entry->id) break; //Check message type if(!message->qr) break; //The DNS message shall contain one question if(ntohs(message->qdcount) != 1) break; //Point to the first question pos = sizeof(DnsHeader); //Parse domain name n = dnsParseName(message, length, pos, NULL, 0); //Invalid name? if(!n) break; //Malformed mDNS message? if((n + sizeof(DnsQuestion)) > length) break; //Compare domain name if(!dnsCompareName(message, length, pos, entry->name, 0)) break; //Point to the corresponding entry question = DNS_GET_QUESTION(message, n); //Check the class of the query if(ntohs(question->qclass) != DNS_RR_CLASS_IN) break; //Check the type of the query if(entry->type == HOST_TYPE_IPV4 && ntohs(question->qtype) != DNS_RR_TYPE_A) break; if(entry->type == HOST_TYPE_IPV6 && ntohs(question->qtype) != DNS_RR_TYPE_AAAA) break; //Make sure recursion is available if(!message->ra) { //The entry should be deleted since name resolution has failed dnsDeleteEntry(entry); //Exit immediately break; } //Check return code if(message->rcode != DNS_RCODE_NO_ERROR) { //The entry should be deleted since name resolution has failed dnsDeleteEntry(entry); //Exit immediately break; } //Point to the first answer pos = n + sizeof(DnsQuestion); //Parse answer resource records for(j = 0; j < ntohs(message->ancount); j++) { //Parse domain name pos = dnsParseName(message, length, pos, NULL, 0); //Invalid name? if(!pos) break; //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) break; if((pos + ntohs(resourceRecord->rdlength)) > length) break; #if (IPV4_SUPPORT == ENABLED) //IPv4 address expected? if(entry->type == HOST_TYPE_IPV4) { //A resource record found? if(ntohs(resourceRecord->rtype) == DNS_RR_TYPE_A) { //Verify the length of the data field if(ntohs(resourceRecord->rdlength) == sizeof(Ipv4Addr)) { //Copy the IPv4 address entry->ipAddr.length = sizeof(Ipv4Addr); ipv4CopyAddr(&entry->ipAddr.ipv4Addr, resourceRecord->rdata); //Save current time entry->timestamp = osGetTickCount(); //Save TTL value entry->timeout = ntohl(resourceRecord->ttl) * 1000; //Limit the lifetime of the DNS cache entries entry->timeout = min(entry->timeout, DNS_MAX_LIFETIME); //Unregister UDP callback function udpDetachRxCallback(interface, entry->port); //Host name successfully resolved entry->state = DNS_STATE_RESOLVED; //Exit immediately break; } } } #endif #if (IPV6_SUPPORT == ENABLED) //IPv6 address expected? if(entry->type == HOST_TYPE_IPV6) { //AAAA resource record found? if(ntohs(resourceRecord->rtype) == DNS_RR_TYPE_AAAA) { //Verify the length of the data field if(ntohs(resourceRecord->rdlength) == sizeof(Ipv6Addr)) { //Copy the IPv6 address entry->ipAddr.length = sizeof(Ipv6Addr); ipv6CopyAddr(&entry->ipAddr.ipv6Addr, resourceRecord->rdata); //Save current time entry->timestamp = osGetTickCount(); //Save TTL value entry->timeout = ntohl(resourceRecord->ttl) * 1000; //Limit the lifetime of the DNS cache entries entry->timeout = min(entry->timeout, DNS_MAX_LIFETIME); //Unregister UDP callback function udpDetachRxCallback(interface, entry->port); //Host name successfully resolved entry->state = DNS_STATE_RESOLVED; //Exit immediately break; } } } #endif //Point to the next resource record pos += ntohs(resourceRecord->rdlength); } //We are done break; } } } //Release exclusive access to the DNS cache osMutexRelease(dnsCacheMutex); }