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