Annotation of nono/host/netdriver_bpf.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2019 [email protected]
        !             4: //
        !             5: 
        !             6: #include "header.h"
        !             7: #include "netdriver_bpf.h"
        !             8: #include "cvprompt.h"
        !             9: #include "mystring.h"
        !            10: #include <fcntl.h>
        !            11: #include <ifaddrs.h>
        !            12: #include <sys/ioctl.h>
        !            13: #include <sys/socket.h>
        !            14: #if defined(HAVE_SYS_EVENT_H)
        !            15: #include <sys/event.h>
        !            16: #endif
        !            17: #if defined(HAVE_KQUEUE_SYS_EVENT_H)
        !            18: #include <kqueue/sys/event.h>
        !            19: #endif
        !            20: #include <net/bpf.h>
        !            21: #include <net/if.h>
        !            22: #include <net/if_dl.h>
        !            23: #include <net/if_types.h>
        !            24: 
        !            25: // コンストラクタ
        !            26: NetDriverBPF::NetDriverBPF(EthernetDevice *p,
        !            27:        std::mutex *m, std::condition_variable *c)
        !            28:        : inherited("BPF", p, m, c)
        !            29: {
        !            30:        fd = -1;
        !            31: }
        !            32: 
        !            33: // デストラクタ
        !            34: NetDriverBPF::~NetDriverBPF()
        !            35: {
        !            36:        Close();
        !            37: 
        !            38:        if (bpfbuf) {
        !            39:                delete[] bpfbuf;
        !            40:        }
        !            41: }
        !            42: 
        !            43: // 初期化 & オープン
        !            44: bool
        !            45: NetDriverBPF::Init()
        !            46: {
        !            47:        struct ifreq ifr;
        !            48:        struct bpf_program prog;
        !            49:        u_int val;
        !            50:        struct bpf_insn insn[] = {
        !            51:                // すべてのパケットを全長受信
        !            52:                BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
        !            53:        };
        !            54: 
        !            55:        // XXX tap はデバイスを開くとインタフェースが出来る、という方向だが、
        !            56:        //     bpf はインタフェースを指定してデバイスを開く、という方向で、逆…。
        !            57: 
        !            58:        if (ifname.empty()) {
        !            59:                // インタフェース指定がなければそれっぽいのを探すか
        !            60:                ifname = FindInterface();
        !            61:                if (ifname.empty()) {
        !            62:                        warn("NetDriverBPF: no interface specified");
        !            63:                        return false;
        !            64:                }
        !            65:        }
        !            66: 
        !            67:        // 最大値は適当
        !            68:        fd = -1;
        !            69:        for (int i = -1; i < 10; i++) {
        !            70:                // i == -1 なら /dev/bpf、0..10 は /dev/bpfN。
        !            71:                // まず /dev/bpf を cloning デバイスだと思って開いてみる。
        !            72:                // そうでなければ従来どおり 0 から順番に試してみる。
        !            73:                if (i == -1) {
        !            74:                        devpath = "/dev/bpf";
        !            75:                } else {
        !            76:                        devpath = string_format("/dev/bpf%d", i);
        !            77:                }
        !            78: 
        !            79:                fd = open(devpath.c_str(), O_RDWR);
        !            80:                if (fd == -1) {
        !            81:                        warn("NetDriverBPF.Open: skip %s", devpath.c_str());
        !            82:                        continue;
        !            83:                }
        !            84:                break;
        !            85:        }
        !            86:        if (fd == -1) {
        !            87:                warnx("NetDriverBPF.Open: no bpf device available");
        !            88:                return false;
        !            89:        }
        !            90: 
        !            91:        // インタフェースにバインド
        !            92:        memset(&ifr, 0, sizeof(ifr));
        !            93:        strlcpy(ifr.ifr_name, ifname.c_str(), sizeof(ifr.ifr_name));
        !            94:        if (ioctl(fd, BIOCSETIF, &ifr) == -1) {
        !            95:                warn("NetDriverBPF.Open: %s(%s) BIOCSETIF failed",
        !            96:                        devpath.c_str(), ifname.c_str());
        !            97:                goto abort;
        !            98:        }
        !            99:        // バインドまで出来たところでログを出しておきたい
        !           100:        // XXX 本当は warn じゃないよね
        !           101:        warnx("NetDriverBPF.Open: %s opened for %s",
        !           102:                devpath.c_str(), ifname.c_str());
        !           103: 
        !           104:        if (ioctl(fd, BIOCPROMISC, (void *)0) == -1) {
        !           105:                warn("NetDriverBPF.Open: %s(%s): BIOCPROMISC failed",
        !           106:                        devpath.c_str(), ifname.c_str());
        !           107:                goto abort;
        !           108:        }
        !           109: 
        !           110:        val = 1;
        !           111:        if (ioctl(fd, BIOCIMMEDIATE, &val) == -1) {
        !           112:                warn("NetDriverBPF.Open: %s(%s): BIOCIMMEDIATE failed",
        !           113:                        devpath.c_str(), ifname.c_str());
        !           114:                goto abort;
        !           115:        }
        !           116: 
        !           117:        if (ioctl(fd, BIOCSHDRCMPLT, &val) == -1) {
        !           118:                warn("NetDriverBPF.Open: %s(%s): BIOCSHDRCMPLT failed",
        !           119:                        devpath.c_str(), ifname.c_str());
        !           120:                goto abort;
        !           121:        }
        !           122: 
        !           123:        // XXX BIOCFEEDBACK...
        !           124:        warn("NetDriverBPF.Open: %s(%s): ローカルホストとのみ通信はできません",
        !           125:                devpath.c_str(), ifname.c_str());
        !           126: 
        !           127:        // フィルタをセット
        !           128:        prog.bf_len = countof(insn);
        !           129:        prog.bf_insns = insn;
        !           130:        if (ioctl(fd, BIOCSETF, &prog) == -1) {
        !           131:                warn("NetDriverBPF.Open: %s(%s): BIOCSETF failed",
        !           132:                        devpath.c_str(), ifname.c_str());
        !           133:                goto abort;
        !           134:        }
        !           135: 
        !           136:        // バッファサイズを取得
        !           137:        if (ioctl(fd, BIOCGBLEN, &bpfbuflen) == -1) {
        !           138:                warn("NetDriverBPF.Open: %s(%s): BIOCGBLEN failed",
        !           139:                        devpath.c_str(), ifname.c_str());
        !           140:                goto abort;
        !           141:        }
        !           142: 
        !           143:        // 受信用バッファを確保
        !           144:        try {
        !           145:                bpfbuf = new char [bpfbuflen];
        !           146:        } catch (...) {
        !           147:                bpfbuf = NULL;
        !           148:        }
        !           149:        if (bpfbuf == NULL) {
        !           150:                warnx("NetDriverBPF.Open: %s(%s): memory allocation failed",
        !           151:                        devpath.c_str(), ifname.c_str());
        !           152:                goto abort;
        !           153:        }
        !           154: 
        !           155:        // オープンできたので受信スレッド起動。
        !           156:        if (InitRecvThread() == false) {
        !           157:                goto abort;
        !           158:        }
        !           159: 
        !           160:        // bpf では ifup スクリプトは実行しない
        !           161: 
        !           162:        return true;
        !           163: 
        !           164:  abort:
        !           165:        close(fd);
        !           166:        fd = -1;
        !           167:        return false;
        !           168: }
        !           169: 
        !           170: // クローズ
        !           171: // (private)
        !           172: void
        !           173: NetDriverBPF::Close()
        !           174: {
        !           175:        if (IsOpen()) {
        !           176:                close(fd);
        !           177:                fd = -1;
        !           178:        }
        !           179: }
        !           180: 
        !           181: // パケットを送信する
        !           182: bool
        !           183: NetDriverBPF::SendPacket(const std::vector<uint8>& data)
        !           184: {
        !           185:        int n;
        !           186: 
        !           187:        assert(IsOpen());
        !           188: 
        !           189:        putlog(2, "SendPacket %zu bytes", data.size());
        !           190:        tx_pkts++;
        !           191:        tx_bytes += data.size();
        !           192: 
        !           193:        n = write(fd, data.data(), data.size());
        !           194:        if (n == -1) {
        !           195:                warn("NetDriverBPF.SendPacket: write failed: fd=%d datalen=%zu",
        !           196:                        fd, data.size());
        !           197:                return false;
        !           198:        }
        !           199: 
        !           200:        if (n < (int)data.size()) {
        !           201:                return false;
        !           202:        }
        !           203:        return true;
        !           204: }
        !           205: 
        !           206: // 最初に見付かった使えそうなインタフェース名を返す。
        !           207: // 物理インタフェースが明らかに1つしかないところで、
        !           208: // インタフェース名の指定を省略できるようにするため。
        !           209: std::string
        !           210: NetDriverBPF::FindInterface()
        !           211: {
        !           212:        char name[IFNAMSIZ];
        !           213:        struct ifaddrs *ifa_list, *ifa;
        !           214:        struct sockaddr_dl *dl;
        !           215: 
        !           216:        if (getifaddrs(&ifa_list) == -1) {
        !           217:                return "";
        !           218:        }
        !           219: 
        !           220:        name[0] = '\0';
        !           221:        for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
        !           222:                dl = (struct sockaddr_dl *)ifa->ifa_addr;
        !           223:                if ((ifa->ifa_flags & IFF_UP) != 0 && dl->sdl_type == IFT_ETHER) {
        !           224:                        strlcpy(name, ifa->ifa_name, sizeof(name));
        !           225:                        break;
        !           226:                }
        !           227:        }
        !           228:        freeifaddrs(ifa_list);
        !           229: 
        !           230:        return std::string(name);
        !           231: }
        !           232: 
        !           233: // 受信スレッド
        !           234: void
        !           235: NetDriverBPF::ThreadRun()
        !           236: {
        !           237:        struct kevent kev;
        !           238:        int kq;
        !           239:        int r;
        !           240: 
        !           241:        kq = kqueue();
        !           242:        if (kq == -1) {
        !           243:                warn("kqueue failed");
        !           244:                return;
        !           245:        }
        !           246: 
        !           247:        EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, (kevent_udata_t)0);
        !           248:        r = kevent_set(kq, &kev, 1);
        !           249:        if (r == -1) {
        !           250:                warn("kevent_set(fd=%d) failed", fd);
        !           251:                close(kq);
        !           252:                return;
        !           253:        }
        !           254: 
        !           255:        for (;;) {
        !           256:                int n;
        !           257:                char *bpfptr;
        !           258:                int bpfcaplen;
        !           259: 
        !           260:                // 何か起きるまで待つ
        !           261:                r = kevent_poll(kq, &kev, 1, NULL);
        !           262:                if (r == -1) {
        !           263:                        if (errno == EINTR) {
        !           264:                                continue;
        !           265:                        }
        !           266:                        // XXX ?
        !           267:                        warn("NetDriverBPF.ThreadRun: kevent_poll failed");
        !           268:                        break;
        !           269:                }
        !           270: 
        !           271:                // 自動的にデバイスに着信があったことになるはず
        !           272:                assert(r > 0);
        !           273: 
        !           274:                n = read(fd, bpfbuf, bpfbuflen);
        !           275:                if (n == -1) {
        !           276:                        if (errno == EINTR) {
        !           277:                                continue;
        !           278:                        }
        !           279:                        warn("NetDriverBPF.ThreadRun: read(fd=%d) failed", fd);
        !           280:                        break;
        !           281:                }
        !           282:                if (n == 0) {   // EOF
        !           283:                        return;
        !           284:                }
        !           285:                bpfptr = bpfbuf;
        !           286:                bpfcaplen = n;
        !           287: 
        !           288:                while (bpfptr < bpfbuf + bpfcaplen) {
        !           289:                        uint8 buf[1600];
        !           290: 
        !           291:                        // BPF ヘッダを除いた部分
        !           292:                        struct bpf_hdr *bh = (struct bpf_hdr *)bpfptr;
        !           293:                        n = bh->bh_caplen;
        !           294:                        memcpy(buf, bpfptr + bh->bh_hdrlen, n);
        !           295: 
        !           296:                        // 次のフレームの先頭を指す
        !           297:                        int framelen = BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
        !           298:                        bpfptr += framelen;
        !           299: 
        !           300:                        // 60バイトパディングされないまま読み出せたらここでパディングする。
        !           301:                        if (n < 60) {
        !           302:                                memset(buf + n, 0, 60 - n);
        !           303:                                n = 60;
        !           304:                        }
        !           305: 
        !           306:                        // CRC XXX 計算すること
        !           307:                        memset(buf + n, 0, 4);
        !           308:                        n += 4;
        !           309: 
        !           310:                        // 受信処理に引き渡す
        !           311:                        // ただしデバッガプロンプトで停止してる状態なら VM に干渉しない。
        !           312:                        if (parent->RecvEnabled && gCVPrompt->IsPrompt() == false) {
        !           313:                                putlog(2, "RecvPacket %d bytes", n);
        !           314:                                rx_pkts++;
        !           315:                                rx_bytes += n;
        !           316: 
        !           317:                                qvector<uint8> recvbuf(buf, buf + n);
        !           318:                                parent->RecvPacket(recvbuf);
        !           319:                        }
        !           320:                }
        !           321:        }
        !           322: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.