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

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #include "netdriver_bpf.h"
1.1.1.4   root        8: #include "autofd.h"
1.1       root        9: #include <fcntl.h>
                     10: #include <ifaddrs.h>
                     11: #include <sys/ioctl.h>
                     12: #include <sys/socket.h>
                     13: #include <net/bpf.h>
                     14: #include <net/if.h>
                     15: #include <net/if_dl.h>
                     16: #include <net/if_types.h>
                     17: 
                     18: // コンストラクタ
1.1.1.5 ! root       19: NetDriverBPF::NetDriverBPF(EthernetDevice *parent_, int loglevel_,
        !            20:        const std::string& ifname_)
        !            21:        : inherited("BPF", parent_, loglevel_)
1.1       root       22: {
1.1.1.5 ! root       23:        ifname = ifname_;
        !            24:        if (ifname.empty()) {
        !            25:                ifname = "auto";
        !            26:        }
1.1       root       27: }
                     28: 
                     29: // デストラクタ
                     30: NetDriverBPF::~NetDriverBPF()
                     31: {
                     32:        Close();
                     33: }
                     34: 
1.1.1.5 ! root       35: // ドライバ初期化 & オープン
1.1       root       36: bool
1.1.1.5 ! root       37: NetDriverBPF::InitDriver()
1.1       root       38: {
                     39:        struct ifreq ifr;
                     40:        struct bpf_program prog;
                     41:        u_int val;
                     42:        struct bpf_insn insn[] = {
                     43:                // すべてのパケットを全長受信
                     44:                BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
                     45:        };
                     46: 
1.1.1.5 ! root       47:        putmsg(1, "trying bpf...");
        !            48:        putmsg(1, "argument: ifname=\"%s\"", ifname.c_str());
1.1       root       49: 
1.1.1.5 ! root       50:        if (ifname == "auto") {
1.1       root       51:                // インタフェース指定がなければそれっぽいのを探すか
                     52:                ifname = FindInterface();
                     53:                if (ifname.empty()) {
1.1.1.5 ! root       54:                        errmsg = "auto could not find a suitable interface";
        !            55:                        goto abort;
1.1       root       56:                }
1.1.1.5 ! root       57:                putmsg(1, "auto-selected ifname: \"%s\"", ifname.c_str());
1.1       root       58:        }
                     59: 
                     60:        // 最大値は適当
                     61:        fd = -1;
                     62:        for (int i = -1; i < 10; i++) {
                     63:                // i == -1 なら /dev/bpf、0..10 は /dev/bpfN。
                     64:                // まず /dev/bpf を cloning デバイスだと思って開いてみる。
                     65:                // そうでなければ従来どおり 0 から順番に試してみる。
                     66:                if (i == -1) {
                     67:                        devpath = "/dev/bpf";
                     68:                } else {
                     69:                        devpath = string_format("/dev/bpf%d", i);
                     70:                }
                     71: 
                     72:                fd = open(devpath.c_str(), O_RDWR);
1.1.1.4   root       73:                if (fd < 0) {
                     74:                        // ファイルがないのを表示したら結構うるさいので除く
                     75:                        if (errno != ENOENT) {
1.1.1.5 ! root       76:                                putmsg(1, "open %s: %s", devpath.c_str(), strerror(errno));
1.1.1.4   root       77:                        }
1.1       root       78:                        continue;
                     79:                }
1.1.1.5 ! root       80:                // 成功したら抜ける
1.1       root       81:                break;
                     82:        }
1.1.1.4   root       83:        if (fd < 0) {
1.1.1.5 ! root       84:                errmsg = "no bpf devices available";
        !            85:                goto abort;
1.1       root       86:        }
                     87: 
                     88:        // インタフェースにバインド
                     89:        memset(&ifr, 0, sizeof(ifr));
                     90:        strlcpy(ifr.ifr_name, ifname.c_str(), sizeof(ifr.ifr_name));
                     91:        if (ioctl(fd, BIOCSETIF, &ifr) == -1) {
1.1.1.5 ! root       92:                errmsg = string_format("%s(%s): BIOCSETIF: %s", 
        !            93:                        devpath.c_str(), ifname.c_str(), strerror(errno));
1.1       root       94:                goto abort;
                     95:        }
                     96: 
                     97:        if (ioctl(fd, BIOCPROMISC, (void *)0) == -1) {
1.1.1.5 ! root       98:                errmsg = string_format("%s(%s): %s: %s",
        !            99:                        devpath.c_str(), ifname.c_str(), "BIOCPROMISC", strerror(errno));
1.1       root      100:                goto abort;
                    101:        }
                    102: 
                    103:        val = 1;
                    104:        if (ioctl(fd, BIOCIMMEDIATE, &val) == -1) {
1.1.1.5 ! root      105:                errmsg = string_format("%s(%s): %s: %s",
        !           106:                        devpath.c_str(), ifname.c_str(), "BIOCIMMEDIATE", strerror(errno));
1.1       root      107:                goto abort;
                    108:        }
                    109: 
                    110:        if (ioctl(fd, BIOCSHDRCMPLT, &val) == -1) {
1.1.1.5 ! root      111:                errmsg = string_format("%s(%s): %s: %s",
        !           112:                        devpath.c_str(), ifname.c_str(), "BIOCSHDRCMPLT", strerror(errno));
1.1       root      113:                goto abort;
                    114:        }
                    115: 
                    116:        // フィルタをセット
                    117:        prog.bf_len = countof(insn);
                    118:        prog.bf_insns = insn;
                    119:        if (ioctl(fd, BIOCSETF, &prog) == -1) {
1.1.1.5 ! root      120:                errmsg = string_format("%s(%s): %s: %s",
        !           121:                        devpath.c_str(), ifname.c_str(), "BIOCSETF", strerror(errno));
1.1       root      122:                goto abort;
                    123:        }
                    124: 
                    125:        // バッファサイズを取得
                    126:        if (ioctl(fd, BIOCGBLEN, &bpfbuflen) == -1) {
1.1.1.5 ! root      127:                errmsg = string_format("%s(%s): %s: %s",
        !           128:                        devpath.c_str(), ifname.c_str(), "BIOCGBLEN", strerror(errno));
1.1       root      129:                goto abort;
                    130:        }
                    131: 
                    132:        // 受信用バッファを確保
                    133:        try {
1.1.1.5 ! root      134:                bpfbuf.reset(new uint8 [bpfbuflen]);
1.1       root      135:        } catch (...) {
1.1.1.5 ! root      136:                errmsg = "memory allocation failed";
1.1       root      137:                goto abort;
                    138:        }
                    139: 
1.1.1.5 ! root      140:        putmsg(1, "opened %s for %s", devpath.c_str(), ifname.c_str());
        !           141:        putmsg(1, "warning: communicating with the localhost is not possible");
1.1       root      142: 
                    143:        // bpf では ifup スクリプトは実行しない
                    144: 
                    145:        return true;
                    146: 
                    147:  abort:
1.1.1.5 ! root      148:        putmsg(1, "%s", errmsg.c_str());
        !           149:        Close();
1.1       root      150:        return false;
                    151: }
                    152: 
                    153: // クローズ
                    154: // (private)
                    155: void
                    156: NetDriverBPF::Close()
                    157: {
                    158:        if (IsOpen()) {
                    159:                close(fd);
                    160:                fd = -1;
                    161:        }
                    162: }
                    163: 
