コード例 #1
0
ファイル: FreeRTOS_DNS.c プロジェクト: unnamet/Repo
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;
}
コード例 #2
0
ファイル: FreeRTOS_DNS.c プロジェクト: unnamet/Repo
	static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, uint32_t ulIPAddress )
	{
		uint16_t usFlags, usType, usClass;
		uint8_t *pucSource, *pucTarget;
		uint8_t ucByte;
		uint8_t ucNBNSName[ 17 ];

		usFlags = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usFlags ) );

		if( ( usFlags & dnsNBNS_FLAGS_OPCODE_MASK ) == dnsNBNS_FLAGS_OPCODE_QUERY )
		{
			usType  = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );
			usClass = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usClass ) );

			/* Not used for now */
			( void )usClass;
			/* For NBNS a name is 16 bytes long, written with capitals only.
			Make sure that the copy is terminated with a zero. */
			pucTarget = ucNBNSName + sizeof(ucNBNSName ) - 2;
			pucTarget[ 1 ] = '\0';

			/* Start with decoding the last 2 bytes. */
			pucSource = pucUDPPayloadBuffer + ( offsetof( NBNSRequest_t, ucName ) + ( dnsNBNS_ENCODED_NAME_LENGTH - 2 ) );

			for( ;; )
			{
				ucByte = ( uint8_t ) ( ( ( pucSource[ 0 ] - 0x41 ) << 4 ) | ( pucSource[ 1 ] - 0x41 ) );

				/* Make sure there are no trailing spaces in the name. */
				if( ( ucByte == ' ' ) && ( pucTarget[ 1 ] == '\0' ) )
				{
					ucByte = '\0';
				}

				*pucTarget = ucByte;

				if( pucTarget == ucNBNSName )
				{
					break;
				}

				pucTarget -= 1;
				pucSource -= 2;
			}

			#if( ipconfigUSE_DNS_CACHE == 1 )
			{
				if( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) != 0 )
				{
					/* If this is a response from another device,
					add the name to the DNS cache */
					prvProcessDNSCache( ( char * ) ucNBNSName, &ulIPAddress, pdFALSE );
				}
			}
			#else
			{
				/* Avoid compiler warnings. */
				( void ) ulIPAddress;
			}
			#endif /* ipconfigUSE_DNS_CACHE */

			if( ( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) == 0 ) &&
				( usType == dnsNBNS_TYPE_NET_BIOS ) &&
				( xApplicationDNSQueryHook( ( const char * ) ucNBNSName ) != pdFALSE ) )
			{
			uint16_t usLength;
			DNSMessage_t *pxMessage;
			NBNSAnswer_t *pxAnswer;

				/* Someone is looking for a device with ucNBNSName,
				prepare a positive reply. */
				NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );

				if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )
				{
				NetworkBufferDescriptor_t *pxNewBuffer;
				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 duplicated into a bigger buffer */
					pxNetworkBuffer->xDataLength = xDataLength;
					pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 );
					if( pxNewBuffer != NULL )
					{
						pucUDPPayloadBuffer = pxNewBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );
						pxNetworkBuffer = pxNewBuffer;
					}
					else
					{
						/* Just prevent that a reply will be sent */
						pxNetworkBuffer = NULL;
					}
				}

				/* Should not occur: pucUDPPayloadBuffer is part of a xNetworkBufferDescriptor */
				if( pxNetworkBuffer != NULL )
				{
					pxMessage = (DNSMessage_t *)pucUDPPayloadBuffer;

					/* As the fields in the structures are not word-aligned, we have to
					copy the values byte-by-byte using macro's vSetField16() and vSetField32() */
					vSetField16( pxMessage, DNSMessage_t, usFlags, dnsNBNS_QUERY_RESPONSE_FLAGS ); /* 0x8500 */
					vSetField16( pxMessage, DNSMessage_t, usQuestions, 0 );
					vSetField16( pxMessage, DNSMessage_t, usAnswers, 1 );
					vSetField16( pxMessage, DNSMessage_t, usAuthorityRRs, 0 );
					vSetField16( pxMessage, DNSMessage_t, usAdditionalRRs, 0 );

					pxAnswer = (NBNSAnswer_t *)( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );

					vSetField16( pxAnswer, NBNSAnswer_t, usType, usType );	/* Type */
					vSetField16( pxAnswer, NBNSAnswer_t, usClass, dnsNBNS_CLASS_IN );	/* Class */
					vSetField32( pxAnswer, NBNSAnswer_t, ulTTL, dnsNBNS_TTL_VALUE );
					vSetField16( pxAnswer, NBNSAnswer_t, usDataLength, 6 ); /* 6 bytes including the length field */
					vSetField16( pxAnswer, NBNSAnswer_t, usNbFlags, dnsNBNS_NAME_FLAGS );
					vSetField32( pxAnswer, NBNSAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );

					usLength = ( uint16_t ) ( offsetof( NBNSRequest_t, usType ) + sizeof( NBNSAnswer_t ) );

					prvReplyDNSMessage( pxNetworkBuffer, usLength );
				}
			}
		}
	}
コード例 #3
0
ファイル: x_emacpsif_dma.c プロジェクト: oska874/freertos
XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxFirstBuffer, int iReleaseAfterSend )
{
NetworkBufferDescriptor_t *pxBuffer;
int head = xemacpsif->txHead;
int tail = xemacpsif->txTail;
int iHasSent = 0;
uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;

#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
	if( iReleaseAfterSend == pdFALSE )
	{
	NetworkBufferDescriptor_t *pxNewBuffer;

		pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxFirstBuffer, pxFirstBuffer->xDataLength );
		if( pxNewBuffer )
		{
			pxFirstBuffer = pxNewBuffer;
			iReleaseAfterSend = pdTRUE;
		}
	}
#endif

	/* Although it looks like more that 1 message can be sent,
	this possibility is NOT being used and not yet tested. */
	for( pxBuffer = pxFirstBuffer; pxBuffer != NULL;  )
	{
	NetworkBufferDescriptor_t *pxNextBuffer;

		if( ( head == tail ) && ( xemacpsif->txSegments[ head ].flags & XEMACPS_TXBUF_USED_MASK ) == 0 )
		{
//			FreeRTOS_printf( ( "emacps_send_message: All TX buffers full\n" ) );
			break;
		}
		if( xValidLength( pxBuffer->xDataLength ) )
		{
			/* Just a sanity check, the TX buffer will be assigned permanently. */
#if( ipconfigZERO_COPY_TX_DRIVER == 0 )
			if( pxDMA_tx_buffers[ head ] != NULL )
#endif
			{
				uint32_t flags = 0;
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
				/* Move the message to unbuffered space in RAM. */
				pxDMA_tx_buffers[ head ] = ( uint32_t )pxBuffer->pucEthernetBuffer;
				if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
				{
					Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
				}
#else
				/* Copy the message to unbuffered space in RAM. */
				memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
#endif
				/* Packets will be sent one-by-one, so for each packet
				the TXBUF_LAST bit will be set. */
				flags |= XEMACPS_TXBUF_LAST_MASK;
				flags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );
				if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )
				{
					flags |= XEMACPS_TXBUF_WRAP_MASK;
				}

				/* Copy the address of the buffer and set the flags. */
				xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];
				xemacpsif->txSegments[ head ].flags = flags;

				iHasSent = pdTRUE;
			}
			if( ++head == ipconfigNIC_N_TX_DESC )
			{
				head = 0;
			}
		}
		/* Make a copy of the next field, before pxBuffer gets deleted */
		pxNextBuffer = pxBuffer->pxNextBuffer;
#if( ipconfigZERO_COPY_TX_DRIVER == 0 )
		if( iReleaseAfterSend != pdFALSE )
		{
			vReleaseNetworkBufferAndDescriptor( pxBuffer );
		}
#endif
		pxBuffer = pxNextBuffer;
	}
	/* Update the TX-head index. These variable are declared volatile so they will be
	accessed as little as possible.	*/
	xemacpsif->txHead = head;

	/* Data Synchronization Barrier */
	dsb();

	if( iHasSent != pdFALSE )
	{
		/* Make STARTTX high */
		uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);
		/* Start transmit */
		xemacpsif->txBusy = pdTRUE;
		XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );
	}
	dsb();

	return 0;
}