|
|
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 "cvprompt.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: // コンストラクタ
1.1.1.3 root 26: NetDriverBPF::NetDriverBPF(EthernetDevice *parent_,
27: std::mutex *mtx_, std::condition_variable *cv_)
28: : inherited("BPF", parent_, mtx_, cv_)
1.1 root 29: {
30: fd = -1;
31: }
32:
33: // デストラクタ
34: NetDriverBPF::~NetDriverBPF()
35: {
36: Close();
37: }
38:
39: // 初期化 & オープン
40: bool
41: NetDriverBPF::Init()
42: {
43: struct ifreq ifr;
44: struct bpf_program prog;
45: u_int val;
46: struct bpf_insn insn[] = {
47: // すべてのパケットを全長受信
48: BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
49: };
50:
1.1.1.4 ! root 51: putmsg(1, "NetDriverBPF");
! 52:
1.1 root 53: // XXX tap はデバイスを開くとインタフェースが出来る、という方向だが、
54: // bpf はインタフェースを指定してデバイスを開く、という方向で、逆…。
55:
56: if (ifname.empty()) {
57: // インタフェース指定がなければそれっぽいのを探すか
58: ifname = FindInterface();
59: if (ifname.empty()) {
1.1.1.4 ! root 60: warn("NetDriverBPF.Open: no interface specified");
1.1 root 61: return false;
62: }
63: }
64:
65: // 最大値は適当
66: fd = -1;
67: for (int i = -1; i < 10; i++) {
68: // i == -1 なら /dev/bpf、0..10 は /dev/bpfN。
69: // まず /dev/bpf を cloning デバイスだと思って開いてみる。
70: // そうでなければ従来どおり 0 から順番に試してみる。
71: if (i == -1) {
72: devpath = "/dev/bpf";
73: } else {
74: devpath = string_format("/dev/bpf%d", i);
75: }
76:
77: fd = open(devpath.c_str(), O_RDWR);
1.1.1.4 ! root 78: if (fd < 0) {
! 79: // ファイルがないのを表示したら結構うるさいので除く
! 80: if (errno != ENOENT) {
! 81: putmsg(1, "%s: %s", devpath.c_str(), strerror(errno));
! 82: }
1.1 root 83: continue;
84: }
1.1.1.4 ! root 85: putmsg(1, "%s: found", devpath.c_str());
1.1 root 86: break;
87: }
1.1.1.4 ! root 88: if (fd < 0) {
! 89: putmsg(1, "no bpf devices available");
! 90: warnx("NetDriverBPF.Open: no bpf devices available");
1.1 root 91: return false;
92: }
93:
94: // インタフェースにバインド
95: memset(&ifr, 0, sizeof(ifr));
96: strlcpy(ifr.ifr_name, ifname.c_str(), sizeof(ifr.ifr_name));
97: if (ioctl(fd, BIOCSETIF, &ifr) == -1) {
1.1.1.4 ! root 98: warn("NetDriverBPF.Open: %s(%s): BIOCSETIF",
1.1 root 99: devpath.c_str(), ifname.c_str());
100: goto abort;
101: }
102: // バインドまで出来たところでログを出しておきたい
103: // XXX 本当は warn じゃないよね
104: warnx("NetDriverBPF.Open: %s opened for %s",
105: devpath.c_str(), ifname.c_str());
106:
107: if (ioctl(fd, BIOCPROMISC, (void *)0) == -1) {
1.1.1.4 ! root 108: warn("NetDriverBPF.Open: %s(%s): BIOCPROMISC",
1.1 root 109: devpath.c_str(), ifname.c_str());
110: goto abort;
111: }
112:
113: val = 1;
114: if (ioctl(fd, BIOCIMMEDIATE, &val) == -1) {
1.1.1.4 ! root 115: warn("NetDriverBPF.Open: %s(%s): BIOCIMMEDIATE",
1.1 root 116: devpath.c_str(), ifname.c_str());
117: goto abort;
118: }
119:
120: if (ioctl(fd, BIOCSHDRCMPLT, &val) == -1) {
1.1.1.4 ! root 121: warn("NetDriverBPF.Open: %s(%s): BIOCSHDRCMPLT",
1.1 root 122: devpath.c_str(), ifname.c_str());
123: goto abort;
124: }
125:
126: // XXX BIOCFEEDBACK...
127: warn("NetDriverBPF.Open: %s(%s): ローカルホストとのみ通信はできません",
128: devpath.c_str(), ifname.c_str());
129:
130: // フィルタをセット
131: prog.bf_len = countof(insn);
132: prog.bf_insns = insn;
133: if (ioctl(fd, BIOCSETF, &prog) == -1) {
1.1.1.4 ! root 134: warn("NetDriverBPF.Open: %s(%s): BIOCSETF",
1.1 root 135: devpath.c_str(), ifname.c_str());
136: goto abort;
137: }
138:
139: // バッファサイズを取得
140: if (ioctl(fd, BIOCGBLEN, &bpfbuflen) == -1) {
1.1.1.4 ! root 141: warn("NetDriverBPF.Open: %s(%s): BIOCGBLEN",
1.1 root 142: devpath.c_str(), ifname.c_str());
143: goto abort;
144: }
145:
146: // 受信用バッファを確保
147: try {
1.1.1.2 root 148: bpfbuf.reset(new char [bpfbuflen]);
1.1 root 149: } catch (...) {
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;
1.1.1.4 ! root 238: autofd kq;
1.1 root 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: return;
252: }
253:
254: for (;;) {
255: int n;
256: char *bpfptr;
257: int bpfcaplen;
258:
259: // 何か起きるまで待つ
260: r = kevent_poll(kq, &kev, 1, NULL);
261: if (r == -1) {
262: if (errno == EINTR) {
263: continue;
264: }
265: // XXX ?
266: warn("NetDriverBPF.ThreadRun: kevent_poll failed");
267: break;
268: }
269:
270: // 自動的にデバイスに着信があったことになるはず
271: assert(r > 0);
272:
1.1.1.2 root 273: n = read(fd, bpfbuf.get(), bpfbuflen);
1.1 root 274: if (n == -1) {
275: if (errno == EINTR) {
276: continue;
277: }
278: warn("NetDriverBPF.ThreadRun: read(fd=%d) failed", fd);
279: break;
280: }
281: if (n == 0) { // EOF
282: return;
283: }
1.1.1.2 root 284: bpfptr = bpfbuf.get();
1.1 root 285: bpfcaplen = n;
286:
1.1.1.2 root 287: while (bpfptr < bpfbuf.get() + bpfcaplen) {
1.1 root 288: uint8 buf[1600];
289:
290: // BPF ヘッダを除いた部分
291: struct bpf_hdr *bh = (struct bpf_hdr *)bpfptr;
292: n = bh->bh_caplen;
293: memcpy(buf, bpfptr + bh->bh_hdrlen, n);
294:
295: // 次のフレームの先頭を指す
296: int framelen = BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
297: bpfptr += framelen;
298:
299: // 60バイトパディングされないまま読み出せたらここでパディングする。
300: if (n < 60) {
301: memset(buf + n, 0, 60 - n);
302: n = 60;
303: }
304:
305: // CRC XXX 計算すること
306: memset(buf + n, 0, 4);
307: n += 4;
308:
309: // 受信処理に引き渡す
310: // ただしデバッガプロンプトで停止してる状態なら VM に干渉しない。
311: if (parent->RecvEnabled && gCVPrompt->IsPrompt() == false) {
312: putlog(2, "RecvPacket %d bytes", n);
313: rx_pkts++;
314: rx_bytes += n;
315:
316: qvector<uint8> recvbuf(buf, buf + n);
317: parent->RecvPacket(recvbuf);
318: }
319: }
320: }
321: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.