FreeRTOSを動かしてみる(15)

[前回](https://qiita.com/t-yano-tryhard/items/105b6badc6ed57c5bb2f)の続き

# 正しい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);
```

関係ありそうなのは上３つくらいだけだな
あと、やっぱりドライバでARPテーブル更新するわけないので他のNICドライバ内には見当たらなかった。

1個めはヒットしたらの話なので論外
```c
 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個めは送り元を登録。あれ、こっちで調べたときは送り元も登録されてなかったのでここ通ってないぞ
そもそもこの関数が呼ばれてないことがおかしい気がする。
```c
 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 関数は検索が楽でいいな
```c
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,
```

呼び出している関数
```c
 145     eFrameProcessingResult_t eARPProcessPacket( const NetworkBufferDescriptor_t * pxNetworkBuffer )
```
その前
```shell
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 );
```
の前
```c
1541 static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
```

以下同
```shell
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で出来るのはここまでかなぁ