static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms ) { struct freertos_sockaddr xAddress; Socket_t xDNSSocket; uint32_t ulIPAddress = 0UL; uint8_t *pucUDPPayloadBuffer; static uint32_t ulAddressLength; BaseType_t xAttempt; int32_t lBytes; size_t xPayloadLength, xExpectedPayloadLength; TickType_t xWriteTimeOut_ms = 100U; #if( ipconfigUSE_LLMNR == 1 ) BaseType_t bHasDot = pdFALSE; #endif /* ipconfigUSE_LLMNR == 1 */ /* If LLMNR is being used then determine if the host name includes a '.' - if not then LLMNR can be used as the lookup method. */ #if( ipconfigUSE_LLMNR == 1 ) { const char *pucPtr; for( pucPtr = pcHostName; *pucPtr; pucPtr++ ) { if( *pucPtr == '.' ) { bHasDot = pdTRUE; break; } } } #endif /* ipconfigUSE_LLMNR == 1 */ /* Two is added at the end for the count of characters in the first subdomain part and the string end byte. */ xExpectedPayloadLength = sizeof( DNSMessage_t ) + strlen( pcHostName ) + sizeof( uint16_t ) + sizeof( uint16_t ) + 2u; xDNSSocket = prvCreateDNSSocket(); if( xDNSSocket != NULL ) { FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xWriteTimeOut_ms, sizeof( TickType_t ) ); FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xReadTimeOut_ms, sizeof( TickType_t ) ); for( xAttempt = 0; xAttempt < ipconfigDNS_REQUEST_ATTEMPTS; xAttempt++ ) { /* Get a buffer. This uses a maximum delay, but the delay will be capped to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value still needs to be tested. */ pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xExpectedPayloadLength, portMAX_DELAY ); if( pucUDPPayloadBuffer != NULL ) { /* Create the message in the obtained buffer. */ xPayloadLength = prvCreateDNSMessage( pucUDPPayloadBuffer, pcHostName, xIdentifier ); iptraceSENDING_DNS_REQUEST(); /* Obtain the DNS server address. */ FreeRTOS_GetAddressConfiguration( NULL, NULL, NULL, &ulIPAddress ); /* Send the DNS message. */ #if( ipconfigUSE_LLMNR == 1 ) if( bHasDot == pdFALSE ) { /* Use LLMNR addressing. */ ( ( DNSMessage_t * ) pucUDPPayloadBuffer) -> usFlags = 0; xAddress.sin_addr = ipLLMNR_IP_ADDR; /* Is in network byte order. */ xAddress.sin_port = FreeRTOS_ntohs( ipLLMNR_PORT ); } else #endif { /* Use DNS server. */ xAddress.sin_addr = ulIPAddress; xAddress.sin_port = dnsDNS_PORT; } ulIPAddress = 0UL; if( FreeRTOS_sendto( xDNSSocket, pucUDPPayloadBuffer, xPayloadLength, FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) != 0 ) { /* Wait for the reply. */ lBytes = FreeRTOS_recvfrom( xDNSSocket, &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xAddress, &ulAddressLength ); if( lBytes > 0 ) { /* The reply was received. Process it. */ ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, xIdentifier ); /* Finished with the buffer. The zero copy interface is being used, so the buffer must be freed by the task. */ FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer ); if( ulIPAddress != 0UL ) { /* All done. */ break; } } } else { /* The message was not sent so the stack will not be releasing the zero copy - it must be released here. */ FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer ); } } } /* Finished with the socket. */ FreeRTOS_closesocket( xDNSSocket ); } return ulIPAddress; }
static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, TickType_t xIdentifier ) { DNSMessage_t *pxDNSMessageHeader; uint32_t ulIPAddress = 0UL; #if( ipconfigUSE_LLMNR == 1 ) char *pcRequestedName = NULL; #endif uint8_t *pucByte; uint16_t x, usDataLength, usQuestions; #if( ipconfigUSE_LLMNR == 1 ) uint16_t usType = 0, usClass = 0; #endif #if( ipconfigUSE_DNS_CACHE == 1 ) char pcName[128] = ""; /*_RB_ What is the significance of 128? Probably too big to go on the stack for a small MCU but don't know how else it could be made re-entrant. Might be necessary. */ #endif pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; if( pxDNSMessageHeader->usIdentifier == ( uint16_t ) xIdentifier ) { /* Start at the first byte after the header. */ pucByte = pucUDPPayloadBuffer + sizeof( DNSMessage_t ); /* Skip any question records. */ usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions ); for( x = 0; x < usQuestions; x++ ) { #if( ipconfigUSE_LLMNR == 1 ) { if( x == 0 ) { pcRequestedName = ( char * ) pucByte; } } #endif #if( ipconfigUSE_DNS_CACHE == 1 ) if( x == 0 ) { pucByte = prvReadNameField( pucByte, pcName, sizeof( pcName ) ); } else #endif /* ipconfigUSE_DNS_CACHE */ { /* Skip the variable length pcName field. */ pucByte = prvSkipNameField( pucByte ); } #if( ipconfigUSE_LLMNR == 1 ) { /* usChar2u16 returns value in host endianness. */ usType = usChar2u16( pucByte ); usClass = usChar2u16( pucByte + 2 ); } #endif /* ipconfigUSE_LLMNR */ /* Skip the type and class fields. */ pucByte += sizeof( uint32_t ); } /* Search through the answers records. */ pxDNSMessageHeader->usAnswers = FreeRTOS_ntohs( pxDNSMessageHeader->usAnswers ); if( ( pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK ) == dnsEXPECTED_RX_FLAGS ) { for( x = 0; x < pxDNSMessageHeader->usAnswers; x++ ) { pucByte = prvSkipNameField( pucByte ); /* Is the type field that of an A record? */ if( usChar2u16( pucByte ) == dnsTYPE_A_HOST ) { /* This is the required record. Skip the type, class, and time to live fields, plus the first byte of the data length. */ pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) + sizeof( uint8_t ) ); /* Sanity check the data length. */ if( ( size_t ) *pucByte == sizeof( uint32_t ) ) { /* Skip the second byte of the length. */ pucByte++; /* Copy the IP address out of the record. */ memcpy( ( void * ) &ulIPAddress, ( void * ) pucByte, sizeof( uint32_t ) ); #if( ipconfigUSE_DNS_CACHE == 1 ) { prvProcessDNSCache( pcName, &ulIPAddress, pdFALSE ); } #endif /* ipconfigUSE_DNS_CACHE */ #if( ipconfigDNS_USE_CALLBACKS != 0 ) { /* See if any asynchronous call was made to FreeRTOS_gethostbyname_a() */ vDNSDoCallback( ( TickType_t ) pxDNSMessageHeader->usIdentifier, pcName, ulIPAddress ); } #endif /* ipconfigDNS_USE_CALLBACKS != 0 */ } break; } else { /* Skip the type, class and time to live fields. */ pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) ); /* Determine the length of the data in the field. */ memcpy( ( void * ) &usDataLength, ( void * ) pucByte, sizeof( uint16_t ) ); usDataLength = FreeRTOS_ntohs( usDataLength ); /* Jump over the data length bytes, and the data itself. */ pucByte += usDataLength + sizeof( uint16_t ); } } } #if( ipconfigUSE_LLMNR == 1 ) else if( ( usQuestions != ( uint16_t )0u ) && ( usType == ( uint16_t )dnsTYPE_A_HOST ) && ( usClass == ( uint16_t )dnsCLASS_IN ) ) { /* If this is not a reply to our DNS request, it might an LLMNR request. */ if( xApplicationDNSQueryHook ( ( pcRequestedName + 1 ) ) ) { int16_t usLength; NetworkBufferDescriptor_t *pxNewBuffer = NULL; NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer ); LLMNRAnswer_t *pxAnswer; if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) ) { BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) + sizeof( EthernetHeader_t ) + sizeof( IPHeader_t ); /* The field xDataLength was set to the length of the UDP payload. The answer (reply) will be longer than the request, so the packet must be duplicaed into a bigger buffer */ pxNetworkBuffer->xDataLength = xDataLength; pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 ); if( pxNewBuffer != NULL ) { BaseType_t xOffset1, xOffset2; xOffset1 = ( BaseType_t ) ( pucByte - pucUDPPayloadBuffer ); xOffset2 = ( BaseType_t ) ( ( ( uint8_t * ) pcRequestedName ) - pucUDPPayloadBuffer ); pxNetworkBuffer = pxNewBuffer; pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + ipUDP_PAYLOAD_OFFSET_IPv4; pucByte = pucUDPPayloadBuffer + xOffset1; pcRequestedName = ( char * ) ( pucUDPPayloadBuffer + xOffset2 ); pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; } else { /* Just to indicate that the message may not be answered. */ pxNetworkBuffer = NULL; } } if( pxNetworkBuffer != NULL ) { pxAnswer = (LLMNRAnswer_t *)pucByte; /* Leave 'usIdentifier' and 'usQuestions' untouched. */ vSetField16( pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE ); /* Set the response flag */ vSetField16( pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */ vSetField16( pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */ vSetField16( pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */ pxAnswer->ucNameCode = dnsNAME_IS_OFFSET; pxAnswer->ucNameOffset = ( uint8_t )( pcRequestedName - ( char * ) pucUDPPayloadBuffer ); vSetField16( pxAnswer, LLMNRAnswer_t, usType, dnsTYPE_A_HOST ); /* Type A: host */ vSetField16( pxAnswer, LLMNRAnswer_t, usClass, dnsCLASS_IN ); /* 1: Class IN */ vSetField32( pxAnswer, LLMNRAnswer_t, ulTTL, dnsLLMNR_TTL_VALUE ); vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, 4 ); vSetField32( pxAnswer, LLMNRAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) ); usLength = ( int16_t ) ( sizeof( *pxAnswer ) + ( size_t ) ( pucByte - pucUDPPayloadBuffer ) ); prvReplyDNSMessage( pxNetworkBuffer, usLength ); if( pxNewBuffer != NULL ) { vReleaseNetworkBufferAndDescriptor( pxNewBuffer ); } } } } #endif /* ipconfigUSE_LLMNR == 1 */ } return ulIPAddress; }
static void prvConnectionListeningTask( void *pvParameters ) { struct freertos_sockaddr xClient, xBindAddress; xSocket_t xListeningSocket; socklen_t xSize = sizeof( xClient ); static const TickType_t xReceiveTimeOut = 0; //portMAX_DELAY; const BaseType_t xBacklog = 10; xSocketSet_t xSocketSet; struct xTCP_SERVER *pxServerList = NULL; struct xTCP_SERVER *pxIterator; xWinProperties_t winProps; /* Just to prevent compiler warnings. */ ( void ) pvParameters; /* Attempt to open the socket. */ xListeningSocket = FreeRTOS_socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET ); /* Set a time out so accept() will just wait for a connection. */ FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); memset(&winProps, '\0', sizeof( winProps ) ); // Size in units of MSS winProps.lTxBufSize = 1 * 1460;//1000; winProps.lTxWinSize = 2; winProps.lRxBufSize = 2 * 1460; winProps.lRxWinSize = 2; FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &winProps, sizeof( winProps ) ); /* The strange casting is to remove compiler errors. */ xBindAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL; xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port ); /* Bind the socket to the port that the client task will send to, then listen for incoming connections. */ while( FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) ) != 0 ); FreeRTOS_listen( xListeningSocket, xBacklog ); lastTickTime = xTaskGetTickCount (); pxServerList = NULL; xSocketSet = FreeRTOS_createsocketset( ); configASSERT( xSocketSet != NULL ); FreeRTOS_FD_SET( xListeningSocket, xSocketSet, eSELECT_READ ); for( ;; ) { TickType_t xMask = FreeRTOS_select( xSocketSet, 3000 ); if( FreeRTOS_FD_ISSET( xListeningSocket, xSocketSet ) ) { xSocket_t xNewSocket; xNewSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize ); if ( xNewSocket && xNewSocket != FREERTOS_INVALID_SOCKET ) { xTcpServer_t *pxServer; FreeRTOS_debug_printf( ( "prvConnectionListeningTask: new connection %xip:%u\n", FreeRTOS_ntohl( xClient.sin_addr ), FreeRTOS_ntohs( xClient.sin_port ) ) ); pxServer = (xTcpServer_t *)pvPortMalloc( sizeof( *pxServer ) ); memset( pxServer, '\0', sizeof( *pxServer )); pxServer->xSocket = xNewSocket; FreeRTOS_FD_SET( xNewSocket, xSocketSet, eSELECT_READ | eSELECT_EXCEPT ); if( pxServerList == NULL ) { /* This is the first server */ pxServerList = pxServer; } else { /* Attach it to the end of the list */ for( pxIterator = pxServerList; pxIterator->pxNext != NULL; pxIterator = pxIterator->pxNext ) { } pxIterator->pxNext = pxServer; } prvTcpInit( pxServer ); } } { xTcpServer_t *pxThisServer = NULL; for( pxIterator = pxServerList; pxIterator != NULL; ) { BaseType_t rc; pxThisServer = pxIterator; /* Move to the next one before the current gets deleted */ pxIterator = pxIterator->pxNext; if( FreeRTOS_FD_ISSET( pxThisServer->xSocket, xSocketSet ) == 0 ) { continue; } rc = prvTcpWork( pxThisServer ); if( rc < 0) { FreeRTOS_FD_CLR( pxThisServer->xSocket, xSocketSet, eSELECT_ALL ); if( pxServerList = pxThisServer ) { pxServerList = pxThisServer->pxNext; } else { struct xTCP_SERVER *pxOther; for( pxOther = pxServerList; pxOther->pxNext != NULL; pxOther = pxOther->pxNext ) { if( pxOther->pxNext == pxThisServer ) { pxOther->pxNext == pxThisServer->pxNext; break; } } } /* Close the socket and free the space */ prvTcpClose( pxThisServer ); } else { pxThisServer->bHasSendRequest = prvTcpHasSendData( pxThisServer ); if( pxThisServer->bHasSendRequest ) FreeRTOS_FD_SET( pxThisServer->xSocket, xSocketSet, eSELECT_WRITE ); else FreeRTOS_FD_CLR( pxThisServer->xSocket, xSocketSet, eSELECT_WRITE ); //FreeRTOS_debug_printf( ( "SET_FD WRITE %d\n", pxServerFound->bHasSendRequest != 0 ) ); } } } if( ( xTaskGetTickCount () - lastTickTime ) > 30000 ) { lastTickTime = xTaskGetTickCount (); //plusPrintf( "ListeningTask %ld,%ld tasks\n", xTaskCount, xConfirmedCount ); } } }
BaseType_t FreeRTOS_bind( xSocket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength ) { BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */ xFreeRTOS_Socket_t *pxSocket; #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 struct freertos_sockaddr xAddress; #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */ pxSocket = ( xFreeRTOS_Socket_t * ) xSocket; /* The function prototype is designed to maintain the expected Berkeley sockets standard, but this implementation does not use all the parameters. */ ( void ) xAddressLength; configASSERT( xSocket ); configASSERT( xSocket != FREERTOS_INVALID_SOCKET ); #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 { /* pxAddress will be NULL if sendto() was called on a socket without the socket being bound to an address. In this case, automatically allocate an address to the socket. There is a very tiny chance that the allocated port will already be in use - if that is the case, then the check below [pxListFindListItemWithValue()] will result in an error being returned. */ if( pxAddress == NULL ) { pxAddress = &xAddress; pxAddress->sin_port = prvGetPrivatePortNumber(); } } #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */ /* Sockets must be bound before calling FreeRTOS_sendto() if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */ configASSERT( pxAddress ); if( pxAddress != NULL ) { if( pxAddress->sin_port == 0 ) { pxAddress->sin_port = prvGetPrivatePortNumber(); } vTaskSuspendAll(); { /* Check to ensure the port is not already in use. */ if( pxListFindListItemWithValue( &xBoundSocketsList, ( TickType_t ) pxAddress->sin_port ) != NULL ) { xReturn = FREERTOS_EADDRINUSE; } } xTaskResumeAll(); /* Check that xReturn has not been set before continuing. */ if( xReturn == 0 ) { if( pxSocket->xWaitingPacketSemaphore == NULL ) { /* Create the semaphore used to count the number of packets that are queued on this socket. */ pxSocket->xWaitingPacketSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFERS, 0 ); if( pxSocket->xWaitingPacketSemaphore != NULL ) { /* Allocate the port number to the socket. */ socketSET_SOCKET_ADDRESS( pxSocket, pxAddress->sin_port ); taskENTER_CRITICAL(); { /* Add the socket to the list of bound ports. */ vListInsertEnd( &xBoundSocketsList, &( pxSocket->xBoundSocketListItem ) ); } taskEXIT_CRITICAL(); } else { /* Out of memory. */ xReturn = FREERTOS_ENOBUFS; } } else { /* The socket is already bound. */ xReturn = FREERTOS_EINVAL; } } } else { xReturn = FREERTOS_EADDRNOTAVAIL; } if( xReturn != 0 ) { iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) ); } return xReturn; } /* Tested */
static void prvNTPTask( void *pvParameters ) { BaseType_t xServerIndex = 3; struct freertos_sockaddr xAddress; #if( ipconfigUSE_CALLBACKS != 0 ) F_TCP_UDP_Handler_t xHandler; #endif /* ipconfigUSE_CALLBACKS != 0 */ xStatus = EStatusLookup; #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) || ( ipconfigUSE_CALLBACKS != 0 ) { xNTPWakeupSem = xSemaphoreCreateBinary(); } #endif #if( ipconfigUSE_CALLBACKS != 0 ) { memset( &xHandler, '\0', sizeof ( xHandler ) ); xHandler.pOnUdpReceive = xOnUdpReceive; FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_UDP_RECV_HANDLER, ( void * ) &xHandler, sizeof( xHandler ) ); } #endif #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) { FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_SET_SEMAPHORE, ( void * ) &xNTPWakeupSem, sizeof( xNTPWakeupSem ) ); } #endif for( ; ; ) { switch( xStatus ) { case EStatusLookup: if( ( ulIPAddressFound == 0ul ) || ( ulIPAddressFound == ~0ul ) ) { if( ++xServerIndex == sizeof pcTimeServers / sizeof pcTimeServers[ 0 ] ) { xServerIndex = 0; } FreeRTOS_printf( ( "Looking up server '%s'\n", pcTimeServers[ xServerIndex ] ) ); FreeRTOS_gethostbyname_a( pcTimeServers[ xServerIndex ], vDNS_callback, (void *)NULL, 1200 ); } else { xStatus = EStatusAsking; } break; case EStatusAsking: { char pcBuf[16]; prvNTPPacketInit( ); xAddress.sin_addr = ulIPAddressFound; xAddress.sin_port = FreeRTOS_htons( NTP_PORT ); FreeRTOS_inet_ntoa( xAddress.sin_addr, pcBuf ); FreeRTOS_printf( ( "Sending UDP message to %s:%u\n", pcBuf, FreeRTOS_ntohs( xAddress.sin_port ) ) ); uxSendTime = xTaskGetTickCount( ); FreeRTOS_sendto( xUDPSocket, ( void * )&xNTPPacket, sizeof( xNTPPacket ), 0, &xAddress, sizeof( xAddress ) ); } break; case EStatusPause: break; case EStatusFailed: break; } #if( ipconfigUSE_CALLBACKS != 0 ) { xSemaphoreTake( xNTPWakeupSem, 5000 ); } #else { uint32_t xAddressSize; BaseType_t xReturned; xAddressSize = sizeof( xAddress ); xReturned = FreeRTOS_recvfrom( xUDPSocket, ( void * ) cRecvBuffer, sizeof( cRecvBuffer ), 0, &xAddress, &xAddressSize ); switch( xReturned ) { case 0: case -pdFREERTOS_ERRNO_EAGAIN: case -pdFREERTOS_ERRNO_EINTR: break; default: if( xReturned < sizeof( xNTPPacket ) ) { FreeRTOS_printf( ( "FreeRTOS_recvfrom: returns %ld\n", xReturned ) ); } else { prvReadTime( ( struct SNtpPacket *)cRecvBuffer ); if( xStatus != EStatusPause ) { xStatus = EStatusPause; } } break; } } #endif } }
BaseType_t xProcessReceivedUDPPacket( xNetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort ) { BaseType_t xReturn = pdPASS; xFreeRTOS_Socket_t *pxSocket; xUDPPacket_t *pxUDPPacket = (xUDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer; pxSocket = pxUDPSocketLookup( usPort ); if( pxSocket ) { /* When refreshing the ARP cache with received UDP packets we must be careful; hundreds of broadcast messages may pass and if we're not handling them, no use to fill the ARP cache with those IP addresses. */ vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress ); #if( ipconfigUSE_CALLBACKS == 1 ) { /* Did the owner of this socket register a reception handler ? */ if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUdp.pHndReceive ) ) { struct freertos_sockaddr xSourceAddress, destinationAddress; void *pcData = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ); FOnUdpReceive xHandler = ( FOnUdpReceive ) pxSocket->u.xUdp.pHndReceive; xSourceAddress.sin_port = pxNetworkBuffer->usPort; xSourceAddress.sin_addr = pxNetworkBuffer->ulIPAddress; destinationAddress.sin_port = usPort; destinationAddress.sin_addr = pxUDPPacket->xIPHeader.ulDestinationIPAddress; if( xHandler( (xSocket_t *)pxSocket, ( void* ) pcData, ( size_t ) pxNetworkBuffer->xDataLength, &xSourceAddress, &destinationAddress ) ) { xReturn = pdFAIL; /* FAIL means that we did not consume or release the buffer */ } } } #endif /* ipconfigUSE_CALLBACKS */ #if( ipconfigUDP_MAX_RX_PACKETS > 0 ) { if( xReturn == pdPASS ) { if ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUdp.xWaitingPacketsList ) ) >= pxSocket->u.xUdp.xMaxPackets ) { FreeRTOS_debug_printf( ( "xProcessReceivedUDPPacket: buffer full %ld >= %ld port %u\n", listCURRENT_LIST_LENGTH( &( pxSocket->u.xUdp.xWaitingPacketsList ) ), pxSocket->u.xUdp.xMaxPackets, pxSocket->usLocPort ) ); xReturn = pdFAIL; /* we did not consume or release the buffer */ } } } #endif if( xReturn == pdPASS ) { vTaskSuspendAll(); { if( xReturn == pdPASS ) { taskENTER_CRITICAL(); { /* Add the network packet to the list of packets to be processed by the socket. */ vListInsertEnd( &( pxSocket->u.xUdp.xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) ); } taskEXIT_CRITICAL(); } } xTaskResumeAll(); /* Set the socket's receive event */ if( pxSocket->xEventGroup != NULL ) { xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_RECEIVE ); } #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) { if( ( pxSocket->pxSocketSet != NULL ) && ( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) ) { xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, eSELECT_READ ); } } #endif #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 ) { if( pxSocket->pxUserSemaphore != NULL ) { xSemaphoreGive( pxSocket->pxUserSemaphore ); } } #endif #if( ipconfigUSE_DHCP == 1 ) { if( xIsDHCPSocket( pxSocket ) ) { xSendEventToIPTask( eDHCPEvent ); } } #endif } } else { /* There is no socket listening to the target port, but still it might be for this node. */ #if( ipconfigUSE_DNS == 1 ) /* a DNS reply, check for the source port. Although the DNS client does open a UDP socket to send a messages, this socket will be closed after a short timeout. Messages that come late (after the socket is closed) will be treated here. */ if( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usSourcePort ) == ipDNS_PORT ) { vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress ); xReturn = ( BaseType_t )ulDNSHandlePacket( pxNetworkBuffer ); } else #endif #if( ipconfigUSE_LLMNR == 1 ) /* a LLMNR request, check for the destination port. */ if( usPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) { vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress ); xReturn = ( BaseType_t )ulDNSHandlePacket( pxNetworkBuffer ); } else #endif /* ipconfigUSE_LLMNR */ #if( ipconfigUSE_NBNS == 1 ) /* a NetBIOS request, check for the destination port */ if( usPort == FreeRTOS_ntohs( ipNBNS_PORT ) ) { vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress ); xReturn = ( BaseType_t )ulNBNSHandlePacket( pxNetworkBuffer ); } else #endif /* ipconfigUSE_NBNS */ { xReturn = pdFAIL; } } return xReturn; }
static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, uint16_t usIdentifier ) { xDNSMessage_t *pxDNSMessageHeader; uint32_t ulIPAddress = 0UL; uint8_t *pucByte; uint16_t x, usDataLength; const uint16_t usARecordType = dnsTYPE; pxDNSMessageHeader = ( xDNSMessage_t * ) pucUDPPayloadBuffer; if( pxDNSMessageHeader->usIdentifier == usIdentifier ) { if( ( pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK ) == dnsEXPECTED_RX_FLAGS ) { /* Start at the first byte after the header. */ pucByte = pucUDPPayloadBuffer + sizeof( xDNSMessage_t ); /* Skip any question records. */ pxDNSMessageHeader->usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions ); for( x = 0; x < pxDNSMessageHeader->usQuestions; x++ ) { /* Skip the variable length name field. */ pucByte = prvSkipNameField( pucByte ); /* Skip the type and class fields. */ pucByte += sizeof( uint32_t ); } /* Search through the answers records. */ pxDNSMessageHeader->usAnswers = FreeRTOS_ntohs( pxDNSMessageHeader->usAnswers ); for( x = 0; x < pxDNSMessageHeader->usAnswers; x++ ) { pucByte = prvSkipNameField( pucByte ); /* Is the type field that of an A record? */ if( memcmp( ( void * ) pucByte, ( void * ) &usARecordType, sizeof( uint16_t ) ) == 0 ) { /* This is the required record. Skip the type, class, and time to live fields, plus the first byte of the data length. */ pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) + sizeof( uint8_t ) ); /* Sanity check the data length. */ if( *pucByte == sizeof( uint32_t ) ) { /* Skip the second byte of the length. */ pucByte++; /* Copy the IP address out of the record. */ memcpy( ( void * ) &ulIPAddress, ( void * ) pucByte, sizeof( uint32_t ) ); } break; } else { /* Skip the type, class and time to live fields. */ pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) ); /* Determine the length of the data in the field. */ memcpy( ( void * ) &usDataLength, ( void * ) pucByte, sizeof( uint16_t ) ); usDataLength = FreeRTOS_ntohs( usDataLength ); /* Jump over the data lenth bytes, and the data itself. */ pucByte += usDataLength + sizeof( uint16_t ); } } } } return ulIPAddress; }