FreeRTOSを動かしてみる(12)

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

ということで普通にクラサバアプリが作れるか試してみる。

# パラメータとか
![images](https://kroki.io/graphviz/svg/eNp9UMlqwzAQvfsrhM6JsQJNN5xTKBQCCa1vaSlyNVgirizGMqQU_3st2XFEnHYOgzRv0RsJVSA3kqzJT0S6Qq4PQiFJSbZ-9BNdCdjXkhtIaV4d6YzU9rvsLlg1WoCg755WN3nv9Fk2tQX82CjdHAdXVyXPoUypH9NoHE90GccCbCAMxLbHuDGBg8eV2Q-c592bZveLmC3vYpYkMXu4ZTfJkPLsN_LBSkAN9pKhzHzlaN1vuMWtDAhtdO6TBZ4Q4CXbvk53PyF0BPDv3AuXmwWP4r-Z0eXFK3lb1_qk1RecHNzZSqWLgdVtOl95wqUeryLtLzWmn5M=)

アプリケーション側では<font color="red">TCP</font>を使うのでダミーで使用したポートとかぶっても良いのだが
わかりやすいように別にしておく。

# サンプルアプリケーションの流れ

標準入力から文字列を受け取ってFreeRTOS側でprefixをつけるだけの単純なecho backです。

```plantuml
@startuml
!pragma teoz true

title sample_app sequence

box Linux #F0E0E0
box sample_app #FFFCF0
participant "server\nport:7150" as ls
participant "client" as lc
end box

participant stdin as sin
participant stdout
end box

box FreeRTOS #E0fFC0
participant "server\nport:7151" as rs
participant "client" as rc
end box

activate rc
activate rs
activate lc
activate ls

sin -> lc : manual input
lc -> rs : send to tcp
activate rs
rs --> lc : response
rs -> rc : queue
lc --> rs : close
deactivate rs
rc -> rc : queue pop
rc -> rc : add prefix
rc -> ls : send to tcp
activate ls
ls --> rc : response
ls -> stdout : printf
rc --> ls : close
deactivate ls
deactivate lc
deactivate ls
deactivate rs
deactivate rc

@enduml
```

# Linux側

これは特に目新しいことも無いので普通に作る

<details>
<summary>こんなかんじ</summary>

sample_app.c
```c
#include <pthread.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>

/* definitions */
#define NEVENTS 2
#define TARGET_SERVER_IP "192.168.100.2"
#define TARGET_SERVER_PORT 7151
#define SERVER_IP INADDR_ANY
#define SERVER_PORT 7150
#define STDIN_BUF_SIZE 256
#define BUF_SIZE 0x10000

#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

#define d(s, ...)                                                                 \
    do                                                                            \
    {                                                                             \
        pthread_mutex_lock(&mutex);                                               \
        printf("%s(%d) %s " s "\n", __FILENAME__, __LINE__, __func__, ##__VA_ARGS__); \
        pthread_mutex_unlock(&mutex);                                             \
    } while (0)

#define ERRRET(c, s, ...)                                                                      \
    do                                                                                         \
    {                                                                                          \
        if (c)                                                                                 \
        {                                                                                      \
            fprintf(stderr, "%s(%d) %s " s "\n", __FILENAME__, __LINE__, __func__, ##__VA_ARGS__); \
            goto error_return;                                                                 \
        }                                                                                      \
    } while (0)

#ifndef min
#define min(a, b) (a) > (b) ? (b) : (a)
#endif

enum SERVER_STATUS
{
    ST_SRV_NONE,
    ST_SRV_RUNNING,
    ST_SRV_FAILED,
};

static void *server_thread(void *param);
static void init_sock_addr(int *sock, struct sockaddr_in *addr, uint32_t ip, uint16_t port);
static int set_epoll_event(int epfd, int sock, struct epoll_event *ev);
static char *b2s(uint8_t *data, size_t len);
static void send_tcp_to_freertos(uint8_t *data, size_t len);

/* variables */
pthread_t th;
enum SERVER_STATUS server_status = ST_SRV_NONE;
static char stdin_buf[STDIN_BUF_SIZE];
static __thread char rx_buf[BUF_SIZE];
static char print_buf[BUF_SIZE];
static pthread_mutex_t mutex;

int main(void)
{
    int ret;
    char *p;

    pthread_mutex_init(&mutex, NULL);
    ret = pthread_create(&th, NULL, server_thread, NULL);
    if (ret)
    {
        d("pthread_create failed.");
        return 0;
    }

    while (server_status != ST_SRV_FAILED)
    {
        if (fgets(stdin_buf, STDIN_BUF_SIZE, stdin))
        {
            p = strchr(stdin_buf, '\n');
            if (!p)
                continue;

            *p = '\0';
            send_tcp_to_freertos(p, strlen(p));
        }
    }
    return 0;
}

static void init_sock_addr(int *sock, struct sockaddr_in *addr, uint32_t ip, uint16_t port)
{
    *sock = socket(AF_INET, SOCK_STREAM, 0);
    memset(addr, 0, sizeof(struct sockaddr_in));
    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = ip;
    addr->sin_port = htons(port);
}

static int set_epoll_event(int epfd, int sock, struct epoll_event *ev)
{

    memset(ev, 0, sizeof(struct epoll_event));
    ev->events = EPOLLIN;
    ev->data.fd = sock;
    return epoll_ctl(epfd, EPOLL_CTL_ADD, sock, ev);
}

static inline char b2c(uint8_t b)
{
    return (0x20 <= b && b <= 0x7e) ? b : '.';
}

static char *b2s(uint8_t *data, size_t org_len)
{
    int i;
    char *p;
    char str[0x11] = {0};
    size_t len = min(sizeof(print_buf) / 5, org_len);

    p = (char *)print_buf;
    for (i = 0; i < len; i++)
    {
        p += sprintf(p, "%02x ", data[i]);
        str[i % 16] = b2c(data[i]);

        if ((i % 16) == 15)
        {
            p += sprintf(p, "%s\n", str);
        }
    }

    if (i % 16)
    {
        str[i] = '\0';
        memset(p, ' ', (16 - (i % 16)) * 3);
        p += (16 - (i % 16)) * 3;
        p += sprintf(p, "%s\n", str);
    }
    return print_buf;
}

static void *server_thread(void *param)
{
    int sock, csock = -1;
    struct sockaddr_in addr, caddr;
    socklen_t csize;
    int epfd;
    struct epoll_event ev[NEVENTS], ev_ret[NEVENTS];
    int i, n, nfds;
    (void)param;

    init_sock_addr(&sock, &addr, SERVER_IP, SERVER_PORT);

    n = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
    ERRRET(n != 0, "bind failed.%d", n);

    n = listen(sock, NEVENTS);
    ERRRET(n != 0, "listen failed.");

    epfd = epoll_create(NEVENTS);
    ERRRET(epfd < 0, "epoll_create failed.");

    n = set_epoll_event(epfd, sock, &ev[0]);
    ERRRET(n != 0, "epoll_ctl failed.");

    server_status = ST_SRV_RUNNING;
    while (1)
    {
        nfds = epoll_wait(epfd, ev_ret, NEVENTS, -1);
        ERRRET(nfds <= 0, "epoll_wait");

        for (i = 0; i < nfds; i++)
        {
            if (ev_ret[i].data.fd == sock)
            {
                csize = sizeof(caddr);
                csock = accept(sock, (struct sockaddr *)&caddr, &csize);
                ev[i].events = EPOLLIN;
                ev[i].data.fd = csock;
                epoll_ctl(epfd, EPOLL_CTL_ADD, csock, &ev[i]);
                d("accept from %x", caddr.sin_addr.s_addr);
            }
            else
            {
                n = read(ev_ret[i].data.fd, rx_buf, BUF_SIZE);
                if (n == 0)
                {
                    epoll_ctl(epfd, EPOLL_CTL_DEL, ev_ret[i].data.fd, NULL);
                    close(ev_ret[i].data.fd);
                    d("close");
                }
                else
                {
                    d("received from FreeRTOS: %s", b2s(rx_buf, n));
                    send(ev_ret[i].data.fd, rx_buf, n, 0);
                }
            }
        }
    }

error_return:
    server_status = ST_SRV_FAILED;
    if (sock >= 0)
        close(sock);
    if (csock >= 0)
        close(csock);
    return NULL;
}

static void send_tcp_to_freertos(uint8_t *data, size_t len)
{
    int sock, ret;
    struct sockaddr_in addr;

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    ERRRET(sock < 0, "socket create failed.%d", sock);

    addr.sin_addr.s_addr = inet_addr(TARGET_SERVER_IP);
    addr.sin_family = PF_INET;
    addr.sin_port = htons(TARGET_SERVER_PORT);

    ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
    ERRRET(ret, "connect failed.%d", ret);

    ret = send(sock, data, len, 0);
    ERRRET(ret < 0, "send failed.%d", ret);

    ret = recv(sock, rx_buf, BUF_SIZE, 0);
    ERRRET(ret < 0, "recv failed.%d", ret);

    d("send to freertos");

error_return:
    if (sock >= 0)
        close(sock);
    return;
}
```
</details>

# FreeRTOS側
マニュアルを見ながら書いてみる
多分意図的だろうと思うけどAPIがLinuxに寄せている気がしてわかりやすい。

- [FreeRTOS側の実装](https://github.com/tyano461/freertos_cm3/commit/9547220dae41e8f64c2745b35a9a54670e5764f8)

なんか送ってみる
```
$ ./sample_app 
aiueo

```

FreeRTOSのドライバまでは行ってるが、サーバタスクが受信出来ていないっぽい。
```
mps2.c(846) send_to_freertos irq fire cpu:0x5635e3d76c80 n:74
[01a4] NetworkInterface.c(272) ether_rx_handler waken sz:74 fr:0xfffffffd 
[23e8] NetworkInterface.c(220) ether_task be waken sz:74 fr:0x291 
[23e8] NetworkInterface.c(233) ether_task xSendEventStructToIPTask:1 sz:74 fr:0x291 

```

ためしにFreeRTOS側から送信してみる。
```
[3458] app_client.c(67) vTCPSend socket fr:0xd825 
[3458] FreeRTOS_Sockets.c(3783) FreeRTOS_connect  fr:0xd741 
[6748] NetworkInterface.c(112) xApplicationGetRandomNumber  fr:0x8879 
[3458] FreeRTOS_Sockets.c(3694) prvTCPConnectStart  fr:0x9bf5 
[3458] FreeRTOS_Sockets.c(3701) prvTCPConnectStart fam:2 fr:0x9bf5 
[3458] FreeRTOS_Sockets.c(3717) prvTCPConnectStart FreeRTOS_connect: lp:1024 -> c0a86401:7150 fr:0x9bf5 
mps2.c(751) udp_send2dummy sz:42
mps2.c(846) send_to_freertos irq fire cpu:0x558105197c80 n:42
[6748] NetworkInterface.c(272) ether_rx_handler waken sz:42 fr:0xfffffffd 
[6748] NetworkInterface.c(180) pfOutput ip:164a8c0 po:0 bp:0 len:42 r:1 data:
ff ff ff ff ff ff aa 00 02 aa bb cc 08 06 00 01
08 00 06 04 00 01 aa 00 02 aa bb cc c0 a8 64 02
00 00 00 00 00 00 c0 a8 64 01 
 fr:0x3d3d 
[23e8] NetworkInterface.c(220) ether_task be waken sz:42 fr:0x291 
[3458] FreeRTOS_Sockets.c(3797) FreeRTOS_connect prvTCPConnectStart:0 fr:0xd741 
[3458] FreeRTOS_Sockets.c(3826) FreeRTOS_connect xResult:0 fr:0xd741 
[23e8] NetworkInterface.c(233) ether_task xSendEventStructToIPTask:1 sz:42 fr:0x291 
mps2.c(751) udp_send2dummy sz:42
mps2.c(846) send_to_freertos irq fire cpu:0x558105197c80 n:42
[6748] NetworkInterface.c(180) pfOutput ip:164a8c0 po:[6748] NetworkInterface.c(272) ether_rx_handler waken sz:42 fr:0xfffffff1 
0 bp:0 len:42 r:1 data:
ff ff ff ff ff ff aa 00 02 aa bb cc 08 06 00 01
08 00 06 04 00 01 aa 00 02 aa bb cc c0 a8 64 02
00 00 00 00 00 00 c0 a8 64 01 
 fr:0x3d3d 
[23e8] NetworkInterface.c(220) ether_task be waken sz:42 fr:0x291 
[23e8] NetworkInterface.c(233) ether_task xSendEventStructToIPTask:1 sz:42 fr:0x291 
mps2.c(751) udp_send2dummy sz:42
[67mps2.c(846) send_to_freertos irq fire cpu:0x558105197c80 n:42
][6748] NetworkInterface.c(272) ether_rx_handler waken sz:42 fr:0xfffffffd 
 NetworkInterface.c(272) ether_rx_handler waken sz:42 fr:0xfffffffd 
a:
ff ff ff ff ff ff aa 00 02 aa bb cc 08 06 00 01
08 00 06 04 00 01 aa 00 02 aa bb cc c0 a8 64 02
00 00 00 00 00 00 c0 a8 64 01 
 fr:0x3d3d 
[23e8] NetworkInterface.c(220) ether_task be waken sz:42 fr:0x291 
[23e8] NetworkInterface.c(233) ether_task xSendEventStructToIPTask:1 sz:42 fr:0x291 
[3458] FreeRTOS_Sockets.c(3854) FreeRTOS_connect uxEvents:20 xResut:0 fr:0xd741 
[3458] app_client.c(97) vTCPSend not connected fr:0xd825 

```

つながらない。なんでだろう。
pingはとぶのになぁ
```
$ ping -w1 192.168.100.2
PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
64 bytes from 192.168.100.2: icmp_seq=1 ttl=64 time=10.7 ms

--- 192.168.100.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 10.690/10.690/10.690/0.000 ms
```

戻り値を見てみると特別なエラーとかではなく`pdFREERTOS_ERRNO_ENOTCONN(128)`が返っている
```
[3458] app_client.c(98) vTCPSend not connected. -128 fr:0xd825
```

以下の5パターンのどこかと思われるのでログを埋めてみる
```shell
FreeRTOS-Plus-TCP$ grep pdFREERTOS_ERRNO_ENOTCONN . -wnrI
./source/FreeRTOS_IP_Utils.c:1515:        case pdFREERTOS_ERRNO_ENOTCONN:
./source/include/FreeRTOS_Sockets.h:85:    #define FREERTOS_ECLOSED                 ( -pdFREERTOS_ERRNO_ENOTCONN )
./source/include/FreeRTOS_errno_TCP.h:78:    #define pdFREERTOS_ERRNO_ENOTCONN            128 /* Socket is not connected */
./source/FreeRTOS_Sockets.c:3857:                    xResult = -pdFREERTOS_ERRNO_ENOTCONN;
./source/FreeRTOS_Sockets.c:4159:                xByteCount = -pdFREERTOS_ERRNO_ENOTCONN;
./source/FreeRTOS_Sockets.c:4337:            xResult = -pdFREERTOS_ERRNO_ENOTCONN;
./source/FreeRTOS_Sockets.c:4619:                    xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOTCONN;
./source/FreeRTOS_Sockets.c:4744:            xResult = -pdFREERTOS_ERRNO_ENOTCONN;
```

uxEventsが`eSOCKET_CLOSED(0x20)`になっている
```c
3848                 /* Go sleeping until we get any down-stream event */
3849                 uxEvents = xEventGroupWaitBits( pxSocket->xEventGroup,
3850                                                 ( EventBits_t ) eSOCKET_CONNECT | ( EventBits_t ) eSOCKET_CLOSED,
3851                                                 pdTRUE /*xClearOnExit*/,
3852                                                 pdFALSE /*xWaitAllBits*/,
3853                                                 xRemainingTime );
```

どうもエラールートっぽい
```c
3857                     xResult = -pdFREERTOS_ERRNO_ENOTCONN;
3858                     FreeRTOS_debug_printf( ( "FreeRTOS_connect() stopped due to an error\n" ) );

```

Linux上でサーバに送信すると普通につながるので
サーバ側のプログラムは問題ない。
```
sample_app.c(185) server_thread accept from 100007f
sample_app.c(198) server_thread received from FreeRTOS: 61 69 75 65 6f                                  aiueo

sample_app.c(194) server_thread close
```
というかそもそもSYN(IPv4)パケットがpfOutputに来ていない。

途中で捨てていないのに0806(ARPパケット)しか来ていない

なんか[こんな記事](https://www.reddit.com/r/embedded/comments/14pnwvb/freertos_tcp_doesnt_connect_when_adding_suspend/?rdt=41253)もあったけど
これが本当なら大分使い勝手悪そう、、、


FreeRTOSをサーバにしてLinuxから送ると当然だがSYNパケットが送られている。
(13バイトめの08 00がIv4パケット、48バイトめ(3行目末尾)のa0 02の 002の部分がSYN)
```
[24b8] NetworkInterface.c(237) ether_task xSendEventStructToIPTask:1 sz:74 data:
aa 00 02 aa bb cc aa 00 02 11 22 33 08 00 45 00
00 3c 84 a0 40 00 40 06 6c c7 c0 a8 64 01 c0 a8
64 02 85 fe 1b ef 32 8b df 50 00 00 00 00 a0 02
fe 2e 72 1f 00 00 02 04 05 a6 04 02 08 0a ec 8b
ee 15 00 00 00 00 01 03 03 07 
 fr:0x291 
```
で、FreeRTOSが受け取ったこのパケットはどこかに消えていき、その後はひたすらARPを打ち続ける。

完全にFreeRTOSだけの問題なので設定とかドライバの書き方に問題があるかなにかと思われるが、、、

`xSendEventStructToIPTask`の先を見てみる
FreeRTOS-Plus-TCP/source/FreeRTOS_IP.c 
```c
1379 BaseType_t xSendEventStructToIPTask( const IPStackEvent_t * pxEvent,
1380                                      TickType_t uxTimeout )
...
1425             xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, uxUseTimeout );

```

Queueに積んでるだけ

使ってる人
```c
FreeRTOS-Plus-TCP$ grep xNetworkEventQueue . -wnrI | fgrep -v "/test/"
./source/FreeRTOS_IP_Timers.c:279:            if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0U )
./source/FreeRTOS_IP_Utils.c:953:    configASSERT( xNetworkEventQueue == NULL );
./source/include/FreeRTOS_IP_Private.h:104:extern QueueHandle_t xNetworkEventQueue;
./source/portable/BufferManagement/BufferAllocation_2.c:138:                    extern QueueHandle_t xNetworkEventQueue;
./source/portable/BufferManagement/BufferAllocation_2.c:139:                    vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" );
./source/portable/NetworkInterface/LPC17xx/NetworkInterface.c:79:extern QueueHandle_t xNetworkEventQueue;
./source/portable/NetworkInterface/SH2A/NetworkInterface.c:75:extern QueueHandle_t xNetworkEventQueue;
./source/portable/NetworkInterface/pic32mzef/BufferAllocation_2.c:281:                    extern QueueHandle_t xNetworkEventQueue;
./source/portable/NetworkInterface/pic32mzef/BufferAllocation_2.c:282:                    vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" );
./source/FreeRTOS_Sockets.c:6188:        xReturn = xQueueSendToBackFromISR( xNetworkEventQueue, &xEvent, pxHigherPriorityTaskWoken );
./source/FreeRTOS_IP.c:181:QueueHandle_t xNetworkEventQueue = NULL;
./source/FreeRTOS_IP.c:214:    /** @brief Keep track of the lowest amount of space in 'xNetworkEventQueue'. */
./source/FreeRTOS_IP.c:226: *        'xNetworkEventQueue'. prvIPTask() is the only task which has access to
./source/FreeRTOS_IP.c:276:    if( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE )
./source/FreeRTOS_IP.c:287:                uxCount = uxQueueSpacesAvailable( xNetworkEventQueue );
./source/FreeRTOS_IP.c:785:    if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )
./source/FreeRTOS_IP.c:967:            xNetworkEventQueue = xQueueCreateStatic( ipconfigEVENT_QUEUE_LENGTH,
./source/FreeRTOS_IP.c:974:            xNetworkEventQueue = xQueueCreate( ipconfigEVENT_QUEUE_LENGTH, sizeof( IPStackEvent_t ) );
./source/FreeRTOS_IP.c:975:            configASSERT( xNetworkEventQueue != NULL );
./source/FreeRTOS_IP.c:979:    if( xNetworkEventQueue != NULL )
./source/FreeRTOS_IP.c:986:                vQueueAddToRegistry( xNetworkEventQueue, "NetEvnt" );
./source/FreeRTOS_IP.c:1029:            vQueueDelete( xNetworkEventQueue );
./source/FreeRTOS_IP.c:1030:            xNetworkEventQueue = NULL;
./source/FreeRTOS_IP.c:1405:                    if( uxQueueMessagesWaiting( xNetworkEventQueue ) != 0U )
./source/FreeRTOS_IP.c:1425:            xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, uxUseTimeout );

```
待ってる人一人だけっぽい。
ログ仕込んでみると
```
[24b8] NetworkInterface.c(237) ether_task xSendEventStructToIPTask:1 sz:74 data:
aa 00 02 aa bb cc aa 00 02 11 22 33 08 00 45 00
00 3c 13 0a 40 00 40 06 de 5d c0 a8 64 01 c0 a8
64 02 dd 1e 1b ef 89 27 cb fd 00 00 00 00 a0 02
fe 2e d6 09 00 00 02 04 05 a6 04 02 08 0a ec a1
ef ab 00 00 00 00 01 03 03 07 
 fr:0x291 
[6748] FreeRTOS_IP.c(279) prvProcessIPEventsAndTimers queue no event fr:0x5cff 
[6748] FreeRTOS_IP.c(1419) xSendEventStructToIPTask send fr:0x57a3 

```
送ってるデータが無いことにされているっぽい

```
mps2.c(846) send_to_freertos irq fire cpu:0x55c69fb34880 n:74
[01a4] NetworkInterface.c(276) ether_rx_handler waken sz:74 fr:0xfffffffd 
[24b8] NetworkInterface.c(224) ether_task be waken sz:74 fr:0x291 
[24b8] FreeRTOS_IP.c(1419) xSendEventStructToIPTask send ev:1 to:0 fr:0xd49f 
[6748] FreeRTOS_IP.c(276) prvProcessIPEventsAndTimers wait queue wait:1000 fr:0x5d0b 
[24b8] FreeRTOS_IP.c(1429) xSendEventStructToIPTask queue push is 1 fr:0xd49f 
[24b8] NetworkInterface.c(237) ether_task xSendEventStructToIPTask:1 sz:74 data:
aa 00 02 aa bb cc aa 00 02 11 22 33 08 00 45 00
00 3c fa aa 40 00 40 06 f6 bc c0 a8 64 01 c0 a8
64 02 e3 6c 1b ef 7d f5 22 7f 00 00 00 00 a0 02
fe 2e 4e 89 00 00 02 04 05 a6 04 02 08 0a ec b5
25 7b 00 00 00 00 01 03 03 07 
 fr:0x291 
[6748] FreeRTOS_IP.c(279) prvProcessIPEventsAndTimers queue no event fr:0x5d0b 
```
`xSendEventStructToIPTask`のタイムアウトを変えてみたりしたが関係なかった。

FreeRTOSからはarpリクエストがひたすら来てるからこれドライバで応答返さないといけない？
IPスタックにそのまま投げてるが応答返す気配がないのが問題かも？？？

ドライバからIPを取得する方法がわからなかったので
試しに固定値で返すようにしてみた。
```c
static void arp_reply(uint8_t *data, size_t len)
{
    memcpy(reply_data, data, len);
    struct ethhdr *eth = (struct ethhdr*)data;
    struct arphdr *arp = (struct arphdr *)&eth[1];
    struct arpbdy *bdy = (struct arpbdy *)&arp[1];
    macaddr_t tomac = *(macaddr_t *)eth->h_source;
    ipaddr_t toip = bdy->src_ip;

    eth = (struct ethhdr *)reply_data;
    arp = (struct arphdr *)&eth[1];
    bdy = (struct arpbdy *)&arp[1];

    *(macaddr_t*)eth->h_dest = tomac;
    *(macaddr_t*)eth->h_source = self_mac_addr;
    arp->ar_op = 0x0200;
    *(uint32_t*)&bdy->src_ip = 0x0164a8c0;
    bdy->src_mac = self_mac_addr;
    bdy->tgt_ip = toip;
    bdy->tgt_mac = tomac;

    send_udp(reply_data, len);
}

```

FreeRTOSも同様にしてみるが、まぁ関係なかった
```c
static void arp_reply(uint8_t *data, size_t len)
{
    EthernetHeader_t *eth = (EthernetHeader_t *)data;
    ARPHeader_t *arp = (ARPHeader_t *)&eth[1];
    MACAddress_t mac;
    IP_Address_t ip;
    MACAddress_t tomac = eth->xSourceAddress;
    IP_Address_t toip = *(IP_Address_t *)arp->ucSenderProtocolAddress;

    NetworkEndPoint_t *ep = FreeRTOS_FirstEndPoint(NULL);
    if (ep)
    {
        ip = *(IP_Address_t *)&ep->ipv4_defaults.ulIPAddress;
        mac = ep->xMACAddress;
        eth = (EthernetHeader_t *)reply_buf;
        arp = (ARPHeader_t *)&eth[1];

        eth->xDestinationAddress = tomac;
        eth->xSourceAddress = mac;
        arp->usOperation = 0x0200;
        arp->xSenderHardwareAddress = mac;
        *(IP_Address_t *)arp->ucSenderProtocolAddress = ip;
        arp->xTargetHardwareAddress = tomac;
        *(IP_Address_t*)&arp->ulTargetProtocolAddress = toip;
        mmio_write_on();
        *TX_SIZE = len;
        mmio_write(0, (uint8_t *)reply_buf, len);
        mmio_write_off();
    }
}

```

ドライバがarp理解しないとダメとかさすがにないよな。
とするとIPスタックのどこかで詰まっている。

ICMP(24バイトめが01)の場合はQueueに積む関数を抜ける前に即返している
➡受信時の出力をxSendEventStructToIPTaskを抜けたあとにしているので順序逆転している。

```
[24b8] NetworkInterface.c(228) ether_task be waken sz:98 fr:0x291 
[24b8] FreeRTOS_IP.c(1419) xSendEventStructToIPTask send ev:1 to:0 fr:0xd421 
mps2.c(751) udp_send2dummy sz:98
[674c] NetworkInterface.c(187) pfOutput ip:0 po:0 bp:0 len:98 r:1 data:
aa 00 02 11 22 33 aa 00 02 aa bb cc 08 00 45 00
00 54 5e 40 00 00 40 01 d3 14 c0 a8 64 02 c0 a8
64 01 00 00 06 ec 00 17 00 01 e3 51 89 65 00 00
00 00 c3 71 0a 00 00 00 00 00 10 11 12 13 14 15
16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25
 fr:0x5873 
[24b8] FreeRTOS_IP.c(1429) xSendEventStructToIPTask queue push is 1 fr:0xd421 
[24b8] NetworkInterface.c(249) ether_task rx data to stack:1 sz:98 data:
aa 00 02 11 22 33 aa 00 02 aa bb cc 08 00 45 00
00 54 5e 40 00 00 40 01 d3 14 c0 a8 64 02 c0 a8
64 01 00 00 06 ec 00 17 00 01 e3 51 89 65 00 00
00 00 c3 71 0a 00 00 00 00 00 10 11 12 13 14 15
16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25
 fr:0x291 

```

# ここまでのコード
- [FreeRTOS](https://github.com/tyano461/freertos_cm3/tree/24d02031414b5f077977451423677b0566d67a08)
- [FreeRTOSのドライバ](https://github.com/tyano461/freertos_tcpv4/tree/4f032b81183984cf314deae0dbae90be94bfb745)
- [改造QEMU](https://github.com/tyano461/qemu_an385_ex/tree/d0c293423fd960f4f9c491b31522e2fd69525105)
- [Linuxの仮想デバイスドライバ](https://github.com/tyano461/virtether/tree/95fcc9a1906070724c71e97b1e48742c1cf2e610)

----
# 参考
https://ameblo.jp/hyunseok4384/entry-12405907324.html