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