2303947_ja-JP

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

2303947_ja-JP

2303947_ja-JP

ENET ドライバフリーズ LPC546
こんにちは、

LPC54628J512の ENET ドライバに問題があります。VLAN下のネットワークで、別のVLANからMTUサイズのパケットを受信すると、デバイスがフリーズしました。

1 - コンテキスト

ネットワーク設定は次の図に示されています。
Capture d'écran 2026-01-30 114010.png

2 - 問題

問題は、MTU サイズのパケット、または断片化されたパケットの最初のフラグメントを受信すると発生します (この場合、これは KDEConnect クライアント ソフトウェアからの ≃2000 サイズのペイロード パケットです)。パケットがデバイス VLAN (192.168.16.255) に直接送信される場合、問題はありません。しかし、デバイスが別の VLAN (192.168.11.255) から来て、メインスイッチによって他の VLAN に再送信されると、フリーズが発生します。

3 - 分析

LWIP_ASSERTをアクティブにした後、ethernetif_rx_frame_to_pbufs()でアサートを取得しました。
 
buffer       = rxFrame->rxBuffArray[i].buffer;    // corrupted
bufferLength = rxFrame->rxBuffArray[i].length;    // corrupted
len += bufferLength;

/* Find pbuf wrapper for the actually read byte buffer */
idx = ((rx_buffer_t *)(((uint8_t *)buffer) - ETH_PAD_SIZE)) - ethernetif->RxDataBuff;
LWIP_ASSERT("Buffer returned by ENET_GetRxFrame() doesn't match any RX buffer descriptor",
            ((idx >= 0) && (idx < ENET_RXBUFF_NUM)));

- idx = 1953659110
- bufferLenght = 65535 (または -1)

この時点で、rxFrame からのデータは非常に無効なデータであることがわかります。SO、この構造体を埋める ENET_GetRxFrame() の値を分析してみましょう。

結果は次のとおりです (簡略化されたコード)。
/* Get the valid frame */
index = 0;
do
{
    rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx];

    /* Calculate the buffer and frame length. */
    if ((rxDesc->rdes3 & ENET_RXDESCRIP_WR_LD_MASK) != 0U)
    {
        isLastBuff      = true;
        rxFrame->totLen = (uint16_t)(rxDesc->rdes3 & ENET_RXDESCRIP_WR_PACKETLEN_MASK);

        if (rxFrame->totLen - offset > (uint16_t)rxBdRing->rxBuffSizeAlign)
        {
            buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
            if (handle->doubleBuffEnable)
            {
                buff2Len = rxFrame->totLen - offset - (uint16_t)rxBdRing->rxBuffSizeAlign - ENET_FCS_LEN;
            }
        }
        else
        {
            buff1Len = rxFrame->totLen - offset - ENET_FCS_LEN;
        }
        rxFrame->totLen -= ENET_FCS_LEN;
    }
    else
    {
        if (!handle->doubleBuffEnable)
        {
            buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
            offset += buff1Len;
        }
        else
        {
            buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
            buff2Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
            offset += buff1Len + buff2Len;
        }
    }

    // <-- Check data here (assert on invalid buff1Len)

    /* Allocate new buffer to replace the buffer taken by application */

    if (!isDrop)
    {
        /* Get the frame data information into Rx frame structure. */

        /* Give new buffer from application to BD */
    }
    else
    {
        /* Drop frame if there's no new buffer memory */
    }
} while (!isLastBuff);
 
- buff1Len = 65534 (または -2)
- rxDesc->rdes3 & ENET_RXDESCRIP_WR_LD_MASK = 1522
- rxFrame->totLen = 1518
-オフセット = 1520

最大バッファ サイズが aligned(1518) = 1520 であることがわかっているので、rxDescriptor によって報告されるフレームの長さはこの値の 2 倍になります。これはデータオーバーフローの原因である可能性があります...

4 - 不良パケット

問題のパケットは、別の VLAN から送信され、メイン スイッチによって再送信される断片化されたパケットです。
同じパケットをデバイス VLAN から直接送信しても、別の VLAN から送信しても、同じ効果は得られませんが、Wireshark でパケットを分析すると、MAC 層ヘッダーからペイロード データまでまったく同じになります (もちろん、ソースとタイムスタンプは除きます)。
 
VLAN コントローラがパケットを送信すると、IP レイヤー ヘッダーにいくつかの追加情報が追加されることがわかりました。https://en.wikipedia.org/wiki/IEEE_802.1Qを参照してください。これは 4 つの追加バイトを表し、1518 の長さのパケットを 1522 にすることができます。
ほとんどのネットワーク インターフェイスはこれらのデータを独自に処理し、パケットから削除するため、通常、これらのデータは Wireshark には表示されません。これは、いくつかのより「インテリジェント」なスイッチの場合でも同様であり、それらのスイッチを使用すると、問題は解消されます。
Linux では、これらのパケットの削除を停止するためのいくつかのトリックを実行できます。Wiresharkで見てみましょう

image (5).png

5 - ENETドライバの代替についてさらに情報が必要
私のプログラムでは、NXP MCUXPresso SDk Core の ドライバ/lpc_enet/ フォルダーから fsl_enet.c/.h を使用します。現在、v2.12.0 を使用していますが、github の最新バージョンも試しました。
ドライバ/enet/ の下に、ENET の別の実装があることがわかります。私の理解では、これはより汎用的な実装ですが、iMX シリーズなどのより高度な CPU 向けに、より多くのネットワーク機能 (VLAN など) もサポートしています。
enet/ ドライバでコンパイルできませんでした。iMX プラットフォームでのみ利用可能な定義がいくつか不足しているからです。このドライバを LPC546 で使用できる可能性はありますか?

lucas3_0-1769791382375.png
このバグの処理や、ドライバの他のバリエーションへの移行について、誰かが手助けしてくれることを願っています。
ありがとうございます
ルーカス


Re: ENET driver freeze LPC546

こんにちは@lucas3

enet/ ドライバでコンパイルできませんでした。iMX プラットフォームでのみ利用可能な定義がいくつか不足しているからです。このドライバを LPC546 で使用できる可能性はありますか?

ドライバ/ネット/(i.MXシリーズユニバーサルドライバー)に直接切り替えることはできません

このドライバは LPC ではなく i.MX 用に設計されており、すぐには使用できません。

あなたの説明に基づきます。

フリーズは、別の VLAN から送信される VLAN タグ付きフレーム (回線上で約 1522 バイト) によってのみトリガーされます。現在の lpc_enet RX パスは 1518 バイトのフレームを想定しています。

1522 バイトのフレームが到着すると、RX の長さ/オフセットの計算がアンダーフローし (例: buff1Len = -2)、RX フレーム構造が破損し、LWIP_ASSERT がトリップします。

Harry_Zhang_0-1770366880148.png


SO i think you CAN try to change the ENET_RXBUFF_SIZE to 1522.

BR

ハリー

Tags (1)
No ratings
Version history
Last update:
‎02-07-2026 02:29 AM
Updated by: