--- nono/vm/ethernet.cpp 2026/04/29 17:05:18 1.1.1.7 +++ nono/vm/ethernet.cpp 2026/04/29 17:05:46 1.1.1.12 @@ -8,14 +8,15 @@ // Ethernet 基本クラス // +#if !defined(SELFTEST) #include "ethernet.h" #include "config.h" #include "hostnet.h" #include "scheduler.h" // コンストラクタ -EthernetDevice::EthernetDevice() - : inherited(OBJ_ETHERNET) +EthernetDevice::EthernetDevice(uint objid_) + : inherited(objid_) { } @@ -23,7 +24,7 @@ EthernetDevice::EthernetDevice() EthernetDevice::~EthernetDevice() { if ((bool)hostnet) { - hostnet->SetCallbackDevice(NULL); + hostnet->ResetRxCallback(); } } @@ -31,21 +32,30 @@ EthernetDevice::~EthernetDevice() bool EthernetDevice::Create() { - // ホストドライバを作成してこのデバイスと紐付ける - hostnet.reset(new HostNetDevice()); + // ホストドライバを作成してこのデバイスと紐付ける。 + // ポート名は継承先ごとに Init() で設定している。 + int n = GetId() - OBJ_ETHERNET0; + try { + hostnet.reset(new HostNetDevice(this, n, "")); + } catch (...) { } + if ((bool)hostnet == false) { + warnx("Failed to initialize HostNetDevice(%u) at %s", n, __method__); + return false; + } - hostnet->SetRxCallback(ToDeviceCallback(&EthernetDevice::HostRxCallback)); - hostnet->SetCallbackDevice(this); + auto func = ToDeviceCallback(&EthernetDevice::HostRxCallback); + hostnet->SetRxCallback(func, 0); return true; } // これは Host スレッドから呼ばれる void -EthernetDevice::HostRxCallback() +EthernetDevice::HostRxCallback(uint32 dummy) { // スレッドを超えるためにメッセージを投げる - scheduler->SendMessage(MessageID::HOSTNET_RX); + int n = GetId() - OBJ_ETHERNET0; + scheduler->SendMessage(MessageID::HOSTNET_RX(n)); } // 設定ファイルから MAC アドレスを読み込む。 @@ -62,9 +72,10 @@ EthernetDevice::HostRxCallback() // MAC アドレスが指定されているか自動生成したかで取得できれば mac に格納して // true を返す。それ以外の場合は、エラーメッセージを表示して false を返す。 /*static*/ bool -EthernetDevice::GetConfigMacAddr(macaddr_t *mac, bool accept_rom) +EthernetDevice::GetConfigMacAddr(uint n, MacAddr *mac, bool accept_rom) { - const ConfigItem& item = gConfig->Find("ethernet-macaddr"); + std::string keyname = string_format("ethernet%u-macaddr", n); + const ConfigItem& item = gConfig->Find(keyname); const std::string& val = item.AsString(); if (val == "rom") { @@ -94,3 +105,73 @@ EthernetDevice::GetConfigMacAddr(macaddr return true; } + +#endif // !SELFTEST + +// CRC32 を計算する。 +// +// CRC と言ってもおそらく5つのパラメータによって定まる亜種が多数あるが、 +// Ethernet で使われる CRC32 はおそらく以下のもの。 +// 初期値: 0xffffffff +// 多項式: 0x04c11db6 +// RefIn : false +// RefOut: false (出力をビットリバースしない) +// XorOut: false (出力を XOR しない) +// +// NetBSD の src/sys/net/if_ethersubr.c にある ether_crc32_be() がこれと同じ。 +// +// その隣にある ether_crc32_le() は +// 初期値: 0xffffffff +// 多項式: 0xedb88320 +// RefIn : true +// RefOut: false (出力をビットリバースしない) +// XorOut: false (出力を XOR しない) +// というパラメータだが、RefIn と多項式のビットが反転しているだけなので +// 結果をビットリバースすれば同じものになる。 +// +// ちなみに ether_crc32_* の_le, _be はエンディアンではなく、どっち向きに +// 処理するかを示しており、名前が紛らわしい。 +/*static*/ uint32 +EthernetDevice::CRC32(const uint8 *buf, size_t buflen) +{ + static const uint32 CRC_POLY = 0x04c11db6; + uint32 crc; + uint32 cy; + + crc = 0xffffffff; + for (size_t i = 0; i < buflen; i++) { + uint32 s = buf[i]; + for (size_t j = 0; j < 8; j++) { + cy = ((crc & 0x80000000U) ? 0x01 : 0x00) ^ (s & 0x01); + crc <<= 1; + s >>= 1; + if (cy) { + crc = (crc ^ CRC_POLY) | cy; + } + } + } + + return crc; +} + +// MAC アドレスの CRC32 を計算する限定版。 +// 6バイトが uint64 にリトルエンディアン的に格納されていると分かっている。 +/*static*/ uint32 +EthernetDevice::CRC32(const MacAddr& mac) +{ + static const uint32 CRC_POLY = 0x04c11db6; + uint32 crc; + uint64 s = mac.Get(); + + crc = 0xffffffff; + for (size_t i = 0; i < mac.size() * 8; i++) { + uint32 cy = ((crc & 0x80000000U) ? 0x01 : 0x00) ^ (s & 0x01); + crc <<= 1; + s >>= 1; + if (cy) { + crc = (crc ^ CRC_POLY) | cy; + } + } + + return crc; +}