1.1.1.5 ! root      164: // モニタ (ドライバ依存情報のみ)
        !           165: void
        !           166: NetDriverBPF::MonitorUpdateMD(TextScreen& screen)
        !           167: {
        !           168:        screen.Print(0, 1, "Device   : %s", devpath.c_str());
        !           169:        screen.Print(0, 2, "Interface: %s", ifname.c_str());
        !           170: }
        !           171: 
1.1       root      172: // パケットを送信する
                    173: bool
                    174: NetDriverBPF::SendPacket(const std::vector<uint8>& data)
                    175: {
                    176:        int n;
                    177: 
                    178:        assert(IsOpen());
                    179: 
                    180:        putlog(2, "SendPacket %zu bytes", data.size());
                    181:        tx_pkts++;
                    182:        tx_bytes += data.size();
                    183: 
                    184:        n = write(fd, data.data(), data.size());
                    185:        if (n == -1) {
1.1.1.5 ! root      186:                putmsg(0, "%s: write failed: fd=%d datalen=%zu: %s",
        !           187:                        __func__, fd, data.size(), strerror(errno));
1.1       root      188:                return false;
                    189:        }
                    190: 
                    191:        if (n < (int)data.size()) {
                    192:                return false;
                    193:        }
                    194:        return true;
                    195: }
                    196: 
                    197: // 最初に見付かった使えそうなインタフェース名を返す。
                    198: // 物理インタフェースが明らかに1つしかないところで、
                    199: // インタフェース名の指定を省略できるようにするため。
                    200: std::string
1.1.1.5 ! root      201: NetDriverBPF::FindInterface() const
1.1       root      202: {
                    203:        char name[IFNAMSIZ];
                    204:        struct ifaddrs *ifa_list, *ifa;
                    205:        struct sockaddr_dl *dl;
                    206: 
                    207:        if (getifaddrs(&ifa_list) == -1) {
                    208:                return "";
                    209:        }
                    210: 
                    211:        name[0] = '\0';
                    212:        for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
                    213:                dl = (struct sockaddr_dl *)ifa->ifa_addr;
                    214:                if ((ifa->ifa_flags & IFF_UP) != 0 && dl->sdl_type == IFT_ETHER) {
                    215:                        strlcpy(name, ifa->ifa_name, sizeof(name));
                    216:                        break;
                    217:                }
                    218:        }
                    219:        freeifaddrs(ifa_list);
                    220: 
                    221:        return std::string(name);
                    222: }
                    223: 
1.1.1.5 ! root      224: // パケットを受信する
        !           225: ssize_t
        !           226: NetDriverBPF::RecvPacket()
1.1       root      227: {
1.1.1.5 ! root      228:        uint8 *buf = bpfbuf.get();
        !           229:        uint8 *bpfptr = buf;
        !           230:        ssize_t n;
1.1       root      231: 
1.1.1.5 ! root      232:        n = read(fd, buf, bpfbuflen);
        !           233:        if (n <= 0) {
        !           234:                return n;
        !           235:        }
1.1       root      236: 
1.1.1.5 ! root      237:        while (bpfptr < buf + n) {
        !           238:                // BPF ヘッダを除いた部分が 1 パケット
        !           239:                struct bpf_hdr *bh = (struct bpf_hdr *)bpfptr;
        !           240:                RecvEnqueue(bpfptr + bh->bh_hdrlen, bh->bh_caplen);
1.1       root      241: 
1.1.1.5 ! root      242:                // 次のフレームの先頭を指す
        !           243:                int framelen = BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
        !           244:                bpfptr += framelen;
1.1       root      245:        }
1.1.1.5 ! root      246:        return n;
1.1       root      247: }

unix.superglobalmegacorp.com

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