|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.