前回の続き
正しいARP解決の流れ
ChatGPTに聞いてみる
Q
This is a story about FreeRTOS-Plus-TCP.
The FreeRTOS-Plus-TCP source code repository can be found below.
https://github.com/FreeRTOS/FreeRTOS-Plus-TCP
The ARP request sent from pfOutput listed in NetworkInterface.c is
received by the opposite node
A response is returned as an ARP reply.
If received on NetworkInterface.c
Please explain in detail the flow from reception at NetworkInterface.c to entry being written in the ARP table, including function names.
A
To explain the flow from the reception of an ARP reply in the FreeRTOS-Plus-TCP stack, let's go through the relevant parts of the code in the FreeRTOS-Plus-TCP repository on GitHub.
Reception at NetworkInterface.c:
When an ARP reply is received, it is typically handled in the prvEMACRxTask function within the NetworkInterface.c file. This function is part of the Ethernet MAC driver and is responsible for processing received frames.
ARP Frame Processing:
Within prvEMACRxTask, the received Ethernet frame is checked to determine if it is an ARP frame. This is usually done by examining the EtherType field in the Ethernet header.
If the frame is an ARP frame, the prvHandleARPFrame function is called to process the ARP packet.
Handling ARP Frame (prvHandleARPFrame):
The prvHandleARPFrame function is responsible for parsing the ARP packet, extracting information such as sender's MAC and IP addresses.
The ARP reply is validated to ensure it is a response to a previously sent ARP request. This is typically done by comparing the target IP address in the ARP reply with the IP address the original ARP request was sent for.
Updating ARP Table (vARPRefreshCacheEntry):
Once the ARP reply is validated, the FreeRTOS-Plus-TCP stack updates its ARP table. This is usually done by calling the vARPRefreshCacheEntry function.
The vARPRefreshCacheEntry function updates an existing ARP table entry or adds a new entry if the sender's IP address is not already present in the table.
The ARP table is a critical data structure that maps IP addresses to MAC addresses and is used for efficient address resolution.
Notification (vARPGenerateL2PChange):
After updating the ARP table, a notification is often sent to other parts of the TCP/IP stack to inform them about the change in the mapping from IP to MAC address. This notification is typically generated by calling the vARPGenerateL2PChange function.
Usage in Higher Layers:
Other parts of the TCP/IP stack, such as the IP layer, can now use the updated ARP table to determine the MAC address corresponding to a given IP address.
For example, when sending an IP packet, the IP layer may check the ARP table to find the MAC address associated with the destination IP address and use it to construct the Ethernet frame for transmission.
Please note that the exact function names and code structure may vary based on the specific version of FreeRTOS-Plus-TCP you are using, and the information provided here is based on general principles commonly found in networking stacks. It's recommended to refer to the specific source code and documentation for the version you are working with for precise details.
prvHandleARPFrame
は存在しなかったがやっぱりvARPRefreshCacheEntry
が呼ばれるらしい
で、vARPGenerateL2PChange
も無い
v3.1.0でもv4.0.0でも同じ結果だった
ちょっと怪しいが一応見てみる
$ grep vARPRefreshCacheEntry . -wnrI | fgrep -v "/test/"
./source/FreeRTOS_ARP.c:330: vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint );
./source/FreeRTOS_ARP.c:388: vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint );
./source/FreeRTOS_ARP.c:437: vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint );
./source/FreeRTOS_ARP.c:690:void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress,
./source/FreeRTOS_UDP_IPv4.c:254: vARPRefreshCacheEntry( NULL, ulIPAddress, NULL );
./source/FreeRTOS_UDP_IPv4.c:505: vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress,
./source/FreeRTOS_UDP_IPv4.c:517: vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress,
./source/FreeRTOS_UDP_IPv4.c:536: vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress,
./source/FreeRTOS_UDP_IPv4.c:550: vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress,
./source/FreeRTOS_UDP_IPv6.c:174: vARPRefreshCacheEntry( NULL, ulIPAddress, NULL );
./source/include/FreeRTOS_ARP.h:95:/*void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress, */
./source/include/FreeRTOS_ARP.h:98:void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress,
./source/portable/NetworkInterface/virtether/NetworkInterface.c:343: vARPRefreshCacheEntry(&arp->xSenderHardwareAddress, *(uint32_t *)&arp->ucSenderProtocolAddress, ep);
関係ありそうなのは上3つくらいだけだな
あと、やっぱりドライバでARPテーブル更新するわけないので他のNICドライバ内には見当たらなかった。
1個めはヒットしたらの話なので論外
325 if( eARPGetCacheEntry( &( ulSenderProtocolAddress ), &( xHardwareAddress ), &( pxCachedEn dPoint ) ) == eARPCacheHit )
326 {
327 /* Check if the endpoint matches with the one present in the ARP cache */
328 if( pxCachedEndPoint == pxTargetEndPoint )
329 {
330 vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocol Address, pxTargetEndPoint );
331 }
2個めは送り元を登録。あれ、こっちで調べたときは送り元も登録されてなかったのでここ通ってないぞ
そもそもこの関数が呼ばれてないことがおかしい気がする。
370 static void vARPProcessPacketRequest( ARPPacket_t * pxARPFrame,
371 NetworkEndPoint_t * pxTargetEndPoint,
372 uint32_t ulSenderProtocolAddress )
...
388 vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint );
3個め。これが本命っぽい
425 static void vARPProcessPacketReply( const ARPPacket_t * pxARPFrame,
426 NetworkEndPoint_t * pxTargetEndPoint,
427 uint32_t ulSenderProtocolAddress )
...
433 if( ( ulTargetProtocolAddress == pxTargetEndPoint->ipv4_settings.ulIPAddress ) || 434 ( xIsIPInARPCache( ulSenderProtocolAddress ) == pdTRUE ) )
435 {
436 iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress );
437 vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint );
438 }
static 関数は検索が楽でいいな
FreeRTOS-Plus-TCP$ grep vARPProcessPacketReply . -wnrI
./source/FreeRTOS_ARP.c:91: static void vARPProcessPacketReply( const ARPPacket_t * pxARPFrame,
./source/FreeRTOS_ARP.c:343: vARPProcessPacketReply( pxARPFrame, pxTargetEndPoint, ulSenderProtocolAddress );
./source/FreeRTOS_ARP.c:425: static void vARPProcessPacketReply( const ARPPacket_t * pxARPFrame,
呼び出している関数
145 eFrameProcessingResult_t eARPProcessPacket( const NetworkBufferDescriptor_t * pxNetworkBuffer )
その前
FreeRTOS-Plus-TCP$ grep eARPProcessPacket . -wnrI | fgrep -v "/test/"
./source/FreeRTOS_ARP.c:145: eFrameProcessingResult_t eARPProcessPacket( const NetworkBufferDescriptor_t * pxNetworkBuffer )
./source/include/FreeRTOS_IP_Private.h:451:eFrameProcessingResult_t eARPProcessPacket( const NetworkBufferDescriptor_t * pxNetworkBuffer );
./source/FreeRTOS_IP.c:1579: eReturned = eARPProcessPacket( pxNetworkBuffer );
の前
1541 static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
以下同
FreeRTOS-Plus-TCP$ grep prvProcessEthernetPacket . -wnrI | fgrep -v "/test/"
./source/FreeRTOS_IP.c:141:static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
./source/FreeRTOS_IP.c:683: prvProcessEthernetPacket( pxBuffer );
./source/FreeRTOS_IP.c:705: prvProcessEthernetPacket( pxBuffer );
./source/FreeRTOS_IP.c:1541:static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
683Lも705も同じ関数でした。で、こんな感じ。queueにeNetworkRxEvent
が来たらなので
ここが本命っぽい
prvProcessIPEventsAndTimers
└prvHandleEthernetPacket
└prvProcessEthernetPacket
Queueを空にするのは日立が大好きなやり方なので
また日立の嫌がらせっぽい
ということで集スト会社のPCで出来るのはここまでかなぁ