xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_IPv4_Sockets.c (revision 2d3f4daa567ffe71aeda2e0f6d0bc02850db0627)
1 /*
2  * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 /**
29  * @file FreeRTOS_IPv4_Sockets.c
30  * @brief Implements the Sockets API based on Berkeley sockets for the FreeRTOS+TCP network stack.
31  *        Sockets are used by the application processes to interact with the IP-task which in turn
32  *        interacts with the hardware.
33  */
34 
35 /* Standard includes. */
36 #include <stdint.h>
37 #include <stdio.h>
38 
39 /* FreeRTOS includes. */
40 #include "FreeRTOS.h"
41 #include "task.h"
42 #include "queue.h"
43 #include "semphr.h"
44 
45 /* FreeRTOS+TCP includes. */
46 #include "FreeRTOS_UDP_IP.h"
47 #include "FreeRTOS_IP.h"
48 #include "FreeRTOS_IPv4_Sockets.h"
49 
50 
51 /** @brief The number of octets that make up an IP address. */
52 #define socketMAX_IP_ADDRESS_OCTETS    ( 4U )
53 
54 /* Just make sure the contents doesn't get compiled if IPv4 is not enabled. */
55 /* *INDENT-OFF* */
56     #if( ipconfigUSE_IPv4 != 0 )
57 /* *INDENT-ON* */
58 
59 /**
60  * @brief This function converts the character string pcSource into a network address
61  *        structure, then copies the network address structure to pvDestination.
62  *        pvDestination is written in network byte order.
63  *
64  * @param[in] pcSource The character string in holding the IP address.
65  * @param[out] pvDestination The returned network address in 32-bit network-endian format.
66  *
67  * @return pdPASS if the translation was successful or else pdFAIL.
68  */
FreeRTOS_inet_pton4(const char * pcSource,void * pvDestination)69 BaseType_t FreeRTOS_inet_pton4( const char * pcSource,
70                                 void * pvDestination )
71 {
72     const uint32_t ulDecimalBase = 10U;
73     uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
74     uint32_t ulReturn = 0U, ulValue;
75     UBaseType_t uxOctetNumber;
76     BaseType_t xResult = pdPASS;
77     const char * pcIPAddress = pcSource;
78     const void * pvCopySource;
79 
80     ( void ) memset( pvDestination, 0, sizeof( ulReturn ) );
81 
82     /* Translate "192.168.2.100" to a 32-bit number, network-endian. */
83     for( uxOctetNumber = 0U; uxOctetNumber < socketMAX_IP_ADDRESS_OCTETS; uxOctetNumber++ )
84     {
85         ulValue = 0U;
86 
87         if( pcIPAddress[ 0 ] == '0' )
88         {
89             /* Test for the sequence "0[0-9]", which would make it an octal representation. */
90             if( ( pcIPAddress[ 1 ] >= '0' ) && ( pcIPAddress[ 1 ] <= '9' ) )
91             {
92                 FreeRTOS_printf( ( "Octal representation of IP-addresses is not supported." ) );
93                 /* Don't support octal numbers. */
94                 xResult = pdFAIL;
95                 break;
96             }
97         }
98 
99         while( ( *pcIPAddress >= '0' ) && ( *pcIPAddress <= '9' ) )
100         {
101             BaseType_t xChar;
102 
103             /* Move previous read characters into the next decimal
104              * position. */
105             ulValue *= ulDecimalBase;
106 
107             /* Add the binary value of the ascii character. */
108             xChar = ( BaseType_t ) pcIPAddress[ 0 ];
109             xChar = xChar - ( BaseType_t ) '0';
110             ulValue += ( uint32_t ) xChar;
111 
112             /* Move to next character in the string. */
113             pcIPAddress++;
114         }
115 
116         /* Check characters were read. */
117         if( pcIPAddress == pcSource )
118         {
119             xResult = pdFAIL;
120         }
121 
122         /* Check the value fits in an 8-bit number. */
123         if( ulValue > 0xffU )
124         {
125             xResult = pdFAIL;
126         }
127         else
128         {
129             ucOctet[ uxOctetNumber ] = ( uint8_t ) ulValue;
130 
131             /* Check the next character is as expected. */
132             if( uxOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1U ) )
133             {
134                 if( *pcIPAddress != '.' )
135                 {
136                     xResult = pdFAIL;
137                 }
138                 else
139                 {
140                     /* Move past the dot. */
141                     pcIPAddress++;
142                 }
143             }
144         }
145 
146         if( xResult == pdFAIL )
147         {
148             /* No point going on. */
149             break;
150         }
151     }
152 
153     if( *pcIPAddress != ( char ) 0 )
154     {
155         /* Expected the end of the string. */
156         xResult = pdFAIL;
157     }
158 
159     if( uxOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
160     {
161         /* Didn't read enough octets. */
162         xResult = pdFAIL;
163     }
164 
165     if( xResult == pdPASS )
166     {
167         /* lint: ucOctet has been set because xResult == pdPASS. */
168         ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
169     }
170     else
171     {
172         ulReturn = 0U;
173     }
174 
175     if( xResult == pdPASS )
176     {
177         pvCopySource = ( const void * ) &ulReturn;
178         ( void ) memcpy( pvDestination, pvCopySource, sizeof( ulReturn ) );
179     }
180 
181     return xResult;
182 }
183 /*-----------------------------------------------------------*/
184 
185 /**
186  * @brief Convert the 32-bit representation of the IP-address to the dotted decimal format.
187  *
188  * @param[in] pvSource The pointer to the 32-bit representation of the IP-address.
189  * @param[out] pcDestination The pointer to a character array where the string of the
190  *                           dotted decimal IP format.
191  * @param[in] uxSize Size of the character array. This value makes sure that the code
192  *                    doesn't write beyond it's bounds.
193  *
194  * @return The pointer to the string holding the dotted decimal format of the IP-address. If
195  *         everything passes correctly, then the pointer being returned is the same as
196  *         pcDestination, else a NULL is returned.
197  */
FreeRTOS_inet_ntop4(const void * pvSource,char * pcDestination,socklen_t uxSize)198 const char * FreeRTOS_inet_ntop4( const void * pvSource,
199                                   char * pcDestination,
200                                   socklen_t uxSize )
201 {
202     uint32_t ulIPAddress;
203     void * pvCopyDest;
204     const char * pcReturn;
205 
206     if( uxSize < 16U )
207     {
208         /* There must be space for "255.255.255.255". */
209         pcReturn = NULL;
210     }
211     else
212     {
213         pvCopyDest = ( void * ) &ulIPAddress;
214         ( void ) memcpy( pvCopyDest, pvSource, sizeof( ulIPAddress ) );
215         ( void ) FreeRTOS_inet_ntoa( ulIPAddress, pcDestination );
216         pcReturn = pcDestination;
217     }
218 
219     return pcReturn;
220 }
221 
222 /**
223  * @brief Called by prvSendUDPPacket(), this function will UDP packet
224  *        fields and IPv4 address for the packet to be send.
225  * @param[in] pxNetworkBuffer  The packet to be sent.
226  * @param[in] pxDestinationAddress The IPv4 socket address.
227  * @return  Returns NULL, always.
228  */
xSend_UDP_Update_IPv4(NetworkBufferDescriptor_t * pxNetworkBuffer,const struct freertos_sockaddr * pxDestinationAddress)229 void * xSend_UDP_Update_IPv4( NetworkBufferDescriptor_t * pxNetworkBuffer,
230                               const struct freertos_sockaddr * pxDestinationAddress )
231 {
232     UDPPacket_t * pxUDPPacket;
233 
234     if( ( pxNetworkBuffer != NULL ) && ( pxDestinationAddress != NULL ) )
235     {
236         /* MISRA Ref 11.3.1 [Misaligned access] */
237         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
238         /* coverity[misra_c_2012_rule_11_3_violation] */
239         pxUDPPacket = ( ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
240 
241         pxNetworkBuffer->xIPAddress.ulIP_IPv4 = pxDestinationAddress->sin_address.ulIP_IPv4;
242         /* Map the UDP packet onto the start of the frame. */
243         pxUDPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;
244     }
245 
246     return NULL;
247 }
248 
249 /**
250  * @brief Called by FreeRTOS_recvfrom(), this function will update socket
251  *        address with IPv4 address from the packet received.
252  * @param[in] pxNetworkBuffer  The packet received.
253  * @param[in] pxSourceAddress The IPv4 socket address.
254  * @return  The Payload Offset.
255  */
xRecv_Update_IPv4(const NetworkBufferDescriptor_t * pxNetworkBuffer,struct freertos_sockaddr * pxSourceAddress)256 size_t xRecv_Update_IPv4( const NetworkBufferDescriptor_t * pxNetworkBuffer,
257                           struct freertos_sockaddr * pxSourceAddress )
258 {
259     size_t uxPayloadOffset = 0;
260 
261     if( ( pxNetworkBuffer != NULL ) && ( pxSourceAddress != NULL ) )
262     {
263         pxSourceAddress->sin_family = ( uint8_t ) FREERTOS_AF_INET;
264         pxSourceAddress->sin_address.ulIP_IPv4 = pxNetworkBuffer->xIPAddress.ulIP_IPv4;
265         pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
266     }
267 
268     uxPayloadOffset = ipUDP_PAYLOAD_OFFSET_IPv4;
269 
270     return uxPayloadOffset;
271 }
272 
273 /*-----------------------------------------------------------*/
274 
275 /* *INDENT-OFF* */
276     #endif /* ipconfigUSE_IPv4 != 0 ) */
277 /* *INDENT-ON* */
278