Annotation of nono/host/netdriver_tap.cpp, revision 1.1.1.2

1.1       root        1: //
                      2: // nono
1.1.1.2 ! root        3: // Copyright (C) 2020 nono project
        !             4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #include "netdriver_tap.h"
                      8: #include "cvprompt.h"
                      9: #include <fcntl.h>
                     10: #include <poll.h>
                     11: #include <sys/ioctl.h>
                     12: #include <sys/socket.h>
                     13: #if defined(HAVE_SYS_EVENT_H)
                     14: #include <sys/event.h>
                     15: #endif
                     16: #if defined(HAVE_KQUEUE_SYS_EVENT_H)
                     17: #include <kqueue/sys/event.h>
                     18: #endif
                     19: #if defined(__linux__)
                     20: #include <linux/if.h>
                     21: #include <linux/if_tun.h>
                     22: #else
                     23: #include <ifaddrs.h>
                     24: #include <net/if.h>
                     25: #include <net/if_dl.h>
                     26: #include <net/if_tap.h>
                     27: #endif
                     28: 
                     29: // コンストラクタ
1.1.1.2 ! root       30: NetDriverTap::NetDriverTap(EthernetDevice *parent_,
        !            31:        std::mutex *mtx_, std::condition_variable *cv_)
        !            32:        : inherited("BSD tap", parent_, mtx_, cv_)
