|
|
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.