1 /*
2 * FreeRTOS+TCP V2.3.1
3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * http://aws.amazon.com/freertos
23 * http://www.FreeRTOS.org
24 */
25
26 /**
27 * @file FreeRTOS_Routing.c
28 * @brief Implements endpoint interfaces functions and utilities.
29 */
30
31 /* Standard includes. */
32 #include <stdint.h>
33 #include <stdio.h>
34
35 /* FreeRTOS includes. */
36 #include "FreeRTOS.h"
37 #include "task.h"
38
39 /* FreeRTOS+TCP includes. */
40 #include "FreeRTOS_IP.h"
41 #include "FreeRTOS_Sockets.h"
42 #include "FreeRTOS_IP_Private.h"
43 #include "FreeRTOS_ARP.h"
44 #include "FreeRTOS_UDP_IP.h"
45 #include "FreeRTOS_DHCP.h"
46 #include "NetworkBufferManagement.h"
47 #if ( ipconfigUSE_LLMNR == 1 )
48 #include "FreeRTOS_DNS.h"
49 #endif /* ipconfigUSE_LLMNR */
50 #include "FreeRTOS_Routing.h"
51
52 /** @brief A list of all network end-points. Each element has a next pointer. */
53 struct xNetworkEndPoint * pxNetworkEndPoints = NULL;
54
55 /** @brief A list of all network interfaces: */
56 struct xNetworkInterface * pxNetworkInterfaces = NULL;
57
58 /*
59 * Add a new IP-address to a Network Interface. The object pointed to by
60 * 'pxEndPoint' and the interface must continue to exist.
61 */
62 static NetworkEndPoint_t * FreeRTOS_AddEndPoint( NetworkInterface_t * pxInterface,
63 NetworkEndPoint_t * pxEndPoint );
64
65 /** @brief A util struct to list the IPv6 IP types, prefix and type bit mask */
66 struct xIPv6_Couple
67 {
68 IPv6_Type_t eType; /**< IPv6 IP type enum */
69 uint16_t usMask; /**< IPv6 IP type bit mask */
70 uint16_t usExpected; /**< IPv6 IP type prefix */
71 };
72 /*-----------------------------------------------------------*/
73
74
75 #if ( ipconfigUSE_IPv4 != 0 )
76
77 /**
78 * @brief Configure and install a new IPv4 end-point.
79 *
80 * @param[in] pxNetworkInterface The interface to which it belongs.
81 * @param[in] pxEndPoint Space for the new end-point. This memory is dedicated for the
82 * end-point and should not be freed or get any other purpose.
83 * @param[in] ucIPAddress The IP-address.
84 * @param[in] ucNetMask The prefix which shall be used for this end-point.
85 * @param[in] ucGatewayAddress The IP-address of a device on the LAN which can serve as
86 * as a gateway to the Internet.
87 * @param[in] ucDNSServerAddress The IP-address of a DNS server.
88 * @param[in] ucMACAddress The MAC address of the end-point.
89 */
FreeRTOS_FillEndPoint(NetworkInterface_t * pxNetworkInterface,NetworkEndPoint_t * pxEndPoint,const uint8_t ucIPAddress[ipIP_ADDRESS_LENGTH_BYTES],const uint8_t ucNetMask[ipIP_ADDRESS_LENGTH_BYTES],const uint8_t ucGatewayAddress[ipIP_ADDRESS_LENGTH_BYTES],const uint8_t ucDNSServerAddress[ipIP_ADDRESS_LENGTH_BYTES],const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES])90 void FreeRTOS_FillEndPoint( NetworkInterface_t * pxNetworkInterface,
91 NetworkEndPoint_t * pxEndPoint,
92 const uint8_t ucIPAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
93 const uint8_t ucNetMask[ ipIP_ADDRESS_LENGTH_BYTES ],
94 const uint8_t ucGatewayAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
95 const uint8_t ucDNSServerAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
96 const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] )
97 {
98 uint32_t ulIPAddress;
99
100 if( ( pxNetworkInterface == NULL ) || ( pxEndPoint == NULL ) )
101 {
102 /* Invalid input. */
103 FreeRTOS_printf( ( "FreeRTOS_FillEndPoint: Invalid input, netif=%p, endpoint=%p\n",
104 ( void * ) pxNetworkInterface,
105 ( void * ) pxEndPoint ) );
106 }
107 else
108 {
109 /* Fill in and add an end-point to a network interface.
110 * The user must make sure that the object pointed to by 'pxEndPoint'
111 * will remain to exist. */
112 ( void ) memset( pxEndPoint, 0, sizeof( *pxEndPoint ) );
113
114 ulIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] );
115 pxEndPoint->ipv4_settings.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] );
116 pxEndPoint->ipv4_settings.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] );
117 pxEndPoint->ipv4_settings.ulDNSServerAddresses[ 0 ] = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] );
118 pxEndPoint->ipv4_settings.ulBroadcastAddress = ulIPAddress | ~( pxEndPoint->ipv4_settings.ulNetMask );
119
120 /* Copy the current values to the default values. */
121 ( void ) memcpy( &( pxEndPoint->ipv4_defaults ), &( pxEndPoint->ipv4_settings ), sizeof( pxEndPoint->ipv4_defaults ) );
122
123 /* The default IP-address will be used in case DHCP is not used, or also if DHCP has failed, or
124 * when the user chooses to use the default IP-address. */
125 pxEndPoint->ipv4_defaults.ulIPAddress = ulIPAddress;
126
127 /* The field 'ipv4_settings.ulIPAddress' will be set later on. */
128
129 ( void ) memcpy( pxEndPoint->xMACAddress.ucBytes, ucMACAddress, sizeof( pxEndPoint->xMACAddress ) );
130 ( void ) FreeRTOS_AddEndPoint( pxNetworkInterface, pxEndPoint );
131 }
132 }
133 /*-----------------------------------------------------------*/
134 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
135
136 #if ( ipconfigCOMPATIBLE_WITH_SINGLE == 0 )
137
138 #if ( ipconfigHAS_ROUTING_STATISTICS == 1 )
139 RoutingStats_t xRoutingStatistics;
140 #endif
141
142 /*-----------------------------------------------------------*/
143
144 /**
145 * @brief Add a network interface to the list of interfaces. Check if the interface was
146 * already added in an earlier call.
147 *
148 * @param[in] pxInterface The address of the new interface.
149 *
150 * @return The value of the parameter 'pxInterface'.
151 */
FreeRTOS_AddNetworkInterface(NetworkInterface_t * pxInterface)152 NetworkInterface_t * FreeRTOS_AddNetworkInterface( NetworkInterface_t * pxInterface )
153 {
154 NetworkInterface_t * pxIterator = NULL;
155
156 if( pxInterface != NULL )
157 {
158 /* This interface will be added to the end of the list of interfaces, so
159 * there is no pxNext yet. */
160 pxInterface->pxNext = NULL;
161
162 /* The end point for this interface has not yet been set. */
163 /*_RB_ As per other comments, why not set the end point at the same time? */
164 pxInterface->pxEndPoint = NULL;
165
166 if( pxNetworkInterfaces == NULL )
167 {
168 /* No other interfaces are set yet, so this is the first in the list. */
169 pxNetworkInterfaces = pxInterface;
170 }
171 else
172 {
173 /* Other interfaces are already defined, so iterate to the end of the
174 * list. */
175
176 /*_RB_ Question - if ipconfigMULTI_INTERFACE is used to define the
177 * maximum number of interfaces, would it be more efficient to have an
178 * array of interfaces rather than a linked list of interfaces? */
179 pxIterator = pxNetworkInterfaces;
180
181 for( ; ; )
182 {
183 if( pxIterator == pxInterface )
184 {
185 /* This interface was already added. */
186 break;
187 }
188
189 if( pxIterator->pxNext == NULL )
190 {
191 pxIterator->pxNext = pxInterface;
192 break;
193 }
194
195 pxIterator = pxIterator->pxNext;
196 }
197 }
198 }
199
200 return pxInterface;
201 }
202 /*-----------------------------------------------------------*/
203
204 /**
205 * @brief Get the first Network Interface, or NULL if none has been added.
206 *
207 * @return The first interface, or NULL if none has been added
208 */
FreeRTOS_FirstNetworkInterface(void)209 NetworkInterface_t * FreeRTOS_FirstNetworkInterface( void )
210 {
211 return pxNetworkInterfaces;
212 }
213 /*-----------------------------------------------------------*/
214
215 /**
216 * @brief Get the next interface.
217 *
218 * @return The interface that comes after 'pxInterface'. NULL when either 'pxInterface'
219 * is NULL, or when 'pxInterface' is the last interface.
220 */
FreeRTOS_NextNetworkInterface(const NetworkInterface_t * pxInterface)221 NetworkInterface_t * FreeRTOS_NextNetworkInterface( const NetworkInterface_t * pxInterface )
222 {
223 NetworkInterface_t * pxReturn;
224
225 if( pxInterface != NULL )
226 {
227 pxReturn = pxInterface->pxNext;
228 }
229 else
230 {
231 pxReturn = NULL;
232 }
233
234 return pxReturn;
235 }
236 /*-----------------------------------------------------------*/
237
238 /**
239 * @brief Add an end-point to a given interface.
240 *
241 * @param[in] pxInterface The interface that gets a new end-point.
242 * @param[in] pxEndPoint The end-point to be added.
243 *
244 * @return The value of the parameter 'pxEndPoint'.
245 */
FreeRTOS_AddEndPoint(NetworkInterface_t * pxInterface,NetworkEndPoint_t * pxEndPoint)246 static NetworkEndPoint_t * FreeRTOS_AddEndPoint( NetworkInterface_t * pxInterface,
247 NetworkEndPoint_t * pxEndPoint )
248 {
249 NetworkEndPoint_t * pxIterator = NULL;
250
251 /* This end point will go to the end of the list, so there is no pxNext
252 * yet. */
253 pxEndPoint->pxNext = NULL;
254
255 /* Double link between the NetworkInterface_t that is using the addressing
256 * defined by this NetworkEndPoint_t structure. */
257 pxEndPoint->pxNetworkInterface = pxInterface;
258
259 if( pxInterface->pxEndPoint == NULL )
260 {
261 /*_RB_ When would pxInterface->pxEndPoint ever not be NULL unless this is called twice? */
262 /*_HT_ It may be called twice. */
263 pxInterface->pxEndPoint = pxEndPoint;
264 }
265
266 if( pxNetworkEndPoints == NULL )
267 {
268 /* No other end points are defined yet - so this is the first in the
269 * list. */
270 pxNetworkEndPoints = pxEndPoint;
271 }
272 else
273 {
274 /* Other end points are already defined so iterate to the end of the
275 * list. */
276 pxIterator = pxNetworkEndPoints;
277
278 for( ; ; )
279 {
280 if( pxIterator == pxEndPoint )
281 {
282 /* This end-point has already been added to the list. */
283 break;
284 }
285
286 if( pxIterator->pxNext == NULL )
287 {
288 pxIterator->pxNext = pxEndPoint;
289 break;
290 }
291
292 pxIterator = pxIterator->pxNext;
293 }
294 }
295
296 #if ( ipconfigUSE_IPv6 != 0 )
297 if( pxEndPoint->bits.bIPv6 == pdTRUE_UNSIGNED )
298 {
299 FreeRTOS_printf( ( "FreeRTOS_AddEndPoint: MAC: %02x-%02x IPv6: %pip\n",
300 pxEndPoint->xMACAddress.ucBytes[ 4 ],
301 pxEndPoint->xMACAddress.ucBytes[ 5 ],
302 ( void * ) pxEndPoint->ipv6_defaults.xIPAddress.ucBytes ) );
303 }
304 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
305 #if ( ipconfigUSE_IPv4 != 0 )
306 if( pxEndPoint->bits.bIPv6 == pdFALSE_UNSIGNED )
307 {
308 FreeRTOS_printf( ( "FreeRTOS_AddEndPoint: MAC: %02x-%02x IPv4: %xip\n",
309 pxEndPoint->xMACAddress.ucBytes[ 4 ],
310 pxEndPoint->xMACAddress.ucBytes[ 5 ],
311 ( unsigned ) FreeRTOS_ntohl( pxEndPoint->ipv4_defaults.ulIPAddress ) ) );
312 }
313 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
314
315 return pxEndPoint;
316 }
317 /*-----------------------------------------------------------*/
318
319 /**
320 * @brief Find the first end-point bound to a given interface.
321 *
322 * @param[in] pxInterface The interface whose first end-point will be returned.
323 *
324 * @return The first end-point that is found to the interface, or NULL when the
325 * interface doesn't have any end-point yet.
326 */
FreeRTOS_FirstEndPoint(const NetworkInterface_t * pxInterface)327 NetworkEndPoint_t * FreeRTOS_FirstEndPoint( const NetworkInterface_t * pxInterface )
328 {
329 NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
330
331 /* Find and return the NetworkEndPoint_t structure that is associated with
332 * the pxInterface NetworkInterface_t. *//*_RB_ Could this be made a two way link, so the NetworkEndPoint_t can just be read from the NetworkInterface_t structure? Looks like there is a pointer in the struct already. */
333 while( pxEndPoint != NULL )
334 {
335 if( ( pxInterface == NULL ) || ( pxEndPoint->pxNetworkInterface == pxInterface ) )
336 {
337 break;
338 }
339
340 pxEndPoint = pxEndPoint->pxNext;
341 }
342
343 return pxEndPoint;
344 }
345 /*-----------------------------------------------------------*/
346
347 /**
348 * @brief Get the next end-point. The parameter 'pxInterface' may be NULL, which means:
349 * don't care which interface the end-point is bound to.
350 *
351 * @param[in] pxInterface An interface of interest, or NULL when iterating through all
352 * end-points.
353 * @param[in] pxEndPoint This is the current end-point.
354 *
355 * @return The end-point that is found, or NULL when there are no more end-points in the list.
356 */
FreeRTOS_NextEndPoint(const NetworkInterface_t * pxInterface,NetworkEndPoint_t * pxEndPoint)357 NetworkEndPoint_t * FreeRTOS_NextEndPoint( const NetworkInterface_t * pxInterface,
358 NetworkEndPoint_t * pxEndPoint )
359 {
360 NetworkEndPoint_t * pxResult = pxEndPoint;
361
362 if( pxResult != NULL )
363 {
364 pxResult = pxResult->pxNext;
365
366 while( pxResult != NULL )
367 {
368 if( ( pxInterface == NULL ) || ( pxResult->pxNetworkInterface == pxInterface ) )
369 {
370 break;
371 }
372
373 pxResult = pxResult->pxNext;
374 }
375 }
376 else
377 {
378 pxResult = FreeRTOS_FirstEndPoint( pxInterface );
379 }
380
381 return pxResult;
382 }
383 /*-----------------------------------------------------------*/
384
385 /**
386 * @brief Find the end-point which has a given IPv4 address.
387 *
388 * @param[in] ulIPAddress The IP-address of interest, or 0 if any IPv4 end-point may be returned.
389 * @param[in] ulWhere For maintaining routing statistics ulWhere acts as an index to the data structure
390 * that keep track of the number of times 'FreeRTOS_FindEndPointOnIP_IPv4()'
391 * has been called from a particular location. Used only if
392 * ipconfigHAS_ROUTING_STATISTICS is enabled.
393 *
394 * @return The end-point found or NULL.
395 */
FreeRTOS_FindEndPointOnIP_IPv4(uint32_t ulIPAddress,uint32_t ulWhere)396 NetworkEndPoint_t * FreeRTOS_FindEndPointOnIP_IPv4( uint32_t ulIPAddress,
397 uint32_t ulWhere )
398 {
399 NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
400
401 #if ( ipconfigHAS_ROUTING_STATISTICS == 1 )
402 uint32_t ulLocationCount = ( uint32_t ) ( sizeof( xRoutingStatistics.ulLocationsIP ) / sizeof( xRoutingStatistics.ulLocationsIP[ 0 ] ) );
403
404 xRoutingStatistics.ulOnIp++;
405
406 if( ulWhere < ulLocationCount )
407 {
408 xRoutingStatistics.ulLocationsIP[ ulWhere ]++;
409 }
410 #endif /* ( ipconfigHAS_ROUTING_STATISTICS == 1 ) */
411
412 while( pxEndPoint != NULL )
413 {
414 #if ( ipconfigUSE_IPv4 != 0 )
415 #if ( ipconfigUSE_IPv6 != 0 )
416 if( pxEndPoint->bits.bIPv6 == 0U )
417 #endif
418 {
419 if( ( ulIPAddress == 0U ) ||
420 ( pxEndPoint->ipv4_settings.ulIPAddress == 0U ) ||
421 ( pxEndPoint->ipv4_settings.ulIPAddress == ulIPAddress ) )
422 {
423 break;
424 }
425 }
426 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
427
428 pxEndPoint = pxEndPoint->pxNext;
429 }
430
431 ( void ) ulIPAddress;
432
433 return pxEndPoint;
434 }
435 /*-----------------------------------------------------------*/
436
437 #if ( ipconfigUSE_IPv6 != 0 )
438
439 /**
440 * @brief Find the end-point which handles a given IPv6 address.
441 *
442 * @param[in] pxIPAddress The IP-address of interest.
443 *
444 * @return The end-point found or NULL.
445 */
FreeRTOS_FindEndPointOnIP_IPv6(const IPv6_Address_t * pxIPAddress)446 NetworkEndPoint_t * FreeRTOS_FindEndPointOnIP_IPv6( const IPv6_Address_t * pxIPAddress )
447 {
448 NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
449
450 while( pxEndPoint != NULL )
451 {
452 if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED )
453 {
454 if( xCompareIPv6_Address( &( pxEndPoint->ipv6_settings.xIPAddress ), pxIPAddress, pxEndPoint->ipv6_settings.uxPrefixLength ) == 0 )
455 {
456 break;
457 }
458 }
459
460 pxEndPoint = pxEndPoint->pxNext;
461 }
462
463 return pxEndPoint;
464 }
465 #endif /* ipconfigUSE_IPv6 */
466 /*-----------------------------------------------------------*/
467
468 /**
469 * @brief Find the end-point that has a certain MAC-address.
470 *
471 * @param[in] pxMACAddress The Ethernet packet.
472 * @param[in] pxInterface The interface on which the packet was received, or NULL when unknown.
473 *
474 * @return The end-point that has the given MAC-address.
475 */
FreeRTOS_FindEndPointOnMAC(const MACAddress_t * pxMACAddress,const NetworkInterface_t * pxInterface)476 NetworkEndPoint_t * FreeRTOS_FindEndPointOnMAC( const MACAddress_t * pxMACAddress,
477 const NetworkInterface_t * pxInterface )
478 {
479 NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
480
481 #if ( ipconfigHAS_ROUTING_STATISTICS == 1 )
482 {
483 xRoutingStatistics.ulOnMAC++;
484 }
485 #endif
486
487 /* If input MAC address is NULL, return NULL. */
488 if( pxMACAddress == NULL )
489 {
490 pxEndPoint = NULL;
491 }
492
493 /*_RB_ Question - would it be more efficient to store the mac addresses in
494 * uin64_t variables for direct comparison instead of using memcmp()? [don't
495 * know if there is a quick way of creating a 64-bit number from the 48-byte
496 * MAC address without getting junk in the top 2 bytes]. */
497
498 /* Find the end-point with given MAC-address. */
499 while( pxEndPoint != NULL )
500 {
501 if( ( pxInterface == NULL ) || ( pxInterface == pxEndPoint->pxNetworkInterface ) )
502 {
503 if( memcmp( pxEndPoint->xMACAddress.ucBytes, pxMACAddress->ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 )
504 {
505 break;
506 }
507 }
508
509 pxEndPoint = pxEndPoint->pxNext;
510 }
511
512 return pxEndPoint;
513 }
514 /*-----------------------------------------------------------*/
515
516 /**
517 * @brief Find an end-point that handles a given IPv4-address.
518 *
519 * @param[in] ulIPAddress The IP-address for which an end-point is looked-up.
520 * @param[in] ulWhere For maintaining routing statistics ulWhere acts as an index to the data structure
521 * that keep track of the number of times 'FreeRTOS_InterfaceEndPointOnNetMask()'
522 * has been called from a particular location. Used only if
523 * ipconfigHAS_ROUTING_STATISTICS is enabled.
524 *
525 * @return An end-point that has the same network mask as the given IP-address.
526 */
FreeRTOS_FindEndPointOnNetMask(uint32_t ulIPAddress,uint32_t ulWhere)527 NetworkEndPoint_t * FreeRTOS_FindEndPointOnNetMask( uint32_t ulIPAddress,
528 uint32_t ulWhere )
529 {
530 /* The 'ulWhere' parameter is only for debugging purposes. */
531 return FreeRTOS_InterfaceEndPointOnNetMask( NULL, ulIPAddress, ulWhere );
532 }
533 /*-----------------------------------------------------------*/
534
535 /**
536 * @brief Find an end-point that handles a given IPv4-address.
537 *
538 * @param[in] pxInterface Only end-points that have this interface are returned, unless
539 * pxInterface is NULL.
540 * @param[in] ulIPAddress The IP-address for which an end-point is looked-up.
541 *
542 * @param[in] ulWhere For maintaining routing statistics ulWhere acts as an index to the data structure
543 * that keep track of the number of times 'FreeRTOS_InterfaceEndPointOnNetMask()'
544 * has been called from a particular location. Used only if
545 * ipconfigHAS_ROUTING_STATISTICS is enabled.
546 *
547 * @return An end-point that has the same network mask as the given IP-address.
548 */
FreeRTOS_InterfaceEndPointOnNetMask(const NetworkInterface_t * pxInterface,uint32_t ulIPAddress,uint32_t ulWhere)549 NetworkEndPoint_t * FreeRTOS_InterfaceEndPointOnNetMask( const NetworkInterface_t * pxInterface,
550 uint32_t ulIPAddress,
551 uint32_t ulWhere )
552 {
553 NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
554
555 #if ( ipconfigHAS_ROUTING_STATISTICS == 1 )
556 uint32_t ulLocationCount = ( uint32_t ) ( sizeof( xRoutingStatistics.ulLocations ) / sizeof( xRoutingStatistics.ulLocations[ 0 ] ) );
557
558 xRoutingStatistics.ulOnNetMask++;
559
560 if( ulWhere < ulLocationCount )
561 {
562 xRoutingStatistics.ulLocations[ ulWhere ]++;
563 }
564 #endif /* ( ipconfigHAS_ROUTING_STATISTICS == 1 ) */
565
566 /* Find the best fitting end-point to reach a given IP-address. */
567
568 /*_RB_ Presumably then a broadcast reply could go out on a different end point to that on
569 * which the broadcast was received - although that should not be an issue if the nodes are
570 * on the same LAN it could be an issue if the nodes are on separate LAN's. */
571
572 while( pxEndPoint != NULL )
573 {
574 if( ( pxInterface == NULL ) || ( pxEndPoint->pxNetworkInterface == pxInterface ) )
575 {
576 #if ( ipconfigUSE_IPv4 != 0 )
577 #if ( ipconfigUSE_IPv6 != 0 )
578 if( pxEndPoint->bits.bIPv6 == pdFALSE_UNSIGNED )
579 #endif
580 {
581 if( ( ulIPAddress == ~0U ) ||
582 ( ( ulIPAddress & pxEndPoint->ipv4_settings.ulNetMask ) == ( pxEndPoint->ipv4_settings.ulIPAddress & pxEndPoint->ipv4_settings.ulNetMask ) ) )
583 {
584 /* Found a match. */
585 break;
586 }
587 }
588 #endif /* if ( ipconfigUSE_IPv4 != 0 ) */
589 }
590
591 pxEndPoint = pxEndPoint->pxNext;
592 }
593
594 /* This was only for debugging. */
595 if( pxEndPoint == NULL )
596 {
597 FreeRTOS_debug_printf( ( "FreeRTOS_FindEndPointOnNetMask[%d]: No match for %xip\n",
598 ( unsigned ) ulWhere, ( unsigned ) FreeRTOS_ntohl( ulIPAddress ) ) );
599 }
600
601 return pxEndPoint;
602 }
603 /*-----------------------------------------------------------*/
604
605 #if ( ipconfigUSE_IPv6 != 0 )
606
607 /**
608 * @brief Configure and install a new IPv6 end-point.
609 *
610 * @param[in] pxNetworkInterface The interface to which it belongs.
611 * @param[in] pxEndPoint Space for the new end-point. This memory is dedicated for the
612 * end-point and should not be freed or get any other purpose.
613 * @param[in] pxIPAddress The IP-address.
614 * @param[in] pxNetPrefix The prefix which shall be used for this end-point.
615 * @param[in] uxPrefixLength The length of the above end-point.
616 * @param[in] pxGatewayAddress The IP-address of a device on the LAN which can serve as
617 * as a gateway to the Internet.
618 * @param[in] pxDNSServerAddress The IP-address of a DNS server.
619 * @param[in] ucMACAddress The MAC address of the end-point.
620 */
FreeRTOS_FillEndPoint_IPv6(NetworkInterface_t * pxNetworkInterface,NetworkEndPoint_t * pxEndPoint,const IPv6_Address_t * pxIPAddress,const IPv6_Address_t * pxNetPrefix,size_t uxPrefixLength,const IPv6_Address_t * pxGatewayAddress,const IPv6_Address_t * pxDNSServerAddress,const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES])621 void FreeRTOS_FillEndPoint_IPv6( NetworkInterface_t * pxNetworkInterface,
622 NetworkEndPoint_t * pxEndPoint,
623 const IPv6_Address_t * pxIPAddress,
624 const IPv6_Address_t * pxNetPrefix,
625 size_t uxPrefixLength,
626 const IPv6_Address_t * pxGatewayAddress,
627 const IPv6_Address_t * pxDNSServerAddress,
628 const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] )
629 {
630 if( ( pxNetworkInterface == NULL ) ||
631 ( pxEndPoint == NULL ) ||
632 ( pxIPAddress == NULL ) ||
633 ( ucMACAddress == NULL ) )
634 {
635 /* Invalid input. */
636 FreeRTOS_printf( ( "FreeRTOS_FillEndPoint_IPv6: Invalid input, netif=%p, endpoint=%p, pxIPAddress=%p, ucMACAddress=%p\n",
637 ( void * ) pxNetworkInterface,
638 ( void * ) pxEndPoint,
639 ( void * ) pxIPAddress,
640 ( void * ) ucMACAddress ) );
641 }
642 else
643 {
644 ( void ) memset( pxEndPoint, 0, sizeof( *pxEndPoint ) );
645
646 pxEndPoint->bits.bIPv6 = pdTRUE_UNSIGNED;
647
648 pxEndPoint->ipv6_settings.uxPrefixLength = uxPrefixLength;
649
650 if( pxGatewayAddress != NULL )
651 {
652 ( void ) memcpy( pxEndPoint->ipv6_settings.xGatewayAddress.ucBytes, pxGatewayAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS );
653 }
654
655 if( pxDNSServerAddress != NULL )
656 {
657 ( void ) memcpy( pxEndPoint->ipv6_settings.xDNSServerAddresses[ 0 ].ucBytes, pxDNSServerAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS );
658 }
659
660 if( pxNetPrefix != NULL )
661 {
662 ( void ) memcpy( pxEndPoint->ipv6_settings.xPrefix.ucBytes, pxNetPrefix->ucBytes, ipSIZE_OF_IPv6_ADDRESS );
663 }
664
665 /* Copy the current values to the default values. */
666 ( void ) memcpy( &( pxEndPoint->ipv6_defaults ), &( pxEndPoint->ipv6_settings ), sizeof( pxEndPoint->ipv6_defaults ) );
667
668 ( void ) memcpy( pxEndPoint->ipv6_defaults.xIPAddress.ucBytes, pxIPAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS );
669
670 ( void ) memcpy( pxEndPoint->xMACAddress.ucBytes, ucMACAddress, ipMAC_ADDRESS_LENGTH_BYTES );
671 ( void ) FreeRTOS_AddEndPoint( pxNetworkInterface, pxEndPoint );
672 }
673 }
674 #endif /* if ( ipconfigUSE_IPv6 != 0 ) */
675 /*-----------------------------------------------------------*/
676
677 #if ( ipconfigUSE_IPv6 != 0 )
678
679 /**
680 * @brief Find an end-point that handles a given IPv6-address.
681 *
682 * @param[in] pxIPv6Address The IP-address for which an end-point is looked-up.
683 *
684 * @return An end-point that has the same network mask as the given IP-address.
685 */
FreeRTOS_FindEndPointOnNetMask_IPv6(const IPv6_Address_t * pxIPv6Address)686 NetworkEndPoint_t * FreeRTOS_FindEndPointOnNetMask_IPv6( const IPv6_Address_t * pxIPv6Address )
687 {
688 NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
689
690 while( pxEndPoint != NULL )
691 {
692 if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED )
693 {
694 if( xCompareIPv6_Address( &( pxEndPoint->ipv6_settings.xIPAddress ), pxIPv6Address, pxEndPoint->ipv6_settings.uxPrefixLength ) == 0 )
695 {
696 break;
697 }
698 }
699
700 pxEndPoint = pxEndPoint->pxNext;
701 }
702
703 return pxEndPoint;
704 }
705 #endif /* ipconfigUSE_IPv6 */
706 /*-----------------------------------------------------------*/
707
708 /**
709 * @brief Check IP-type, IP- and MAC-address found in the network packet.
710 */
711 #define rMATCH_IP_ADDR 0 /**< Find an endpoint with a matching IP-address. */
712 #define rMATCH_IPv6_TYPE 1 /**< Find an endpoint with a matching IPv6 type (both global or non global). */
713 #define rMATCH_MAC_ADDR 2 /**< Find an endpoint with a matching MAC-address. */
714 #define rMATCH_IP_TYPE 3 /**< Find an endpoint with a matching IP-type, v4 or v6. */
715 #define rMATCH_COUNT 4 /**< The number of methods. */
716
717 NetworkEndPoint_t * pxEasyFit( const NetworkInterface_t * pxNetworkInterface,
718 const uint16_t usFrameType,
719 const IP_Address_t * pxIPAddressFrom,
720 const IP_Address_t * pxIPAddressTo,
721 const MACAddress_t * pxMACAddress );
722
723 /**
724 * @brief Find an end-point that handles an incoming packet based on its type, source/destination & MAC address.
725 *
726 * @param[in] pxNetworkInterface The interface via which the packet was received.
727 * @param[in] usFrameType Frame type of the packet.
728 * @param[in] pxIPAddressFrom Source IP address of the packet.
729 * @param[in] pxIPAddressTo Destination IP address of the packet.
730 * @param[in] pxMACAddress Destination MAC address of the packet.
731 *
732 * @return An end-point that handles the packet.
733 */
pxEasyFit(const NetworkInterface_t * pxNetworkInterface,const uint16_t usFrameType,const IP_Address_t * pxIPAddressFrom,const IP_Address_t * pxIPAddressTo,const MACAddress_t * pxMACAddress)734 NetworkEndPoint_t * pxEasyFit( const NetworkInterface_t * pxNetworkInterface,
735 const uint16_t usFrameType,
736 const IP_Address_t * pxIPAddressFrom,
737 const IP_Address_t * pxIPAddressTo,
738 const MACAddress_t * pxMACAddress )
739 {
740 NetworkEndPoint_t * pxEndPoint;
741 NetworkEndPoint_t * pxReturn = NULL;
742 /* endpoints found for IP-type, IP-address, and MAC-address. */
743 NetworkEndPoint_t * pxFound[ rMATCH_COUNT ] = { NULL, NULL, NULL, NULL };
744 BaseType_t xCount[ rMATCH_COUNT ] = { 0, 0, 0, 0 };
745 BaseType_t xIndex;
746 BaseType_t xIsIPv6 = ( usFrameType == ipIPv6_FRAME_TYPE ) ? pdTRUE : pdFALSE;
747 BaseType_t xGatewayTarget = pdFALSE;
748 BaseType_t xTargetGlobal = pdFALSE;
749
750 ( void ) pxIPAddressFrom;
751 ( void ) xGatewayTarget;
752 ( void ) xTargetGlobal;
753
754 #if ( ipconfigUSE_IPv6 != 0 )
755 if( xIsIPv6 == pdTRUE )
756 {
757 /* Generic GW address fe80::1. */
758 static const uint8_t ucBytes[ 16 ] =
759 {
760 0xfe, 0x80, 0x00, 0x00,
761 0x00, 0x00, 0x00, 0x00,
762 0x00, 0x00, 0x00, 0x00,
763 0x00, 0x00, 0x00, 0x01
764 };
765 xGatewayTarget = ( memcmp( ucBytes, pxIPAddressTo->xIP_IPv6.ucBytes, 16 ) == 0 ) ? pdTRUE : pdFALSE;
766
767 if( xGatewayTarget == pdTRUE )
768 {
769 FreeRTOS_debug_printf( ( " GW address %pip to %pip\n",
770 ( void * ) pxIPAddressFrom->xIP_IPv6.ucBytes,
771 ( void * ) pxIPAddressTo->xIP_IPv6.ucBytes ) );
772 }
773
774 xTargetGlobal = ( xIPv6_GetIPType( &( pxIPAddressTo->xIP_IPv6 ) ) == eIPv6_Global ) ? pdTRUE : pdFALSE;
775 }
776 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
777
778 for( pxEndPoint = FreeRTOS_FirstEndPoint( pxNetworkInterface );
779 pxEndPoint != NULL;
780 pxEndPoint = FreeRTOS_NextEndPoint( pxNetworkInterface, pxEndPoint ) )
781 {
782 BaseType_t xSameMACAddress = ( memcmp( pxEndPoint->xMACAddress.ucBytes, pxMACAddress->ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) ? pdTRUE : pdFALSE;
783
784 if( xIsIPv6 == ( BaseType_t ) pxEndPoint->bits.bIPv6 )
785 {
786 pxFound[ rMATCH_IP_TYPE ] = pxEndPoint;
787 xCount[ rMATCH_IP_TYPE ]++;
788
789 /* Case default is impossible to reach because no endpoints for disabled IP type. */
790 switch( xIsIPv6 ) /* LCOV_EXCL_BR_LINE */
791 {
792 #if ( ipconfigUSE_IPv6 != 0 )
793 case ( BaseType_t ) pdTRUE:
794 {
795 IPv6_Type_t xEndpointType = xIPv6_GetIPType( &( pxEndPoint->ipv6_settings.xIPAddress ) );
796
797 if( xEndpointType != eIPv6_Unknown )
798 {
799 BaseType_t xEndpointGlobal = ( xEndpointType == eIPv6_Global ) ? pdTRUE : pdFALSE;
800
801 if( ( memcmp( pxEndPoint->ipv6_settings.xIPAddress.ucBytes, pxIPAddressTo->xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS ) == 0 ) )
802 {
803 pxFound[ rMATCH_IP_ADDR ] = pxEndPoint;
804 xCount[ rMATCH_IP_ADDR ]++;
805 }
806 else if( xTargetGlobal == xEndpointGlobal )
807 {
808 pxFound[ rMATCH_IPv6_TYPE ] = pxEndPoint;
809 xCount[ rMATCH_IPv6_TYPE ]++;
810 }
811 else
812 {
813 /* do nothing, coverity happy */
814 }
815 }
816 else
817 {
818 /* do nothing, coverity happy */
819 }
820 }
821 break;
822 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
823
824 case ( BaseType_t ) pdFALSE:
825 default:
826 #if ( ipconfigUSE_IPv4 != 0 )
827 if( pxEndPoint->ipv4_settings.ulIPAddress == pxIPAddressTo->ulIP_IPv4 )
828 {
829 pxFound[ rMATCH_IP_ADDR ] = pxEndPoint;
830 xCount[ rMATCH_IP_ADDR ]++;
831 }
832 else
833 {
834 /* do nothing, coverity happy */
835 }
836 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
837
838 break;
839 }
840
841 if( xSameMACAddress == pdTRUE )
842 {
843 xCount[ rMATCH_MAC_ADDR ]++;
844 pxFound[ rMATCH_MAC_ADDR ] = pxEndPoint;
845 }
846 }
847 }
848
849 for( xIndex = 0; xIndex < rMATCH_COUNT; xIndex++ )
850 {
851 if( xCount[ xIndex ] >= 1 )
852 {
853 pxReturn = pxFound[ xIndex ];
854 break;
855 }
856 }
857
858 #if ( ipconfigHAS_PRINTF != 0 )
859 if( pxReturn == NULL )
860 {
861 char pcBufferFrom[ 40 ];
862 char pcBufferTo[ 40 ];
863 BaseType_t xFamily = ( usFrameType == ipIPv6_FRAME_TYPE ) ? FREERTOS_AF_INET6 : FREERTOS_AF_INET4;
864 const char * xRetNtopTo;
865 const char * xRetNtopFrom;
866 xRetNtopTo = FreeRTOS_inet_ntop( xFamily,
867 ( void * ) pxIPAddressTo->xIP_IPv6.ucBytes,
868 pcBufferTo,
869 sizeof( pcBufferTo ) );
870 xRetNtopFrom = FreeRTOS_inet_ntop( xFamily,
871 ( void * ) pxIPAddressFrom->xIP_IPv6.ucBytes,
872 pcBufferFrom,
873 sizeof( pcBufferFrom ) );
874
875 FreeRTOS_debug_printf( ( "EasyFit[%x]: %d %d %d ( %s ->%s ) BAD\n",
876 usFrameType,
877 ( unsigned ) xCount[ 0 ],
878 ( unsigned ) xCount[ 1 ],
879 ( unsigned ) xCount[ 2 ],
880 ( xRetNtopFrom == NULL ) ? "INVALID" : pcBufferFrom,
881 ( xRetNtopTo == NULL ) ? "INVALID" : pcBufferTo ) );
882 }
883 #endif /* ( ipconfigHAS_PRINTF != 0 ) */
884
885 return pxReturn;
886 }
887
888 /**
889 * @brief Find out the best matching end-point given an incoming Ethernet packet.
890 *
891 * @param[in] pxNetworkInterface The interface on which the packet was received.
892 * @param[in] pucEthernetBuffer The Ethernet packet that was just received.
893 *
894 * @return The end-point that should handle the incoming Ethernet packet.
895 */
FreeRTOS_MatchingEndpoint(const NetworkInterface_t * pxNetworkInterface,const uint8_t * pucEthernetBuffer)896 NetworkEndPoint_t * FreeRTOS_MatchingEndpoint( const NetworkInterface_t * pxNetworkInterface,
897 const uint8_t * pucEthernetBuffer )
898 {
899 NetworkEndPoint_t * pxEndPoint = NULL;
900 /* MISRA Ref 11.3.1 [Misaligned access] */
901 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
902 /* coverity[misra_c_2012_rule_11_3_violation] */
903 const ProtocolPacket_t * pxPacket = ( ( const ProtocolPacket_t * ) pucEthernetBuffer );
904
905 #if ( ipconfigUSE_IPv6 != 0 )
906 /* MISRA Ref 11.3.1 [Misaligned access] */
907 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
908 /* coverity[misra_c_2012_rule_11_3_violation] */
909 const IPPacket_IPv6_t * pxIPPacket_IPv6 = ( ( const IPPacket_IPv6_t * ) pucEthernetBuffer );
910 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
911
912 configASSERT( pucEthernetBuffer != NULL );
913
914 /* Check if 'pucEthernetBuffer()' has the expected alignment,
915 * which is 32-bits + 2. */
916 #ifndef _lint
917 {
918 /* MISRA Ref 11.4.3 [Casting pointer to int for verification] */
919 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
920 /* coverity[misra_c_2012_rule_11_4_violation] */
921 uintptr_t uxAddress = ( uintptr_t ) pucEthernetBuffer;
922 uxAddress += 2U;
923 configASSERT( ( uxAddress % 4U ) == 0U );
924 /* And in case configASSERT is not defined. */
925 ( void ) uxAddress;
926 }
927 #endif /* ifndef _lint */
928
929 /* An Ethernet packet has been received. Inspect the contents to see which
930 * defined end-point has the best match.
931 */
932
933 #if ( ipconfigHAS_ROUTING_STATISTICS == 1 )
934 {
935 /* Some stats while developing. */
936 xRoutingStatistics.ulMatching++;
937 }
938 #endif
939 {
940 uint16_t usFrameType = pxPacket->xUDPPacket.xEthernetHeader.usFrameType;
941 IP_Address_t xIPAddressFrom;
942 IP_Address_t xIPAddressTo;
943 MACAddress_t xMACAddress;
944 BaseType_t xDoProcessPacket = pdFALSE;
945
946 ( void ) memset( xIPAddressFrom.xIP_IPv6.ucBytes, 0, ipSIZE_OF_IPv6_ADDRESS );
947 ( void ) memset( xIPAddressTo.xIP_IPv6.ucBytes, 0, ipSIZE_OF_IPv6_ADDRESS );
948
949 switch( usFrameType )
950 {
951 case ipIPv6_FRAME_TYPE:
952
953 /* Handle IPv6 frame types if ipconfigUSE_IPv6 != 0 */
954 #if ( ipconfigUSE_IPv6 != 0 )
955 ( void ) memcpy( xIPAddressFrom.xIP_IPv6.ucBytes, pxIPPacket_IPv6->xIPHeader.xSourceAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
956 ( void ) memcpy( xIPAddressTo.xIP_IPv6.ucBytes, pxIPPacket_IPv6->xIPHeader.xDestinationAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
957 xDoProcessPacket = pdTRUE;
958 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
959
960 break;
961
962 case ipARP_FRAME_TYPE:
963
964 /* Handle ARP frame types if ipconfigUSE_IPv4 != 0 */
965 #if ( ipconfigUSE_IPv4 != 0 )
966 {
967 /* MISRA Ref 11.3.1 [Misaligned access] */
968 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
969 /* coverity[misra_c_2012_rule_11_3_violation] */
970 const ARPPacket_t * pxARPFrame = ( const ARPPacket_t * ) pucEthernetBuffer;
971
972 if( pxARPFrame->xARPHeader.usOperation == ( uint16_t ) ipARP_REQUEST )
973 {
974 ( void ) memcpy( xIPAddressFrom.xIP_IPv6.ucBytes, pxPacket->xARPPacket.xARPHeader.ucSenderProtocolAddress, sizeof( uint32_t ) );
975 xIPAddressTo.ulIP_IPv4 = pxPacket->xARPPacket.xARPHeader.ulTargetProtocolAddress;
976 }
977 else if( pxARPFrame->xARPHeader.usOperation == ( uint16_t ) ipARP_REPLY )
978 {
979 ( void ) memcpy( xIPAddressTo.xIP_IPv6.ucBytes, pxPacket->xARPPacket.xARPHeader.ucSenderProtocolAddress, sizeof( uint32_t ) );
980 xIPAddressFrom.ulIP_IPv4 = pxPacket->xARPPacket.xARPHeader.ulTargetProtocolAddress;
981 }
982 else
983 {
984 /* do nothing, coverity happy */
985 }
986
987 FreeRTOS_debug_printf( ( "pxEasyFit: ARP %xip -> %xip\n", ( unsigned ) FreeRTOS_ntohl( xIPAddressFrom.ulIP_IPv4 ), ( unsigned ) FreeRTOS_ntohl( xIPAddressTo.ulIP_IPv4 ) ) );
988 }
989 xDoProcessPacket = pdTRUE;
990 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
991
992 break;
993
994 case ipIPv4_FRAME_TYPE:
995
996 /* Handle IPv4 frame types if ipconfigUSE_IPv4 != 0 */
997 #if ( ipconfigUSE_IPv4 != 0 )
998 xIPAddressFrom.ulIP_IPv4 = pxPacket->xUDPPacket.xIPHeader.ulSourceIPAddress;
999 xIPAddressTo.ulIP_IPv4 = pxPacket->xUDPPacket.xIPHeader.ulDestinationIPAddress;
1000 xDoProcessPacket = pdTRUE;
1001 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1002
1003 break;
1004
1005 default:
1006 #if ( ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES == 1 )
1007 /* Custom frame types, match by MAC address only. */
1008 xDoProcessPacket = pdTRUE;
1009 #endif
1010
1011 break;
1012 }
1013
1014 if( xDoProcessPacket == pdTRUE )
1015 {
1016 ( void ) memcpy( xMACAddress.ucBytes, pxPacket->xUDPPacket.xEthernetHeader.xDestinationAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES );
1017 pxEndPoint = pxEasyFit( pxNetworkInterface,
1018 usFrameType,
1019 &xIPAddressFrom,
1020 &xIPAddressTo,
1021 &xMACAddress );
1022 }
1023 }
1024 return pxEndPoint;
1025 }
1026 /*-----------------------------------------------------------*/
1027
1028 /**
1029 * @brief Find an end-point that defines a gateway of a certain type ( IPv4 or IPv6 ).
1030 *
1031 * @param[in] xIPType The type of Gateway to look for ( ipTYPE_IPv4 or ipTYPE_IPv6 ).
1032 *
1033 * @return The end-point that will lead to the gateway, or NULL when no gateway was found.
1034 */
FreeRTOS_FindGateWay(BaseType_t xIPType)1035 NetworkEndPoint_t * FreeRTOS_FindGateWay( BaseType_t xIPType )
1036 {
1037 NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
1038
1039 while( pxEndPoint != NULL )
1040 {
1041 #if ( ipconfigUSE_IPv6 == 0 )
1042 ( void ) xIPType;
1043
1044 if( pxEndPoint->ipv4_settings.ulGatewayAddress != 0U ) /* access to ipv4_settings is checked. */
1045 {
1046 break;
1047 }
1048 #else
1049 if( ( xIPType == ( BaseType_t ) ipTYPE_IPv6 ) && ( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) )
1050 {
1051 /* Check if the IP-address is non-zero. */
1052 if( memcmp( FreeRTOS_in6addr_any.ucBytes, pxEndPoint->ipv6_settings.xGatewayAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ) != 0 )
1053 {
1054 break;
1055 }
1056 }
1057 else
1058 if( ( xIPType == ( BaseType_t ) ipTYPE_IPv4 ) && ( pxEndPoint->bits.bIPv6 == pdFALSE_UNSIGNED ) )
1059 {
1060 if( pxEndPoint->ipv4_settings.ulGatewayAddress != 0U )
1061 {
1062 break;
1063 }
1064 }
1065 else
1066 {
1067 /* This end-point is not the right IP-type. */
1068 }
1069 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1070 pxEndPoint = pxEndPoint->pxNext;
1071 }
1072
1073 return pxEndPoint;
1074 }
1075 /*-----------------------------------------------------------*/
1076
1077 #if ( ipconfigUSE_IPv6 != 0 )
1078
1079 /* Get the first end-point belonging to a given interface.
1080 * When pxInterface is NULL, the very first end-point will be returned. */
1081
1082 /**
1083 * @brief Find the first IPv6 end-point.
1084 *
1085 * @param[in] pxInterface Either NULL ( don't care ), or a specific interface.
1086 *
1087 * @return The end-point found, or NULL when there are no end-points at all.
1088 */
FreeRTOS_FirstEndPoint_IPv6(const NetworkInterface_t * pxInterface)1089 NetworkEndPoint_t * FreeRTOS_FirstEndPoint_IPv6( const NetworkInterface_t * pxInterface )
1090 {
1091 NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
1092
1093 while( pxEndPoint != NULL )
1094 {
1095 if( ( ( pxInterface == NULL ) || ( pxEndPoint->pxNetworkInterface == pxInterface ) ) && ( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) )
1096 {
1097 break;
1098 }
1099
1100 pxEndPoint = pxEndPoint->pxNext;
1101 }
1102
1103 return pxEndPoint;
1104 }
1105 #endif /* ipconfigUSE_IPv6 */
1106 /*-----------------------------------------------------------*/
1107
1108 /**
1109 * @brief Get the end-point that is bound to a socket.
1110 *
1111 * @param[in] xSocket The socket of interest.
1112 *
1113 * @return An end-point or NULL in case the socket is not bound to an end-point.
1114 */
pxGetSocketEndpoint(ConstSocket_t xSocket)1115 NetworkEndPoint_t * pxGetSocketEndpoint( ConstSocket_t xSocket )
1116 {
1117 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
1118 NetworkEndPoint_t * pxResult;
1119
1120 if( pxSocket != NULL )
1121 {
1122 pxResult = pxSocket->pxEndPoint;
1123 }
1124 else
1125 {
1126 pxResult = NULL;
1127 }
1128
1129 return pxResult;
1130 }
1131 /*-----------------------------------------------------------*/
1132
1133 /**
1134 * @brief Assign an end-point to a socket.
1135 *
1136 * @param[in] xSocket The socket to which an end-point will be assigned.
1137 * @param[in] pxEndPoint The end-point to be assigned.
1138 */
vSetSocketEndpoint(Socket_t xSocket,NetworkEndPoint_t * pxEndPoint)1139 void vSetSocketEndpoint( Socket_t xSocket,
1140 NetworkEndPoint_t * pxEndPoint )
1141 {
1142 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
1143
1144 if( pxSocket != NULL )
1145 {
1146 pxSocket->pxEndPoint = pxEndPoint;
1147 }
1148 }
1149 /*-----------------------------------------------------------*/
1150
1151 #else /* ( ipconfigCOMPATIBLE_WITH_SINGLE == 0 ) */
1152
1153 /* Here below the most important function of FreeRTOS_Routing.c in a short
1154 * version: it is assumed that only 1 interface and 1 end-point will be created.
1155 * The reason for this is downward compatibility with the earlier release of
1156 * FreeRTOS+TCP, which had a single network interface only. */
1157
1158 /**
1159 * @brief Add a network interface to the list of interfaces. Check if this will be
1160 * first and only interface ( ipconfigCOMPATIBLE_WITH_SINGLE = 1 ).
1161 *
1162 * @param[in] pxInterface The address of the new interface.
1163 *
1164 * @return The value of the parameter 'pxInterface'.
1165 */
FreeRTOS_AddNetworkInterface(NetworkInterface_t * pxInterface)1166 NetworkInterface_t * FreeRTOS_AddNetworkInterface( NetworkInterface_t * pxInterface )
1167 {
1168 configASSERT( pxNetworkInterfaces == NULL );
1169 pxNetworkInterfaces = pxInterface;
1170 return pxInterface;
1171 }
1172 /*-----------------------------------------------------------*/
1173
1174 /**
1175 * @brief And an end-point to an interface. Note that when ipconfigCOMPATIBLE_WITH_SINGLE
1176 * is defined, only one interface is allowed, which will have one end-point only.
1177 *
1178 * @param[in] pxInterface The interface to which the end-point is assigned.
1179 * @param[in] pxEndPoint The end-point to be assigned to the above interface.
1180 *
1181 * @return The value of the parameter 'pxEndPoint'.
1182 */
FreeRTOS_AddEndPoint(NetworkInterface_t * pxInterface,NetworkEndPoint_t * pxEndPoint)1183 static NetworkEndPoint_t * FreeRTOS_AddEndPoint( NetworkInterface_t * pxInterface,
1184 NetworkEndPoint_t * pxEndPoint )
1185 {
1186 /* This code is in backward-compatibility mode.
1187 * Only one end-point is allowed, make sure that
1188 * no end-point has been defined yet. */
1189 configASSERT( pxNetworkEndPoints == NULL );
1190
1191 /* This end point will go to the end of the list, so there is no pxNext
1192 * yet. */
1193 pxEndPoint->pxNext = NULL;
1194
1195 /* Double link between the NetworkInterface_t that is using the addressing
1196 * defined by this NetworkEndPoint_t structure. */
1197 pxEndPoint->pxNetworkInterface = pxInterface;
1198
1199 pxInterface->pxEndPoint = pxEndPoint;
1200
1201 /* No other end points are defined yet - so this is the first in the
1202 * list. */
1203 pxNetworkEndPoints = pxEndPoint;
1204
1205 return pxEndPoint;
1206 }
1207 /*-----------------------------------------------------------*/
1208
1209 /**
1210 * @brief Find the end-point which has a given IPv4 address.
1211 *
1212 * @param[in] ulIPAddress The IP-address of interest, or 0 if any IPv4 end-point may be returned.
1213 *
1214 * @return The end-point found or NULL.
1215 */
FreeRTOS_FindEndPointOnIP_IPv4(uint32_t ulIPAddress,uint32_t ulWhere)1216 NetworkEndPoint_t * FreeRTOS_FindEndPointOnIP_IPv4( uint32_t ulIPAddress,
1217 uint32_t ulWhere )
1218 {
1219 NetworkEndPoint_t * pxResult = NULL;
1220
1221 ( void ) ulIPAddress;
1222 ( void ) ulWhere;
1223
1224 if( ( ulIPAddress == 0U ) || ( pxNetworkEndPoints->ipv4_settings.ulIPAddress == ulIPAddress ) )
1225 {
1226 pxResult = pxNetworkEndPoints;
1227 }
1228
1229 return pxResult;
1230 }
1231 /*-----------------------------------------------------------*/
1232
1233 /**
1234 * @brief Find the end-point that has a certain MAC-address.
1235 *
1236 * @param[in] pxMACAddress The Ethernet packet.
1237 * @param[in] pxInterface The interface on which the packet was received, or NULL when unknown.
1238 *
1239 * @return The end-point that has the given MAC-address.
1240 */
FreeRTOS_FindEndPointOnMAC(const MACAddress_t * pxMACAddress,const NetworkInterface_t * pxInterface)1241 NetworkEndPoint_t * FreeRTOS_FindEndPointOnMAC( const MACAddress_t * pxMACAddress,
1242 const NetworkInterface_t * pxInterface )
1243 {
1244 NetworkEndPoint_t * pxResult = NULL;
1245
1246 ( void ) pxMACAddress;
1247 ( void ) pxInterface;
1248
1249 if( ( pxMACAddress != NULL ) && ( memcmp( pxNetworkEndPoints->xMACAddress.ucBytes, pxMACAddress->ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) )
1250 {
1251 pxResult = pxNetworkEndPoints;
1252 }
1253
1254 return pxResult;
1255 }
1256 /*-----------------------------------------------------------*/
1257
1258 /**
1259 * @brief Find an end-point that handles a given IPv4-address.
1260 *
1261 * @param[in] ulIPAddress The IP-address for which an end-point is looked-up.
1262 *
1263 * @return An end-point that has the same network mask as the given IP-address.
1264 */
FreeRTOS_FindEndPointOnNetMask(uint32_t ulIPAddress,uint32_t ulWhere)1265 NetworkEndPoint_t * FreeRTOS_FindEndPointOnNetMask( uint32_t ulIPAddress,
1266 uint32_t ulWhere )
1267 {
1268 return FreeRTOS_InterfaceEndPointOnNetMask( NULL, ulIPAddress, ulWhere );
1269 }
1270 /*-----------------------------------------------------------*/
1271
1272 /**
1273 * @brief Find an end-point that defines a gateway of a certain type ( IPv4 or IPv6 ).
1274 *
1275 * @param[in] xIPType The type of Gateway to look for ( ipTYPE_IPv4 or ipTYPE_IPv6 ).
1276 *
1277 * @return The end-point that will lead to the gateway, or NULL when no gateway was found.
1278 */
FreeRTOS_FindGateWay(BaseType_t xIPType)1279 NetworkEndPoint_t * FreeRTOS_FindGateWay( BaseType_t xIPType )
1280 {
1281 NetworkEndPoint_t * pxReturn = NULL;
1282
1283 ( void ) xIPType;
1284
1285 if( pxNetworkEndPoints != NULL )
1286 {
1287 if( pxNetworkEndPoints->ipv4_settings.ulGatewayAddress != 0U )
1288 {
1289 pxReturn = pxNetworkEndPoints;
1290 }
1291 }
1292
1293 return pxReturn;
1294 }
1295 /*-----------------------------------------------------------*/
1296
1297 /**
1298 * @brief Find the first end-point bound to a given interface.
1299 *
1300 * @param[in] pxInterface The interface whose first end-point will be returned.
1301 *
1302 * @return The first end-point that is found to the interface, or NULL when the
1303 * interface doesn't have any end-point yet.
1304 */
FreeRTOS_FirstEndPoint(const NetworkInterface_t * pxInterface)1305 NetworkEndPoint_t * FreeRTOS_FirstEndPoint( const NetworkInterface_t * pxInterface )
1306 {
1307 ( void ) pxInterface;
1308
1309 /* ipconfigCOMPATIBLE_WITH_SINGLE is defined and this is the simplified version:
1310 * only one interface and one end-point is defined. */
1311 return pxNetworkEndPoints;
1312 }
1313 /*-----------------------------------------------------------*/
1314
1315 /**
1316 * @brief Get the first Network Interface, or NULL if none has been added.
1317 *
1318 * @return The first interface, or NULL if none has been added
1319 */
FreeRTOS_FirstNetworkInterface(void)1320 NetworkInterface_t * FreeRTOS_FirstNetworkInterface( void )
1321 {
1322 /* ipconfigCOMPATIBLE_WITH_SINGLE is defined: only one interface and
1323 * one end-point is defined. */
1324 return pxNetworkInterfaces;
1325 }
1326 /*-----------------------------------------------------------*/
1327
1328 /**
1329 * @brief Find an end-point that handles a given IPv4-address.
1330 *
1331 * @param[in] pxInterface Ignored in this simplified version.
1332 * @param[in] ulIPAddress The IP-address for which an end-point is looked-up.
1333 *
1334 * @return An end-point that has the same network mask as the given IP-address.
1335 */
FreeRTOS_InterfaceEndPointOnNetMask(const NetworkInterface_t * pxInterface,uint32_t ulIPAddress,uint32_t ulWhere)1336 NetworkEndPoint_t * FreeRTOS_InterfaceEndPointOnNetMask( const NetworkInterface_t * pxInterface,
1337 uint32_t ulIPAddress,
1338 uint32_t ulWhere )
1339 {
1340 NetworkEndPoint_t * pxResult = NULL;
1341
1342 ( void ) pxInterface;
1343 ( void ) ulWhere;
1344
1345 if( ( ( ulIPAddress ^ pxNetworkEndPoints->ipv4_settings.ulIPAddress ) & pxNetworkEndPoints->ipv4_settings.ulNetMask ) == 0U )
1346 {
1347 pxResult = pxNetworkEndPoints;
1348 }
1349
1350 return pxResult;
1351 }
1352 /*-----------------------------------------------------------*/
1353
1354 /**
1355 * @brief Find out the best matching end-point given an incoming Ethernet packet.
1356 *
1357 * @param[in] pxNetworkInterface The interface on which the packet was received.
1358 * @param[in] pucEthernetBuffer The Ethernet packet that was just received.
1359 *
1360 * @return The end-point that should handle the incoming Ethernet packet.
1361 */
FreeRTOS_MatchingEndpoint(const NetworkInterface_t * pxNetworkInterface,const uint8_t * pucEthernetBuffer)1362 NetworkEndPoint_t * FreeRTOS_MatchingEndpoint( const NetworkInterface_t * pxNetworkInterface,
1363 const uint8_t * pucEthernetBuffer )
1364 {
1365 ( void ) pxNetworkInterface;
1366 ( void ) pucEthernetBuffer;
1367
1368 /* ipconfigCOMPATIBLE_WITH_SINGLE is defined: only one interface and
1369 * one end-point is defined. */
1370 return pxNetworkEndPoints;
1371 }
1372 /*-----------------------------------------------------------*/
1373
1374 /**
1375 * @brief Get the next end-point. As this is the simplified version, it will always
1376 * return NULL.
1377 *
1378 * @param[in] pxInterface An interface of interest, or NULL when iterating through all
1379 * end-points.
1380 * @param[in] pxEndPoint This is the current end-point.
1381 *
1382 * @return NULL because ipconfigCOMPATIBLE_WITH_SINGLE is defined.
1383 */
FreeRTOS_NextEndPoint(const NetworkInterface_t * pxInterface,NetworkEndPoint_t * pxEndPoint)1384 NetworkEndPoint_t * FreeRTOS_NextEndPoint( const NetworkInterface_t * pxInterface,
1385 NetworkEndPoint_t * pxEndPoint )
1386 {
1387 ( void ) pxInterface;
1388 ( void ) pxEndPoint;
1389
1390 return NULL;
1391 }
1392 /*-----------------------------------------------------------*/
1393
1394 /**
1395 * @brief Get the next interface.
1396 *
1397 * @return NULL because ipconfigCOMPATIBLE_WITH_SINGLE is defined.
1398 */
FreeRTOS_NextNetworkInterface(const NetworkInterface_t * pxInterface)1399 NetworkInterface_t * FreeRTOS_NextNetworkInterface( const NetworkInterface_t * pxInterface )
1400 {
1401 ( void ) pxInterface;
1402
1403 return NULL;
1404 }
1405 /*-----------------------------------------------------------*/
1406
1407 #if ( ipconfigUSE_IPv6 != 0 )
FreeRTOS_FindEndPointOnIP_IPv6(const IPv6_Address_t * pxIPAddress)1408 NetworkEndPoint_t * FreeRTOS_FindEndPointOnIP_IPv6( const IPv6_Address_t * pxIPAddress )
1409 {
1410 ( void ) pxIPAddress;
1411 return pxNetworkEndPoints;
1412 }
1413 #endif
1414 /*-----------------------------------------------------------*/
1415
1416 #if ( ipconfigUSE_IPv6 != 0 )
FreeRTOS_FindEndPointOnNetMask_IPv6(const IPv6_Address_t * pxIPv6Address)1417 NetworkEndPoint_t * FreeRTOS_FindEndPointOnNetMask_IPv6( const IPv6_Address_t * pxIPv6Address )
1418 {
1419 ( void ) pxIPv6Address;
1420 return pxNetworkEndPoints;
1421 }
1422
1423 #endif
1424 /*-----------------------------------------------------------*/
1425
1426 #if ( ipconfigUSE_IPv6 != 0 )
FreeRTOS_FirstEndPoint_IPv6(const NetworkInterface_t * pxInterface)1427 NetworkEndPoint_t * FreeRTOS_FirstEndPoint_IPv6( const NetworkInterface_t * pxInterface )
1428 {
1429 ( void ) pxInterface;
1430 return pxNetworkEndPoints;
1431 }
1432
1433 #endif
1434 /*-----------------------------------------------------------*/
1435
1436 #endif /* ( ipconfigCOMPATIBLE_WITH_SINGLE == 0 ) */
1437
1438 /**
1439 * @brief Returns the IP type of the given IPv6 address.
1440 *
1441 * @param[in] pxAddress The IPv6 address whose type needs to be returned.
1442 * @returns The IP type of the given address.
1443 */
xIPv6_GetIPType(const IPv6_Address_t * pxAddress)1444 IPv6_Type_t xIPv6_GetIPType( const IPv6_Address_t * pxAddress )
1445 {
1446 IPv6_Type_t eResult = eIPv6_Unknown;
1447 BaseType_t xIndex;
1448 static const struct xIPv6_Couple xIPCouples[] =
1449 {
1450 /* IP-type Mask Value */
1451 { eIPv6_Global, 0xE000U, 0x2000U }, /* 001 */
1452 { eIPv6_LinkLocal, 0xFFC0U, 0xFE80U }, /* 1111 1110 10 */
1453 { eIPv6_SiteLocal, 0xFFC0U, 0xFEC0U }, /* 1111 1110 11 */
1454 { eIPv6_Multicast, 0xFF00U, 0xFF00U }, /* 1111 1111 */
1455 };
1456
1457 if( pxAddress != NULL )
1458 {
1459 for( xIndex = 0; xIndex < ARRAY_SIZE_X( xIPCouples ); xIndex++ )
1460 {
1461 uint16_t usAddress =
1462 ( uint16_t ) ( ( ( ( uint16_t ) pxAddress->ucBytes[ 0 ] ) << 8 ) |
1463 ( ( uint16_t ) pxAddress->ucBytes[ 1 ] ) );
1464
1465 if( ( usAddress & xIPCouples[ xIndex ].usMask ) == xIPCouples[ xIndex ].usExpected )
1466 {
1467 eResult = xIPCouples[ xIndex ].eType;
1468 break;
1469 }
1470 }
1471 }
1472
1473 return eResult;
1474 }
1475 /*-----------------------------------------------------------*/
1476
1477 /**
1478 * @brief Returns the string representation of the IP address of the end point.
1479 *
1480 * @param[in] pxEndPoint End point for which IP address needs to be returned.
1481 * @param[in] pcBuffer A char buffer of required size to which the string will be written.
1482 * @param[in] uxSize Size of the char buffer - pcBuffer.
1483 *
1484 * @returns The pointer to the char buffer that contains the string representation of the end point IP address.
1485 * The string will be "NULL" if the end point pointer is NULL.
1486 */
pcEndpointName(const NetworkEndPoint_t * pxEndPoint,char * pcBuffer,size_t uxSize)1487 const char * pcEndpointName( const NetworkEndPoint_t * pxEndPoint,
1488 char * pcBuffer,
1489 size_t uxSize )
1490 {
1491 if( pxEndPoint == NULL )
1492 {
1493 /* MISRA Ref 21.6.1 [snprintf and logging] */
1494 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-216 */
1495 /* coverity[misra_c_2012_rule_21_6_violation] */
1496 ( void ) snprintf( pcBuffer, uxSize, "NULL" );
1497 }
1498 else
1499 {
1500 switch( pxEndPoint->bits.bIPv6 ) /* LCOV_EXCL_BR_LINE */
1501 {
1502 #if ( ipconfigUSE_IPv4 != 0 )
1503 case pdFALSE_UNSIGNED:
1504 ( void ) FreeRTOS_inet_ntop( FREERTOS_AF_INET4,
1505 ( const void * ) &( pxEndPoint->ipv4_settings.ulIPAddress ),
1506 pcBuffer,
1507 ( socklen_t ) uxSize );
1508 break;
1509 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1510
1511 #if ( ipconfigUSE_IPv6 != 0 )
1512 case pdTRUE_UNSIGNED:
1513 ( void ) FreeRTOS_inet_ntop( FREERTOS_AF_INET6,
1514 pxEndPoint->ipv6_settings.xIPAddress.ucBytes,
1515 pcBuffer,
1516 ( socklen_t ) uxSize );
1517 break;
1518 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1519
1520 default:
1521 /* MISRA 16.4 Compliance */
1522 /* MISRA Ref 21.6.1 [snprintf and logging] */
1523 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-216 */
1524 /* coverity[misra_c_2012_rule_21_6_violation] */
1525 ( void ) snprintf( pcBuffer, uxSize, "NULL" );
1526 break;
1527 }
1528 }
1529
1530 return pcBuffer;
1531 }
1532 /*-----------------------------------------------------------*/
1533