1.1       root       33: {
                     34: #if defined(__linux__)
                     35:        devpath = "/dev/net/tun";
                     36: #else
                     37:        devpath = "/dev/tap";
                     38: #endif
                     39: }
                     40: 
                     41: // デストラクタ
                     42: NetDriverTap::~NetDriverTap()
                     43: {
                     44:        Close();
                     45: }
                     46: 
                     47: // 初期化 & オープン
                     48: bool
                     49: NetDriverTap::Init()
                     50: {
                     51:        struct ifreq ifr;
                     52:        int r;
                     53: 
                     54:        // tap デバイスオープン
                     55:        fd = open(devpath.c_str(), O_RDWR);
                     56:        if (fd == -1) {
                     57:                warn("open \"%s\" failed", devpath.c_str());
                     58:                return false;
                     59:        }
                     60: 
                     61:        memset(&ifr, 0, sizeof(ifr));
                     62: #if defined(__linux__)
                     63:        // Linux なら、open() したデバイスに対して tap デバイス作成を指示、
                     64:        // その応答にインタフェース名が入っている。
                     65:        ifr.ifr_flags = IFF_TAP | IFF_NO_PI;    // tap として使う
                     66:        strlcpy(ifr.ifr_name, "tap%d", sizeof(ifr.ifr_name));
                     67:        // インタフェース作成。これには CAP_NET_ADMIN 権限が必要
                     68:        r = ioctl(fd, TUNSETIFF, (void *)&ifr);
                     69:        if (r == -1) {
                     70:                warn("Open: TUNSETIFF failed");
                     71:                if (errno == EPERM) {
                     72:                        fprintf(stderr,
                     73:                                " ** Set CAP_NET_ADMIN capability to the execute file.\n"
                     74:                                " **  ex) sudo setcap cap_net_admin=ep path/to/%s\n",
                     75:                                getprogname());
                     76:                }
                     77:                goto abort;
                     78:        }
                     79: #else
                     80:        // NetBSD なら、open() でインタフェースは作成されているので、
                     81:        // オープンされたこのディスクリプタのインタフェース名を取得。
                     82:        r = ioctl(fd, TAPGIFNAME, &ifr);
                     83:        if (r == -1) {
                     84:                warn("Open: TAPGIFNAME failed");
                     85:                goto abort;
                     86:        }
                     87: #endif
                     88: 
                     89:        // 作成できたインタフェース名を取得
                     90:        ifname = std::string(ifr.ifr_name);
                     91: 
                     92:        // オープンできたので受信スレッド起動。
                     93:        // ifup 実行前なので、ここで失敗しても ifdown 不要。
                     94:        if (InitRecvThread() == false) {
                     95:                goto abort;
                     96:        }
                     97: 
                     98:        // 最後に ifup スクリプトがあれば実行
                     99:        if (!Run_ifup()) {
                    100:                // どこまで実行できたか分からないので念のため ifdown も呼ぶ
                    101:                Close();
                    102:                return false;
                    103:        }
                    104: 
                    105:        return true;
                    106: 
                    107:        // ifdown を実行させないために fd = -1 にして帰る。
                    108:        // (まだ ifup を実行していないので)
                    109:  abort:
                    110:        close(fd);
                    111:        fd = -1;
                    112:        return false;
                    113: }
                    114: 
                    115: // クローズ
                    116: // (private)
                    117: void
                    118: NetDriverTap::Close()
                    119: {
                    120:        if (IsOpen()) {
                    121:                Run_ifdown();
                    122: 
                    123:                close(fd);
                    124:                fd = -1;
                    125:        }
                    126: }
                    127: 
                    128: // パケットを送信する
                    129: bool
                    130: NetDriverTap::SendPacket(const std::vector<uint8>& data)
                    131: {
                    132:        int n;
                    133: 
                    134:        assert(IsOpen());
                    135: 
                    136:        putlog(2, "SendPacket %zd bytes", data.size());
                    137:        tx_pkts++;
                    138:        tx_bytes += data.size();
                    139: 
                    140:        n = write(fd, data.data(), data.size());
                    141:        if (n == -1) {
                    142:                warn("SendPacket: write failed: fd=%d datalen=%zu",
                    143:                        fd, data.size());
                    144:                return false;
                    145:        }
                    146: 
                    147:        if (n < (int)data.size()) {
                    148:                return false;
                    149:        }
                    150:        return true;
                    151: }
                    152: 
                    153: // 受信スレッド
                    154: void
                    155: NetDriverTap::ThreadRun()
                    156: {
                    157:        struct kevent kev;
                    158:        int kq;
                    159:        int r;
                    160: 
                    161:        kq = kqueue();
                    162:        if (kq == -1) {
                    163:                warn("kqueue failed");
                    164:                return;
                    165:        }
                    166: 
                    167:        EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, (kevent_udata_t)0);
                    168:        r = kevent_set(kq, &kev, 1);
                    169:        if (r == -1) {
                    170:                warn("kevent_set(fd=%d) failed", fd);
                    171:                close(kq);
                    172:                return;
                    173:        }
                    174: 
                    175:        for (;;) {
                    176:                uint8 buf[1600];
                    177:                int n;
                    178: 
                    179:                // 何か起きるまで待つ
                    180:                r = kevent_poll(kq, &kev, 1, NULL);
                    181:                if (r == -1) {
                    182:                        if (errno == EINTR) {
                    183:                                continue;
                    184:                        }
                    185:                        // XXX ?
                    186:                        warn("kevent_poll failed");
                    187:                        break;
                    188:                }
                    189: 
                    190:                // 自動的にデバイスに着信があったことになるはず
                    191:                assert(r > 0);
                    192: 
                    193:                n = read(fd, buf, sizeof(buf));
                    194:                if (n == -1) {
                    195:                        if (errno == EINTR) {
                    196:                                continue;
                    197:                        }
                    198:                        warn("read(fd=%d) failed", fd);
                    199:                        break;
                    200:                }
                    201:                if (n == 0) {   // EOF
                    202:                        return;
                    203:                }
                    204: 
                    205:                // カーネルが tap(4) に直接書き込んだパケット(というかフレームか)は
                    206:                // 60バイトパディングされないまま読み出せるので、ここでパディングする。
                    207:                if (n < 60) {
                    208:                        memset(buf + n, 0, 60 - n);
                    209:                        n = 60;
                    210:                }
                    211: 
                    212:                // CRC XXX 計算すること
                    213:                memset(buf + n, 0, 4);
                    214:                n += 4;
                    215: 
                    216:                // 受信処理に引き渡す
                    217:                // ただしデバッガプロンプトで停止してる状態なら VM に干渉しない。
                    218:                if (parent->RecvEnabled && gCVPrompt->IsPrompt() == false) {
                    219:                        putlog(2, "RecvPacket %d bytes", n);
                    220:                        rx_pkts++;
                    221:                        rx_bytes += n;
                    222: 
                    223:                        qvector<uint8> recvbuf(buf, buf + n);
                    224:                        parent->RecvPacket(recvbuf);
                    225:                }
                    226:        }
                    227: }

unix.superglobalmegacorp.com

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