Lines 1-51
Link Here
|
1 |
--- src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c.orig 2019-11-21 17:02:02 UTC |
1 |
--- src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c 2019-12-14 11:59:42.519507000 -0700 |
2 |
+++ src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c |
2 |
+++ src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c 2019-12-14 11:59:42.519507000 -0700 |
3 |
@@ -52,6 +52,7 @@ |
3 |
@@ -52,10 +52,12 @@ |
4 |
#include <net/if_dl.h> |
4 |
#include <net/if_dl.h> |
5 |
#include <net/if_types.h> |
5 |
#include <net/if_types.h> |
6 |
#include <net/ethernet.h> |
6 |
#include <net/ethernet.h> |
7 |
+#include <net/if_vlan_var.h> |
7 |
+#include <net/if_vlan_var.h> |
8 |
|
8 |
|
9 |
#include <netgraph/ng_message.h> |
9 |
#include <netgraph/ng_message.h> |
10 |
#include <netgraph/netgraph.h> |
10 |
#include <netgraph/netgraph.h> |
11 |
@@ -73,6 +74,7 @@ |
11 |
#include <netgraph/ng_parse.h> |
|
|
12 |
+#include <netgraph/ng_ether.h> |
13 |
|
14 |
#define LOG_GROUP LOG_GROUP_NET_FLT_DRV |
15 |
#include <VBox/version.h> |
16 |
@@ -73,6 +75,9 @@ |
12 |
|
17 |
|
13 |
#define VBOXNETFLT_OS_SPECFIC 1 |
18 |
#define VBOXNETFLT_OS_SPECFIC 1 |
14 |
#include "../VBoxNetFltInternal.h" |
19 |
#include "../VBoxNetFltInternal.h" |
15 |
+#include "freebsd/the-freebsd-kernel.h" |
20 |
+#include "freebsd/the-freebsd-kernel.h" |
|
|
21 |
+ |
22 |
+MALLOC_DEFINE(M_VBOXNETFLT, "vboxnetflt", "VBoxNetFlt netgraph node"); |
16 |
|
23 |
|
17 |
static int vboxnetflt_modevent(struct module *, int, void *); |
24 |
static int vboxnetflt_modevent(struct module *, int, void *); |
18 |
static ng_constructor_t ng_vboxnetflt_constructor; |
25 |
static ng_constructor_t ng_vboxnetflt_constructor; |
19 |
@@ -436,6 +438,8 @@ static void vboxNetFltFreeBSDinput(void *arg, int pend |
26 |
@@ -93,6 +98,9 @@ |
|
|
27 |
/** Output netgraph hook name */ |
28 |
#define NG_VBOXNETFLT_HOOK_OUT "output" |
29 |
|
30 |
+/** Maximum time to wait for ng_ether replies */ |
31 |
+#define NG_VBOXNETFLT_RPLY_TIMEOUT (10*hz) |
32 |
+ |
33 |
/** mbuf tag identifier */ |
34 |
#define MTAG_VBOX 0x56424f58 |
35 |
/** mbuf packet tag */ |
36 |
@@ -115,6 +123,18 @@ |
37 |
#endif /* !defined(__FreeBSD_version) || __FreeBSD_version < 800500 */ |
38 |
|
39 |
/* |
40 |
+ * Context used to track synchronous netgraph request state. |
41 |
+ */ |
42 |
+struct vboxnetflt_sreq { |
43 |
+ uint32_t typecookie; /**< Matched type cookie. */ |
44 |
+ uint32_t cmd; /**< Matched command. */ |
45 |
+ uint32_t token; /**< Matched token. */ |
46 |
+ struct ng_mesg *resp; /**< On completion, a copy of the reply */ |
47 |
+ |
48 |
+ STAILQ_ENTRY(vboxnetflt_sreq) sr_link; |
49 |
+}; |
50 |
+ |
51 |
+/* |
52 |
* Netgraph command list, we don't support any |
53 |
* additional commands. |
54 |
*/ |
55 |
@@ -303,24 +323,225 @@ |
56 |
} |
57 |
|
58 |
/** |
59 |
- * Netgraph message processing for node specific messages. |
60 |
- * We don't accept any special messages so this is not used. |
61 |
+ * Enqueue and return a reference to a new synchronous response handler, or |
62 |
+ * NULL if allocation fails. |
63 |
*/ |
64 |
+static struct vboxnetflt_sreq * |
65 |
+vboxnetflt_sreq_enqueue(PVBOXNETFLTINS pThis, uint32_t cookie, uint32_t cmd, |
66 |
+ uint32_t token) |
67 |
+{ |
68 |
+ struct vboxnetflt_sreq *sreq; |
69 |
+ |
70 |
+ mtx_assert(&pThis->u.s.sreq_lck, MA_OWNED); |
71 |
+ |
72 |
+ sreq = malloc(sizeof(*sreq), M_VBOXNETFLT, M_NOWAIT|M_ZERO); |
73 |
+ if (sreq == NULL) |
74 |
+ return (NULL); |
75 |
+ |
76 |
+ sreq->typecookie = cookie; |
77 |
+ sreq->cmd = cmd; |
78 |
+ sreq->token = token; |
79 |
+ |
80 |
+ STAILQ_INSERT_TAIL(&pThis->u.s.sreq_list, sreq, sr_link); |
81 |
+ |
82 |
+ return (sreq); |
83 |
+} |
84 |
+ |
85 |
+/** |
86 |
+ * Dequeue and return the first synchronous responder handler capable of |
87 |
+ * handling the given message, or NULL if no handler is found. |
88 |
+ * |
89 |
+ * The caller assumes ownership of any returned handler. |
90 |
+ */ |
91 |
+static struct vboxnetflt_sreq * |
92 |
+vboxnetflt_sreq_dequeue(PVBOXNETFLTINS pThis, struct ng_mesg *msg) |
93 |
+{ |
94 |
+ struct vboxnetflt_sreq *sreq, *sr_next; |
95 |
+ int error; |
96 |
+ |
97 |
+ mtx_assert(&pThis->u.s.sreq_lck, MA_OWNED); |
98 |
+ |
99 |
+ if (!(msg->header.flags & NGF_RESP)) |
100 |
+ return (EINVAL); |
101 |
+ |
102 |
+ STAILQ_FOREACH_SAFE(sreq, &pThis->u.s.sreq_list, sr_link, sr_next) |
103 |
+ { |
104 |
+ if (sreq->typecookie != msg->header.typecookie) |
105 |
+ continue; |
106 |
+ |
107 |
+ if (sreq->cmd != msg->header.cmd) |
108 |
+ continue; |
109 |
+ |
110 |
+ if (sreq->token != msg->header.token) |
111 |
+ continue; |
112 |
+ |
113 |
+ STAILQ_REMOVE(&pThis->u.s.sreq_list, sreq, vboxnetflt_sreq, |
114 |
+ sr_link); |
115 |
+ |
116 |
+ return (sreq); |
117 |
+ } |
118 |
+ |
119 |
+ return (NULL); |
120 |
+} |
121 |
+ |
122 |
+/** |
123 |
+ * Wait for completion of a previously enqueued response handler. On |
124 |
+ * return, the handler will no longer be enqueued, and the caller is |
125 |
+ * responsible for deallocating it via vboxnetflt_sreq_free(). |
126 |
+ */ |
127 |
+static int |
128 |
+vboxnetflt_sreq_wait_enqueued(PVBOXNETFLTINS pThis, |
129 |
+ struct vboxnetflt_sreq *sreq, int timo) |
130 |
+{ |
131 |
+ int error; |
132 |
+ |
133 |
+ mtx_assert(&pThis->u.s.sreq_lck, MA_OWNED); |
134 |
+ |
135 |
+ while (sreq->resp == NULL) { |
136 |
+ error = mtx_sleep(sreq, &pThis->u.s.sreq_lck, 0, "vboxnetflt_sreq", |
137 |
+ timo); |
138 |
+ |
139 |
+ if (error) |
140 |
+ break; |
141 |
+ } |
142 |
+ |
143 |
+ /* If our request was completed, we don't care if mtx_sleep() |
144 |
+ * timed out or otherwise failed */ |
145 |
+ if (sreq->resp != NULL) |
146 |
+ return (0); |
147 |
+ |
148 |
+ /* |
149 |
+ * Otherwise, we stopped waiting before a response has been |
150 |
+ * received, and we're responsible for removing this handler from |
151 |
+ * the queue. |
152 |
+ * |
153 |
+ * If the expected message is delivered later, it will be dropped as |
154 |
+ * spurious if it fails to match against another registered handler. |
155 |
+ */ |
156 |
+ STAILQ_REMOVE(&pThis->u.s.sreq_list, sreq, vboxnetflt_sreq, |
157 |
+ sr_link); |
158 |
+ |
159 |
+ return (ETIMEDOUT); |
160 |
+} |
161 |
+ |
162 |
+/** |
163 |
+ * Free the given synchronous request handler and all associated |
164 |
+ * state. |
165 |
+ * |
166 |
+ * The handler must be dequeued and owned by the caller. |
167 |
+ */ |
168 |
+static void |
169 |
+vboxnetflt_sreq_free(struct vboxnetflt_sreq *sreq) |
170 |
+{ |
171 |
+ if (sreq->resp != NULL) |
172 |
+ NG_FREE_MSG(sreq->resp); |
173 |
+ |
174 |
+ free(sreq, M_VBOXNETFLT); |
175 |
+} |
176 |
+ |
177 |
+ |
178 |
+ |
179 |
+/** |
180 |
+ * Send a simple control message with no additional bytes, blocking until |
181 |
+ * a response is received or a timeout is reached. |
182 |
+ * |
183 |
+ * On success, the caller assumes ownership of the response message, and |
184 |
+ * is responsible for deallocating it via NG_FREE_MSG(). |
185 |
+ */ |
186 |
+int |
187 |
+vboxnetflt_sreq_simple_rpc(PVBOXNETFLTINS pThis, node_p node, ng_ID_t peer, |
188 |
+ uint32_t cookie, uint32_t cmd, struct ng_mesg **resp) |
189 |
+{ |
190 |
+ struct ng_mesg *msg; |
191 |
+ struct vboxnetflt_sreq *sr; |
192 |
+ int error; |
193 |
+ |
194 |
+ NG_MKMESSAGE(msg, cookie, cmd, 0, M_NOWAIT); |
195 |
+ if (msg == NULL) |
196 |
+ return (ENOMEM); |
197 |
+ |
198 |
+ NG_SEND_MSG_ID(error, node, msg, peer, 0); |
199 |
+ if (error) { |
200 |
+ LogRel(("VBoxNetFlt: error sending netgraph message (cookie=%u, " |
201 |
+ "cmd=%u) to [%x]\n", cookie, cmd, peer)); |
202 |
+ return (error); |
203 |
+ } |
204 |
+ |
205 |
+ mtx_lock(&pThis->u.s.sreq_lck); |
206 |
+ |
207 |
+ /* Enqueue our response handler and wait for completion */ |
208 |
+ if ((sr = vboxnetflt_sreq_enqueue(pThis, cookie, cmd, 0)) == NULL) { |
209 |
+ mtx_unlock(&pThis->u.s.sreq_lck); |
210 |
+ return (ENOMEM); |
211 |
+ } |
212 |
+ |
213 |
+ error = vboxnetflt_sreq_wait_enqueued(pThis, sr, |
214 |
+ NG_VBOXNETFLT_RPLY_TIMEOUT); |
215 |
+ |
216 |
+ mtx_unlock(&pThis->u.s.sreq_lck); |
217 |
+ |
218 |
+ if (error) |
219 |
+ goto cleanup; |
220 |
+ |
221 |
+ /* Transfer ownership of the message to the caller */ |
222 |
+ *resp = sr->resp; |
223 |
+ sr->resp = NULL; |
224 |
+ |
225 |
+ /* fallthrough to common cleanup */ |
226 |
+ |
227 |
+cleanup: |
228 |
+ vboxnetflt_sreq_free(sr); |
229 |
+ return (error); |
230 |
+} |
231 |
+ |
232 |
+/** |
233 |
+ * Netgraph control message processing |
234 |
+ */ |
235 |
static int ng_vboxnetflt_rcvmsg(node_p node, item_p item, hook_p lasthook) |
236 |
{ |
237 |
PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node); |
238 |
struct ng_mesg *msg; |
239 |
- int error = 0; |
240 |
+ struct vboxnetflt_sreq *sreq; |
241 |
+ int error; |
242 |
|
243 |
NGI_GET_MSG(item, msg); |
244 |
- if (msg->header.typecookie != NGM_VBOXNETFLT_COOKIE) |
245 |
- return (EINVAL); |
246 |
|
247 |
- switch (msg->header.cmd) |
248 |
+ /* We don't accept any control messages of our own; drop anything that is |
249 |
+ * not a message response. */ |
250 |
+ if (!(msg->header.flags & NGF_RESP)) |
251 |
{ |
252 |
- default: |
253 |
- error = EINVAL; |
254 |
+ error = EINVAL; |
255 |
+ goto failed; |
256 |
} |
257 |
+ |
258 |
+ /* Deqeueue the first matching response handler, if any */ |
259 |
+ mtx_lock(&pThis->u.s.sreq_lck); |
260 |
+ if ((sreq = vboxnetflt_sreq_dequeue(pThis, msg)) == NULL) |
261 |
+ { |
262 |
+ mtx_unlock(&pThis->u.s.sreq_lck); |
263 |
+ |
264 |
+ LogRel(("VBoxNetFlt: dropping spurious netgraph reply (typecookie=%u, " |
265 |
+ "cmd=%u, token=%u)\n", msg->header.typecookie, msg->header.cmd, |
266 |
+ msg->header.token)); |
267 |
+ |
268 |
+ error = EINVAL; |
269 |
+ goto failed; |
270 |
+ } |
271 |
+ |
272 |
+ /* Populate response data, transfering ownership of the message |
273 |
+ * to the response handler. */ |
274 |
+ KASSERT(sreq->resp == NULL, ("request already completed")); |
275 |
+ sreq->resp = msg; |
276 |
+ msg = NULL; |
277 |
+ |
278 |
+ /* Wake up any waiting threads */ |
279 |
+ mtx_unlock(&pThis->u.s.sreq_lck); |
280 |
+ wakeup(sreq); |
281 |
+ |
282 |
+ return (0); |
283 |
+ |
284 |
+failed: |
285 |
+ NG_FREE_MSG(msg); |
286 |
return (error); |
287 |
} |
288 |
|
289 |
@@ -436,6 +657,8 @@ |
20 |
struct ifnet *ifp = pThis->u.s.ifp; |
290 |
struct ifnet *ifp = pThis->u.s.ifp; |
21 |
unsigned int cSegs = 0; |
291 |
unsigned int cSegs = 0; |
22 |
bool fDropIt = false, fActive; |
292 |
bool fDropIt = false, fActive; |
23 |
+ bool is_vl_tagged = false; |
293 |
+ bool is_vl_tagged = false; |
24 |
+ uint16_t vl_tag; |
294 |
+ uint16_t vl_tag; |
25 |
PINTNETSG pSG; |
295 |
PINTNETSG pSG; |
26 |
|
296 |
|
27 |
VBOXCURVNET_SET(ifp->if_vnet); |
297 |
VBOXCURVNET_SET(ifp->if_vnet); |
28 |
@@ -448,6 +452,19 @@ static void vboxNetFltFreeBSDinput(void *arg, int pend |
298 |
@@ -448,6 +671,19 @@ |
29 |
if (m == NULL) |
299 |
if (m == NULL) |
30 |
break; |
300 |
break; |
31 |
|
301 |
|
32 |
+ /* Prepend a VLAN header for consumption by the virtual switch */ |
302 |
+ /* Prepend a VLAN header for consumption by the virtual switch */ |
33 |
+ if (m->m_flags & M_VLANTAG) { |
303 |
+ if (m->m_flags & M_VLANTAG) { |
34 |
+ vl_tag = m->m_pkthdr.ether_vtag; |
304 |
+ vl_tag = m->m_pkthdr.ether_vtag; |
35 |
+ is_vl_tagged = true; |
305 |
+ is_vl_tagged = true; |
36 |
+ |
306 |
+ |
37 |
+ m = ether_vlanencap(m, m->m_pkthdr.ether_vtag); |
307 |
+ m = ether_vlanencap(m, m->m_pkthdr.ether_vtag); |
38 |
+ if (m == NULL) { |
308 |
+ if (m == NULL) { |
39 |
+ printf("vboxflt: unable to prepend VLAN header\n"); |
309 |
+ printf("vboxflt: unable to prepend VLAN header\n"); |
40 |
+ break; |
310 |
+ break; |
41 |
+ } |
311 |
+ } |
42 |
+ m->m_flags &= ~M_VLANTAG; |
312 |
+ m->m_flags &= ~M_VLANTAG; |
43 |
+ } |
313 |
+ } |
44 |
+ |
314 |
+ |
45 |
for (m0 = m; m0 != NULL; m0 = m0->m_next) |
315 |
for (m0 = m; m0 != NULL; m0 = m0->m_next) |
46 |
if (m0->m_len > 0) |
316 |
if (m0->m_len > 0) |
47 |
cSegs++; |
317 |
cSegs++; |
48 |
@@ -462,6 +479,27 @@ static void vboxNetFltFreeBSDinput(void *arg, int pend |
318 |
@@ -462,6 +698,27 @@ |
49 |
vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0); |
319 |
vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0); |
50 |
fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_WIRE); |
320 |
fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_WIRE); |
51 |
RTMemTmpFree(pSG); |
321 |
RTMemTmpFree(pSG); |
Lines 73-247
Link Here
|
73 |
if (fDropIt) |
343 |
if (fDropIt) |
74 |
m_freem(m); |
344 |
m_freem(m); |
75 |
else |
345 |
else |
76 |
@@ -521,6 +559,7 @@ static void vboxNetFltFreeBSDoutput(void *arg, int pen |
346 |
@@ -521,6 +778,7 @@ |
77 |
*/ |
347 |
*/ |
78 |
int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst) |
348 |
int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst) |
79 |
{ |
349 |
{ |
80 |
+ IPRT_FREEBSD_SAVE_EFL_AC(); |
350 |
+ IPRT_FREEBSD_SAVE_EFL_AC(); |
81 |
NOREF(pvIfData); |
351 |
NOREF(pvIfData); |
82 |
|
352 |
|
83 |
void (*input_f)(struct ifnet *, struct mbuf *); |
353 |
void (*input_f)(struct ifnet *, struct mbuf *); |
84 |
@@ -537,10 +576,16 @@ int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *p |
354 |
@@ -537,10 +795,16 @@ |
85 |
{ |
355 |
{ |
86 |
m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG); |
356 |
m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG); |
87 |
if (m == NULL) |
357 |
if (m == NULL) |
88 |
+ { |
358 |
+ { |
89 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
359 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
90 |
return VERR_NO_MEMORY; |
360 |
return VERR_NO_MEMORY; |
91 |
+ } |
361 |
+ } |
92 |
m = m_pullup(m, ETHER_HDR_LEN); |
362 |
m = m_pullup(m, ETHER_HDR_LEN); |
93 |
if (m == NULL) |
363 |
if (m == NULL) |
94 |
+ { |
364 |
+ { |
95 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
365 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
96 |
return VERR_NO_MEMORY; |
366 |
return VERR_NO_MEMORY; |
97 |
+ } |
367 |
+ } |
98 |
|
368 |
|
99 |
m->m_flags |= M_PKTHDR; |
369 |
m->m_flags |= M_PKTHDR; |
100 |
ether_output_frame(ifp, m); |
370 |
ether_output_frame(ifp, m); |
101 |
@@ -550,10 +595,16 @@ int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *p |
371 |
@@ -550,10 +814,16 @@ |
102 |
{ |
372 |
{ |
103 |
m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG); |
373 |
m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG); |
104 |
if (m == NULL) |
374 |
if (m == NULL) |
105 |
+ { |
375 |
+ { |
106 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
376 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
107 |
return VERR_NO_MEMORY; |
377 |
return VERR_NO_MEMORY; |
108 |
+ } |
378 |
+ } |
109 |
m = m_pullup(m, ETHER_HDR_LEN); |
379 |
m = m_pullup(m, ETHER_HDR_LEN); |
110 |
if (m == NULL) |
380 |
if (m == NULL) |
111 |
+ { |
381 |
+ { |
112 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
382 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
113 |
return VERR_NO_MEMORY; |
383 |
return VERR_NO_MEMORY; |
114 |
+ } |
384 |
+ } |
115 |
/* |
385 |
/* |
116 |
* Delivering packets to the host will be captured by the |
386 |
* Delivering packets to the host will be captured by the |
117 |
* input hook. Tag the packet with a mbuf tag so that we |
387 |
* input hook. Tag the packet with a mbuf tag so that we |
118 |
@@ -564,6 +615,7 @@ int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *p |
388 |
@@ -564,6 +834,7 @@ |
119 |
if (mtag == NULL) |
389 |
if (mtag == NULL) |
120 |
{ |
390 |
{ |
121 |
m_freem(m); |
391 |
m_freem(m); |
122 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
392 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
123 |
return VERR_NO_MEMORY; |
393 |
return VERR_NO_MEMORY; |
124 |
} |
394 |
} |
125 |
|
395 |
|
126 |
@@ -574,6 +626,7 @@ int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *p |
396 |
@@ -574,6 +845,7 @@ |
127 |
ifp->if_input(ifp, m); |
397 |
ifp->if_input(ifp, m); |
128 |
} |
398 |
} |
129 |
VBOXCURVNET_RESTORE(); |
399 |
VBOXCURVNET_RESTORE(); |
130 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
400 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
131 |
return VINF_SUCCESS; |
401 |
return VINF_SUCCESS; |
132 |
} |
402 |
} |
133 |
|
403 |
|
134 |
@@ -586,6 +639,7 @@ static bool vboxNetFltFreeBsdIsPromiscuous(PVBOXNETFLT |
404 |
@@ -584,9 +856,43 @@ |
|
|
405 |
return (pThis->u.s.flags & IFF_PROMISC) ? true : false; |
406 |
} |
135 |
|
407 |
|
|
|
408 |
+static bool vboxNetFltFreeBSDNodeName(const char *ifname, char *output, size_t len) |
409 |
+{ |
410 |
+ size_t i; |
411 |
+ |
412 |
+ /* rewrite all characters in netgraph's reserved set '[]:.' to '_' */ |
413 |
+ for (i = 0; i < len; i++) |
414 |
+ { |
415 |
+ char c = ifname[i]; |
416 |
+ |
417 |
+ switch (c) |
418 |
+ { |
419 |
+ case '[': |
420 |
+ case ']': |
421 |
+ case ':': |
422 |
+ case '.': |
423 |
+ output[i] = '_'; |
424 |
+ break; |
425 |
+ default: |
426 |
+ output[i] = c; |
427 |
+ break; |
428 |
+ } |
429 |
+ |
430 |
+ if (c == '\0') |
431 |
+ break; |
432 |
+ } |
433 |
+ |
434 |
+ if (ifname[i] != '\0') |
435 |
+ return false; |
436 |
+ |
437 |
+ return true; |
438 |
+} |
439 |
+ |
136 |
int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext) |
440 |
int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext) |
137 |
{ |
441 |
{ |
138 |
+ IPRT_FREEBSD_SAVE_EFL_AC(); |
442 |
+ IPRT_FREEBSD_SAVE_EFL_AC(); |
139 |
char nam[NG_NODESIZ]; |
443 |
char nam[NG_NODESIZ]; |
|
|
444 |
+ char nam_if[IFNAMSIZ]; |
140 |
struct ifnet *ifp; |
445 |
struct ifnet *ifp; |
141 |
node_p node; |
446 |
node_p node; |
142 |
@@ -594,7 +648,10 @@ int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, voi |
447 |
|
|
|
448 |
@@ -594,11 +900,27 @@ |
143 |
NOREF(pvContext); |
449 |
NOREF(pvContext); |
144 |
ifp = ifunit(pThis->szName); |
450 |
ifp = ifunit(pThis->szName); |
145 |
if (ifp == NULL) |
451 |
if (ifp == NULL) |
146 |
+ { |
452 |
+ { |
|
|
453 |
+ VBOXCURVNET_RESTORE(); |
147 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
454 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
148 |
return VERR_INTNET_FLT_IF_NOT_FOUND; |
455 |
return VERR_INTNET_FLT_IF_NOT_FOUND; |
149 |
+ } |
456 |
+ } |
150 |
|
457 |
|
|
|
458 |
+ /* Rewrite netgraph-reserved characters in the interface name to produce |
459 |
+ * our node's name suffix */ |
460 |
+ if (!vboxNetFltFreeBSDNodeName(pThis->szName, nam_if, sizeof(nam_if))) |
461 |
+ { |
462 |
+ VBOXCURVNET_RESTORE(); |
463 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
464 |
+ return VERR_INTNET_FLT_IF_NOT_FOUND; |
465 |
+ } |
466 |
+ |
151 |
/* Create a new netgraph node for this instance */ |
467 |
/* Create a new netgraph node for this instance */ |
152 |
if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0) |
468 |
- if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0) |
153 |
@@ -638,12 +695,14 @@ int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, voi |
469 |
+ if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0) { |
|
|
470 |
+ VBOXCURVNET_RESTORE(); |
471 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
472 |
return VERR_INTERNAL_ERROR; |
473 |
+ } |
474 |
|
475 |
RTSpinlockAcquire(pThis->hSpinlock); |
476 |
|
477 |
@@ -607,6 +929,10 @@ |
478 |
bcopy(IF_LLADDR(ifp), &pThis->u.s.MacAddr, ETHER_ADDR_LEN); |
479 |
ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false); |
480 |
|
481 |
+ /* Initialize synchronous request state */ |
482 |
+ mtx_init(&pThis->u.s.sreq_lck, "vboxnetflt ng_recv", NULL, MTX_DEF|MTX_NEW); |
483 |
+ STAILQ_INIT(&pThis->u.s.sreq_list); |
484 |
+ |
485 |
/* Initialize deferred input queue */ |
486 |
bzero(&pThis->u.s.inq, sizeof(struct ifqueue)); |
487 |
mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN); |
488 |
@@ -622,7 +948,7 @@ |
489 |
NG_NODE_SET_PRIVATE(node, pThis); |
490 |
|
491 |
/* Attempt to name it vboxnetflt_<ifname> */ |
492 |
- snprintf(nam, NG_NODESIZ, "vboxnetflt_%s", pThis->szName); |
493 |
+ snprintf(nam, NG_NODESIZ, "vboxnetflt_%s", nam_if); |
494 |
ng_name_node(node, nam); |
495 |
|
496 |
/* Report MAC address, promiscuous mode and GSO capabilities. */ |
497 |
@@ -638,12 +964,14 @@ |
154 |
vboxNetFltRelease(pThis, true /*fBusy*/); |
498 |
vboxNetFltRelease(pThis, true /*fBusy*/); |
155 |
} |
499 |
} |
156 |
VBOXCURVNET_RESTORE(); |
500 |
VBOXCURVNET_RESTORE(); |
157 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
501 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
158 |
|
502 |
|
159 |
return VINF_SUCCESS; |
503 |
return VINF_SUCCESS; |
160 |
} |
504 |
} |
161 |
|
505 |
|
162 |
bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis) |
506 |
bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis) |
163 |
{ |
507 |
{ |
164 |
+ IPRT_FREEBSD_SAVE_EFL_AC(); |
508 |
+ IPRT_FREEBSD_SAVE_EFL_AC(); |
165 |
struct ifnet *ifp, *ifp0; |
509 |
struct ifnet *ifp, *ifp0; |
166 |
|
510 |
|
167 |
ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *); |
511 |
ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *); |
168 |
@@ -660,6 +719,7 @@ bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThi |
512 |
@@ -660,6 +988,7 @@ |
169 |
pThis->u.s.node = NULL; |
513 |
pThis->u.s.node = NULL; |
170 |
} |
514 |
} |
171 |
VBOXCURVNET_RESTORE(); |
515 |
VBOXCURVNET_RESTORE(); |
172 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
516 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
173 |
|
517 |
|
174 |
if (ifp0 != NULL) |
518 |
if (ifp0 != NULL) |
175 |
{ |
519 |
{ |
176 |
@@ -672,6 +732,7 @@ bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThi |
520 |
@@ -672,6 +1001,7 @@ |
177 |
|
521 |
|
178 |
void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis) |
522 |
void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis) |
179 |
{ |
523 |
{ |
180 |
+ IPRT_FREEBSD_SAVE_EFL_AC(); |
524 |
+ IPRT_FREEBSD_SAVE_EFL_AC(); |
181 |
|
525 |
|
182 |
taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin); |
526 |
taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin); |
183 |
taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout); |
527 |
taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout); |
184 |
@@ -684,6 +745,7 @@ void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis) |
528 |
@@ -684,6 +1014,18 @@ |
185 |
ng_rmnode_self(pThis->u.s.node); |
529 |
ng_rmnode_self(pThis->u.s.node); |
186 |
VBOXCURVNET_RESTORE(); |
530 |
VBOXCURVNET_RESTORE(); |
187 |
pThis->u.s.node = NULL; |
531 |
pThis->u.s.node = NULL; |
|
|
532 |
+ |
533 |
+ /* Must be done *after* the node has been destroyed, as any incoming |
534 |
+ * netgraph replies will need to acquire this lock. */ |
535 |
+ mtx_destroy(&pThis->u.s.sreq_lck); |
536 |
+ |
537 |
+ /* Not possible unless a state management bug in VBoxNetFlt triggers |
538 |
+ * instance deletion while also blocked in another thread on an active |
539 |
+ * call into our instance */ |
540 |
+ KASSERT(STAILQ_EMPTY(&pThis->u.s.sreq_list), |
541 |
+ ("incomplete synchronous netgraph requests")); |
542 |
+ |
188 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
543 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
189 |
} |
544 |
} |
190 |
|
545 |
|
191 |
int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis) |
546 |
int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis) |
192 |
@@ -697,6 +759,7 @@ int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis) |
547 |
@@ -695,95 +1037,323 @@ |
|
|
548 |
return VINF_SUCCESS; |
549 |
} |
193 |
|
550 |
|
194 |
void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive) |
551 |
-void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive) |
|
|
552 |
+/** |
553 |
+ * Fetch the list of netgraph nodes. |
554 |
+ * |
555 |
+ * On success, the caller assumes ownership of the list of node names, and |
556 |
+ * is responsible for deallocating it via vboxNetFltFreeBSDFreeNodeList(). |
557 |
+ */ |
558 |
+int vboxNetFltFreeBSDListNodes(PVBOXNETFLTINS pThis, node_p node, |
559 |
+ struct namelist **names) |
195 |
{ |
560 |
{ |
196 |
+ IPRT_FREEBSD_SAVE_EFL_AC(); |
561 |
- struct ifnet *ifp; |
197 |
struct ifnet *ifp; |
562 |
- struct ifreq ifreq; |
198 |
struct ifreq ifreq; |
563 |
+ struct ng_mesg *msg; |
|
|
564 |
+ struct namelist *nl; |
565 |
+ size_t len, ni_len, ni_count; |
199 |
int error; |
566 |
int error; |
200 |
@@ -730,7 +793,10 @@ void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, b |
567 |
- node_p node; |
201 |
NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT, |
568 |
+ |
202 |
sizeof(struct ngm_connect), M_NOWAIT); |
569 |
+ /* Fetch the node list */ |
203 |
if (msg == NULL) |
570 |
+ error = vboxnetflt_sreq_simple_rpc(pThis, node, NG_NODE_ID(node), |
204 |
+ { |
571 |
+ NGM_GENERIC_COOKIE, NGM_LISTNODES, &msg); |
205 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
572 |
+ if (error) |
206 |
return; |
573 |
+ { |
|
|
574 |
+ LogRel(("VBoxNetFlt: NGM_LISTNODES failed (%d)\n", error)); |
575 |
+ return error; |
576 |
+ } |
577 |
+ |
578 |
+ /* Must be at least large enough for the fixed entry count. */ |
579 |
+ nl = (struct namelist *)msg->data; |
580 |
+ if (msg->header.arglen < sizeof(*nl)) { |
581 |
+ error = ENXIO; |
582 |
+ goto cleanup; |
583 |
+ } |
584 |
+ |
585 |
+ /* Must be large enough for the header + (numnames * sizeof(nodeinfo)) */ |
586 |
+ ni_count = nl->numnames; |
587 |
+ ni_len = msg->header.arglen - sizeof(*nl); |
588 |
+ |
589 |
+ if (SIZE_MAX / sizeof(nl->nodeinfo[0]) < ni_count) { |
590 |
+ /* Would overflow */ |
591 |
+ error = ENXIO; |
592 |
+ goto cleanup; |
593 |
+ } |
594 |
+ |
595 |
+ if (ni_len < (sizeof(nl->nodeinfo[0]) * ni_count)) { |
596 |
+ error = ENXIO; |
597 |
+ goto cleanup; |
598 |
+ } |
599 |
+ |
600 |
+ /* Copy out the result */ |
601 |
+ nl = malloc(msg->header.arglen, M_VBOXNETFLT, M_NOWAIT); |
602 |
+ if (nl == NULL) { |
603 |
+ |
604 |
+ error = ENOMEM; |
605 |
+ goto cleanup; |
606 |
+ } |
607 |
+ memcpy(nl, msg->data, msg->header.arglen); |
608 |
+ |
609 |
+ *names = nl; |
610 |
+ error = 0; |
611 |
+ |
612 |
+ /* fallthrough */ |
613 |
+ |
614 |
+cleanup: |
615 |
+ NG_FREE_MSG(msg); |
616 |
+ return (error); |
617 |
+} |
618 |
+ |
619 |
+int vboxNetFltFreeBSDFreeNodeList(struct namelist *names) |
620 |
+{ |
621 |
+ free(names, M_VBOXNETFLT); |
622 |
+} |
623 |
+ |
624 |
+/** |
625 |
+ * Fetch the interface name from an ng_ether node. |
626 |
+ */ |
627 |
+int vboxNetFltFreeBSDEtherGetIfName(PVBOXNETFLTINS pThis, node_p node, |
628 |
+ ng_ID_t ether_node, char *buf, size_t buflen) |
629 |
+{ |
630 |
struct ng_mesg *msg; |
631 |
+ char *ifname; |
632 |
+ size_t namelen; |
633 |
+ int error; |
634 |
+ |
635 |
+ /* Fetch the interface name */ |
636 |
+ error = vboxnetflt_sreq_simple_rpc(pThis, node, ether_node, |
637 |
+ NGM_ETHER_COOKIE, NGM_ETHER_GET_IFNAME, &msg); |
638 |
+ if (error) |
639 |
+ { |
640 |
+ /* May fail for innocuous reasons; e.g. if the node disappeared while |
641 |
+ * iterating the node list, etc. */ |
642 |
+ Log(("VBoxNetFlt: NGM_ETHER_GET_IFNAME failed (%d)\n", error)); |
643 |
+ return (error); |
644 |
+ } |
645 |
+ |
646 |
+ ifname = (const char *)msg->data; |
647 |
+ namelen = strnlen(ifname, msg->header.arglen); |
648 |
+ |
649 |
+ /* Must be NUL-terminated */ |
650 |
+ if (namelen == msg->header.arglen) { |
651 |
+ NG_FREE_MSG(msg); |
652 |
+ return (ENXIO); |
653 |
+ } |
654 |
+ |
655 |
+ /* Copy out the result */ |
656 |
+ if (buflen < namelen+1) { |
657 |
+ NG_FREE_MSG(msg); |
658 |
+ return (ENOMEM); |
659 |
+ } |
660 |
+ |
661 |
+ strlcpy(buf, ifname, buflen); |
662 |
+ NG_FREE_MSG(msg); |
663 |
+ |
664 |
+ return (0); |
665 |
+} |
666 |
+ |
667 |
+/** |
668 |
+ * Find the ng_ether node correspnding to our target interface. |
669 |
+ */ |
670 |
+static int vboxNetFltFreeBSDFindEtherNode(PVBOXNETFLTINS pThis, node_p node, |
671 |
+ ng_ID_t *id) |
672 |
+{ |
673 |
+ struct namelist *nl; |
674 |
+ int error; |
675 |
+ |
676 |
+ /* Fetch the full node list */ |
677 |
+ if ((error = vboxNetFltFreeBSDListNodes(pThis, node, &nl))) { |
678 |
+ LogRel(("VBoxNetFlt: failed to fetch node list (%d)\n", error)); |
679 |
+ return (error); |
680 |
+ } |
681 |
+ |
682 |
+ /* Look for a matching NG_ETHER node */ |
683 |
+ for (uint32_t i = 0; i < nl->numnames; i++) { |
684 |
+ struct nodeinfo *ni; |
685 |
+ char ifname[IF_NAMESIZE]; |
686 |
+ |
687 |
+ ni = &nl->nodeinfo[i]; |
688 |
+ |
689 |
+ /* We only care about ng_ether nodes */ |
690 |
+ if (strcmp(ni->type, NG_ETHER_NODE_TYPE) != 0) |
691 |
+ continue; |
692 |
+ |
693 |
+ /* Fetch the interface name */ |
694 |
+ error = vboxNetFltFreeBSDEtherGetIfName(pThis, node, ni->id, ifname, |
695 |
+ sizeof(ifname)); |
696 |
+ if (error) { |
697 |
+ Log(("VBoxNetFlt: failed to fetch interface name (%d)\n", |
698 |
+ error)); |
699 |
+ continue; |
207 |
+ } |
700 |
+ } |
208 |
con = (struct ngm_connect *)msg->data; |
701 |
+ |
209 |
snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", ifp->if_xname); |
702 |
+ /* Skip non-matching interfaces */ |
210 |
strlcpy(con->ourhook, "lower", NG_HOOKSIZ); |
703 |
+ if (strcmp(ifname, pThis->szName) != 0) |
211 |
@@ -744,7 +810,10 @@ void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, b |
704 |
+ continue; |
212 |
NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT, |
705 |
+ |
213 |
sizeof(struct ngm_connect), M_NOWAIT); |
706 |
+ *id = ni->id; |
214 |
if (msg == NULL) |
707 |
+ vboxNetFltFreeBSDFreeNodeList(nl); |
215 |
+ { |
708 |
+ return (0); |
216 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
709 |
+ } |
217 |
return; |
710 |
+ |
218 |
+ } |
711 |
+ vboxNetFltFreeBSDFreeNodeList(nl); |
219 |
con = (struct ngm_connect *)msg->data; |
712 |
+ return (ENOENT); |
220 |
snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", |
713 |
+} |
221 |
ifp->if_xname); |
714 |
+ |
222 |
@@ -767,7 +836,10 @@ void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, b |
715 |
+/** |
223 |
NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK, |
716 |
+ * Send an NGM_CONNECT message. |
224 |
sizeof(struct ngm_rmhook), M_NOWAIT); |
717 |
+ */ |
225 |
if (msg == NULL) |
718 |
+static int vboxNetFltFreeBSDConnectHook(PVBOXNETFLTINS pThis, node_p node, |
226 |
+ { |
719 |
+ ng_ID_t peer, const char *ourhook, const char *peerhook) |
227 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
720 |
+{ |
228 |
return; |
721 |
+ struct ng_mesg *msg; |
229 |
+ } |
722 |
struct ngm_connect *con; |
230 |
rm = (struct ngm_rmhook *)msg->data; |
723 |
+ int error; |
231 |
strlcpy(rm->ourhook, "input", NG_HOOKSIZ); |
724 |
+ |
232 |
NG_SEND_MSG_PATH(error, node, msg, path, 0); |
725 |
+ if (strlen(ourhook) > NG_HOOKSIZ || strlen(peerhook) > NG_HOOKSIZ) |
233 |
@@ -778,12 +850,16 @@ void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, b |
726 |
+ return (EINVAL); |
234 |
NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK, |
727 |
+ |
235 |
sizeof(struct ngm_rmhook), M_NOWAIT); |
728 |
+ NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT, |
236 |
if (msg == NULL) |
729 |
+ sizeof(struct ngm_connect), M_NOWAIT); |
237 |
+ { |
730 |
+ if (msg == NULL) |
238 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
731 |
+ return (ENOMEM); |
239 |
return; |
732 |
+ |
240 |
+ } |
733 |
+ con = (struct ngm_connect *)msg->data; |
241 |
rm = (struct ngm_rmhook *)msg->data; |
734 |
+ snprintf(con->path, NG_PATHSIZ, "[%x]:", NG_NODE_ID(node)); |
242 |
strlcpy(rm->ourhook, "output", NG_HOOKSIZ); |
735 |
+ strlcpy(con->ourhook, ourhook, NG_HOOKSIZ); |
243 |
NG_SEND_MSG_PATH(error, node, msg, path, 0); |
736 |
+ strlcpy(con->peerhook, peerhook, NG_HOOKSIZ); |
|
|
737 |
+ |
738 |
+ NG_SEND_MSG_ID(error, node, msg, peer, 0); |
739 |
+ return (error); |
740 |
+} |
741 |
+ |
742 |
+/** |
743 |
+ * Send an NGM_RMHOOK message. |
744 |
+ */ |
745 |
+static int vboxNetFltFreeBSDRmHook(PVBOXNETFLTINS pThis, node_p node, |
746 |
+ const char *ourhook) |
747 |
+{ |
748 |
+ struct ng_mesg *msg; |
749 |
struct ngm_rmhook *rm; |
750 |
- char path[NG_PATHSIZ]; |
751 |
+ int error; |
752 |
|
753 |
- Log(("%s: fActive:%d\n", __func__, fActive)); |
754 |
+ if (strlen(ourhook) > NG_HOOKSIZ) |
755 |
+ return (EINVAL); |
756 |
|
757 |
- ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *); |
758 |
- VBOXCURVNET_SET(ifp->if_vnet); |
759 |
- node = ASMAtomicUoReadPtrT(&pThis->u.s.node, node_p); |
760 |
+ NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK, |
761 |
+ sizeof(struct ngm_rmhook), M_NOWAIT); |
762 |
+ if (msg == NULL) |
763 |
+ return (ENOMEM); |
764 |
|
765 |
- memset(&ifreq, 0, sizeof(struct ifreq)); |
766 |
- /* Activate interface */ |
767 |
- if (fActive) |
768 |
- { |
769 |
- pThis->u.s.flags = ifp->if_flags; |
770 |
- ifpromisc(ifp, 1); |
771 |
+ rm = (struct ngm_rmhook *)msg->data; |
772 |
+ strlcpy(rm->ourhook, ourhook, NG_HOOKSIZ); |
773 |
|
774 |
- /* ng_ether nodes are named after the interface name */ |
775 |
- snprintf(path, sizeof(path), "%s:", ifp->if_xname); |
776 |
+ NG_SEND_MSG_PATH(error, node, msg, ".:", 0); |
777 |
+ return (error); |
778 |
+} |
779 |
|
780 |
- /* |
781 |
- * Send a netgraph connect message to the ng_ether node |
782 |
- * assigned to the bridged interface. Connecting |
783 |
- * the hooks 'lower' (ng_ether) to out 'input'. |
784 |
- */ |
785 |
- NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT, |
786 |
- sizeof(struct ngm_connect), M_NOWAIT); |
787 |
- if (msg == NULL) |
788 |
- return; |
789 |
- con = (struct ngm_connect *)msg->data; |
790 |
- snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", ifp->if_xname); |
791 |
- strlcpy(con->ourhook, "lower", NG_HOOKSIZ); |
792 |
- strlcpy(con->peerhook, "input", NG_HOOKSIZ); |
793 |
- NG_SEND_MSG_PATH(error, node, msg, path, 0); |
794 |
+/** |
795 |
+ * Called by vboxNetFltPortOsSetActive() to activate the filter driver instance. |
796 |
+ */ |
797 |
+static int vboxNetFltFreeBSDActivate(PVBOXNETFLTINS pThis, struct ifnet *ifp, |
798 |
+ node_p node) |
799 |
+{ |
800 |
+ ng_ID_t ether_node; |
801 |
+ int error; |
802 |
|
803 |
- /* |
804 |
- * Do the same for the hooks 'upper' (ng_ether) and our |
805 |
- * 'output' hook. |
806 |
- */ |
807 |
- NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT, |
808 |
- sizeof(struct ngm_connect), M_NOWAIT); |
809 |
- if (msg == NULL) |
810 |
- return; |
811 |
- con = (struct ngm_connect *)msg->data; |
812 |
- snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", |
813 |
- ifp->if_xname); |
814 |
- strlcpy(con->ourhook, "upper", sizeof(con->ourhook)); |
815 |
- strlcpy(con->peerhook, "output", sizeof(con->peerhook)); |
816 |
- NG_SEND_MSG_PATH(error, node, msg, path, 0); |
817 |
+ pThis->u.s.flags = ifp->if_flags; |
818 |
+ ifpromisc(ifp, 1); |
819 |
+ |
820 |
+ /* Locate the interface's corresponding NG_ETHER netgraph node */ |
821 |
+ if ((error = vboxNetFltFreeBSDFindEtherNode(pThis, node, ðer_node))) { |
822 |
+ LogRel(("VBoxNetFlt: Failed to locate netgraph node for %s: %d\n", |
823 |
+ ifp->if_xname, error)); |
824 |
+ return (error); |
825 |
} |
826 |
- else |
827 |
- { |
828 |
- /* De-activate interface */ |
829 |
- pThis->u.s.flags = 0; |
830 |
- ifpromisc(ifp, 0); |
831 |
|
832 |
- /* Disconnect msgs are addressed to ourself */ |
833 |
- snprintf(path, sizeof(path), "vboxnetflt_%s:", ifp->if_xname); |
834 |
+ /* |
835 |
+ * Send a netgraph connect message to the ng_ether node |
836 |
+ * assigned to the bridged interface. Connecting |
837 |
+ * the hooks 'lower' (ng_ether) to out 'input'. |
838 |
+ */ |
839 |
+ error = vboxNetFltFreeBSDConnectHook(pThis, node, ether_node, |
840 |
+ NG_ETHER_HOOK_LOWER, NG_VBOXNETFLT_HOOK_IN); |
841 |
+ if (error) { |
842 |
+ LogRel(("VBoxNetFlt: Failed to connect netgraph input hook for %s:" |
843 |
+ " %d\n", ifp->if_xname, error)); |
844 |
+ return (error); |
845 |
+ } |
846 |
|
847 |
- /* |
848 |
- * Send a netgraph message to disconnect our 'input' hook |
849 |
- */ |
850 |
- NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK, |
851 |
- sizeof(struct ngm_rmhook), M_NOWAIT); |
852 |
- if (msg == NULL) |
853 |
- return; |
854 |
- rm = (struct ngm_rmhook *)msg->data; |
855 |
- strlcpy(rm->ourhook, "input", NG_HOOKSIZ); |
856 |
- NG_SEND_MSG_PATH(error, node, msg, path, 0); |
857 |
+ /* |
858 |
+ * Do the same for the hooks 'upper' (ng_ether) and our |
859 |
+ * 'output' hook. |
860 |
+ */ |
861 |
+ error = vboxNetFltFreeBSDConnectHook(pThis, node, ether_node, |
862 |
+ NG_ETHER_HOOK_UPPER, NG_VBOXNETFLT_HOOK_OUT); |
863 |
+ if (error) { |
864 |
+ LogRel(("VBoxNetFlt: Failed to connect netgraph output hook for %s:" |
865 |
+ " %d\n", ifp->if_xname, error)); |
866 |
+ return (error); |
867 |
+ } |
868 |
|
869 |
- /* |
870 |
- * Send a netgraph message to disconnect our 'output' hook |
871 |
- */ |
872 |
- NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK, |
873 |
- sizeof(struct ngm_rmhook), M_NOWAIT); |
874 |
- if (msg == NULL) |
875 |
- return; |
876 |
- rm = (struct ngm_rmhook *)msg->data; |
877 |
- strlcpy(rm->ourhook, "output", NG_HOOKSIZ); |
878 |
- NG_SEND_MSG_PATH(error, node, msg, path, 0); |
879 |
+ return (0); |
880 |
+} |
881 |
+ |
882 |
+/** |
883 |
+ * Called by vboxNetFltPortOsSetActive() to deactivate the filter driver |
884 |
+ * instance. |
885 |
+ */ |
886 |
+static int vboxNetFltFreeBSDDeactivate(PVBOXNETFLTINS pThis, struct ifnet *ifp, |
887 |
+ node_p node) |
888 |
+{ |
889 |
+ int ng_error; |
890 |
+ int error = 0; |
891 |
+ |
892 |
+ pThis->u.s.flags = 0; |
893 |
+ ifpromisc(ifp, 0); |
894 |
+ |
895 |
+ /* |
896 |
+ * Send a netgraph message to disconnect our input and output hooks; on |
897 |
+ * failure, we still attempt to disconnect any remaining hooks. |
898 |
+ */ |
899 |
+ ng_error = vboxNetFltFreeBSDRmHook(pThis, node, NG_VBOXNETFLT_HOOK_IN); |
900 |
+ if (ng_error) { |
901 |
+ LogRel(("VBoxNetFlt: Failed to disconnect netgraph input hook for %s:" |
902 |
+ " %d\n", ifp->if_xname, error)); |
903 |
+ error = ng_error; |
244 |
} |
904 |
} |
|
|
905 |
+ |
906 |
+ ng_error = vboxNetFltFreeBSDRmHook(pThis, node, NG_VBOXNETFLT_HOOK_OUT); |
907 |
+ if (ng_error) { |
908 |
+ LogRel(("VBoxNetFlt: Failed to disconnect netgraph output hook for %s:" |
909 |
+ " %d\n", ifp->if_xname, error)); |
910 |
+ error = ng_error; |
911 |
+ } |
912 |
+ |
913 |
+ return (error); |
914 |
+} |
915 |
+ |
916 |
+void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive) |
917 |
+{ |
918 |
+ IPRT_FREEBSD_SAVE_EFL_AC(); |
919 |
+ struct ifnet *ifp; |
920 |
+ int error; |
921 |
+ node_p node; |
922 |
+ |
923 |
+ Log(("%s: fActive:%d\n", __func__, fActive)); |
924 |
+ |
925 |
+ ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *); |
926 |
+ VBOXCURVNET_SET(ifp->if_vnet); |
927 |
+ node = ASMAtomicUoReadPtrT(&pThis->u.s.node, node_p); |
928 |
+ |
929 |
+ if (fActive) |
930 |
+ error = vboxNetFltFreeBSDActivate(pThis, ifp, node); |
931 |
+ else |
932 |
+ error = vboxNetFltFreeBSDDeactivate(pThis, ifp, node); |
933 |
+ |
934 |
+ if (error) |
935 |
+ LogRel(("VBoxNetFlt: Failed to %s %s filter driver: %d\n", |
936 |
+ (fActive ? "activate" : "deactivate"), ifp->if_xname, error)); |
937 |
+ |
245 |
VBOXCURVNET_RESTORE(); |
938 |
VBOXCURVNET_RESTORE(); |
246 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
939 |
+ IPRT_FREEBSD_RESTORE_EFL_AC(); |
247 |
} |
940 |
} |