FreeRTOS_ARP.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. /*
  2. * FreeRTOS+TCP V2.3.2 LTS Patch 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. * @file FreeRTOS_ARP.c
  27. * @brief Implements the Address Resolution Protocol for the FreeRTOS+TCP network stack.
  28. */
  29. /* Standard includes. */
  30. #include <stdint.h>
  31. #include <stdio.h>
  32. /* FreeRTOS includes. */
  33. #include "FreeRTOS.h"
  34. #include "task.h"
  35. #include "queue.h"
  36. #include "semphr.h"
  37. /* FreeRTOS+TCP includes. */
  38. #include "FreeRTOS_IP.h"
  39. #include "FreeRTOS_Sockets.h"
  40. #include "FreeRTOS_IP_Private.h"
  41. #include "FreeRTOS_ARP.h"
  42. #include "FreeRTOS_UDP_IP.h"
  43. #include "FreeRTOS_DHCP.h"
  44. #if ( ipconfigUSE_LLMNR == 1 )
  45. #include "FreeRTOS_DNS.h"
  46. #endif /* ipconfigUSE_LLMNR */
  47. #include "NetworkBufferManagement.h"
  48. #include "NetworkInterface.h"
  49. /** @brief When the age of an entry in the ARP table reaches this value (it counts down
  50. * to zero, so this is an old entry) an ARP request will be sent to see if the
  51. * entry is still valid and can therefore be refreshed. */
  52. #define arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST ( 3 )
  53. /** @brief The time between gratuitous ARPs. */
  54. #ifndef arpGRATUITOUS_ARP_PERIOD
  55. #define arpGRATUITOUS_ARP_PERIOD ( pdMS_TO_TICKS( 20000U ) )
  56. #endif
  57. /*-----------------------------------------------------------*/
  58. /*
  59. * Lookup an MAC address in the ARP cache from the IP address.
  60. */
  61. static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup,
  62. MACAddress_t * const pxMACAddress );
  63. /*-----------------------------------------------------------*/
  64. /** @brief The ARP cache. */
  65. _static ARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];
  66. /** @brief The time at which the last gratuitous ARP was sent. Gratuitous ARPs are used
  67. * to ensure ARP tables are up to date and to detect IP address conflicts. */
  68. static TickType_t xLastGratuitousARPTime = ( TickType_t ) 0;
  69. /*
  70. * IP-clash detection is currently only used internally. When DHCP doesn't respond, the
  71. * driver can try out a random LinkLayer IP address (169.254.x.x). It will send out a
  72. * gratuitous ARP message and, after a period of time, check the variables here below:
  73. */
  74. #if ( ipconfigARP_USE_CLASH_DETECTION != 0 )
  75. /* Becomes non-zero if another device responded to a gratuitous ARP message. */
  76. BaseType_t xARPHadIPClash;
  77. /* MAC-address of the other device containing the same IP-address. */
  78. MACAddress_t xARPClashMacAddress;
  79. #endif /* ipconfigARP_USE_CLASH_DETECTION */
  80. /*-----------------------------------------------------------*/
  81. /**
  82. * @brief Process the ARP packets.
  83. *
  84. * @param[in] pxARPFrame: The ARP Frame (the ARP packet).
  85. *
  86. * @return An enum which says whether to return the frame or to release it.
  87. */
  88. eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame )
  89. {
  90. eFrameProcessingResult_t eReturn = eReleaseBuffer;
  91. ARPHeader_t * pxARPHeader;
  92. uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress;
  93. /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
  94. const void * pvCopySource;
  95. void * pvCopyDest;
  96. pxARPHeader = &( pxARPFrame->xARPHeader );
  97. /* The field ulSenderProtocolAddress is badly aligned, copy byte-by-byte. */
  98. /*
  99. * Use helper variables for memcpy() to remain
  100. * compliant with MISRA Rule 21.15. These should be
  101. * optimized away.
  102. */
  103. pvCopySource = pxARPHeader->ucSenderProtocolAddress;
  104. pvCopyDest = &ulSenderProtocolAddress;
  105. ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( ulSenderProtocolAddress ) );
  106. /* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */
  107. ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress;
  108. traceARP_PACKET_RECEIVED();
  109. /* Don't do anything if the local IP address is zero because
  110. * that means a DHCP request has not completed. */
  111. if( *ipLOCAL_IP_ADDRESS_POINTER != 0UL )
  112. {
  113. switch( pxARPHeader->usOperation )
  114. {
  115. case ipARP_REQUEST://printf("%s:%d dst:%08x src:%08x\r\n", __func__, __LINE__, ulTargetProtocolAddress, *ipLOCAL_IP_ADDRESS_POINTER);
  116. /* The packet contained an ARP request. Was it for the IP
  117. * address of the node running this code? */
  118. if( ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
  119. {
  120. iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress );
  121. /* The request is for the address of this node. Add the
  122. * entry into the ARP cache, or refresh the entry if it
  123. * already exists. */
  124. vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
  125. /* Generate a reply payload in the same buffer. */
  126. pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY;
  127. if( ulTargetProtocolAddress == ulSenderProtocolAddress )
  128. {
  129. /* A double IP address is detected! */
  130. /* Give the sources MAC address the value of the broadcast address, will be swapped later */
  131. /*
  132. * Use helper variables for memcpy() to remain
  133. * compliant with MISRA Rule 21.15. These should be
  134. * optimized away.
  135. */
  136. pvCopySource = xBroadcastMACAddress.ucBytes;
  137. pvCopyDest = pxARPFrame->xEthernetHeader.xSourceAddress.ucBytes;
  138. ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xBroadcastMACAddress ) );
  139. ( void ) memset( pxARPHeader->xTargetHardwareAddress.ucBytes, 0, sizeof( MACAddress_t ) );
  140. pxARPHeader->ulTargetProtocolAddress = 0UL;
  141. }
  142. else
  143. {
  144. /*
  145. * Use helper variables for memcpy() to remain
  146. * compliant with MISRA Rule 21.15. These should be
  147. * optimized away.
  148. */
  149. pvCopySource = pxARPHeader->xSenderHardwareAddress.ucBytes;
  150. pvCopyDest = pxARPHeader->xTargetHardwareAddress.ucBytes;
  151. ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( MACAddress_t ) );
  152. pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress;
  153. }
  154. /*
  155. * Use helper variables for memcpy() to remain
  156. * compliant with MISRA Rule 21.15. These should be
  157. * optimized away.
  158. */
  159. pvCopySource = ipLOCAL_MAC_ADDRESS;
  160. pvCopyDest = pxARPHeader->xSenderHardwareAddress.ucBytes;
  161. ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( MACAddress_t ) );
  162. pvCopySource = ipLOCAL_IP_ADDRESS_POINTER;
  163. pvCopyDest = pxARPHeader->ucSenderProtocolAddress;
  164. ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxARPHeader->ucSenderProtocolAddress ) );
  165. eReturn = eReturnEthernetFrame;
  166. }
  167. break;
  168. case ipARP_REPLY:printf("%s:%d \r\n", __func__, __LINE__);
  169. iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress );
  170. vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
  171. /* Process received ARP frame to see if there is a clash. */
  172. #if ( ipconfigARP_USE_CLASH_DETECTION != 0 )
  173. {
  174. if( ulSenderProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
  175. {
  176. xARPHadIPClash = pdTRUE;
  177. /* Remember the MAC-address of the other device which has the same IP-address. */
  178. ( void ) memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) );
  179. }
  180. }
  181. #endif /* ipconfigARP_USE_CLASH_DETECTION */
  182. break;
  183. default:
  184. /* Invalid. */
  185. break;
  186. }
  187. }
  188. return eReturn;
  189. }
  190. /*-----------------------------------------------------------*/
  191. #if ( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )
  192. /**
  193. * @brief Remove an ARP cache entry that matches with .pxMACAddress.
  194. *
  195. * @param[in] pxMACAddress: Pointer to the MAC address whose entry shall
  196. * be removed..
  197. * @return When the entry was found and remove: the IP-address, otherwise zero.
  198. */
  199. uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress )
  200. {
  201. BaseType_t x;
  202. uint32_t lResult = 0;
  203. configASSERT( pxMACAddress != NULL );
  204. /* For each entry in the ARP cache table. */
  205. for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
  206. {
  207. if( ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )
  208. {
  209. lResult = xARPCache[ x ].ulIPAddress;
  210. ( void ) memset( &xARPCache[ x ], 0, sizeof( xARPCache[ x ] ) );
  211. break;
  212. }
  213. }
  214. return lResult;
  215. }
  216. #endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */
  217. /*-----------------------------------------------------------*/
  218. /**
  219. * @brief Add/update the ARP cache entry MAC-address to IP-address mapping.
  220. *
  221. * @param[in] pxMACAddress: Pointer to the MAC address whose mapping is being
  222. * updated.
  223. * @param[in] ulIPAddress: 32-bit representation of the IP-address whose mapping
  224. * is being updated.
  225. */
  226. void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress,
  227. const uint32_t ulIPAddress )
  228. {
  229. BaseType_t x = 0;
  230. BaseType_t xIpEntry = -1;
  231. BaseType_t xMacEntry = -1;
  232. BaseType_t xUseEntry = 0;
  233. uint8_t ucMinAgeFound = 0U;
  234. #if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 0 )
  235. /* Only process the IP address if it is on the local network.
  236. * Unless: when '*ipLOCAL_IP_ADDRESS_POINTER' equals zero, the IP-address
  237. * and netmask are still unknown. */
  238. if( ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) ) ||
  239. ( *ipLOCAL_IP_ADDRESS_POINTER == 0UL ) )
  240. #else
  241. /* If ipconfigARP_STORES_REMOTE_ADDRESSES is non-zero, IP addresses with
  242. * a different netmask will also be stored. After when replying to a UDP
  243. * message from a different netmask, the IP address can be looped up and a
  244. * reply sent. This option is useful for systems with multiple gateways,
  245. * the reply will surely arrive. If ipconfigARP_STORES_REMOTE_ADDRESSES is
  246. * zero the the gateway address is the only option. */
  247. if( pdTRUE )
  248. #endif
  249. {
  250. /* Start with the maximum possible number. */
  251. ucMinAgeFound--;
  252. /* For each entry in the ARP cache table. */
  253. for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
  254. {
  255. BaseType_t xMatchingMAC;
  256. if( pxMACAddress != NULL )
  257. {
  258. if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 )
  259. {
  260. xMatchingMAC = pdTRUE;
  261. }
  262. else
  263. {
  264. xMatchingMAC = pdFALSE;
  265. }
  266. }
  267. else
  268. {
  269. xMatchingMAC = pdFALSE;
  270. }
  271. /* Does this line in the cache table hold an entry for the IP
  272. * address being queried? */
  273. if( xARPCache[ x ].ulIPAddress == ulIPAddress )
  274. {
  275. if( pxMACAddress == NULL )
  276. {
  277. /* In case the parameter pxMACAddress is NULL, an entry will be reserved to
  278. * indicate that there is an outstanding ARP request, This entry will have
  279. * "ucValid == pdFALSE". */
  280. xIpEntry = x;
  281. break;
  282. }
  283. /* See if the MAC-address also matches. */
  284. if( xMatchingMAC != pdFALSE )
  285. {
  286. /* This function will be called for each received packet
  287. * As this is by far the most common path the coding standard
  288. * is relaxed in this case and a return is permitted as an
  289. * optimisation. */
  290. xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
  291. xARPCache[ x ].ucValid = ( uint8_t ) pdTRUE;
  292. return;
  293. }
  294. /* Found an entry containing ulIPAddress, but the MAC address
  295. * doesn't match. Might be an entry with ucValid=pdFALSE, waiting
  296. * for an ARP reply. Still want to see if there is match with the
  297. * given MAC address.ucBytes. If found, either of the two entries
  298. * must be cleared. */
  299. xIpEntry = x;
  300. }
  301. else if( xMatchingMAC != pdFALSE )
  302. {
  303. /* Found an entry with the given MAC-address, but the IP-address
  304. * is different. Continue looping to find a possible match with
  305. * ulIPAddress. */
  306. #if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 )
  307. /* If ARP stores the MAC address of IP addresses outside the
  308. * network, than the MAC address of the gateway should not be
  309. * overwritten. */
  310. BaseType_t bIsLocal[ 2 ];
  311. bIsLocal[ 0 ] = ( ( xARPCache[ x ].ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
  312. bIsLocal[ 1 ] = ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
  313. if( bIsLocal[ 0 ] == bIsLocal[ 1 ] )
  314. {
  315. xMacEntry = x;
  316. }
  317. #else /* if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 ) */
  318. xMacEntry = x;
  319. #endif /* if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 ) */
  320. }
  321. /* _HT_
  322. * Shouldn't we test for xARPCache[ x ].ucValid == pdFALSE here ? */
  323. else if( xARPCache[ x ].ucAge < ucMinAgeFound )
  324. {
  325. /* As the table is traversed, remember the table row that
  326. * contains the oldest entry (the lowest age count, as ages are
  327. * decremented to zero) so the row can be re-used if this function
  328. * needs to add an entry that does not already exist. */
  329. ucMinAgeFound = xARPCache[ x ].ucAge;
  330. xUseEntry = x;
  331. }
  332. else
  333. {
  334. /* Nothing happens to this cache entry for now. */
  335. }
  336. }
  337. if( xMacEntry >= 0 )
  338. {
  339. xUseEntry = xMacEntry;
  340. if( xIpEntry >= 0 )
  341. {
  342. /* Both the MAC address as well as the IP address were found in
  343. * different locations: clear the entry which matches the
  344. * IP-address */
  345. ( void ) memset( &( xARPCache[ xIpEntry ] ), 0, sizeof( ARPCacheRow_t ) );
  346. }
  347. }
  348. else if( xIpEntry >= 0 )
  349. {
  350. /* An entry containing the IP-address was found, but it had a different MAC address */
  351. xUseEntry = xIpEntry;
  352. }
  353. else
  354. {
  355. /* No matching entry found. */
  356. }
  357. /* If the entry was not found, we use the oldest entry and set the IPaddress */
  358. xARPCache[ xUseEntry ].ulIPAddress = ulIPAddress;
  359. if( pxMACAddress != NULL )
  360. {
  361. ( void ) memcpy( xARPCache[ xUseEntry ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) );
  362. iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, ( *pxMACAddress ) );
  363. /* And this entry does not need immediate attention */
  364. xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
  365. xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdTRUE;
  366. }
  367. else if( xIpEntry < 0 )
  368. {
  369. xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_RETRANSMISSIONS;
  370. xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdFALSE;
  371. }
  372. else
  373. {
  374. /* Nothing will be stored. */
  375. }
  376. }
  377. }
  378. /*-----------------------------------------------------------*/
  379. #if ( ipconfigUSE_ARP_REVERSED_LOOKUP == 1 )
  380. /**
  381. * @brief Retrieve an entry from the cache table
  382. *
  383. * @param[in] pxMACAddress: The MAC-address of the entry of interest.
  384. * @param[out] pulIPAddress: set to the IP-address found, or unchanged when not found.
  385. *
  386. * @return Either eARPCacheMiss or eARPCacheHit.
  387. */
  388. eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress,
  389. uint32_t * pulIPAddress )
  390. {
  391. BaseType_t x;
  392. eARPLookupResult_t eReturn = eARPCacheMiss;
  393. configASSERT( pxMACAddress != NULL );
  394. configASSERT( pulIPAddress != NULL );
  395. /* Loop through each entry in the ARP cache. */
  396. for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
  397. {
  398. /* Does this row in the ARP cache table hold an entry for the MAC
  399. * address being searched? */
  400. if( memcmp( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
  401. {
  402. *pulIPAddress = xARPCache[ x ].ulIPAddress;
  403. eReturn = eARPCacheHit;
  404. break;
  405. }
  406. }
  407. return eReturn;
  408. }
  409. #endif /* ipconfigUSE_ARP_REVERSED_LOOKUP */
  410. /*-----------------------------------------------------------*/
  411. /**
  412. * @brief Look for ulIPAddress in the ARP cache.
  413. *
  414. * @param[in,out] pulIPAddress: Pointer to the IP-address to be queried to the ARP cache.
  415. * @param[in,out] pxMACAddress: Pointer to a MACAddress_t variable where the MAC address
  416. * will be stored, if found.
  417. *
  418. * @return If the IP address exists, copy the associated MAC address into pxMACAddress,
  419. * refresh the ARP cache entry's age, and return eARPCacheHit. If the IP
  420. * address does not exist in the ARP cache return eARPCacheMiss. If the packet
  421. * cannot be sent for any reason (maybe DHCP is still in process, or the
  422. * addressing needs a gateway but there isn't a gateway defined) then return
  423. * eCantSendPacket.
  424. */
  425. eARPLookupResult_t eARPGetCacheEntry( uint32_t * pulIPAddress,
  426. MACAddress_t * const pxMACAddress )
  427. {
  428. eARPLookupResult_t eReturn;
  429. uint32_t ulAddressToLookup;
  430. ulAddressToLookup = *pulIPAddress;
  431. #if ( ipconfigUSE_LLMNR == 1 )
  432. if( ulAddressToLookup == ipLLMNR_IP_ADDR ) /* Is in network byte order. */
  433. {
  434. /* The LLMNR IP-address has a fixed virtual MAC address. */
  435. ( void ) memcpy( pxMACAddress->ucBytes, xLLMNR_MacAdress.ucBytes, sizeof( MACAddress_t ) );
  436. eReturn = eARPCacheHit;
  437. }
  438. else
  439. #endif
  440. if( xIsIPv4Multicast( ulAddressToLookup ) != 0 )
  441. {
  442. /* Get the lowest 23 bits of the IP-address. */
  443. vSetMultiCastIPv4MacAddress( ulAddressToLookup, pxMACAddress );
  444. eReturn = eARPCacheHit;
  445. }
  446. else if( ( *pulIPAddress == ipBROADCAST_IP_ADDRESS ) || /* Is it the general broadcast address 255.255.255.255? */
  447. ( *pulIPAddress == xNetworkAddressing.ulBroadcastAddress ) ) /* Or a local broadcast address, eg 192.168.1.255? */
  448. {printf("This is a broadcast so it uses the broadcast MAC address\r\n");
  449. /* This is a broadcast so it uses the broadcast MAC address. */
  450. ( void ) memcpy( pxMACAddress->ucBytes, xBroadcastMACAddress.ucBytes, sizeof( MACAddress_t ) );
  451. eReturn = eARPCacheHit;
  452. }
  453. else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL )
  454. {
  455. /* The IP address has not yet been assigned, so there is nothing that
  456. * can be done. */
  457. eReturn = eCantSendPacket;
  458. }
  459. else
  460. {
  461. eReturn = eARPCacheMiss;
  462. if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )
  463. {
  464. /* No matching end-point is found, look for a gateway. */
  465. #if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )
  466. eReturn = prvCacheLookup( *pulIPAddress, pxMACAddress );
  467. if( eReturn == eARPCacheHit )
  468. {
  469. /* The stack is configured to store 'remote IP addresses', i.e. addresses
  470. * belonging to a different the netmask. prvCacheLookup() returned a hit, so
  471. * the MAC address is known. */
  472. }
  473. else
  474. #endif
  475. {
  476. /* The IP address is off the local network, so look up the
  477. * hardware address of the router, if any. */
  478. if( xNetworkAddressing.ulGatewayAddress != ( uint32_t ) 0U )
  479. {
  480. ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;
  481. }
  482. else
  483. {
  484. ulAddressToLookup = *pulIPAddress;
  485. }
  486. }
  487. }
  488. else
  489. {
  490. /* The IP address is on the local network, so lookup the requested
  491. * IP address directly. */
  492. ulAddressToLookup = *pulIPAddress;
  493. }
  494. #if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )
  495. if( eReturn == eARPCacheMiss ) /*lint !e774: (Info -- Boolean within 'if' always evaluates to True, depending on configuration. */
  496. #else
  497. /* No cache look-up was done, so the result is still 'eARPCacheMiss'. */
  498. #endif
  499. {
  500. if( ulAddressToLookup == 0UL )
  501. {
  502. /* The address is not on the local network, and there is not a
  503. * router. */
  504. eReturn = eCantSendPacket;
  505. }
  506. else
  507. {
  508. eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress );
  509. if( eReturn == eARPCacheMiss )
  510. {
  511. /* It might be that the ARP has to go to the gateway. */
  512. *pulIPAddress = ulAddressToLookup;
  513. }
  514. }
  515. }
  516. }
  517. return eReturn;
  518. }
  519. /*-----------------------------------------------------------*/
  520. /**
  521. * @brief Lookup an IP address in the ARP cache.
  522. *
  523. * @param[in] ulAddressToLookup: The 32-bit representation of an IP address to
  524. * lookup.
  525. * @param[out] pxMACAddress: A pointer to MACAddress_t variable where, if there
  526. * is an ARP cache hit, the MAC address corresponding to
  527. * the IP address will be stored.
  528. *
  529. * @return When the IP-address is found: eARPCacheHit, when not found: eARPCacheMiss,
  530. * and when waiting for a ARP reply: eCantSendPacket.
  531. */
  532. static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup,
  533. MACAddress_t * const pxMACAddress )
  534. {
  535. BaseType_t x;
  536. eARPLookupResult_t eReturn = eARPCacheMiss;
  537. /* Loop through each entry in the ARP cache. */
  538. for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
  539. {
  540. /* Does this row in the ARP cache table hold an entry for the IP address
  541. * being queried? */
  542. if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )
  543. {
  544. /* A matching valid entry was found. */
  545. if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
  546. {
  547. /* This entry is waiting an ARP reply, so is not valid. */
  548. eReturn = eCantSendPacket;
  549. }
  550. else
  551. {
  552. /* A valid entry was found. */
  553. ( void ) memcpy( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) );
  554. eReturn = eARPCacheHit;
  555. }
  556. break;
  557. }
  558. }
  559. return eReturn;
  560. }
  561. /*-----------------------------------------------------------*/
  562. /**
  563. * @brief A call to this function will update (or 'Age') the ARP cache entries.
  564. * The function will also try to prevent a removal of entry by sending
  565. * an ARP query. It will also check whether we are waiting on an ARP
  566. * reply - if we are, then an ARP request will be re-sent.
  567. * In case an ARP entry has 'Aged' to 0, it will be removed from the ARP
  568. * cache.
  569. */
  570. void vARPAgeCache( void )
  571. {
  572. BaseType_t x;
  573. TickType_t xTimeNow;
  574. /* Loop through each entry in the ARP cache. */
  575. for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
  576. {
  577. /* If the entry is valid (its age is greater than zero). */
  578. if( xARPCache[ x ].ucAge > 0U )
  579. {
  580. /* Decrement the age value of the entry in this ARP cache table row.
  581. * When the age reaches zero it is no longer considered valid. */
  582. ( xARPCache[ x ].ucAge )--;
  583. /* If the entry is not yet valid, then it is waiting an ARP
  584. * reply, and the ARP request should be retransmitted. */
  585. if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
  586. {
  587. FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
  588. }
  589. else if( xARPCache[ x ].ucAge <= ( uint8_t ) arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )
  590. {
  591. /* This entry will get removed soon. See if the MAC address is
  592. * still valid to prevent this happening. */
  593. iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );
  594. FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
  595. }
  596. else
  597. {
  598. /* The age has just ticked down, with nothing to do. */
  599. }
  600. if( xARPCache[ x ].ucAge == 0U )
  601. {
  602. /* The entry is no longer valid. Wipe it out. */
  603. iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );
  604. xARPCache[ x ].ulIPAddress = 0UL;
  605. }
  606. }
  607. }
  608. xTimeNow = xTaskGetTickCount();
  609. if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) )
  610. {
  611. FreeRTOS_OutputARPRequest( *ipLOCAL_IP_ADDRESS_POINTER );
  612. xLastGratuitousARPTime = xTimeNow;
  613. }
  614. }
  615. /*-----------------------------------------------------------*/
  616. /**
  617. * @brief Send a Gratuitous ARP packet to allow this node to announce the IP-MAC
  618. * mapping to the entire network.
  619. */
  620. void vARPSendGratuitous( void )
  621. {
  622. /* Setting xLastGratuitousARPTime to 0 will force a gratuitous ARP the next
  623. * time vARPAgeCache() is called. */
  624. xLastGratuitousARPTime = ( TickType_t ) 0;
  625. /* Let the IP-task call vARPAgeCache(). */
  626. ( void ) xSendEventToIPTask( eARPTimerEvent );
  627. }
  628. /*-----------------------------------------------------------*/
  629. /**
  630. * @brief Create and send an ARP request packet.
  631. *
  632. * @param[in] ulIPAddress: A 32-bit representation of the IP-address whose
  633. * physical (MAC) address is required.
  634. */
  635. void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress )
  636. {
  637. NetworkBufferDescriptor_t * pxNetworkBuffer;
  638. /* This is called from the context of the IP event task, so a block time
  639. * must not be used. */
  640. pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( ARPPacket_t ), ( TickType_t ) 0U );
  641. if( pxNetworkBuffer != NULL )
  642. {
  643. pxNetworkBuffer->ulIPAddress = ulIPAddress;
  644. vARPGenerateRequestPacket( pxNetworkBuffer );
  645. #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
  646. {
  647. if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
  648. {
  649. BaseType_t xIndex;
  650. for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
  651. {
  652. pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
  653. }
  654. pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
  655. }
  656. }
  657. #endif /* if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) */
  658. if( xIsCallingFromIPTask() != 0 )
  659. {
  660. iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
  661. /* Only the IP-task is allowed to call this function directly. */
  662. ( void ) xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
  663. }
  664. else
  665. {
  666. IPStackEvent_t xSendEvent;
  667. /* Send a message to the IP-task to send this ARP packet. */
  668. xSendEvent.eEventType = eNetworkTxEvent;
  669. xSendEvent.pvData = pxNetworkBuffer;
  670. if( xSendEventStructToIPTask( &xSendEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
  671. {
  672. /* Failed to send the message, so release the network buffer. */
  673. vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
  674. }
  675. }
  676. }
  677. }
  678. /*--------------------------------------*/
  679. /**
  680. * @brief Generate an ARP request packet by copying various constant details to
  681. * the buffer.
  682. *
  683. * @param[in,out] pxNetworkBuffer: Pointer to the buffer which has to be filled with
  684. * the ARP request packet details.
  685. */
  686. void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
  687. {
  688. /* Part of the Ethernet and ARP headers are always constant when sending an IPv4
  689. * ARP packet. This array defines the constant parts, allowing this part of the
  690. * packet to be filled in using a simple memcpy() instead of individual writes. */
  691. static const uint8_t xDefaultPartARPPacketHeader[] =
  692. {
  693. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Ethernet destination address. */
  694. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source address. */
  695. 0x08, 0x06, /* Ethernet frame type (ipARP_FRAME_TYPE). */
  696. 0x00, 0x01, /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */
  697. 0x08, 0x00, /* usProtocolType. */
  698. ipMAC_ADDRESS_LENGTH_BYTES, /* ucHardwareAddressLength. */
  699. ipIP_ADDRESS_LENGTH_BYTES, /* ucProtocolAddressLength. */
  700. 0x00, 0x01, /* usOperation (ipARP_REQUEST). */
  701. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* xSenderHardwareAddress. */
  702. 0x00, 0x00, 0x00, 0x00, /* ulSenderProtocolAddress. */
  703. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* xTargetHardwareAddress. */
  704. };
  705. ARPPacket_t * pxARPPacket;
  706. /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
  707. const void * pvCopySource;
  708. void * pvCopyDest;
  709. /* Buffer allocation ensures that buffers always have space
  710. * for an ARP packet. See buffer allocation implementations 1
  711. * and 2 under portable/BufferManagement. */
  712. configASSERT( pxNetworkBuffer != NULL );
  713. configASSERT( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) );
  714. pxARPPacket = ipCAST_PTR_TO_TYPE_PTR( ARPPacket_t, pxNetworkBuffer->pucEthernetBuffer );
  715. /* memcpy the const part of the header information into the correct
  716. * location in the packet. This copies:
  717. * xEthernetHeader.ulDestinationAddress
  718. * xEthernetHeader.usFrameType;
  719. * xARPHeader.usHardwareType;
  720. * xARPHeader.usProtocolType;
  721. * xARPHeader.ucHardwareAddressLength;
  722. * xARPHeader.ucProtocolAddressLength;
  723. * xARPHeader.usOperation;
  724. * xARPHeader.xTargetHardwareAddress;
  725. */
  726. /*
  727. * Use helper variables for memcpy() to remain
  728. * compliant with MISRA Rule 21.15. These should be
  729. * optimized away.
  730. */
  731. pvCopySource = xDefaultPartARPPacketHeader;
  732. pvCopyDest = pxARPPacket;
  733. ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xDefaultPartARPPacketHeader ) );
  734. pvCopySource = ipLOCAL_MAC_ADDRESS;
  735. pvCopyDest = pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes;
  736. ( void ) memcpy( pvCopyDest, pvCopySource, ipMAC_ADDRESS_LENGTH_BYTES );
  737. pvCopySource = ipLOCAL_MAC_ADDRESS;
  738. pvCopyDest = pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes;
  739. ( void ) memcpy( pvCopyDest, pvCopySource, ipMAC_ADDRESS_LENGTH_BYTES );
  740. pvCopySource = ipLOCAL_IP_ADDRESS_POINTER;
  741. pvCopyDest = pxARPPacket->xARPHeader.ucSenderProtocolAddress;
  742. ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );
  743. pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;
  744. pxNetworkBuffer->xDataLength = sizeof( ARPPacket_t );
  745. iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->ulIPAddress );
  746. }
  747. /*-----------------------------------------------------------*/
  748. /**
  749. * @brief A call to this function will clear the ARP cache.
  750. */
  751. void FreeRTOS_ClearARP( void )
  752. {
  753. ( void ) memset( xARPCache, 0, sizeof( xARPCache ) );
  754. }
  755. /*-----------------------------------------------------------*/
  756. #if 1
  757. /**
  758. * @brief This function will check if the target IP-address belongs to this device.
  759. * If so, the packet will be passed to the IP-stack, who will answer it.
  760. * The function is to be called within the function xNetworkInterfaceOutput().
  761. *
  762. * @param[in] pxDescriptor: The network buffer which is to be checked for loop-back.
  763. * @param[in] bReleaseAfterSend: pdTRUE: Driver is allowed to transfer ownership of descriptor.
  764. * pdFALSE: Driver is not allowed to take ownership of descriptor,
  765. * make a copy of it.
  766. *
  767. * @return pdTRUE/pdFALSE: There is/isn't a loopback address in the packet.
  768. */
  769. BaseType_t xCheckLoopback( NetworkBufferDescriptor_t * const pxDescriptor,
  770. BaseType_t bReleaseAfterSend )
  771. {
  772. BaseType_t xResult = pdFALSE;
  773. NetworkBufferDescriptor_t * pxUseDescriptor = pxDescriptor;
  774. const IPPacket_t * pxIPPacket = ipCAST_PTR_TO_TYPE_PTR( IPPacket_t, pxUseDescriptor->pucEthernetBuffer );
  775. if( pxIPPacket->xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
  776. {
  777. if( memcmp( pxIPPacket->xEthernetHeader.xDestinationAddress.ucBytes, ipLOCAL_MAC_ADDRESS, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 )
  778. {
  779. xResult = pdTRUE;
  780. if( bReleaseAfterSend == pdFALSE )
  781. {
  782. /* Driver is not allowed to transfer the ownership
  783. * of descriptor, so make a copy of it */
  784. pxUseDescriptor =
  785. pxDuplicateNetworkBufferWithDescriptor( pxDescriptor, pxDescriptor->xDataLength );
  786. }
  787. if( pxUseDescriptor != NULL )
  788. {
  789. IPStackEvent_t xRxEvent;
  790. xRxEvent.eEventType = eNetworkRxEvent;
  791. xRxEvent.pvData = pxUseDescriptor;
  792. if( xSendEventStructToIPTask( &xRxEvent, 0U ) != pdTRUE )
  793. {
  794. vReleaseNetworkBufferAndDescriptor( pxUseDescriptor );
  795. iptraceETHERNET_RX_EVENT_LOST();
  796. FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
  797. }
  798. }
  799. }
  800. }
  801. return xResult;
  802. }
  803. #endif /* 0 */
  804. /*-----------------------------------------------------------*/
  805. #if ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 )
  806. void FreeRTOS_PrintARPCache( void )
  807. {
  808. BaseType_t x, xCount = 0;
  809. /* Loop through each entry in the ARP cache. */
  810. for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
  811. {
  812. if( ( xARPCache[ x ].ulIPAddress != 0UL ) && ( xARPCache[ x ].ucAge > ( uint8_t ) 0U ) )
  813. {
  814. /* See if the MAC-address also matches, and we're all happy */
  815. FreeRTOS_printf( ( "Arp %2ld: %3u - %16lxip : %02x:%02x:%02x : %02x:%02x:%02x\n",
  816. x,
  817. xARPCache[ x ].ucAge,
  818. xARPCache[ x ].ulIPAddress,
  819. xARPCache[ x ].xMACAddress.ucBytes[ 0 ],
  820. xARPCache[ x ].xMACAddress.ucBytes[ 1 ],
  821. xARPCache[ x ].xMACAddress.ucBytes[ 2 ],
  822. xARPCache[ x ].xMACAddress.ucBytes[ 3 ],
  823. xARPCache[ x ].xMACAddress.ucBytes[ 4 ],
  824. xARPCache[ x ].xMACAddress.ucBytes[ 5 ] ) );
  825. xCount++;
  826. }
  827. }
  828. FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) );
  829. }
  830. #endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */