FreeRTOSを動かしてみる(13)

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

つながるつながらない以前にFreeRTOSのIPスタックがどうなっているのか理解しないと
調べようが無いのでちょっと動きを追ってみる

といってもコードだけ見ていても眠くなるだけなので
サンプルを動かしながら確認してみる

# FreeRTOS-Plus-TCPのサンプルの動作

WindowsPCが無いので FreeRTOS_Plus_TCP_Echo_Qemu_mps2 を動かしてみる

## 環境の確認


IPアドレス
```shell
$ ip a | grep enp0s
2: enp0s25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master virbr0 state UP group default qlen 1000
    inet 192.168.1.80/24 scope global enp0s25
```

### サーバを起動
```
$ sudo nc -l 7
```

### クライアントプログラム

<details>
<summary>適当に固定メッセージ送るだけのを作る</summary>


```c
#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>

#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define d(s, ...)                                                                 \
    do                                                                            \
    {                                                                             \
        printf("%s(%d) %s " s "\n", __FILENAME__, __LINE__, __func__, ##__VA_ARGS__); \
    } while (0)

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

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

#define TARGET_SERVER_IP "192.168.1.80"
#define TARGET_SERVER_PORT 7
#define BUF_SIZE 0x10000


static char *b2s(uint8_t *data, size_t len);
static void send_tcp(uint8_t *data, size_t len);

static char rx_buf[BUF_SIZE];
static char print_buf[BUF_SIZE];

int main(void) {
    const char* msg = "this is sample\n";
    send_tcp((uint8_t*)msg, strlen(msg));
    return 0;
}

static void send_tcp(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.");

    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");

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

    ret = recv(sock, rx_buf, BUF_SIZE, 0);
    if (ret > 0) {
        d("response:%s", b2s((uint8_t*)rx_buf, ret));
    }

error_return:
    if (sock >= 0)
        close(sock);
    return;
}

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;
}
```

</details>

実行すると
```shell
$ ./a.out
```

サーバが受け取れている
```shell
$ sudo nc -l 7
this is sample
```

サーバ側で文字入力すると
```shell
$ sudo nc -l 7
this is sample
this is nc
$ 

```
返ってくる
```
~$ ./a.out 
a.c(69) send_tcp response:74 68 69 73 20 69 73 20 6e 63 0a                this is nc.

```

これで環境は問題無いことがわかった

