前回の続き
NICの実装
connectが弾かれる原因を調べる
NetworkInterface.cはgitに含まれないので現時点のものを転記
NetworkInterface.c
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
* Note: This file is Not! to be used as is. The purpose of this file is to provide
* a template for writing a network interface. Each network interface will have to provide
* concrete implementations of the functions in this file.
*
* See the following URL for an explanation of this file and its functions:
* https://freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Porting.html
*
*****************************************************************************/
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "list.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "dlog.h"
/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
* driver will filter incoming packets and only pass the stack those packets it
* considers need processing. */
#if (ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0)
#define ipCONSIDER_FRAME_FOR_PROCESSING(pucEthernetBuffer) eProcessBuffer
#else
#define ipCONSIDER_FRAME_FOR_PROCESSING(pucEthernetBuffer) eConsiderFrameForProcessing((pucEthernetBuffer))
#endif
BaseType_t xNetworkInterfaceInitialise(void)
{
/* FIX ME. */
d("");
return pdTRUE;
}
BaseType_t xNetworkInterfaceOutput(NetworkBufferDescriptor_t *const pxNetworkBuffer,
BaseType_t xReleaseAfterSend)
{
if (pxNetworkBuffer)
{
d("eb:%p ip:%lu bp:%u p:%u"
" ct:%p ow:%p n:%p p:%p iv:%lu len:%u aft:%ld",
pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->ulIPAddress, pxNetworkBuffer->usBoundPort, pxNetworkBuffer->usPort, pxNetworkBuffer->xBufferListItem.pvContainer, pxNetworkBuffer->xBufferListItem.pvOwner, pxNetworkBuffer->xBufferListItem.pxNext, pxNetworkBuffer->xBufferListItem.pxPrevious, pxNetworkBuffer->xBufferListItem.xItemValue, pxNetworkBuffer->xDataLength, xReleaseAfterSend);
}
else
{
d("");
}
return pdTRUE;
}
void vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])
{
(void)pxNetworkBuffers;
/* FIX ME. */
d("");
}
BaseType_t xGetPhyLinkStatus(void)
{
/* FIX ME. */
d("");
return pdFALSE;
}
BaseType_t xApplicationGetRandomNumber(uint32_t *pulNumber)
{
d("");
return *pulNumber + 1;
}
uint32_t ulApplicationGetNextSequenceNumber(uint32_t ulSourceAddress,
uint16_t usSourcePort,
uint32_t ulDestinationAddress,
uint16_t usDestinationPort)
{
(void)ulSourceAddress;
(void)usSourcePort;
(void)ulDestinationAddress;
(void)usDestinationPort;
uint32_t pulNumber = 0;
d("");
xApplicationGetRandomNumber(&pulNumber);
return pulNumber;
}
struct xNetworkInterface *pxFillInterfaceDescriptor(BaseType_t xEMACIndex,
struct xNetworkInterface *pxInterface)
{
d("mac:%lx", (uint32_t)xEMACIndex);
return pxInterface;
}
connectが弾かれる原因
こんな感じで呼ばれているけど
(gdb) bt
#0 prvTCPConnectStart (pxSocket=pxSocket@entry=0x20012d90, pxAddress=pxAddress@entry=0x20012a1c) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_Sockets.c:3660
#1 0x0000a686 in FreeRTOS_connect (xClientSocket=xClientSocket@entry=0x20012d90, pxAddress=0x20012a1c, pxAddress@entry=0x20012a60, xAddressLength=xAddressLength@entry=24) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_Sockets.c:3792
#2 0x0000df04 in vTCPSend (pcBufferToTransmit=pcBufferToTransmit@entry=0x20011414 <buf> "aiueo", xTotalLengthToSend=xTotalLengthToSend@entry=5) at app_client.c:55
#3 0x0000e000 in client_task (param=<optimized out>) at app_client.c:32
#4 0x00000280 in prvPortStartFirstTask () at /home/voyager/workspace/freertos/FreeRTOSv202212.01/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c:247
prvTCPConnectStart
にはすでに接続済みじゃなければ
設定だけしてつないでくれるのを待っているっぽい
3714 #if ( ipconfigUSE_IPv4 != 0 )
3715 case FREERTOS_AF_INET4:
3716 pxSocket->bits.bIsIPv6 = pdFALSE_UNSIGNED;
3717 FreeRTOS_printf( ( "FreeRTOS_connect: %u to %xip:%u\n",
3718 pxSocket->usLocalPort, ( unsigned int ) FreeRTOS_ntohl( pxAddress-> sin_address.ulIP_IPv4 ), FreeRTOS_ntohs( pxAddress->sin_port ) ) );
3719 pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 = FreeRTOS_ntohl( pxAddress->sin_address.ulIP_IPv 4 );
3720 break;
3721 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
なので誰か(まず間違いなくNIC)から接続完了を送ってやる必要がある
ドキュメントをよく読んで見る。
xSendEventStructToIPTask
を呼び出す必要があるらしい。
実機につながっていないので 偽のether_task
を作成し、
そこから呼び出すようにする。
あとTCP部分(NetworkInerface.c)は別にした
https://github.com/tyano461/freertos_cm3/commit/d0065333f02b60a60f010da731308fe2cfa8bc88
https://github.com/tyano461/freertos_tcpv4
sudo qemu-system-arm -machine mps2-an385 -monitor null -semihosting --semihosting-config enable=on,target=native -kernel ./build/RTOSDemo.axf -serial stdio -nographic
[0000] NetworkInterface.c(127) pxFillInterfaceDescriptor mac:0 fr:0x5437
[1c18] NetworkInterface.c(170) ether_task fr:0x281
[1c18] NetworkInterface.c(176) ether_task i:0 ep:0 ip:0 po:0 bp:0 fr:0x281
[67ac] FreeRTOS_IP.c(1397) xSendEventStructToIPTask et:0 fr:0x574d
[2450] app_server.c(14) server_task fr:0x281
[2450] app_server.c(31) vCreateTCPServerSocket sock:536948040 fr:0xd8bd
[2450] FreeRTOS_IP.c(1397) xSendEventStructToIPTask et:9 fr:0x99f7
[2c88] app_client.c(28) client_task fr:0x281
[2c88] app_client.c(44) vTCPSend IN fr:0xd7a1
[2c88] app_client.c(54) vTCPSend socket fr:0xd7a1
[2c88] FreeRTOS_Sockets.c(3783) FreeRTOS_connect fr:0xd6a5
[2c88] FreeRTOS_IP.c(1397) xSendEventStructToIPTask et:9 fr:0x99f7
[67ac] NetworkInterface.c(103) xApplicationGetRandomNumber fr:0x89a7
[2450] app_server.c(45) vCreateTCPServerSocket bind fr:0xd8bd
[2450] app_server.c(48) vCreateTCPServerSocket listen fr:0xd8bd
[2c88] FreeRTOS_Sockets.c(3694) prvTCPConnectStart fr:0x9d1f
[2c88] FreeRTOS_Sockets.c(3701) prvTCPConnectStart fam:2 fr:0x9d1f
[2c88] FreeRTOS_Sockets.c(3717) prvTCPConnectStart FreeRTOS_connect: lp:1024 -> a0a0ac8:10000 fr:0x9d1f
[2c88] FreeRTOS_IP.c(1397) xSendEventStructToIPTask et:6 fr:0x57c3
[67ac] NetworkInterface.c(151) pfOutput fr:0x3db9
[2c88] FreeRTOS_Sockets.c(3797) FreeRTOS_connect prvTCPConnectStart:0 fr:0xd6a5
[67ac] NetworkInterface.c(151) pfOutput fr:0x3db9
[1c18] NetworkInterface.c(176) ether_task i:0 ep:0 ip:0 po:0 bp:0 fr:0x281
[1c18] FreeRTOS_IP.c(1397) xSendEventStructToIPTask et:1 fr:0xd3b1
[67ac] NetworkInterface.c(151) pfOutput fr:0x3db9
[2c88] app_client.c(84) vTCPSend not connected fr:0xd7a1
[2c88] FreeRTOS_IP.c(1397) xSendEventStructToIPTask et:10 fr:0x9e53
[2c88] app_client.c(105) vTCPSend OUT fr:0xd7a1
[1c18] NetworkInterface.c(176) ether_task i:0 ep:0 ip:0 po:0 bp:0 fr:0x281
[1c18] FreeRTOS_IP.c(1397) xSendEventStructToIPTask et:1 fr:0xd3b1
うーんあまり代わり映えがない。
ちゃんとしたパケットを送ってやらないとだめっぽい。(そりゃそうか)
ARP Request
pfOutputが呼ばれているのでどこから何を呼ばれているかよく見てみる
0x3db9は−1して0x3db8から呼ばれているはず
arm-none-eabi-objdump -d build/RTOSDemo.axf | grep 3db8: -B15
3d9a: bf00 nop
3d9c: 00010734 .word 0x00010734
00003da0 <FreeRTOS_OutputARPRequest>:
3da0: b570 push {r4, r5, r6, lr}
3da2: b082 sub sp, #8
3da4: 4606 mov r6, r0
3da6: 2000 movs r0, #0
3da8: f004 f93a bl 8020 <FreeRTOS_FirstEndPoint>
3dac: 4604 mov r4, r0
3dae: e008 b.n 3dc2 <FreeRTOS_OutputARPRequest+0x22>
3db0: 68c3 ldr r3, [r0, #12]
3db2: 2201 movs r2, #1
3db4: 4629 mov r1, r5
3db6: 4798 blx r3
3db8: 4621 mov r1, r4
FreeRTOS_OutputARPRequest
から呼ばれている
ARP Requestが行われているらしい。
gdb でも確認してみる。
(gdb) bt
#0 pfOutput (pxDescriptor=0x20006804 <xInterfaces.6>, pxNetworkBuffer=0x20010a2c <xNetworkBufferDescriptors.0+56>, xReleaseAfterSend=1) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/portable/NetworkInterface/virtether/NetworkInterface.c:147
#1 0x00003db8 in FreeRTOS_OutputARPRequest (ulIPAddress=3356101130) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_ARP.c:1316
#2 0x0000bdec in prvTCPPrepareConnect_IPV4 (pxSocket=0x20012f30) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_TCP_Transmission_IPv4.c:367
#3 0x0000b59a in prvTCPPrepareConnect (pxSocket=<optimized out>) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_TCP_Transmission.c:496
#4 0x0000b5b6 in prvTCPMakeSurePrepared (pxSocket=<optimized out>) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_TCP_Transmission.c:87
#5 0x0000ba2c in prvTCPSendPacket (pxSocket=pxSocket@entry=0x20012f30) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_TCP_Transmission.c:139
#6 0x0000a3fe in xTCPSocketCheck (pxSocket=pxSocket@entry=0x20012f30) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_TCP_IP.c:226
#7 0x00009246 in xTCPTimerCheck (xWillSleep=xWillSleep@entry=1) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_Sockets.c:4824
#8 0x00005f14 in vCheckNetworkTimers () at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_IP_Timers.c:302
#9 0x00005bbc in prvProcessIPEventsAndTimers () at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_IP.c:268
#10 0x00005ce6 in prvIPTask (pvParameters=<optimized out>) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_IP.c:249
#11 0x00000280 in prvPortStartFirstTask () at /home/voyager/workspace/freertos/FreeRTOSv202212.01/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c:247
pxEndPoint->pxNetworkInterface->pfOutputから呼ばれているで間違いなさそう
(gdb) f 1
#1 0x00003db8 in FreeRTOS_OutputARPRequest (ulIPAddress=3356101130) at /home/voyager/workspace/freertos/FreeRTOS-Plus-TCP/source/FreeRTOS_ARP.c:1316
1316 ( void ) pxEndPoint->pxNetworkInterface->pfOutput( pxEndPoint->pxNetworkInterface, pxNetworkBuffer, pdTRUE );
(gdb) l
1311 iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
1312
1313 /* Only the IP-task is allowed to call this function directly. */
1314 if( pxEndPoint->pxNetworkInterface != NULL )
1315 {
1316 ( void ) pxEndPoint->pxNetworkInterface->pfOutput( pxEndPoint->pxNetworkInterface, pxNetworkBuffer, pdTRUE );
1317 }
1318 }
1319 else
1320 {
なので受け側で内容をよく見てみる。
[67ac] NetworkInterface.c(150) pfOutput ip:c80a0a0a po:0 bp:0 fr:0x3db9
IPが今回設定したものになっている。
arpなのでportとかは設定されていない。
詳細はこんな感じ。ARPパケットとは微妙に違うっぽい気がするけど
etherフレームがくっついてきているらしい
[67ac] NetworkInterface.c(151) pfOutput ip:c80a0a0a po:0 bp:0 len:42 data:
ff ff ff ff ff ff 00 11 22 33 44 55 08 06 00 01
08 00 06 04 00 01 00 11 22 33 44 55 0a 0a 0a c8
00 00 00 00 00 00 0a 0a 0a c8
ここの0x14番目の 00 01
が usOperation
で ipARP_REQUEST
に該当するらしい
https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/d70a21ce03569118e030b348844477b92f5fd227/source/FreeRTOS_ARP.c#L1420
なので 00 01
を受け取ったらARP応答を投げれば良さそう???
pfOutput
で受け取ったものをこんな感じで埋めていって投げてみる
if (descriptor)
{
ev.eEventType = eNetworkRxEvent;
memcpy(descriptor, &g_desc, sizeof(NetworkBufferDescriptor_t));
descriptor->pucEthernetBuffer = (uint8_t *)&g_arp;
ev.pvData = descriptor;
arp = (ARPPacket_t *)descriptor->pucEthernetBuffer;
ah = &arp->xARPHeader;
eth = &arp->xEthernetHeader;
if (ah->usOperation == ipARP_REQUEST)
{
mac = ah->xSenderHardwareAddress;
from = *(uint32_t *)ah->ucSenderProtocolAddress;
addr = ah->ulTargetProtocolAddress;
ah->usOperation = ipARP_REPLY;
ah->xSenderHardwareAddress = connectedMac;
memcpy(ah->ucSenderProtocolAddress, &addr, sizeof(addr));
ah->ulTargetProtocolAddress = from;
ah->xTargetHardwareAddress = mac;
eth->xDestinationAddress = mac;
eth->xSourceAddress = connectedMac;
d("send %s", b2s(arp, sizeof(ARPPacket_t)));
xSendEventStructToIPTask(&ev, 0);
}
else
{
d("arp op:%d", arp->xARPHeader.usOperation);
}
descriptor = NULL;
}
else
{
d("descriptor is null");
}
受信パケットはこんな感じ
送信パケットはこんな感じ
[1d48] NetworkInterface.c(220) ether_task send
00 11 22 33 44 55 00 11 22 33 44 55 08 06 00 01
08 00 06 04 00 02 00 11 22 33 44 55 0a 0a 0a c8
00 11 22 33 44 55 0a 0a 0a c8
[67ac] NetworkInterface.c(169) pfOutput ip:c80a0a0a po:0 bp:0 len:42 data:
ff ff ff ff ff ff 00 11 22 33 44 55 08 06 00 01
08 00 06 04 00 01 00 11 22 33 44 55 0a 0a 0a c8
00 00 00 00 00 00 0a 0a 0a c8
r:1 fr:0x3db9
FreeRTOS_connectの中でなぜか固まった
(gdb) n
3849 uxEvents = xEventGroupWaitBits( pxSocket->xEventGroup,
(gdb)
^C
Program received signal SIGINT, Interrupt.
prvGetRegistersFromStack (warning: no PSP thread stack unwinding supported.
pulFaultStackAddress=0x20010430 <xIPTaskStack.2+39696>) at init/startup.c:96
96 for( ; ; )
ここまでのcommit
https://github.com/tyano461/freertos_cm3/commit/d55447f7e5790668ca861a3af3140a5de31a389f
https://github.com/tyano461/freertos_tcpv4/commit/e431dbde42f8d252b094a96f9a99b65fc6e0dba6
参考