--- nono/vm/ethernet.cpp 2026/04/29 17:04:28 1.1 +++ nono/vm/ethernet.cpp 2026/04/29 17:05:18 1.1.1.7 @@ -1,28 +1,29 @@ // // nono -// Copyright (C) 2019 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // -#include "configfile.h" -#include "ethernet.h" -#include "netdriver_bpf.h" -#include "netdriver_tap.h" -#include "netdriver_none.h" -#include +// +// Ethernet 基本クラス +// -EthernetDevice *gEthernet; +#include "ethernet.h" +#include "config.h" +#include "hostnet.h" +#include "scheduler.h" // コンストラクタ EthernetDevice::EthernetDevice() + : inherited(OBJ_ETHERNET) { } // デストラクタ EthernetDevice::~EthernetDevice() { - if (gNetDriver) { - delete gNetDriver; - gNetDriver = NULL; + if ((bool)hostnet) { + hostnet->SetCallbackDevice(NULL); } } @@ -30,114 +31,66 @@ EthernetDevice::~EthernetDevice() bool EthernetDevice::Create() { - const std::string key = "ethernet.hostdriver"; - const std::string type = gConfig->ReadStr(key, "none"); - if (type == "none") { - gNetDriver = new NetDriverNone(); - } else if (type == "tap") { -#if defined(NETDRIVER_TAP) - try { - gNetDriver = new NetDriverTap(this, &mtx, &cv); - } catch (...) { - warnx("Creating NetDriverTap failed"); - return false; - } -#else - gConfig->Err(key, "\"%s\" not supported", type.c_str()); - return false; -#endif - } else if (type == "bpf") { -#if defined(NETDRIVER_BPF) - try { - gNetDriver = new NetDriverBPF(this, &mtx, &cv); - } catch (...) { - warnx("Creating NetDriverBPF failed"); - return false; - } -#else - gConfig->Err(key, "\"%s\" not supported", type.c_str()); - return false; -#endif - } else { - gConfig->Err(key, "unknown \"%s\"", type.c_str()); - return false; - } - assert(gNetDriver); - - return true; -} + // ホストドライバを作成してこのデバイスと紐付ける + hostnet.reset(new HostNetDevice()); -// 初期化 -bool -EthernetDevice::Init() -{ - if (gNetDriver->Init() == false) { - delete gNetDriver; - gNetDriver = NULL; - return false; - } + hostnet->SetRxCallback(ToDeviceCallback(&EthernetDevice::HostRxCallback)); + hostnet->SetCallbackDevice(this); return true; } -// MAC アドレスをてきとーに生成する。 -// 02:00:01 はローカルだし割り当てもされてなさそうなので使っちゃえ。 -// 下3バイトは乱数。 -/*static*/ void -EthernetDevice::GenerateMacAddr(macaddr_t *addrp) -{ - std::random_device rnd; - uint32 x = rnd(); - - macaddr_t& addr = *addrp; - addr[0] = 0x02; - addr[1] = 0x00; - addr[2] = 0x01; - addr[3] = (x >> 16) & 0xff; - addr[4] = (x >> 8) & 0xff; - addr[5] = x & 0xff; +// これは Host スレッドから呼ばれる +void +EthernetDevice::HostRxCallback() +{ + // スレッドを超えるためにメッセージを投げる + scheduler->SendMessage(MessageID::HOSTNET_RX); } -// MAC アドレス文字列をバイナリに変換して返す。 -// "HH:HH:HH:HH:HH:HH" 形式のみ。 -// 成功すれば true を返す。 +// 設定ファイルから MAC アドレスを読み込む。 +// MAC アドレスを保持するデバイスが呼び出すこと。MAC アドレスを保持する +// デバイスがイーサネットデバイスとは限らず、例えば LANCE を採用している +// 機種ではたいてい ROM か誰かが MAC アドレスを持っている。 +// +// 引数 accept_rom が true なら、設定 ethernet-macaddr=rom を許可する。 +// これは (お手持ちの実機) ROM イメージが MAC アドレスを保持しているため、 +// 指定(や生成)不要なケースで指定できる (prom.cpp 参照)。 +// 引数 accept_rom が false で、設定値に "rom" が指定されるとエラーにする。 +// +// "rom" が指定されて許可されている場合 mac は触らず true を返す。 +// MAC アドレスが指定されているか自動生成したかで取得できれば mac に格納して +// true を返す。それ以外の場合は、エラーメッセージを表示して false を返す。 /*static*/ bool -EthernetDevice::ParseMacAddr(macaddr_t& dst, const std::string& src) +EthernetDevice::GetConfigMacAddr(macaddr_t *mac, bool accept_rom) { - const char *p; - char *e; + const ConfigItem& item = gConfig->Find("ethernet-macaddr"); + const std::string& val = item.AsString(); - p = src.data(); - for (int i = 0; ; ) { - unsigned long val = strtoul(p, &e, 16); - - if (p == e) { + if (val == "rom") { + // ROM に書いてあるのを使う。 + if (accept_rom) { + return true; + } else { + item.Err("\"rom\" cannot be specified in this vmtype"); return false; } - if (val > 0xff) { - return false; - } - dst[i++] = val; - p = e; - - // 最後だけ ':' をチェックしないので - if (i == 6) { - break; - } - - if (*p++ != ':') { - return false; + } else { + if (val == "auto") { + // 自動生成。 + // 出来れば生成したのを覚えといて、次からそれを使いたい。 + if (0) { + } else { + mac->Generate(); + } + } else { + // ユーザ指定 + if (mac->FromString(val) == false) { + item.Err("Invalid MAC address"); + return false; + } } } - if (*p != '\0') { - return false; - } - return true; -} -// パケットを送信する (VM から呼ばれる) -bool -EthernetDevice::SendPacket(const std::vector& buf) -{ - return gNetDriver->SendPacket(buf); + return true; }