## 各種パラメータの設定
[README](https://github.com/FreeRTOS/FreeRTOS/blob/202212.01/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Qemu_mps2/Readme.md)を見て関係ありそうなのを抽出していく

これは
```
Local Host IP address:          192.168.1.81
Local FreeRTOS IP address:      192.168.1.80
Local FreeRTOS Subnet mask:     255.255.255.0
Default Gateway IP address:     192.168.1.254
Default DNS IP address:         192.168.1.254
Echo Server IP address:         192.168.1.204
Echo Server Port:               7
Local FreeRTOS Mac address:     52:54:00:12:34:AD
```
こうやって
```shell
sudo ip link add virbr0 type bridge
sudo ip tuntap add dev virbr0-nic mode tap

sudo ip addr add 192.168.1.80/24 dev virbr0

sudo brctl addif virbr0 enp0s25
sudo brctl addif virbr0 virbr0-nic

sudo ip link set virbr0 up
sudo ip link set virbr0-nic up

# sudo ip route add default via 192.168.1.254 dev virbr0
```

こうなる
```
ip a
...
22: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 74:2b:62:85:92:fe brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.80/24 scope global virbr0
       valid_lft forever preferred_lft forever
    inet6 2404:7a80:3300:4500:762b:62ff:fe85:92fe/64 scope global dynamic mngtmpaddr proto kernel_ra 
       valid_lft 268sec preferred_lft 268sec
    inet6 fe80::762b:62ff:fe85:92fe/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever
23: virbr0-nic: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel master virbr0 state DOWN group default qlen 1000
    link/ether f6:78:99:65:f6:32 brd ff:ff:ff:ff:ff:ff

```

brctlが無い場合は以下
```
$ sudo yum provides brctl | grep x86_64
bridge-utils-1.7.1-7.fc39.x86_64 : Utilities for configuring the linux ethernet bridge
bridge-utils-1.7.1-7.fc39.x86_64 : Utilities for configuring the linux ethernet bridge
$ sudo yum install bridge-utils-1.7.1-7.fc39.x86_64
```

この辺は修正
```diff
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Qemu_mps2/FreeRTOSConfig.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Qemu_mps2/FreeRTOSConfig.h
index d037f4fe..828ed671 100644
--- a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Qemu_mps2/FreeRTOSConfig.h
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Qemu_mps2/FreeRTOSConfig.h
@@ -99,4 +99,4 @@ http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_Echo_Clients.html */
-#define configECHO_SERVER_ADDR0 10
-#define configECHO_SERVER_ADDR1 136
-#define configECHO_SERVER_ADDR2 206
-#define configECHO_SERVER_ADDR3 133
+#define configECHO_SERVER_ADDR0 192
+#define configECHO_SERVER_ADDR1 168
+#define configECHO_SERVER_ADDR2 1
+#define configECHO_SERVER_ADDR3 80
@@ -110,6 +110,6 @@ configure the real network connection to use. */
-#define configMAC_ADDR0    0x52
-#define configMAC_ADDR1    0x54
-#define configMAC_ADDR2    0x00
-#define configMAC_ADDR3    0x12
-#define configMAC_ADDR4    0x34
-#define configMAC_ADDR5    0xAD
+#define configMAC_ADDR0    0xf6
+#define configMAC_ADDR1    0x78
+#define configMAC_ADDR2    0x99
+#define configMAC_ADDR3    0x65
+#define configMAC_ADDR4    0xf6
+#define configMAC_ADDR5    0x32
@@ -120,4 +120,4 @@ ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */
-#define configIP_ADDR0      10
-#define configIP_ADDR1      211
-#define configIP_ADDR2      55
-#define configIP_ADDR3      5
+#define configIP_ADDR0      192
+#define configIP_ADDR1      168
+#define configIP_ADDR2      1
+#define configIP_ADDR3      81
@@ -128,4 +128,4 @@ ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */
-#define configGATEWAY_ADDR0 10
-#define configGATEWAY_ADDR1 211
-#define configGATEWAY_ADDR2 55
-#define configGATEWAY_ADDR3 1
+#define configGATEWAY_ADDR0 192
+#define configGATEWAY_ADDR1 168
+#define configGATEWAY_ADDR2 1
+#define configGATEWAY_ADDR3 80
@@ -137,4 +137,4 @@ to 1 but a DNS server cannot be contacted.*/
-#define configDNS_SERVER_ADDR0  127
-#define configDNS_SERVER_ADDR1  0
-#define configDNS_SERVER_ADDR2  0
-#define configDNS_SERVER_ADDR3  53
+#define configDNS_SERVER_ADDR0  192
+#define configDNS_SERVER_ADDR1  168
+#define configDNS_SERVER_ADDR2  1
+#define configDNS_SERVER_ADDR3  80
@@ -148,0 +149,2 @@ ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */
+#define mainCREATE_TCP_ECHO_TASKS_SINGLE 1
+

```


## FreeRTOSの実行

### Qemu上の mps2-an385
make して実行してみる

```
$ sudo qemu-system-arm -machine mps2-an385 -cpu cortex-m3           -kernel ./build/freertos_tcp_mps2_demo.axf           -netdev tap,id=mynet0,ifname=virbr0-nic,script=no           -net nic,macaddr=f6:78:99:65:f6:32,model=lan9118,netdev=mynet0           -object filter-dump,id=tap_dump,netdev=mynet0,file=/tmp/qemu_tap_dump          -display gtk -m 16M  -nographic -serial stdio           -monitor null -semihosting -semihosting-config enable=on,target=native 
0->prvMiscInitialisation 253: Seed for randomiser: 0
0->prvMiscInitialisation 260: Random numbers: 00001904 000037D4 0000403D 00001223
0->main_tcp_echo_client_tasks 148: FreeRTOS_IPInit
0x2000bb70->main_tcp_echo_client_tasks 156: vTaskStartScheduler
0x2000bb70->prvIPTask 263: prvIPTask started
0x2000bb70->vApplicationIPNetworkEventHook 210: 

IP Address: 192.168.1.81
0x2000bb70->vApplicationIPNetworkEventHook 213: Subnet Mask: 255.255.255.0
0x2000bb70->vApplicationIPNetworkEventHook 216: Gateway Address: 192.168.1.80
0x2000bb70->vApplicationIPNetworkEventHook 219: DNS Server Address: 192.168.1.80


connecting to echo server....
0x20015940->prvTCPConnectStart 3042: FreeRTOS_connect: 14183 to c0a80150ip:7
0x20015940->vTCPStateChange 499: Socket 14183 -> c0a80150ip:7 State eCLOSED->eCONNECT_SYN
0x2000bb70->prvTCPPrepareConnect 634: ARP for c0a80150ip (using c0a80150ip): rc=0 00:00:00 00:00:00
qemu-system-arm: terminating on signal 2
qemu-system-arm: network script /etc/qemu-ifdown failed with status 256

```

だめですねぇ

取得したパケットダンプをWiresharkで見てみると
arp応答が返ってこなくて接続のトライもせずに諦めてるっぽい

![freertos_demo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2383810/48de42be-a702-9f81-803a-863aebf97f4d.png)



### QEMUなしでPosix版のデモを動かしてみる

```
Starting program: /home/voyager/workspace/freertos/freertos_cm3/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Posix/build/posix_tcp_demo 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[New Thread 0x59a000 (LWP 54945)]

Trace started.
The trace will be dumped to disk if a call to configASSERT() fails.

The trace will be dumped to disk if Enter is hit.
Starting echo client demo
Seed for randomiser: 1703575036
Random numbers: 00007EA6 00007EC1 000021FC 0000077B
FreeRTOS_IPInit

Trace output saved to Trace.dump
[New Thread 0x590440 (LWP 54947)]
vTaskStartScheduler
[New Thread 0x4d0100 (LWP 54949)]
prvIPTask started


The following network interfaces are available:

Interface 1 - enp0s25
              (No description)

Interface 2 - wlp3s0
              (No description)

Interface 3 - docker0
              (No description)

Interface 4 - vethd804e4b
              (No description)

Interface 5 - virbr0
              (No description)

Interface 6 - any
              (Pseudo-device that captures on all interfaces)

Interface 7 - lo
              (No description)

Interface 8 - virbr0-nic
              (No description)

Interface 9 - bluetooth0
              (Bluetooth adapter number 0)

Interface 10 - bluetooth-monitor
              (Bluetooth Linux Monitor)

Interface 11 - usbmon2
              (Raw USB traffic, bus number 2)

Interface 12 - usbmon1
              (Raw USB traffic, bus number 1)

Interface 13 - usbmon0
              (Raw USB traffic, all USB buses)

Interface 14 - nflog
              (Linux netfilter log (NFLOG) interface)

Interface 15 - nfqueue
              (Linux netfilter queue (NFQUEUE) interface)


The interface that will be opened is set by "configNETWORK_INTERFACE_TO_USE", which
should be defined in FreeRTOSConfig.h
Attempting to open interface number 1.
opening interface enp0s25
setting device modes of operation...
Configuring Capture behaviour
pcap filter to compile: broadcast or multicast or ether host 0:11:22:33:44:41
Successfully opened interface number 1.
Creating Threads ..
[New Thread 0x7ffff7afa6c0 (LWP 54950)]
[New Thread 0x7ffff72f96c0 (LWP 54951)]
[New Thread 0x7ffff6af7680 (LWP 54952)]
[New Thread 0x4ae400 (LWP 54953)]
connecting to echo server....
FreeRTOS_connect: 30611 to c0a80150ip:7
Socket 30611 -> c0a80150ip:7 State eCLOSED->eCONNECT_SYN
ARP for c0a80150ip (using c0a80150ip): rc=0 9F:C7:41 00:00:00
Connect[c0a80150ip:7]: next timeout 1: 500 ms
Sending  ========== > data pcap_sendpadcket 42
FF FF FF FF FF FF 00 11 22 33 44 41 08 06 00 01 08 00 06 04 00 01 00 11 22 33 44 41 C0 A8 01 52 00 00 00 00 00 00 C0 A8 01 50 
ARP for c0a80150ip (using c0a80150ip): rc=0 9F:C7:41 00:00:00
Connect[c0a80150ip:7]: next timeout 2: 500 ms
Sending  ========== > data pcap_sendpadcket 42
FF FF FF FF FF FF 00 11 22 33 44 41 08 06 00 01 08 00 06 04 00 01 00 11 22 33 44 41 C0 A8 01 52 00 00 00 00 00 00 C0 A8 01 50 
ARP for c0a80150ip (using c0a80150ip): rc=0 9F:C7:41 00:00:00
Connect[c0a80150ip:7]: next timeout 3: 500 ms
Sending  ========== > data pcap_sendpadcket 42
FF FF FF FF FF FF 00 11 22 33 44 41 08 06 00 01 08 00 06 04 00 01 00 11 22 33 44 41 C0 A8 01 52 00 00 00 00 00 00 C0 A8 01 50 
Connect: giving up c0a80150ip:7
Move from eCONNECT_SYN to eCLOSE_WAIT
Socket 30611 -> c0a80150ip:7 State eCONNECT_SYN->eCLOSE_WAIT
FreeRTOS_connect() stopped due to an error
Could not connect to server -128
FreeRTOS_closesocket[30611 to c0a80150ip:7]: buffers 60 socks 0
connecting to echo server....
FreeRTOS_connect: 28283 to c0a80150ip:7
Socket 28283 -> c0a80150ip:7 State eCLOSED->eCONNECT_SYN
ARP for c0a80150ip (using c0a80150ip): rc=0 9F:C7:41 00:00:00
Connect[c0a80150ip:7]: next timeout 1: 500 ms
Sending  ========== > data pcap_sendpadcket 42
FF FF FF FF FF FF 00 11 22 33 44 41 08 06 00 01 08 00 06 04 00 01 00 11 22 33 44 41 C0 A8 01 52 00 00 00 00 00 00 C0 A8 01 50 
ARP for c0a80150ip (using c0a80150ip): rc=0 9F:C7:41 00:00:00
Connect[c0a80150ip:7]: next timeout 2: 500 ms
Sending  ========== > data pcap_sendpadcket 42
FF FF FF FF FF FF 00 11 22 33 44 41 08 06 00 01 08 00 06 04 00 01 00 11 22 33 44 41 C0 A8 01 52 00 00 00 00 00 00 C0 A8 01 50 
ARP for c0a80150ip (using c0a80150ip): rc=0 9F:C7:41 00:00:00
Connect[c0a80150ip:7]: next timeout 3: 500 ms
Sending  ========== > data pcap_sendpadcket 42
FF FF FF FF FF FF 00 11 22 33 44 41 08 06 00 01 08 00 06 04 00 01 00 11 22 33 44 41 C0 A8 01 52 00 00 00 00 00 00 C0 A8 01 50 
Connect: giving up c0a80150ip:7
```

stateはSYNと表示されているがSYNパケット送って無いぞ？？？
つまり全く同じ事象が発生している。

ちなみに使ったデモ2つは3.1.0版。ARPの解決が出来ないのでいつまでたってもつながらない。

### qemu上のLinuxから試してみる

[ディスクイメージ](https://ftp.yz.yamagata-u.ac.jp/pub/linux/centos-altarch/7.9.2009/isos/armhfp/CentOS-Userland-7-armv7hl-generic-Minimal-2009-sda.raw.xz)と[u-boot](https://git.altlinux.org/tasks/331918/build/100/armh/rpms/u-boot-qemu-2023.10-alt1.armh.rpm)を落としてきて

qemuを実行
```
qemu-system-arm -M virt -m 1G \
 -netdev user,id=unet -device virtio-net-pci,netdev=unet \
 -drive id=sda,format=raw,file=CentOS-Userland-7-armv7hl-generic-Minimal-2009-sda.raw \
 -bios u-boot_armh.bin \
 -nographic
 
```
ん？ログイン出来ないぞ？
なんかrootパスワード変更しないとダメらしい

```
sudo yum install -y /usr/bin/virt-customize
virt-customize --format raw -a CentOS-Userland-7-armv7hl-generic-Minimal-2009-sda.raw --root-password password:root
```
ログイン出来た
```
localhost login: root
Password: 
[root@localhost ~]# 
```

pingは飛ぶ
```
ping 192.168.1.80
PING 192.168.1.80 (192.168.1.80) 56(84) bytes of data.
64 bytes from 192.168.1.80: icmp_seq=1 ttl=255 time=24.7 ms
64 bytes from 192.168.1.80: icmp_seq=2 ttl=255 time=1.49 ms

--- 192.168.1.80 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1012ms
rtt min/avg/max/mdev = 1.496/13.140/24.785/11.645 ms
```

gcc 入れて
```
yum install -y gcc vim
...
Transaction check error:
  installing package glibc-common-2.17-326.el7_9.armv7hl needs 44MB on the / filesystem
```
まじかー。1.7Gしかない
```
# df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
devtmpfs       devtmpfs  441M     0  441M   0% /dev
tmpfs          tmpfs     500M     0  500M   0% /dev/shm
tmpfs          tmpfs     500M   13M  487M   3% /run
tmpfs          tmpfs     500M     0  500M   0% /sys/fs/cgroup
/dev/vda4      ext4      1.7G  1.4G  194M  89% /
/dev/vda2      ext3      641M  203M  432M  32% /boot
/dev/vda1      vfat       95M   26M   70M  27% /boot/fw
tmpfs          tmpfs     100M     0  100M   0% /run/user/0
```

ディスクを拡張してリトライ

```
qemu-img resize CentOS-Userland-7-armv7hl-generic-Minimal-2009-sda.raw 8G
qemu-system-arm -M virt -m 1G \
 -netdev user,id=unet -device virtio-net-pci,netdev=unet \
 -drive id=sda,format=raw,file=CentOS-Userland-7-armv7hl-generic-Minimal-2009-sda.raw \
 -bios u-boot_armh.bin \
 -nographic
```
起動したらパーティションとファイルシステムをそれぞれ拡張して
```
# growpart /dev/vda 4
CHANGED: partition=4 start=2570240 old: size=3516416 end=6086656 new: size=14206943 end=16777183
# df -hT
...
/dev/vda4      ext4      1.7G  1.3G  354M  79% /
# lsblk 
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
vda    252:0    0    8G  0 disk 
├─vda4 252:4    0  6.8G  0 part /
...
# resize2fs /dev/vda4
resize2fs 1.42.9 (28-Dec-2013)
Filesystem at /dev/vda4 is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 1
The filesystem on /dev/vda4 is now 1775867 blocks long.
# df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
...
/dev/vda4      ext4      6.7G  1.3G  5.4G  19% /
```
インストールして
```
# yum install -y gcc vim
```


適当にコード書いてgccでコンパイル
<details>
<summary>環境チェックで使ったのと一緒</summary>

```c
#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>

#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define d(s, ...)                                                                 \
    do                                                                            \
    {                                                                             \
        printf("%s(%d) %s " s "\n", __FILENAME__, __LINE__, __func__, ##__VA_ARGS__); \
    } while (0)

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

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

#define TARGET_SERVER_IP "192.168.1.80"
#define TARGET_SERVER_PORT 7
#define BUF_SIZE 0x10000


static char *b2s(uint8_t *data, size_t len);
static void send_tcp(uint8_t *data, size_t len);

static char rx_buf[BUF_SIZE];
static char print_buf[BUF_SIZE];

int main(void) {
    const char* msg = "this is sample\n";
    send_tcp((uint8_t*)msg, strlen(msg));
    return 0;
}

static void send_tcp(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.");

    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");

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

    ret = recv(sock, rx_buf, BUF_SIZE, 0);
    if (ret > 0) {
        d("response:%s", b2s((uint8_t*)rx_buf, ret));
    }

error_return:
    if (sock >= 0)
        close(sock);
    return;
}

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;
}

```
</details>



ホストにサーバ立てて
```shell
sudo nc -l 7
```
qemuから実行
```
./a.out
```
つながりますねぇ
```shell
$ sudo nc -l 7
this is sample
this is nc
```
```shell
# ./a.out 
a.c(69) send_tcp response:74 68 69 73 20 69 73 20 6e 63 0a                this is nc.

```

パケットダンプも見てみる
-object filter-dumpを追加してnetdevを紐付ける
```
qemu-system-arm -M virt -m 1G \
 -netdev user,id=unet -device virtio-net-pci,netdev=unet \
 -object filter-dump,id=f1,netdev=unet,file=/tmp/packet.dat \
 -drive id=sda,format=raw,file=CentOS-Userland-7-armv7hl-generic-Minimal-2009-sda.raw \
 -bios u-boot_armh.bin \
 -nographic
```

arp replyがすぐに返っていることがわかる。しかもフォーマットが違うっぽい
0padding以外は一緒なんだけど関係あるのか？
![arp_reply_ok.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2383810/fd388a6f-3f46-582b-5d78-e3a69266af1c.png)

一旦ドライバに実装してみるか
これでだめならFreeRTOSのIPスタックみるしかなさそう

----
# 参考
https://mikoto2000.blogspot.com/2021/01/qemu-system-arm-debian-buster-armhf.html