--- nono/host/netdriver_bpf.cpp 2026/04/29 17:04:34 1.1.1.3 +++ nono/host/netdriver_bpf.cpp 2026/04/29 17:04:54 1.1.1.5 @@ -5,29 +5,25 @@ // #include "netdriver_bpf.h" -#include "cvprompt.h" -#include "mystring.h" +#include "autofd.h" #include #include #include #include -#if defined(HAVE_SYS_EVENT_H) -#include -#endif -#if defined(HAVE_KQUEUE_SYS_EVENT_H) -#include -#endif #include #include #include #include // コンストラクタ -NetDriverBPF::NetDriverBPF(EthernetDevice *parent_, - std::mutex *mtx_, std::condition_variable *cv_) - : inherited("BPF", parent_, mtx_, cv_) +NetDriverBPF::NetDriverBPF(EthernetDevice *parent_, int loglevel_, + const std::string& ifname_) + : inherited("BPF", parent_, loglevel_) { - fd = -1; + ifname = ifname_; + if (ifname.empty()) { + ifname = "auto"; + } } // デストラクタ @@ -36,9 +32,9 @@ NetDriverBPF::~NetDriverBPF() Close(); } -// 初期化 & オープン +// ドライバ初期化 & オープン bool -NetDriverBPF::Init() +NetDriverBPF::InitDriver() { struct ifreq ifr; struct bpf_program prog; @@ -48,16 +44,17 @@ NetDriverBPF::Init() BPF_STMT(BPF_RET + BPF_K, (u_int)-1), }; - // XXX tap はデバイスを開くとインタフェースが出来る、という方向だが、 - // bpf はインタフェースを指定してデバイスを開く、という方向で、逆…。 + putmsg(1, "trying bpf..."); + putmsg(1, "argument: ifname=\"%s\"", ifname.c_str()); - if (ifname.empty()) { + if (ifname == "auto") { // インタフェース指定がなければそれっぽいのを探すか ifname = FindInterface(); if (ifname.empty()) { - warn("NetDriverBPF: no interface specified"); - return false; + errmsg = "auto could not find a suitable interface"; + goto abort; } + putmsg(1, "auto-selected ifname: \"%s\"", ifname.c_str()); } // 最大値は適当 @@ -73,90 +70,83 @@ NetDriverBPF::Init() } fd = open(devpath.c_str(), O_RDWR); - if (fd == -1) { - warn("NetDriverBPF.Open: skip %s", devpath.c_str()); + if (fd < 0) { + // ファイルがないのを表示したら結構うるさいので除く + if (errno != ENOENT) { + putmsg(1, "open %s: %s", devpath.c_str(), strerror(errno)); + } continue; } + // 成功したら抜ける break; } - if (fd == -1) { - warnx("NetDriverBPF.Open: no bpf device available"); - return false; + if (fd < 0) { + errmsg = "no bpf devices available"; + goto abort; } // インタフェースにバインド memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname.c_str(), sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, &ifr) == -1) { - warn("NetDriverBPF.Open: %s(%s) BIOCSETIF failed", - devpath.c_str(), ifname.c_str()); + errmsg = string_format("%s(%s): BIOCSETIF: %s", + devpath.c_str(), ifname.c_str(), strerror(errno)); goto abort; } - // バインドまで出来たところでログを出しておきたい - // XXX 本当は warn じゃないよね - warnx("NetDriverBPF.Open: %s opened for %s", - devpath.c_str(), ifname.c_str()); if (ioctl(fd, BIOCPROMISC, (void *)0) == -1) { - warn("NetDriverBPF.Open: %s(%s): BIOCPROMISC failed", - devpath.c_str(), ifname.c_str()); + errmsg = string_format("%s(%s): %s: %s", + devpath.c_str(), ifname.c_str(), "BIOCPROMISC", strerror(errno)); goto abort; } val = 1; if (ioctl(fd, BIOCIMMEDIATE, &val) == -1) { - warn("NetDriverBPF.Open: %s(%s): BIOCIMMEDIATE failed", - devpath.c_str(), ifname.c_str()); + errmsg = string_format("%s(%s): %s: %s", + devpath.c_str(), ifname.c_str(), "BIOCIMMEDIATE", strerror(errno)); goto abort; } if (ioctl(fd, BIOCSHDRCMPLT, &val) == -1) { - warn("NetDriverBPF.Open: %s(%s): BIOCSHDRCMPLT failed", - devpath.c_str(), ifname.c_str()); + errmsg = string_format("%s(%s): %s: %s", + devpath.c_str(), ifname.c_str(), "BIOCSHDRCMPLT", strerror(errno)); goto abort; } - // XXX BIOCFEEDBACK... - warn("NetDriverBPF.Open: %s(%s): ローカルホストとのみ通信はできません", - devpath.c_str(), ifname.c_str()); - // フィルタをセット prog.bf_len = countof(insn); prog.bf_insns = insn; if (ioctl(fd, BIOCSETF, &prog) == -1) { - warn("NetDriverBPF.Open: %s(%s): BIOCSETF failed", - devpath.c_str(), ifname.c_str()); + errmsg = string_format("%s(%s): %s: %s", + devpath.c_str(), ifname.c_str(), "BIOCSETF", strerror(errno)); goto abort; } // バッファサイズを取得 if (ioctl(fd, BIOCGBLEN, &bpfbuflen) == -1) { - warn("NetDriverBPF.Open: %s(%s): BIOCGBLEN failed", - devpath.c_str(), ifname.c_str()); + errmsg = string_format("%s(%s): %s: %s", + devpath.c_str(), ifname.c_str(), "BIOCGBLEN", strerror(errno)); goto abort; } // 受信用バッファを確保 try { - bpfbuf.reset(new char [bpfbuflen]); + bpfbuf.reset(new uint8 [bpfbuflen]); } catch (...) { - warnx("NetDriverBPF.Open: %s(%s): memory allocation failed", - devpath.c_str(), ifname.c_str()); + errmsg = "memory allocation failed"; goto abort; } - // オープンできたので受信スレッド起動。 - if (InitRecvThread() == false) { - goto abort; - } + putmsg(1, "opened %s for %s", devpath.c_str(), ifname.c_str()); + putmsg(1, "warning: communicating with the localhost is not possible"); // bpf では ifup スクリプトは実行しない return true; abort: - close(fd); - fd = -1; + putmsg(1, "%s", errmsg.c_str()); + Close(); return false; } @@ -171,6 +161,14 @@ NetDriverBPF::Close() } } +// モニタ (ドライバ依存情報のみ) +void +NetDriverBPF::MonitorUpdateMD(TextScreen& screen) +{ + screen.Print(0, 1, "Device : %s", devpath.c_str()); + screen.Print(0, 2, "Interface: %s", ifname.c_str()); +} + // パケットを送信する bool NetDriverBPF::SendPacket(const std::vector& data) @@ -185,8 +183,8 @@ NetDriverBPF::SendPacket(const std::vect n = write(fd, data.data(), data.size()); if (n == -1) { - warn("NetDriverBPF.SendPacket: write failed: fd=%d datalen=%zu", - fd, data.size()); + putmsg(0, "%s: write failed: fd=%d datalen=%zu: %s", + __func__, fd, data.size(), strerror(errno)); return false; } @@ -200,7 +198,7 @@ NetDriverBPF::SendPacket(const std::vect // 物理インタフェースが明らかに1つしかないところで、 // インタフェース名の指定を省略できるようにするため。 std::string -NetDriverBPF::FindInterface() +NetDriverBPF::FindInterface() const { char name[IFNAMSIZ]; struct ifaddrs *ifa_list, *ifa; @@ -223,93 +221,27 @@ NetDriverBPF::FindInterface() return std::string(name); } -// 受信スレッド -void -NetDriverBPF::ThreadRun() +// パケットを受信する +ssize_t +NetDriverBPF::RecvPacket() { - struct kevent kev; - int kq; - int r; - - kq = kqueue(); - if (kq == -1) { - warn("kqueue failed"); - return; - } - - EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, (kevent_udata_t)0); - r = kevent_set(kq, &kev, 1); - if (r == -1) { - warn("kevent_set(fd=%d) failed", fd); - close(kq); - return; - } - - for (;;) { - int n; - char *bpfptr; - int bpfcaplen; - - // 何か起きるまで待つ - r = kevent_poll(kq, &kev, 1, NULL); - if (r == -1) { - if (errno == EINTR) { - continue; - } - // XXX ? - warn("NetDriverBPF.ThreadRun: kevent_poll failed"); - break; - } + uint8 *buf = bpfbuf.get(); + uint8 *bpfptr = buf; + ssize_t n; - // 自動的にデバイスに着信があったことになるはず - assert(r > 0); - - n = read(fd, bpfbuf.get(), bpfbuflen); - if (n == -1) { - if (errno == EINTR) { - continue; - } - warn("NetDriverBPF.ThreadRun: read(fd=%d) failed", fd); - break; - } - if (n == 0) { // EOF - return; - } - bpfptr = bpfbuf.get(); - bpfcaplen = n; - - while (bpfptr < bpfbuf.get() + bpfcaplen) { - uint8 buf[1600]; - - // BPF ヘッダを除いた部分 - struct bpf_hdr *bh = (struct bpf_hdr *)bpfptr; - n = bh->bh_caplen; - memcpy(buf, bpfptr + bh->bh_hdrlen, n); - - // 次のフレームの先頭を指す - int framelen = BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen); - bpfptr += framelen; - - // 60バイトパディングされないまま読み出せたらここでパディングする。 - if (n < 60) { - memset(buf + n, 0, 60 - n); - n = 60; - } + n = read(fd, buf, bpfbuflen); + if (n <= 0) { + return n; + } - // CRC XXX 計算すること - memset(buf + n, 0, 4); - n += 4; - - // 受信処理に引き渡す - // ただしデバッガプロンプトで停止してる状態なら VM に干渉しない。 - if (parent->RecvEnabled && gCVPrompt->IsPrompt() == false) { - putlog(2, "RecvPacket %d bytes", n); - rx_pkts++; - rx_bytes += n; + while (bpfptr < buf + n) { + // BPF ヘッダを除いた部分が 1 パケット + struct bpf_hdr *bh = (struct bpf_hdr *)bpfptr; + RecvEnqueue(bpfptr + bh->bh_hdrlen, bh->bh_caplen); - qvector recvbuf(buf, buf + n); - parent->RecvPacket(recvbuf); - } - } + // 次のフレームの先頭を指す + int framelen = BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen); + bpfptr += framelen; } + return n; }