VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFlt-solaris.c@ 12479

最後變更 在這個檔案從12479是 12326,由 vboxsync 提交於 16 年 前

Solaris/vboxnetflt: Premature raw mode check eliminations.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 85.3 KB
 
1/* $Id: VBoxNetFlt-solaris.c 12326 2008-09-10 08:11:30Z vboxsync $ */
2/** @file
3 * VBoxNetFlt - Network Filter Driver (Host), Solaris Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * Sun Microsystems, Inc. confidential
10 * All rights reserved
11 */
12
13/*******************************************************************************
14* Header Files *
15*******************************************************************************/
16#if defined(DEBUG_ramshankar) && !defined(LOG_ENABLED)
17# define LOG_ENABLED
18#endif
19#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
20#include <VBox/log.h>
21#include <VBox/err.h>
22#include <VBox/cdefs.h>
23#include <iprt/string.h>
24#include <iprt/initterm.h>
25#include <iprt/assert.h>
26#include <iprt/alloca.h>
27#include <iprt/net.h>
28#include <iprt/mem.h>
29#include <iprt/thread.h>
30
31#include <inet/ip.h>
32#include <net/if.h>
33#include <sys/socket.h>
34#include <sys/kstr.h>
35#include <sys/file.h>
36#include <sys/sockio.h>
37#include <sys/strsubr.h>
38#include <sys/pathname.h>
39#include <sys/t_kuser.h>
40
41#include <sys/types.h>
42#include <sys/dlpi.h>
43#include <sys/types.h>
44#include <sys/param.h>
45#include <sys/ethernet.h>
46#include <sys/stat.h>
47#include <sys/stream.h>
48#include <sys/stropts.h>
49#include <sys/strsun.h>
50#include <sys/modctl.h>
51#include <sys/ddi.h>
52#include <sys/sunddi.h>
53#include <sys/sunldi.h>
54
55// Workaround for very strange define in sys/user.h
56// #define u (curproc->p_user) /* user is now part of proc structure */
57#ifdef u
58#undef u
59#endif
60
61#define VBOXNETFLT_OS_SPECFIC 1
62#include "../VBoxNetFltInternal.h"
63
64/*******************************************************************************
65* Defined Constants And Macros *
66*******************************************************************************/
67/** The module name. */
68#define DEVICE_NAME "vboxflt"
69/** The module descriptions as seen in 'modinfo'. */
70#define DEVICE_DESC_DRV "VirtualBox NetFilter Driver"
71#define DEVICE_DESC_MOD "VirtualBox NetFilter Module"
72
73/** @todo Remove the below hackery once done! */
74#if defined(DEBUG_ramshankar) && defined(LOG_ENABLED)
75# undef Log
76# define Log LogRel
77# undef LogFlow
78# define LogFlow LogRel
79#endif
80
81/** Dynamic module binding specific oddities. */
82#define VBOXNETFLT_IFNAME_LEN LIFNAMSIZ + 1
83
84
85/*******************************************************************************
86* Global Functions *
87*******************************************************************************/
88/**
89 * Stream Driver hooks.
90 */
91static int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
92static int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
93static int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
94
95/**
96 * Stream Module hooks.
97 */
98static int VBoxNetFltSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fFile, int fStream, cred_t *pCred);
99static int VBoxNetFltSolarisModClose(queue_t *pQueue, int fFile, cred_t *pCred);
100static int VBoxNetFltSolarisModReadPut(queue_t *pQueue, mblk_t *pMsg);
101static int VBoxNetFltSolarisModWritePut(queue_t *pQueue, mblk_t *pMsg);
102static int VBoxNetFltSolarisModWriteService(queue_t *pQueue);
103
104/**
105 * OS specific hooks invoked from common VBoxNetFlt ring-0.
106 */
107bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis);
108void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac);
109bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac);
110void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive);
111int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis);
112int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis);
113void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis);
114int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis);
115int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis);
116
117
118/*******************************************************************************
119* Structures and Typedefs *
120*******************************************************************************/
121/**
122 * Streams: module info.
123 */
124static struct module_info g_VBoxNetFltSolarisModInfo =
125{
126 0xbad, /* module id */
127 DEVICE_NAME,
128 0, /* min. packet size */
129 INFPSZ, /* max. packet size */
130 0, /* hi-water mask */
131 0 /* lo-water mask */
132};
133
134/**
135 * Streams: read queue hooks.
136 */
137static struct qinit g_VBoxNetFltSolarisReadQ =
138{
139 VBoxNetFltSolarisModReadPut,
140 NULL, /* service */
141 VBoxNetFltSolarisModOpen,
142 VBoxNetFltSolarisModClose,
143 NULL, /* admin (reserved) */
144 &g_VBoxNetFltSolarisModInfo,
145 NULL /* module stats */
146};
147
148/**
149 * Streams: write queue hooks.
150 */
151static struct qinit g_VBoxNetFltSolarisWriteQ =
152{
153 VBoxNetFltSolarisModWritePut,
154 VBoxNetFltSolarisModWriteService,
155 NULL, /* open */
156 NULL, /* close */
157 NULL, /* admin (reserved) */
158 &g_VBoxNetFltSolarisModInfo,
159 NULL /* module stats */
160};
161
162/**
163 * Streams: IO stream tab.
164 */
165static struct streamtab g_VBoxNetFltSolarisStreamTab =
166{
167 &g_VBoxNetFltSolarisReadQ,
168 &g_VBoxNetFltSolarisWriteQ,
169 NULL, /* muxread init */
170 NULL /* muxwrite init */
171};
172
173/**
174 * cb_ops: driver char/block entry points
175 */
176static struct cb_ops g_VBoxNetFltSolarisCbOps =
177{
178 nulldev, /* cb open */
179 nulldev, /* cb close */
180 nodev, /* b strategy */
181 nodev, /* b dump */
182 nodev, /* b print */
183 nodev, /* cb read */
184 nodev, /* cb write */
185 nodev, /* cb ioctl */
186 nodev, /* c devmap */
187 nodev, /* c mmap */
188 nodev, /* c segmap */
189 nochpoll, /* c poll */
190 ddi_prop_op, /* property ops */
191 &g_VBoxNetFltSolarisStreamTab,
192 D_NEW | D_MP | D_MTPERMOD, /* compat. flag */
193 CB_REV /* revision */
194};
195
196/**
197 * dev_ops: driver entry/exit and other ops.
198 */
199static struct dev_ops g_VBoxNetFltSolarisDevOps =
200{
201 DEVO_REV, /* driver build revision */
202 0, /* ref count */
203 VBoxNetFltSolarisGetInfo,
204 nulldev, /* identify */
205 nulldev, /* probe */
206 VBoxNetFltSolarisAttach,
207 VBoxNetFltSolarisDetach,
208 nodev, /* reset */
209 &g_VBoxNetFltSolarisCbOps,
210 (struct bus_ops *)0,
211 nodev /* power */
212};
213
214/**
215 * modldrv: export driver specifics to kernel
216 */
217static struct modldrv g_VBoxNetFltSolarisDriver =
218{
219 &mod_driverops, /* extern from kernel */
220 DEVICE_DESC_DRV,
221 &g_VBoxNetFltSolarisDevOps
222};
223
224/**
225 * fmodsw: streams module ops
226 */
227static struct fmodsw g_VBoxNetFltSolarisModOps =
228{
229 DEVICE_NAME,
230 &g_VBoxNetFltSolarisStreamTab,
231 D_NEW | D_MP | D_MTPERMOD
232};
233
234/**
235 * modlstrmod: streams module specifics to kernel
236 */
237static struct modlstrmod g_VBoxNetFltSolarisModule =
238{
239 &mod_strmodops, /* extern from kernel */
240 DEVICE_DESC_MOD,
241 &g_VBoxNetFltSolarisModOps
242};
243
244/**
245 * modlinkage: export install/remove/info to the kernel
246 */
247static struct modlinkage g_VBoxNetFltSolarisModLinkage =
248{
249 MODREV_1, /* loadable module system revision */
250 &g_VBoxNetFltSolarisDriver, /* streams driver framework */
251 &g_VBoxNetFltSolarisModule, /* streams module framework */
252 NULL /* terminate array of linkage structures */
253};
254
255struct vboxnetflt_state_t;
256
257/**
258 * vboxnetflt_dladdr_t: DL SAP address format
259 */
260typedef struct vboxnetflt_dladdr_t
261{
262 ether_addr_t Mac;
263 uint16_t SAP;
264} vboxnetflt_dladdr_t;
265
266#define VBOXNETFLT_DLADDRL sizeof(vboxnetflt_dladdr_t)
267
268/**
269 * which stream is this?
270 */
271typedef enum VBOXNETFLTSTREAMTYPE
272{
273 kUndefined = 0,
274 kIpStream = 0x1b,
275 kArpStream = 0xab
276} VBOXNETFLTSTREAMTYPE;
277
278/**
279 * vboxnetflt_stream_t: per-stream data
280 */
281typedef struct vboxnetflt_stream_t
282{
283 int DevMinor; /* minor device no. (for clone) */
284 queue_t *pReadQueue; /* read side queue */
285 queue_t *pArpReadQueue; /* ARP read queue */
286 struct vboxnetflt_state_t *pState; /* state associated with this queue */
287 struct vboxnetflt_stream_t *pNext; /* next stream in list */
288 bool fPromisc; /* cached promiscous value */
289 bool fRawMode; /* whether raw mode request was successful */
290 uint32_t ModeReqId; /* track MIOCTLs for swallowing our fake request acknowledgements */
291 t_uscalar_t UnAckPrim; /* unacknowledged primitive sent by this stream, again fake DL request tracking stuff */
292 PVBOXNETFLTINS pThis; /* the backend instance */
293 VBOXNETFLTSTREAMTYPE Type; /* the type of the stream Ip/Arp */
294} vboxnetflt_stream_t;
295
296/**
297 * vboxnetflt_state_t: per-driver data
298 */
299typedef struct vboxnetflt_state_t
300{
301 /** Global device info handle. */
302 dev_info_t *pDip;
303 /** The list of all opened streams. */
304 vboxnetflt_stream_t *pOpenedStreams;
305 /**
306 * pCurInstance is the currently VBox instance to be associated with the stream being created
307 * in ModOpen. This is just shared global data between the dynamic attach and the ModOpen procedure.
308 */
309 PVBOXNETFLTINS pCurInstance;
310 /** Goes along with pCurInstance to determine type of stream being opened/created. */
311 VBOXNETFLTSTREAMTYPE CurType;
312} vboxnetflt_state_t;
313
314
315/*******************************************************************************
316* Internal Functions *
317*******************************************************************************/
318static int vboxNetFltSolarisSetRawMode(queue_t *pQueue);
319static int vboxNetFltSolarisSetFastMode(queue_t *pQueue);
320
321static int vboxNetFltSolarisPhysAddrReq(queue_t *pQueue);
322static void vboxNetFltSolarisCachePhysAddr(PVBOXNETFLTINS pThis, mblk_t *pPhysAddrAckMsg);
323
324static int vboxNetFltSolarisUnitDataToRaw(PVBOXNETFLTINS pThis, mblk_t *pMsg, mblk_t **ppRawMsg);
325static int vboxNetFltSolarisRawToUnitData(mblk_t *pMsg, mblk_t **ppDlpiMsg);
326
327static mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst);
328static unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg);
329static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc);
330static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pMsg);
331static PVBOXNETFLTINS vboxNetFltSolarisFindInstance(vboxnetflt_stream_t *pStream);
332static mblk_t *vboxNetFltSolarisFixChecksums(mblk_t *pMsg);
333static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg);
334
335
336/*******************************************************************************
337* Global Variables *
338*******************************************************************************/
339/** The (common) global data. */
340static VBOXNETFLTGLOBALS g_VBoxNetFltSolarisGlobals;
341/** Global state. */
342static vboxnetflt_state_t g_VBoxNetFltSolarisState;
343/** GCC C++ hack. */
344unsigned __gxx_personality_v0 = 0xdecea5ed;
345/** Global Mutex protecting global state. */
346RTSEMFASTMUTEX g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
347
348
349/**
350 * Kernel entry points
351 */
352int _init(void)
353{
354 LogFlow((DEVICE_NAME ":_init\n"));
355
356 /*
357 * Prevent module autounloading.
358 */
359 modctl_t *pModCtl = mod_getctl(&g_VBoxNetFltSolarisModLinkage);
360 if (pModCtl)
361 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
362 else
363 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
364
365 /*
366 * Initialize IPRT.
367 */
368 int rc = RTR0Init(0);
369 if (RT_SUCCESS(rc))
370 {
371 /*
372 * Initialize Solaris specific globals here.
373 */
374 g_VBoxNetFltSolarisState.pOpenedStreams = NULL;
375 g_VBoxNetFltSolarisState.pCurInstance = NULL;
376 rc = RTSemFastMutexCreate(&g_VBoxNetFltSolarisMtx);
377 if (RT_SUCCESS(rc))
378 {
379 /*
380 * Initialize the globals and connect to the support driver.
381 *
382 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
383 * for establishing the connect to the support driver.
384 */
385 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
386 rc = vboxNetFltInitGlobals(&g_VBoxNetFltSolarisGlobals);
387 if (RT_SUCCESS(rc))
388 {
389 rc = mod_install(&g_VBoxNetFltSolarisModLinkage);
390 if (!rc)
391 return rc;
392
393 LogRel((DEVICE_NAME ":mod_install failed. rc=%d\n", rc));
394 vboxNetFltTryDeleteGlobals(&g_VBoxNetFltSolarisGlobals);
395 }
396 else
397 LogRel((DEVICE_NAME ":failed to initialize globals.\n"));
398
399 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
400 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
401 }
402 else
403 LogRel((DEVICE_NAME ":failed to create mutex.\n"));
404
405 RTR0Term();
406 }
407 else
408 LogRel((DEVICE_NAME ":failed to initialize IPRT (rc=%d)\n", rc));
409
410 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
411 return -1;
412}
413
414
415int _fini(void)
416{
417 int rc;
418 LogFlow((DEVICE_NAME ":_fini\n"));
419
420 /*
421 * Undo the work done during start (in reverse order).
422 */
423 rc = vboxNetFltTryDeleteGlobals(&g_VBoxNetFltSolarisGlobals);
424 if (RT_FAILURE(rc))
425 {
426 LogRel((DEVICE_NAME ":_fini - busy!\n"));
427 return EBUSY;
428 }
429
430 if (g_VBoxNetFltSolarisMtx != NIL_RTSEMFASTMUTEX)
431 {
432 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
433 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
434 }
435
436 RTR0Term();
437
438 return mod_remove(&g_VBoxNetFltSolarisModLinkage);
439}
440
441
442int _info(struct modinfo *pModInfo)
443{
444 LogFlow((DEVICE_NAME ":_info\n"));
445
446 int rc = mod_info(&g_VBoxNetFltSolarisModLinkage, pModInfo);
447
448 LogFlow((DEVICE_NAME ":_info returns %d\n", rc));
449 return rc;
450}
451
452
453/**
454 * Attach entry point, to attach a device to the system or resume it.
455 *
456 * @param pDip The module structure instance.
457 * @param enmCmd Operation type (attach/resume).
458 *
459 * @returns corresponding solaris error code.
460 */
461static int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
462{
463 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
464
465 switch (enmCmd)
466 {
467 case DDI_ATTACH:
468 {
469 int instance = ddi_get_instance(pDip);
470 int rc = ddi_create_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, CLONE_DEV);
471 if (rc == DDI_SUCCESS)
472 {
473 g_VBoxNetFltSolarisState.pDip = pDip;
474 ddi_report_dev(pDip);
475 return DDI_SUCCESS;
476 }
477 else
478 LogRel((DEVICE_NAME ":VBoxNetFltSolarisAttach failed to create minor node. rc%d\n", rc));
479 return DDI_FAILURE;
480 }
481
482 case DDI_RESUME:
483 {
484 /* Nothing to do here... */
485 return DDI_SUCCESS;
486 }
487 }
488 return DDI_FAILURE;
489}
490
491
492/**
493 * Detach entry point, to detach a device to the system or suspend it.
494 *
495 * @param pDip The module structure instance.
496 * @param enmCmd Operation type (detach/suspend).
497 *
498 * @returns corresponding solaris error code.
499 */
500static int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
501{
502 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
503
504 switch (enmCmd)
505 {
506 case DDI_DETACH:
507 {
508 int instance = ddi_get_instance(pDip);
509 ddi_remove_minor_node(pDip, NULL);
510 return DDI_SUCCESS;
511 }
512
513 case DDI_RESUME:
514 {
515 /* Nothing to do here... */
516 return DDI_SUCCESS;
517 }
518 }
519 return DDI_FAILURE;
520}
521
522
523/**
524 * Info entry point, called by solaris kernel for obtaining driver info.
525 *
526 * @param pDip The module structure instance (do not use).
527 * @param enmCmd Information request type.
528 * @param pvArg Type specific argument.
529 * @param ppvResult Where to store the requested info.
530 *
531 * @returns corresponding solaris error code.
532 */
533static int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppResult)
534{
535 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd,
536 getminor((dev_t)pvArg)));
537
538 switch (enmCmd)
539 {
540 case DDI_INFO_DEVT2DEVINFO:
541 {
542 *ppResult = g_VBoxNetFltSolarisState.pDip;
543 return DDI_SUCCESS;
544 }
545
546 case DDI_INFO_DEVT2INSTANCE:
547 {
548 int instance = getminor((dev_t)pvArg);
549 *ppResult = (void *)(uintptr_t)instance;
550 return DDI_SUCCESS;
551 }
552 }
553
554 return DDI_FAILURE;
555}
556
557
558/**
559 * Stream module open entry point, initializes the queue and allows streams processing.
560 *
561 * @param pQueue Pointer to the queue (cannot be NULL).
562 * @param pDev Pointer to the dev_t associated with the driver at the end of the stream.
563 * @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
564 * @param fStreamMode Stream open mode.
565 * @param pCred Pointer to user credentials.
566 *
567 * @returns corresponding solaris error code.
568 */
569static int VBoxNetFltSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fOpenMode, int fStreamMode, cred_t *pCred)
570{
571 Assert(pQueue);
572
573 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModOpen pQueue=%p pDev=%p fOpenMode=%d fStreamMode=%d\n", pQueue, pDev,
574 fOpenMode, fStreamMode));
575
576 /*
577 * Already open?
578 */
579 if (pQueue->q_ptr)
580 {
581 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen invalid open.\n"));
582 return ENOENT;
583 }
584
585 /*
586 * Check for the VirtualBox instance.
587 */
588 vboxnetflt_state_t *pState = &g_VBoxNetFltSolarisState;
589 if (RT_UNLIKELY(!pState->pCurInstance))
590 {
591 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to get VirtualBox instance.\n"));
592 return ENOENT;
593 }
594
595 /*
596 * Check VirtualBox stream type.
597 */
598 if (pState->CurType == kUndefined)
599 {
600 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed due to undefined VirtualBox open mode.\n"));
601 return ENOENT;
602 }
603
604 /*
605 * Get minor number. For clone opens provide a new dev_t.
606 */
607 minor_t DevMinor = 0;
608 vboxnetflt_stream_t *pStream = NULL;
609 vboxnetflt_stream_t **ppPrevStream = &pState->pOpenedStreams;
610 if (fStreamMode == CLONEOPEN)
611 {
612 for (; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
613 {
614 if (DevMinor < pStream->DevMinor)
615 break;
616 DevMinor++;
617 }
618 *pDev = makedevice(getmajor(*pDev), DevMinor);
619 }
620 else
621 DevMinor = getminor(*pDev);
622
623 /*
624 * Allocate & initialize per-stream data. Hook it into the (read and write) queue's module specific data.
625 */
626 pStream = RTMemAlloc(sizeof(*pStream));
627 if (RT_UNLIKELY(!pStream))
628 {
629 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to allocate stream data.\n"));
630 return ENOMEM;
631 }
632 pStream->DevMinor = DevMinor;
633 pStream->pReadQueue = pQueue;
634 pStream->pArpReadQueue = NULL;
635 pStream->pState = pState;
636 pStream->fPromisc = false;
637 pStream->fRawMode = false;
638
639 /*
640 * Pick up the current global VBOXNETFLTINS instance as
641 * the one that we will associate this stream with.
642 */
643 pStream->pThis = pState->pCurInstance;
644 pStream->Type = pState->CurType;
645 if (pState->CurType == kIpStream)
646 pState->pCurInstance->u.s.pvStream = pStream;
647 else
648 pState->pCurInstance->u.s.pvArpStream = pStream;
649
650 pStream->ModeReqId = 0;
651 pStream->UnAckPrim = 0;
652 pQueue->q_ptr = pStream;
653 WR(pQueue)->q_ptr = pStream;
654
655 /*
656 * Link it to the list of streams.
657 */
658 pStream->pNext = *ppPrevStream;
659 *ppPrevStream = pStream;
660
661 qprocson(pQueue);
662
663 /*
664 * Request the physical address (we cache the acknowledgement).
665 */
666 if (pStream->Type == kIpStream)
667 vboxNetFltSolarisPhysAddrReq(pStream->pReadQueue);
668
669 /*
670 * Enable raw mode.
671 */
672 if (pStream->Type == kIpStream)
673 vboxNetFltSolarisSetRawMode(pStream->pReadQueue);
674
675 pStream->pThis->fDisconnectedFromHost = false;
676
677 NOREF(fOpenMode);
678 NOREF(pCred);
679
680 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModOpen returns 0, DevMinor=%d pQueue=%p\n", DevMinor, pStream->pReadQueue));
681
682 return 0;
683}
684
685
686/**
687 * Stream module close entry point, undoes the work done on open and closes the stream.
688 *
689 * @param pQueue Pointer to the queue (cannot be NULL).
690 * @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
691 * @param pCred Pointer to user credentials.
692 *
693 * @returns corresponding solaris error code.
694 */
695static int VBoxNetFltSolarisModClose(queue_t *pQueue, int fOpenMode, cred_t *pCred)
696{
697 Assert(pQueue);
698
699 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModClose pQueue=%p fOpenMode=%d\n", pQueue, fOpenMode));
700
701 vboxnetflt_stream_t *pStream = NULL;
702 vboxnetflt_stream_t **ppPrevStream = NULL;
703 vboxnetflt_state_t *pState = NULL;
704
705 /*
706 * Get instance data.
707 */
708 pStream = (vboxnetflt_stream_t *)pQueue->q_ptr;
709 if (RT_UNLIKELY(!pStream))
710 {
711 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModClose failed to get stream.\n"));
712 return ENXIO;
713 }
714 pState = pStream->pState;
715 Assert(pState);
716
717 /*
718 * Enable native mode.
719 */
720 if (pStream->Type == kIpStream)
721 vboxNetFltSolarisSetFastMode(pStream->pReadQueue);
722
723 pStream->pThis->fDisconnectedFromHost = true;
724 qprocsoff(pQueue);
725
726 /*
727 * Unlink it from the list of streams.
728 */
729 for (ppPrevStream = &pState->pOpenedStreams; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
730 if (pStream == (vboxnetflt_stream_t *)pQueue->q_ptr)
731 break;
732 *ppPrevStream = pStream->pNext;
733
734 /*
735 * Delete the stream.
736 */
737 if (pStream->Type == kIpStream)
738 pStream->pThis->u.s.pvStream = NULL;
739 else
740 pStream->pThis->u.s.pvArpStream = NULL;
741 RTMemFree(pStream);
742 pQueue->q_ptr = NULL;
743 WR(pQueue)->q_ptr = NULL;
744
745 NOREF(fOpenMode);
746 NOREF(pCred);
747
748 return 0;
749}
750
751
752/**
753 * Read side put procedure for processing messages in the read queue.
754 *
755 * @param pQueue Pointer to the queue.
756 * @param pMsg Pointer to the message.
757 *
758 * @returns corresponding solaris error code.
759 */
760static int VBoxNetFltSolarisModReadPut(queue_t *pQueue, mblk_t *pMsg)
761{
762 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut pQueue=%p pMsg=%p\n"));
763
764 bool fSendUpstream = true;
765 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
766
767 /*
768 * In the unlikely case where VirtualBox crashed and this filter
769 * is somehow still in the host stream we must try not to panic the host.
770 */
771 if ( pStream
772 && pStream->Type == kIpStream
773 && pMsg)
774 {
775 PVBOXNETFLTINS pThis = vboxNetFltSolarisFindInstance(pStream);
776 if (RT_LIKELY(pThis))
777 {
778 switch (DB_TYPE(pMsg))
779 {
780 case M_DATA:
781 {
782 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut M_DATA\n"));
783
784 vboxNetFltSolarisRecv(pThis, pStream, pQueue, pMsg);
785 fSendUpstream = false; /* vboxNetFltSolarisRecv would send it if required, do nothing more here. */
786 break;
787 }
788
789 case M_PROTO:
790 case M_PCPROTO:
791 {
792 union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
793 t_uscalar_t Prim = pPrim->dl_primitive;
794
795 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO %d\n", Prim));
796 switch (Prim)
797 {
798 case DL_UNITDATA_IND:
799 {
800 /*
801 * I do not think control would come here... We convert all outgoing fast mode requests
802 * to raw mode; so I don't think we should really receive any fast mode replies.
803 */
804 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_UNITDATA_IND\n"));
805
806 vboxNetFltSolarisRecv(pThis, pStream, pQueue, pMsg);
807 fSendUpstream = false; /* vboxNetFltSolarisRecv would send it if required, do nothing more here. */
808 break;
809 }
810
811 case DL_PHYS_ADDR_ACK:
812 {
813 vboxNetFltSolarisCachePhysAddr(pThis, pMsg);
814
815 /*
816 * Swallow our fake physical address request acknowledgement.
817 */
818 if (pStream->UnAckPrim == DL_PHYS_ADDR_REQ)
819 {
820 freemsg(pMsg);
821 fSendUpstream = false;
822 }
823 break;
824 }
825
826 case DL_OK_ACK:
827 {
828 dl_ok_ack_t *pOkAck = (dl_ok_ack_t *)pMsg->b_rptr;
829 if (pOkAck->dl_correct_primitive == DL_PROMISCON_REQ)
830 {
831 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO: DL_OK_ACK: fPromisc is ON.\n"));
832 pStream->fPromisc = true;
833 }
834 else if (pOkAck->dl_correct_primitive == DL_PROMISCOFF_REQ)
835 {
836 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO: DL_OK_ACK: fPromisc is OFF.\n"));
837 pStream->fPromisc = false;
838 }
839
840 /*
841 * Swallow our fake promiscous request acknowledgement.
842 */
843 if (pStream->UnAckPrim == pOkAck->dl_correct_primitive)
844 {
845 freemsg(pMsg);
846 fSendUpstream = false;
847 }
848 break;
849 }
850 }
851 break;
852 }
853
854 case M_IOCACK:
855 {
856 /*
857 * Swallow our fake raw/fast path mode request acknowledgement.
858 */
859 struct iocblk *pIOC = (struct iocblk *)pMsg->b_rptr;
860 if (pIOC->ioc_id == pStream->ModeReqId)
861 {
862 pStream->fRawMode = !pStream->fRawMode;
863 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Mode acknowledgement. RawMode is %s\n",
864 pStream->fRawMode ? "ON" : "OFF"));
865
866 freemsg(pMsg);
867 fSendUpstream = false;
868 }
869 break;
870 }
871
872 case M_FLUSH:
873 {
874 /*
875 * We must support flushing queues.
876 */
877 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_FLUSH\n"));
878 if (*pMsg->b_rptr & FLUSHR)
879 flushq(pQueue, FLUSHALL);
880 break;
881 }
882 }
883 }
884 else
885 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Could not find VirtualBox instance!!\n"));
886 }
887
888 if ( fSendUpstream
889 && pMsg)
890 {
891 /*
892 * Pass foward high priority messages or when there's no flow control
893 * on an empty queue, otherwise queue them.
894 */
895 if ( queclass(pMsg) == QPCTL
896 || (pQueue->q_first == NULL && canputnext(pQueue)))
897 {
898 putnext(pQueue, pMsg);
899 }
900 else
901 putq(pQueue, pMsg);
902 }
903
904 return 0;
905}
906
907
908/**
909 * Write side put procedure for processing messages in the write queue.
910 *
911 * @param pQueue Pointer to the queue.
912 * @param pMsg Pointer to the message.
913 *
914 * @returns corresponding solaris error code.
915 */
916static int VBoxNetFltSolarisModWritePut(queue_t *pQueue, mblk_t *pMsg)
917{
918 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut pQueue=%p pMsg=%p\n", pQueue, pMsg));
919
920 /*
921 * Check for the VirtualBox connection.
922 */
923 bool fSendDownstream = true;
924 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
925
926 /*
927 * In the unlikely case where VirtualBox crashed and this filter
928 * is somehow still in the host stream we must try not to panic the host.
929 */
930 if ( pStream
931 && pStream->Type == kIpStream
932 && pMsg)
933 {
934 PVBOXNETFLTINS pThis = vboxNetFltSolarisFindInstance(pStream);
935 if (RT_LIKELY(pThis))
936 {
937 switch (DB_TYPE(pMsg))
938 {
939 case M_DATA:
940 {
941 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut M_DATA\n"));
942 break;
943 }
944
945 case M_PROTO:
946 case M_PCPROTO:
947 {
948 /*
949 * If we are not yet in raw mode; just pass through.
950 */
951 if (!pStream->fRawMode)
952 break;
953
954 /*
955 * Queue up other primitives to the service routine.
956 */
957 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut M_PROTO/M_PCPROTO\n"));
958
959 union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
960 t_uscalar_t Prim = pPrim->dl_primitive;
961 switch (Prim)
962 {
963 case DL_UNITDATA_REQ:
964 {
965 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut DL_UNITDATA_REQ\n"));
966 mblk_t *pRawMsg;
967 int rc = vboxNetFltSolarisUnitDataToRaw(pThis, pMsg, &pRawMsg);
968 if (RT_SUCCESS(rc))
969 pMsg = pRawMsg;
970 else
971 fSendDownstream = false;
972 break;
973 }
974
975 default:
976 {
977 /*
978 * Enqueue other DLPI primitives and service them later.
979 */
980 fSendDownstream = false;
981 putq(pQueue, pMsg);
982 break;
983 }
984 }
985 break;
986 }
987
988 case M_IOCTL:
989 {
990 struct iocblk *pIOC = (struct iocblk *)pMsg->b_rptr;
991 if (pIOC->ioc_cmd == DL_IOC_HDR_INFO)
992 {
993 if (pThis->fActive)
994 {
995 fSendDownstream = false;
996
997 /*
998 * Some sanity checks.
999 */
1000 if ( !pMsg->b_cont
1001 || (MBLKL(pMsg->b_cont) < sizeof(dl_unitdata_req_t) + VBOXNETFLT_DLADDRL)
1002 || (*((uint32_t *)pMsg->b_cont->b_rptr) != DL_UNITDATA_REQ))
1003 {
1004 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModWritePut: Invalid fast path request!\n"));
1005 miocnak(pQueue, pMsg, 0, EPROTO);
1006 break;
1007 }
1008
1009 dl_unitdata_req_t *pDlReq = (dl_unitdata_req_t *)pMsg->b_cont->b_rptr;
1010 size_t cbOffset = pDlReq->dl_dest_addr_offset;
1011 size_t cbAddr = pDlReq->dl_dest_addr_length;
1012 if ( !MBLKIN(pMsg->b_cont, cbOffset, cbAddr)
1013 || cbAddr != VBOXNETFLT_DLADDRL)
1014 {
1015 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModWritePut: Invalid header in fast path request!\n"));
1016 miocnak(pQueue, pMsg, 0, EPROTO);
1017 break;
1018 }
1019
1020 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_cont->b_rptr + cbOffset);
1021 mblk_t *pReplyMsg = allocb(sizeof(RTNETETHERHDR), BPRI_MED);
1022 if (RT_UNLIKELY(!pReplyMsg))
1023 {
1024 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModWritePut: Invalid header in fast path request!\n"));
1025 miocnak(pQueue, pMsg, 0, ENOMEM);
1026 break;
1027 }
1028
1029 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
1030 bcopy(&pDLSapAddr->Mac, &pEthHdr->DstMac, sizeof(RTMAC));
1031 bcopy(&pThis->u.s.Mac, &pEthHdr->SrcMac, sizeof(RTMAC));
1032 pEthHdr->EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
1033
1034 linkb(pMsg, pReplyMsg);
1035
1036 /*
1037 * Somebody is wanting fast path when we need raw mode.
1038 * Since we are evil, let's acknowledge the request ourselves!
1039 */
1040 miocack(pQueue, pMsg, msgsize(pMsg->b_cont), EINVAL);
1041 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut: Fast path request acknowledged.\n"));
1042 }
1043 }
1044 break;
1045 }
1046
1047 case M_FLUSH:
1048 {
1049 /*
1050 * Canonical flush courtesy man qreply(9F) while we have a service routine.
1051 */
1052 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut M_FLUSH\n"));
1053 if (*pMsg->b_rptr & FLUSHW)
1054 {
1055 /*
1056 * Flush and mark as serviced.
1057 */
1058 flushq(pQueue, FLUSHALL);
1059 *pMsg->b_rptr &= ~FLUSHW;
1060 }
1061
1062 if (*pMsg->b_rptr & FLUSHR)
1063 {
1064 /*
1065 * Send the request upstream.
1066 */
1067 flushq(RD(pQueue), FLUSHALL);
1068 qreply(pQueue, pMsg);
1069 }
1070 else
1071 freemsg(pMsg);
1072
1073 break;
1074 }
1075 }
1076 }
1077 else
1078 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModWritePut: Could not find VirtualBox instance!!\n"));
1079 }
1080
1081 if ( fSendDownstream
1082 && pMsg)
1083 {
1084 /*
1085 * Pass foward high priority messages or when there's no flow control
1086 * on an empty queue, otherwise queue them.
1087 */
1088 if ( queclass(pMsg) == QPCTL
1089 || (pQueue->q_first == NULL && canputnext(pQueue)))
1090 {
1091 putnext(pQueue, pMsg);
1092 }
1093 else
1094 putq(pQueue, pMsg);
1095 }
1096
1097 return 0;
1098}
1099
1100
1101/**
1102 * Write side service procedure for deferred message processing on the write queue.
1103 *
1104 * @param pQueue Pointer to the queue.
1105 *
1106 * @returns corresponding solaris error code.
1107 */
1108static int VBoxNetFltSolarisModWriteService(queue_t *pQueue)
1109{
1110 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWriteService pQueue=%p\n", pQueue));
1111
1112 /*
1113 * Implment just the flow controlled service draining of the queue.
1114 * Nothing else to do here, we handle all the important stuff in the Put procedure.
1115 */
1116 mblk_t *pMsg;
1117 while (pMsg = getq(pQueue))
1118 {
1119 if (canputnext(pQueue))
1120 putnext(pQueue, pMsg);
1121 else
1122 {
1123 putbq(pQueue, pMsg);
1124 break;
1125 }
1126 }
1127
1128 return 0;
1129}
1130
1131
1132/**
1133 * Put the stream in raw mode.
1134 *
1135 * @returns VBox status code.
1136 * @param pQueue Pointer to the queue.
1137 */
1138static int vboxNetFltSolarisSetRawMode(queue_t *pQueue)
1139{
1140 LogFlow((DEVICE_NAME ":vboxNetFltSolarisSetRawMode pQueue=%p\n", pQueue));
1141
1142 mblk_t *pRawMsg = NULL;
1143 pRawMsg = mkiocb(DLIOCRAW);
1144 if (RT_UNLIKELY(!pRawMsg))
1145 return VERR_NO_MEMORY;
1146
1147 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
1148 struct iocblk *pIOC = (struct iocblk *)pRawMsg->b_rptr;
1149 pStream->ModeReqId = pIOC->ioc_id;
1150 pIOC->ioc_count = 0;
1151
1152 qreply(pQueue, pRawMsg);
1153 return VINF_SUCCESS;
1154}
1155
1156
1157/**
1158 * Put the stream back in fast path mode.
1159 *
1160 * @returns VBox status code.
1161 * @param pQueue Pointer to the queue.
1162 */
1163static int vboxNetFltSolarisSetFastMode(queue_t *pQueue)
1164{
1165 LogFlow((DEVICE_NAME ":vboxNetFltSolarisSetFastMode pQueue=%p\n", pQueue));
1166
1167 mblk_t *pFastMsg = mkiocb(DL_IOC_HDR_INFO);
1168 if (RT_UNLIKELY(!pFastMsg))
1169 return VERR_NO_MEMORY;
1170
1171 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
1172 struct iocblk *pIOC = (struct iocblk *)pFastMsg->b_rptr;
1173 pStream->ModeReqId = pIOC->ioc_id;
1174
1175 size_t cbReq = sizeof(dl_unitdata_req_t) + sizeof(vboxnetflt_dladdr_t);
1176 mblk_t *pDataReqMsg = allocb(cbReq, BPRI_MED);
1177 if (RT_UNLIKELY(!pDataReqMsg))
1178 return VERR_NO_MEMORY;
1179
1180 DB_TYPE(pDataReqMsg) = M_PROTO;
1181 dl_unitdata_req_t *pDataReq = (dl_unitdata_req_t *)pDataReqMsg->b_rptr;
1182 pDataReq->dl_primitive = DL_UNITDATA_REQ;
1183 pDataReq->dl_dest_addr_length = sizeof(vboxnetflt_dladdr_t);
1184 pDataReq->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
1185 pDataReq->dl_priority.dl_min = 0;
1186 pDataReq->dl_priority.dl_max = 0;
1187
1188 bzero(pDataReqMsg->b_rptr + sizeof(dl_unitdata_req_t), sizeof(vboxnetflt_dladdr_t));
1189 pDataReqMsg->b_wptr = pDataReqMsg->b_rptr + cbReq;
1190
1191 /*
1192 * Link the data format request message into the header ioctl message.
1193 */
1194 pFastMsg->b_cont = pDataReqMsg;
1195 pIOC->ioc_count = msgdsize(pDataReqMsg);
1196
1197 qreply(pQueue, pFastMsg);
1198 return VINF_SUCCESS;
1199}
1200
1201
1202/**
1203 * Send fake promiscous mode requests downstream.
1204 *
1205 * @param pQueue Pointer to the queue.
1206 * @param fPromisc Whether to enable promiscous mode or not.
1207 * @param PromiscLevel Promiscous level; DL_PROMISC_PHYS/SAP/MULTI.
1208 *
1209 * @returns VBox error code.
1210 */
1211static int vboxNetFltSolarisPromiscReq(queue_t *pQueue, bool fPromisc)
1212{
1213 LogFlow((DEVICE_NAME ":vboxNetFltSolarisPromiscReq pQueue=%p fPromisc=%d\n", pQueue, fPromisc));
1214
1215 t_uscalar_t Cmd;
1216 size_t cbReq = 0;
1217 if (fPromisc)
1218 {
1219 Cmd = DL_PROMISCON_REQ;
1220 cbReq = DL_PROMISCON_REQ_SIZE;
1221 }
1222 else
1223 {
1224 Cmd = DL_PROMISCOFF_REQ;
1225 cbReq = DL_PROMISCOFF_REQ_SIZE;
1226 }
1227
1228 mblk_t *pPromiscPhysMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1229 if (RT_UNLIKELY(!pPromiscPhysMsg))
1230 return VERR_NO_MEMORY;
1231
1232 mblk_t *pPromiscSapMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1233 if (RT_UNLIKELY(!pPromiscSapMsg))
1234 {
1235 freemsg(pPromiscPhysMsg);
1236 return VERR_NO_MEMORY;
1237 }
1238
1239 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
1240 pStream->UnAckPrim = Cmd;
1241
1242 if (fPromisc)
1243 {
1244 ((dl_promiscon_req_t *)pPromiscPhysMsg->b_rptr)->dl_level = DL_PROMISC_PHYS;
1245 ((dl_promiscon_req_t *)pPromiscSapMsg->b_rptr)->dl_level = DL_PROMISC_SAP;
1246 }
1247 else
1248 {
1249 ((dl_promiscoff_req_t *)pPromiscPhysMsg->b_rptr)->dl_level = DL_PROMISC_PHYS;
1250 ((dl_promiscoff_req_t *)pPromiscSapMsg->b_rptr)->dl_level = DL_PROMISC_SAP;
1251 }
1252
1253 qreply(pQueue, pPromiscPhysMsg);
1254 qreply(pQueue, pPromiscSapMsg);
1255
1256 return VINF_SUCCESS;
1257}
1258
1259
1260/**
1261 * Send a fake physical address request downstream.
1262 *
1263 * @returns VBox status code.
1264 * @param pQueue Pointer to the queue.
1265 * @param pMsg Pointer to the request message.
1266 */
1267static int vboxNetFltSolarisPhysAddrReq(queue_t *pQueue)
1268{
1269 LogFlow((DEVICE_NAME ":vboxNetFltSolarisPhysAddrReq pQueue=%p\n", pQueue));
1270
1271 t_uscalar_t Cmd = DL_PHYS_ADDR_REQ;
1272 size_t cbReq = DL_PHYS_ADDR_REQ_SIZE;
1273 mblk_t *pPhysAddrMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1274 if (RT_UNLIKELY(!pPhysAddrMsg))
1275 return VERR_NO_MEMORY;
1276
1277 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
1278 pStream->UnAckPrim = Cmd;
1279
1280 dl_phys_addr_req_t *pPhysAddrReq = (dl_phys_addr_req_t *)pPhysAddrMsg->b_rptr;
1281 pPhysAddrReq->dl_addr_type = DL_CURR_PHYS_ADDR;
1282
1283 qreply(pQueue, pPhysAddrMsg);
1284 return VERR_GENERAL_FAILURE;
1285}
1286
1287
1288/**
1289 * Cache the MAC address into the VirtualBox instance given a physical
1290 * address acknowledgement message.
1291 *
1292 * @param pThis The instance.
1293 * @param pMsg Pointer to the physical address acknowledgement message.
1294 */
1295static void vboxNetFltSolarisCachePhysAddr(PVBOXNETFLTINS pThis, mblk_t *pMsg)
1296{
1297 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr pThis=%p pMsg=%p\n", pThis, pMsg));
1298
1299 AssertCompile(sizeof(RTMAC) == ETHERADDRL);
1300 dl_phys_addr_ack_t *pPhysAddrAck = (dl_phys_addr_ack_t *)pMsg->b_rptr;
1301 if (pPhysAddrAck->dl_addr_length == sizeof(pThis->u.s.Mac))
1302 {
1303 bcopy(pMsg->b_rptr + pPhysAddrAck->dl_addr_offset, &pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
1304
1305 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr: DL_PHYS_ADDR_ACK: Mac=%.*Rhxs\n", sizeof(pThis->u.s.Mac),
1306 &pThis->u.s.Mac));
1307 }
1308}
1309
1310
1311/**
1312 * Opens the required device and returns the vnode_t associated with it.
1313 * We require this for the funny attach/detach routine.
1314 *
1315 * @returns VBox status code.
1316 * @param pszDev The device path.
1317 * @param ppVNode Where to store the vnode_t pointer associated with the opened device.
1318 * @param ppVNodeHeld Where to store the vnode_t required during closing of the device.
1319 * @param ppUser Open handle required while closing the device.
1320 */
1321static int vboxNetFltSolarisOpenDev(char *pszDev, vnode_t **ppVNode, vnode_t **ppVNodeHeld, TIUSER **ppUser)
1322{
1323 int rc;
1324 vnode_t *pVNodeHeld = NULL;
1325 rc = lookupname(pszDev, UIO_SYSSPACE, FOLLOW, NULLVPP, &pVNodeHeld);
1326 if (!rc)
1327 {
1328 TIUSER *pUser;
1329 rc = t_kopen((file_t *)NULL, pVNodeHeld->v_rdev, FREAD | FWRITE, &pUser, kcred);
1330 if (!rc)
1331 {
1332 *ppVNode = pUser->fp->f_vnode;
1333 *ppVNodeHeld = pVNodeHeld;
1334 *ppUser = pUser;
1335 return VINF_SUCCESS;
1336 }
1337 VN_RELE(pVNodeHeld);
1338 }
1339 return VERR_PATH_NOT_FOUND;
1340}
1341
1342
1343/**
1344 * Close the device opened using vboxNetFltSolarisOpenDev.
1345 *
1346 * @param pVNodeHeld Pointer to the held vnode of the device.
1347 * @param pUser Pointer to the file handle.
1348 */
1349static void vboxNetFltSolarisCloseDev(vnode_t *pVNodeHeld, TIUSER *pUser)
1350{
1351 t_kclose(pUser, 0);
1352 VN_RELE(pVNodeHeld);
1353}
1354
1355
1356/**
1357 * Get the logical interface flags from the stream.
1358 *
1359 * @returns VBox status code.
1360 * @param hDevice Layered device handle.
1361 * @param pInterface Pointer to the interface.
1362 */
1363static int vboxNetFltSolarisGetIfFlags(ldi_handle_t hDevice, struct lifreq *pInterface)
1364{
1365 struct strioctl IOCReq;
1366 int rc;
1367 int ret;
1368 IOCReq.ic_cmd = SIOCGLIFFLAGS;
1369 IOCReq.ic_timout = 40;
1370 IOCReq.ic_len = sizeof(struct lifreq);
1371 IOCReq.ic_dp = (caddr_t)pInterface;
1372 rc = ldi_ioctl(hDevice, I_STR, (intptr_t)&IOCReq, FKIOCTL, kcred, &ret);
1373 if (!rc)
1374 return VINF_SUCCESS;
1375
1376 return RTErrConvertFromErrno(rc);
1377}
1378
1379
1380/**
1381 * Sets the multiplexor ID from the interface.
1382 *
1383 * @returns VBox status code.
1384 * @param pVNode Pointer to the device vnode.
1385 * @param pInterface Pointer to the interface.
1386 */
1387static int vboxNetFltSolarisSetMuxId(vnode_t *pVNode, struct lifreq *pInterface)
1388{
1389 struct strioctl IOCReq;
1390 int rc;
1391 int ret;
1392 IOCReq.ic_cmd = SIOCSLIFMUXID;
1393 IOCReq.ic_timout = 40;
1394 IOCReq.ic_len = sizeof(struct lifreq);
1395 IOCReq.ic_dp = (caddr_t)pInterface;
1396
1397 rc = strioctl(pVNode, I_STR, (intptr_t)&IOCReq, 0, K_TO_K, kcred, &ret);
1398 if (!rc)
1399 return VINF_SUCCESS;
1400
1401 return RTErrConvertFromErrno(rc);
1402}
1403
1404
1405/**
1406 * Get the multiplexor file descriptor of the lower stream.
1407 *
1408 * @returns VBox status code.
1409 * @param MuxId The multiplexor ID.
1410 * @param pFd Where to store the lower stream file descriptor.
1411 */
1412static int vboxNetFltSolarisMuxIdToFd(vnode_t *pVNode, int MuxId, int *pFd)
1413{
1414 int ret;
1415 int rc = strioctl(pVNode, _I_MUXID2FD, (intptr_t)MuxId, 0, K_TO_K, kcred, &ret);
1416 if (!rc)
1417 {
1418 *pFd = ret;
1419 return VINF_SUCCESS;
1420 }
1421
1422 return RTErrConvertFromErrno(rc);
1423}
1424
1425
1426/**
1427 * Relinks the lower and the upper stream.
1428 *
1429 * @returns VBox status code.
1430 * @param pVNode Pointer to the device vnode.
1431 * @param pInterface Pointer to the interface.
1432 * @param IpMuxFd The IP multiplexor ID.
1433 * @param ArpMuxFd The ARP multiplexor ID.
1434 */
1435static int vboxNetFltSolarisRelink(vnode_t *pVNode, struct lifreq *pInterface, int IpMuxFd, int ArpMuxFd)
1436{
1437 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRelink: pVNode=%p pInterface=%p IpMuxFd=%d ArpMuxFd=%d\n", pVNode,
1438 pInterface, IpMuxFd, ArpMuxFd));
1439
1440 int NewIpMuxId;
1441 int NewArpMuxId;
1442 int rc = strioctl(pVNode, I_PLINK, (intptr_t)IpMuxFd, 0, K_TO_K, kcred, &NewIpMuxId);
1443 int rc2 = strioctl(pVNode, I_PLINK, (intptr_t)ArpMuxFd, 0, K_TO_K, kcred, &NewArpMuxId);
1444 if ( !rc
1445 && !rc2)
1446 {
1447 pInterface->lifr_ip_muxid = NewIpMuxId;
1448 pInterface->lifr_arp_muxid = NewArpMuxId;
1449 rc = vboxNetFltSolarisSetMuxId(pVNode, pInterface);
1450 if (RT_SUCCESS(rc))
1451 return VINF_SUCCESS;
1452
1453 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelink: failed to set new Mux Id.\n"));
1454 }
1455 else
1456 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelink: failed to link.\n"));
1457
1458 return VERR_GENERAL_FAILURE;
1459}
1460
1461
1462/**
1463 * Dynamically find the position on the host stack where to attach/detach ourselves.
1464 *
1465 * @returns VBox status code.
1466 * @param pVNode Pointer to the lower stream vnode.
1467 * @param pModPos Where to store the module position.
1468 */
1469static int vboxNetFltSolarisDetermineModPos(bool fAttach, vnode_t *pVNode, int *pModPos)
1470{
1471 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: fAttach=%d pVNode=%p pModPos=%p\n", fAttach, pVNode, pModPos));
1472
1473 int cMod;
1474 int rc = strioctl(pVNode, I_LIST, (intptr_t)NULL, 0, K_TO_K, kcred, &cMod);
1475 if (!rc)
1476 {
1477 if (cMod < 1)
1478 {
1479 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: too few modules on host interface. cMod=%d\n"));
1480 return VERR_OUT_OF_RANGE;
1481 }
1482
1483 /*
1484 * While attaching we make sure we are at the bottom most of the stack, excepting
1485 * the host driver.
1486 */
1487 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: cMod=%d\n", cMod));
1488 if (fAttach)
1489 {
1490 *pModPos = cMod - 1;
1491 return VINF_SUCCESS;
1492 }
1493
1494 /*
1495 * Detaching is a bit more complicated; since user could have altered the stack positions
1496 * we take the safe approach by finding our position.
1497 */
1498 struct str_list StrList;
1499 StrList.sl_nmods = cMod;
1500 StrList.sl_modlist = RTMemAllocZ(cMod * sizeof(struct str_list));
1501 if (RT_UNLIKELY(!StrList.sl_modlist))
1502 {
1503 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to alloc memory for StrList.\n"));
1504 return VERR_NO_MEMORY;
1505 }
1506
1507 /*
1508 * Get the list of all modules on the stack.
1509 */
1510 int ret;
1511 rc = strioctl(pVNode, I_LIST, (intptr_t)&StrList, 0, K_TO_K, kcred, &ret);
1512 if (!rc)
1513 {
1514 /*
1515 * Find our filter.
1516 */
1517 for (int i = 0; i < StrList.sl_nmods; i++)
1518 {
1519 if (!strcmp(DEVICE_NAME, StrList.sl_modlist[i].l_name))
1520 {
1521 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: Success! Found %s at %d.\n", DEVICE_NAME, i));
1522 *pModPos = i;
1523 return VINF_SUCCESS;
1524 }
1525 }
1526
1527 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to find %s in the host stack.\n"));
1528 }
1529 else
1530 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get module information. rc=%d\n"));
1531 }
1532 else
1533 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get list of modules on host interface. rc=%d\n", rc));
1534 return VERR_GENERAL_FAILURE;
1535}
1536
1537
1538/**
1539 * Dynamically attaches this streams module on to the host stack.
1540 * As a side-effect, this streams also gets opened/closed during
1541 * the actual injection/ejection phase.
1542 *
1543 * @returns VBox status code.
1544 * @param pThis The instance.
1545 * @param fAttach Is this an attach or detach.
1546 */
1547static int vboxNetFltSolarisModSetup(PVBOXNETFLTINS pThis, bool fAttach)
1548{
1549 LogFlow(("vboxNetFltSolarisModSetup: pThis=%p (%s) fAttach=%s\n", pThis, pThis->szName, fAttach ? "true" : "false"));
1550
1551 /*
1552 * Statuatory Warning: Hackish code ahead.
1553 */
1554 if (strlen(pThis->szName) > VBOXNETFLT_IFNAME_LEN - 1)
1555 {
1556 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: interface name too long %s\n", pThis->szName));
1557 return VERR_INTNET_FLT_IF_NOT_FOUND;
1558 }
1559
1560 char *pszModName = DEVICE_NAME;
1561
1562 struct lifreq Interface;
1563 bzero(&Interface, sizeof(Interface));
1564 Interface.lifr_addr.ss_family = AF_INET;
1565 strncpy(Interface.lifr_name, pThis->szName, sizeof(Interface.lifr_name));
1566
1567 struct strmodconf StrMod;
1568 StrMod.mod_name = pszModName;
1569 StrMod.pos = -1; /* this is filled in later. */
1570
1571 struct strmodconf ArpStrMod;
1572 bcopy(&StrMod, &ArpStrMod, sizeof(StrMod));
1573
1574 int rc;
1575 int rc2;
1576 int ret;
1577 ldi_ident_t IPDevId = ldi_ident_from_anon();
1578 ldi_ident_t ARPDevId = ldi_ident_from_anon();
1579 ldi_handle_t IPDevHandle;
1580 ldi_handle_t UDPDevHandle;
1581 ldi_handle_t ARPDevHandle;
1582
1583 /*
1584 * Open the IP and ARP streams as layered devices.
1585 */
1586 rc = ldi_open_by_name(IP_DEV_NAME, FREAD | FWRITE, kcred, &IPDevHandle, IPDevId);
1587 ldi_ident_release(IPDevId);
1588 if (rc)
1589 {
1590 LogRel((DEVICE_NAME ":failed to open the IP stream on '%s'.\n", pThis->szName));
1591 return VERR_INTNET_FLT_IF_FAILED;
1592 }
1593
1594 rc = ldi_open_by_name("/dev/arp", FREAD | FWRITE, kcred, &ARPDevHandle, ARPDevId);
1595 ldi_ident_release(ARPDevId);
1596 if (rc)
1597 {
1598 LogRel((DEVICE_NAME ":failed to open the ARP stream on '%s'.\n", pThis->szName));
1599 ldi_close(IPDevHandle, FREAD | FWRITE, kcred);
1600 return VERR_INTNET_FLT_IF_FAILED;
1601 }
1602
1603 /*
1604 * Obtain the interface flags from IP.
1605 */
1606 rc = vboxNetFltSolarisGetIfFlags(IPDevHandle, &Interface);
1607 if (RT_SUCCESS(rc))
1608 {
1609 /*
1610 * Open the UDP stream. We sort of cheat here and obtain the vnode so that we can perform
1611 * things that are not possible from the layered interface.
1612 */
1613 vnode_t *pVNodeUDP = NULL;
1614 vnode_t *pVNodeUDPHeld = NULL;
1615 TIUSER *pUserUDP = NULL;
1616 rc = vboxNetFltSolarisOpenDev(UDP_DEV_NAME, &pVNodeUDP, &pVNodeUDPHeld, &pUserUDP);
1617 if (RT_SUCCESS(rc))
1618 {
1619 /*
1620 * Get the multiplexor IDs.
1621 */
1622 rc = ldi_ioctl(IPDevHandle, SIOCGLIFMUXID, (intptr_t)&Interface, FKIOCTL, kcred, &ret);
1623 if (!rc)
1624 {
1625 /*
1626 * Get the multiplex file descriptor to the lower streams. Generally this is lost
1627 * once a module is I_PLINK, we need to reobtain it for inserting/removing ourselves from the stack.
1628 */
1629 int IpMuxFd;
1630 int ArpMuxFd;
1631 rc = vboxNetFltSolarisMuxIdToFd(pVNodeUDP, Interface.lifr_ip_muxid, &IpMuxFd);
1632 rc2 = vboxNetFltSolarisMuxIdToFd(pVNodeUDP, Interface.lifr_arp_muxid, &ArpMuxFd);
1633 if ( RT_SUCCESS(rc)
1634 && RT_SUCCESS(rc2))
1635 {
1636 /*
1637 * We need to I_PUNLINK on these multiplexor IDs before we can start
1638 * operating on the lower stream as insertions are direct operations on the lower stream.
1639 */
1640 int ret;
1641 rc = strioctl(pVNodeUDP, I_PUNLINK, (intptr_t)Interface.lifr_ip_muxid, 0, K_TO_K, kcred, &ret);
1642 rc2 = strioctl(pVNodeUDP, I_PUNLINK, (intptr_t)Interface.lifr_arp_muxid, 0, K_TO_K, kcred, &ret);
1643 if ( !rc
1644 && !rc2)
1645 {
1646 /*
1647 * Obtain the vnode from the useless userland file descriptor.
1648 */
1649 file_t *pIpFile = getf(IpMuxFd);
1650 file_t *pArpFile = getf(ArpMuxFd);
1651 if ( pIpFile
1652 && pArpFile
1653 && pArpFile->f_vnode
1654 && pIpFile->f_vnode)
1655 {
1656 vnode_t *pVNodeIp = pIpFile->f_vnode;
1657 vnode_t *pVNodeArp = pArpFile->f_vnode;
1658
1659 /*
1660 * Find the position on the host stack for attaching/detaching ourselves.
1661 */
1662 rc = vboxNetFltSolarisDetermineModPos(fAttach, pVNodeIp, &StrMod.pos);
1663 rc2 = vboxNetFltSolarisDetermineModPos(fAttach, pVNodeArp, &ArpStrMod.pos);
1664 if ( RT_SUCCESS(rc)
1665 && RT_SUCCESS(rc2))
1666 {
1667 /*
1668 * Set global data which will be grabbed by ModOpen.
1669 * There is a known (though very unlikely) race here because
1670 * of the inability to pass user data while inserting.
1671 */
1672 g_VBoxNetFltSolarisState.pCurInstance = pThis;
1673 g_VBoxNetFltSolarisState.CurType = kIpStream;
1674
1675 /*
1676 * Inject/Eject from the host IP stack.
1677 */
1678 rc = strioctl(pVNodeIp, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K,
1679 kcred, &ret);
1680 if (!rc)
1681 {
1682 /*
1683 * Inject/Eject from the host ARP stack.
1684 */
1685 g_VBoxNetFltSolarisState.CurType = kArpStream;
1686 rc = strioctl(pVNodeArp, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&ArpStrMod, 0, K_TO_K,
1687 kcred, &ret);
1688 if (!rc)
1689 {
1690 g_VBoxNetFltSolarisState.pCurInstance = NULL;
1691 g_VBoxNetFltSolarisState.CurType = kUndefined;
1692
1693 /*
1694 * Our job's not yet over; we need to relink the upper and lower streams
1695 * otherwise we've pretty much screwed up the host interface.
1696 */
1697 rc = vboxNetFltSolarisRelink(pVNodeUDP, &Interface, IpMuxFd, ArpMuxFd);
1698 if (RT_SUCCESS(rc))
1699 {
1700 /*
1701 * Close the devices ONLY during the return from function case; otherwise
1702 * we end up close twice which is an instant kernel panic.
1703 */
1704 vboxNetFltSolarisCloseDev(pVNodeUDPHeld, pUserUDP);
1705 ldi_close(ARPDevHandle, FREAD | FWRITE, kcred);
1706 ldi_close(IPDevHandle, FREAD | FWRITE, kcred);
1707
1708 LogFlow((DEVICE_NAME ":vboxNetFltSolarisModSetup: Success! %s %s@(Ip:%d Arp:%d) "
1709 "%s interface %s\n", fAttach ? "Injected" : "Ejected", StrMod.mod_name,
1710 StrMod.pos, ArpStrMod.pos, fAttach ? "to" : "from", pThis->szName));
1711 return VINF_SUCCESS;
1712 }
1713 else
1714 {
1715 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: Relinking failed. Mode=%s rc=%d.\n",
1716 fAttach ? "inject" : "eject", rc));
1717 }
1718
1719 /*
1720 * Try failing gracefully during attach.
1721 */
1722 if (fAttach)
1723 strioctl(pVNodeIp, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
1724 }
1725 else
1726 {
1727 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to %s the ARP stack. rc=%d\n",
1728 fAttach ? "inject into" : "eject from", rc));
1729 }
1730
1731 if (fAttach)
1732 strioctl(pVNodeIp, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
1733
1734 vboxNetFltSolarisRelink(pVNodeUDP, &Interface, IpMuxFd, ArpMuxFd);
1735 }
1736 else
1737 {
1738 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to %s the IP stack. rc=%d\n",
1739 fAttach ? "inject into" : "eject from", rc));
1740 }
1741 }
1742 else
1743 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to find position. rc=%d rc2=%d\n", rc, rc2));
1744 }
1745 else
1746 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to get vnode from MuxFd.\n"));
1747 }
1748 else
1749 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to unlink upper stream rc=%d rc2=%d.\n", rc, rc2));
1750 }
1751 else
1752 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to get MuxFd from MuxId. rc=%d rc2=%d\n"));
1753 }
1754 else
1755 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to get Mux Ids. rc=%d\n", rc));
1756 vboxNetFltSolarisCloseDev(pVNodeUDPHeld, pUserUDP);
1757 }
1758 else
1759 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to open UDP. rc=%d\n", rc));
1760 }
1761 else
1762 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: invalid interface '%s'.\n", pThis->szName));
1763
1764 ldi_close(ARPDevHandle, FREAD | FWRITE, kcred);
1765 ldi_close(IPDevHandle, FREAD | FWRITE, kcred);
1766
1767 return VERR_INTNET_FLT_IF_FAILED;
1768}
1769
1770
1771/**
1772 * Wrapper for attaching ourselves to the interface.
1773 *
1774 * @returns VBox status code.
1775 * @param pThis The instance.
1776 * @remarks Owns the globals mutex, so re-requesting it anytime during this phase
1777 * would panic the system e.g. in vboxNetFltSolarisFindInstance).
1778 */
1779static int vboxNetFltSolarisAttachToInterface(PVBOXNETFLTINS pThis)
1780{
1781 int rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
1782 AssertRC(rc);
1783
1784 rc = vboxNetFltSolarisModSetup(pThis, true);
1785
1786 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
1787 return rc;
1788}
1789
1790
1791/**
1792 * Wrapper for detaching ourselves from the interface.
1793 *
1794 * @returns VBox status code.
1795 * @param pThis The instance.
1796 * @remarks Owns the globals mutex, so re-requesting it anytime during this phase
1797 * would panic the system (e.g. in vboxNetFltSolarisFindInstance).
1798 */
1799static int vboxNetFltSolarisDetachFromInterface(PVBOXNETFLTINS pThis)
1800{
1801 int rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
1802 AssertRC(rc);
1803
1804 rc = vboxNetFltSolarisModSetup(pThis, false);
1805
1806 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
1807 return rc;
1808}
1809
1810
1811/**
1812 * Create a solaris message block from the SG list.
1813 *
1814 * @returns Solaris message block.
1815 * @param pThis The instance.
1816 * @param pSG Pointer to the scatter-gather list.
1817 */
1818static mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
1819{
1820 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG pThis=%p pSG=%p\n"));
1821
1822 mblk_t *pMsg = allocb(pSG->cbTotal, BPRI_MED);
1823 if (RT_UNLIKELY(!pMsg))
1824 {
1825 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed to alloc %d bytes for mblk_t.\n", pSG->cbTotal));
1826 return NULL;
1827 }
1828
1829 /*
1830 * Single buffer copy. Maybe later explore the
1831 * need/possibility for using a mblk_t chain rather.
1832 */
1833 for (unsigned i = 0; i < pSG->cSegsUsed; i++)
1834 {
1835 if (pSG->aSegs[i].pv)
1836 {
1837 bcopy(pSG->aSegs[i].pv, pMsg->b_wptr, pSG->aSegs[i].cb);
1838 pMsg->b_wptr += pSG->aSegs[i].cb;
1839 }
1840 }
1841 DB_TYPE(pMsg) = M_DATA;
1842 return pMsg;
1843}
1844
1845
1846/**
1847 * Calculate the number of segments required for this message block.
1848 *
1849 * @returns Number of segments.
1850 * @param pThis The instance
1851 * @param pMsg Pointer to the data message.
1852 */
1853static unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg)
1854{
1855 unsigned cSegs = 0;
1856 for (mblk_t *pCur = pMsg; pCur; pCur = pCur->b_cont)
1857 if (MBLKL(pCur))
1858 cSegs++;
1859
1860#ifdef PADD_RUNT_FRAMES_FROM_HOST
1861 if (msgdsize(pMsg) < 60)
1862 cSegs++;
1863#endif
1864
1865 NOREF(pThis);
1866 return RT_MAX(cSegs, 1);
1867}
1868
1869
1870/**
1871 * Initializes an SG list from the given message block.
1872 *
1873 * @returns VBox status code.
1874 * @param pThis The instance.
1875 * @param pMsg Pointer to the data message.
1876 The caller must ensure it's not a control message block.
1877 * @param pSG Pointer to the SG.
1878 * @param cSegs Number of segments in the SG.
1879 * This should match the number in the message block exactly!
1880 * @param fSrc The source of the message.
1881 */
1882static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
1883{
1884 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
1885
1886 pSG->pvOwnerData = NULL;
1887 pSG->pvUserData = NULL;
1888 pSG->pvUserData2 = NULL;
1889 pSG->cUsers = 1;
1890 pSG->cbTotal = 0;
1891 pSG->fFlags = INTNETSG_FLAGS_TEMP;
1892 pSG->cSegsAlloc = cSegs;
1893
1894 /*
1895 * Convert the message block to segments.
1896 */
1897 mblk_t *pCur = pMsg;
1898 unsigned iSeg = 0;
1899 while (pCur)
1900 {
1901 size_t cbSeg = MBLKL(pCur);
1902 if (cbSeg)
1903 {
1904 void *pvSeg = pCur->b_rptr;
1905 pSG->aSegs[iSeg].pv = pvSeg;
1906 pSG->aSegs[iSeg].cb = cbSeg;
1907 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
1908 pSG->cbTotal += cbSeg;
1909 iSeg++;
1910 }
1911 pCur = pCur->b_cont;
1912 }
1913 pSG->cSegsUsed = iSeg;
1914
1915#ifdef PADD_RUNT_FRAMES_FROM_HOST
1916 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
1917 {
1918 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pulling up to length.\n"));
1919
1920 static uint8_t const s_abZero[128] = {0};
1921 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
1922 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
1923 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
1924 pSG->cbTotal = 60;
1925 pSG->cSegsUsed++;
1926 }
1927#endif
1928
1929 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
1930 return VINF_SUCCESS;
1931}
1932
1933
1934/**
1935 * Converts raw mode M_DATA messages to M_PROTO DL_UNITDATA_IND format.
1936 *
1937 * @returns VBox status code.
1938 * @param pMsg Pointer to the raw message.
1939 * @param pDlpiMsg Where to store the M_PROTO message.
1940 *
1941 * @remarks The original raw message would be no longer valid and will be
1942 * linked as part of the new DLPI message. Callers must take care
1943 * not to use the raw message if this routine is successful.
1944 */
1945static int vboxNetFltSolarisRawToUnitData(mblk_t *pMsg, mblk_t **ppDlpiMsg)
1946{
1947 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData pMsg=%p\n", pMsg));
1948
1949 if (DB_TYPE(pMsg) != M_DATA)
1950 return VERR_NO_MEMORY;
1951
1952 size_t cbMsg = sizeof(dl_unitdata_ind_t) + 2 * sizeof(vboxnetflt_dladdr_t);
1953 mblk_t *pDlpiMsg = allocb(cbMsg, BPRI_MED);
1954 if (RT_UNLIKELY(!pDlpiMsg))
1955 return VERR_NO_MEMORY;
1956
1957 DB_TYPE(pDlpiMsg) = M_PROTO;
1958 dl_unitdata_ind_t *pDlpiData = (dl_unitdata_ind_t *)pDlpiMsg->b_rptr;
1959 pDlpiData->dl_primitive = DL_UNITDATA_IND;
1960 pDlpiData->dl_dest_addr_length = VBOXNETFLT_DLADDRL;
1961 pDlpiData->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
1962 pDlpiData->dl_src_addr_length = VBOXNETFLT_DLADDRL;
1963 pDlpiData->dl_src_addr_offset = VBOXNETFLT_DLADDRL + sizeof(dl_unitdata_ind_t);
1964
1965 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
1966
1967 vboxnetflt_dladdr_t *pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_dest_addr_offset);
1968 pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
1969 bcopy(&pEthHdr->DstMac, &pDlAddr->Mac, sizeof(RTMAC));
1970
1971 pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_src_addr_offset);
1972 pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
1973 bcopy(&pEthHdr->SrcMac, &pDlAddr->Mac, sizeof(RTMAC));
1974
1975 pDlpiMsg->b_wptr = pDlpiMsg->b_rptr + cbMsg;
1976
1977 /* Make the message point to the protocol header */
1978 pMsg->b_rptr += sizeof(RTNETETHERHDR);
1979
1980 pDlpiMsg->b_cont = pMsg;
1981 *ppDlpiMsg = pDlpiMsg;
1982 return VINF_SUCCESS;
1983}
1984
1985
1986/**
1987 * Converts DLPI M_PROTO messages to the raw mode M_DATA format.
1988 *
1989 * @returns VBox status code.
1990 * @param pMsg Pointer to the M_PROTO message.
1991 * @param ppRawMsg Where to store the converted message.
1992 *
1993 * @remarks If successful, the original pMsg is no longer valid, it will be deleted.
1994 * Callers must take care not to continue to use pMsg after a successful
1995 * call to this conversion routine.
1996 */
1997static int vboxNetFltSolarisUnitDataToRaw(PVBOXNETFLTINS pThis, mblk_t *pMsg, mblk_t **ppRawMsg)
1998{
1999 LogFlow((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw pMsg=%p\n", pMsg));
2000
2001 if ( !pMsg->b_cont
2002 || DB_TYPE(pMsg) != M_PROTO)
2003 {
2004 LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw invalid input message.\n"));
2005 return VERR_NET_PROTOCOL_ERROR;
2006 }
2007
2008 /*
2009 * Upstream consumers send/receive packets in the fast path mode.
2010 * We of course need to convert them into raw ethernet frames.
2011 */
2012 RTNETETHERHDR EthHdr;
2013 union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
2014 switch (pPrim->dl_primitive)
2015 {
2016 case DL_UNITDATA_IND:
2017 {
2018 /*
2019 * Receive side.
2020 */
2021 dl_unitdata_ind_t *pDlpiMsg = (dl_unitdata_ind_t *)pMsg->b_rptr;
2022 bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
2023 bcopy(pMsg->b_rptr + pDlpiMsg->dl_src_addr_offset, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
2024
2025 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
2026 EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
2027
2028 break;
2029 }
2030
2031 case DL_UNITDATA_REQ:
2032 {
2033 /*
2034 * Send side.
2035 */
2036 dl_unitdata_req_t *pDlpiMsg = (dl_unitdata_req_t *)pMsg->b_rptr;
2037
2038 bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
2039 bcopy(&pThis->u.s.Mac, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
2040
2041 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
2042 EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
2043
2044 break;
2045 }
2046
2047 default:
2048 {
2049 LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw Unknown M_PROTO. This shouldn't be happening!!"));
2050 return VERR_NET_PROTOCOL_ERROR;
2051 }
2052 }
2053
2054 /*
2055 * Let us just link it as a mblk_t chain rather than re-copy the entire message.
2056 * The vboxNetFltSolarisMBlkToSG function will handle chained mblk_t's.
2057 */
2058 size_t cbLen = sizeof(EthHdr);
2059 mblk_t *pEtherMsg = allocb(cbLen, BPRI_MED);
2060 if (RT_UNLIKELY(!pEtherMsg))
2061 return VERR_NO_MEMORY;
2062
2063 DB_TYPE(pEtherMsg) = M_DATA;
2064 bcopy(&EthHdr, pEtherMsg->b_wptr, sizeof(EthHdr));
2065 pEtherMsg->b_wptr += cbLen;
2066
2067 pEtherMsg->b_cont = pMsg->b_cont;
2068
2069 /*
2070 * Change the chained blocks to type M_DATA.
2071 */
2072 for (mblk_t *pTmp = pEtherMsg->b_cont; pTmp; pTmp = pTmp->b_cont)
2073 DB_TYPE(pTmp) = M_DATA;
2074
2075 pMsg->b_cont = NULL;
2076 freemsg(pMsg);
2077
2078 *ppRawMsg = pEtherMsg;
2079 return VINF_SUCCESS;
2080}
2081
2082
2083/**
2084 * Worker for routing messages from the wire or from the host.
2085 *
2086 * @returns VBox status code.
2087 * @param pThis The instance.
2088 * @param pStream Pointer to the stream.
2089 * @param pQueue Pointer to the queue.
2090 * @param pOrigMsg Pointer to the message.
2091 */
2092static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pOrigMsg)
2093{
2094 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRecv pThis=%p pOrigMsg=%p\n", pThis, pOrigMsg));
2095
2096 AssertCompile(sizeof(struct ether_header) == sizeof(RTNETETHERHDR));
2097 Assert(pStream->Type == kIpStream);
2098
2099 /*
2100 * Due to the asynchronous nature of streams we may get messages before the
2101 * raw mode is turned on, in this case just pass through.
2102 */
2103 if (!pStream->fRawMode)
2104 {
2105 LogFlow((DEVICE_NAME ":IP stream not yet in raw mode. Passing through packet.\n"));
2106 putnext(pQueue, pOrigMsg);
2107 return VINF_SUCCESS;
2108 }
2109
2110 /*
2111 * Make a copy as we will alter pMsg.
2112 */
2113 mblk_t *pMsg = copymsg(pOrigMsg);
2114
2115 /*
2116 * Sort out M_PROTO and M_DATA.
2117 */
2118 bool fOriginalIsRaw = true;
2119 if (DB_TYPE(pMsg) == M_PROTO)
2120 {
2121 fOriginalIsRaw = false;
2122 mblk_t *pRawMsg;
2123 int rc = vboxNetFltSolarisUnitDataToRaw(pThis, pMsg, &pRawMsg);
2124 if (RT_SUCCESS(rc))
2125 pMsg = pRawMsg;
2126 else
2127 {
2128 freemsg(pMsg);
2129 LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv invalid message!\n"));
2130 return VERR_GENERAL_FAILURE;
2131 }
2132 }
2133
2134 /*
2135 * Figure out the source of the packet based on the source Mac address.
2136 */
2137 /** @todo Is there a more fool-proof way to determine if the packet was indeed sent from the host?? */
2138 uint32_t fSrc = INTNETTRUNKDIR_WIRE;
2139 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
2140 if (vboxNetFltPortOsIsHostMac(pThis, &pEthHdr->SrcMac))
2141 fSrc = INTNETTRUNKDIR_HOST;
2142
2143 bool fChecksumAdjusted = false;
2144#if 1
2145 if (fSrc & INTNETTRUNKDIR_HOST)
2146 {
2147 mblk_t *pCorrectedMsg = vboxNetFltSolarisFixChecksums(pMsg);
2148 if (pCorrectedMsg)
2149 {
2150 fChecksumAdjusted = true;
2151 pMsg = pCorrectedMsg;
2152 }
2153 }
2154#endif
2155
2156 /*
2157 * Route all received packets into the internal network.
2158 */
2159 unsigned cSegs = vboxNetFltSolarisMBlkCalcSGSegs(pThis, pMsg);
2160 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
2161 int rc = vboxNetFltSolarisMBlkToSG(pThis, pMsg, pSG, cSegs, fSrc);
2162 if (VBOX_FAILURE(rc))
2163 {
2164 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG failed. rc=%d\n", rc));
2165 return rc;
2166 }
2167
2168 bool fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc);
2169
2170 /*
2171 * Drop messages consumed by the internal network.
2172 */
2173 if (fDropIt)
2174 {
2175 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRecv Packet consumed by internal network.\n"));
2176 freemsg(pOrigMsg);
2177 freemsg(pMsg);
2178 }
2179 else
2180 {
2181 /*
2182 * Packets from the host, push them up in raw mode.
2183 * Packets from the wire, we must push them in their original form
2184 * as upstream consumers expect this format.
2185 */
2186 if (fSrc & INTNETTRUNKDIR_HOST)
2187 {
2188 /* Raw packets with correct checksums, pass-through the original */
2189 if ( fOriginalIsRaw
2190 && !fChecksumAdjusted)
2191 {
2192 putnext(pQueue, pOrigMsg);
2193 }
2194 else /* For M_PROTO packets or checksum corrected raw packets, pass-through the raw */
2195 {
2196 putnext(pQueue, pMsg);
2197 pMsg = pOrigMsg; /* for the freemsg that follows */
2198 }
2199 }
2200 else /* INTNETTRUNKDIR_WIRE */
2201 {
2202 if (fOriginalIsRaw)
2203 pOrigMsg->b_rptr += sizeof(RTNETETHERHDR);
2204
2205 putnext(pQueue, pOrigMsg);
2206 }
2207
2208 freemsg(pMsg);
2209 }
2210
2211 return VINF_SUCCESS;
2212}
2213
2214
2215/**
2216 * Find the PVBOXNETFLTINS associated with a stream.
2217 *
2218 * @returns PVBOXNETFLTINS instance, or NULL if there's none.
2219 * @param pStream Pointer to the stream to search for.
2220 */
2221static PVBOXNETFLTINS vboxNetFltSolarisFindInstance(vboxnetflt_stream_t *pStream)
2222{
2223 if (!pStream)
2224 return NULL;
2225
2226 vboxnetflt_stream_t *pCur = g_VBoxNetFltSolarisState.pOpenedStreams;
2227 for (; pCur; pCur = pCur->pNext)
2228 if (pCur == pStream)
2229 return pCur->pThis;
2230
2231 return NULL;
2232}
2233
2234
2235/**
2236 * Finalize the message to be fed into the internal network.
2237 * Verifies and tries to fix checksums for TCP, UDP and IP.
2238 *
2239 * @returns Corrected message or NULL if no change was required.
2240 * @param pMsg Pointer to the message block.
2241 * This must not be DLPI linked messages, must be M_DATA.
2242 *
2243 * @remarks If this function returns a checksum adjusted message, the
2244 * passed in input message has been freed and should not be
2245 * referenced anymore by the caller.
2246 */
2247static mblk_t *vboxNetFltSolarisFixChecksums(mblk_t *pMsg)
2248{
2249 LogFlow((DEVICE_NAME ":vboxNetFltSolarisFixChecksums pMsg=%p\n"));
2250
2251 Assert(DB_TYPE(pMsg) == M_DATA);
2252
2253 if (MBLKL(pMsg) < sizeof(RTNETETHERHDR))
2254 {
2255 LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums Packet shorter than ethernet header size!\n"));
2256 return NULL;
2257 }
2258
2259 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
2260 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
2261 {
2262 /*
2263 * Check if we have a complete packet or being fed a chain.
2264 */
2265 size_t cbIpPacket = 0;
2266 mblk_t *pFullMsg = NULL;
2267 if (pMsg->b_cont)
2268 {
2269 LogFlow((DEVICE_NAME ":Chained mblk_t.\n"));
2270
2271 /*
2272 * Handle chain by making a packet copy to verify if the IP checksum is correct.
2273 * Contributions to calculating IP checksums from a chained message block with
2274 * odd/non-pulled up sizes are welcome.
2275 */
2276 size_t cbFullMsg = msgdsize(pMsg);
2277 mblk_t *pFullMsg = allocb(cbFullMsg, BPRI_MED);
2278 LogFlow((DEVICE_NAME ":msgdsize returns %d\n", cbFullMsg));
2279 if (RT_UNLIKELY(!pFullMsg))
2280 {
2281 LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums failed to alloc new message of %d bytes.\n", cbFullMsg));
2282 return false;
2283 }
2284
2285 for (mblk_t *pTmp = pMsg; pTmp; pTmp = pTmp->b_cont)
2286 {
2287 if (DB_TYPE(pTmp) == M_DATA)
2288 {
2289 bcopy(pTmp->b_rptr, pFullMsg->b_wptr, MBLKL(pTmp));
2290 pFullMsg->b_wptr += MBLKL(pTmp);
2291 }
2292 else
2293 LogFlow((DEVICE_NAME ":Not M_DATA.. this is really bad.\n"));
2294 }
2295
2296 DB_TYPE(pFullMsg) = M_DATA;
2297 pEthHdr = (PRTNETETHERHDR)pFullMsg->b_rptr;
2298 cbIpPacket = MBLKL(pFullMsg) - sizeof(RTNETETHERHDR);
2299 }
2300 else
2301 cbIpPacket = MBLKL(pMsg) - sizeof(RTNETETHERHDR);
2302
2303 /*
2304 * Check if the IP checksum is valid.
2305 */
2306 PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
2307 if (!RTNetIPv4IsHdrValid(pIpHdr, cbIpPacket, cbIpPacket))
2308 {
2309 LogFlow((DEVICE_NAME ":Invalid IP checksum detected. Trying to fix...\n"));
2310
2311 /*
2312 * Fix up TCP/UDP and IP checksums if they're incomplete/invalid.
2313 */
2314 if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
2315 {
2316 size_t cbTcpPacket = cbIpPacket - (pIpHdr->ip_hl << 2);
2317
2318 PRTNETTCP pTcpHdr = (PRTNETTCP)(pIpHdr + 1);
2319 if (!RTNetIPv4IsTCPValid(pIpHdr, pTcpHdr, cbTcpPacket, NULL, cbTcpPacket))
2320 {
2321 RTNetIPv4TCPChecksum(pIpHdr, pTcpHdr, NULL);
2322 LogFlow((DEVICE_NAME ":fixed TCP checkum.\n"));
2323 }
2324 else
2325 LogFlow((DEVICE_NAME ":valid TCP checksum invalid IP checksum...\n"));
2326 }
2327 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
2328 {
2329 size_t cbUdpPacket = cbIpPacket - (pIpHdr->ip_hl << 2);
2330
2331 PRTNETUDP pUdpHdr = (PRTNETUDP)(pIpHdr + 1);
2332 RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1);
2333
2334 LogFlow((DEVICE_NAME ":fixed UDP checksum.\n"));
2335 }
2336 else
2337 {
2338 LogFlow((DEVICE_NAME ":Non TCP/UDP protocol with invalid IP header!\n"));
2339 }
2340
2341 RTNetIPv4HdrChecksum(pIpHdr);
2342 LogFlow((DEVICE_NAME ":fixed IP checkum.\n"));
2343
2344 /*
2345 * If we made a copy and the checksum is corrected on the copy,
2346 * free the original, return the checksum fixed copy.
2347 */
2348 if (pFullMsg)
2349 {
2350 freemsg(pMsg);
2351 return pFullMsg;
2352 }
2353
2354 return pMsg;
2355 }
2356
2357 /*
2358 * If we made a copy and the checksum is NOT corrected, free the copy,
2359 * and return NULL.
2360 */
2361 if (pFullMsg)
2362 freemsg(pFullMsg);
2363 }
2364
2365 return NULL;
2366}
2367
2368
2369/**
2370 * Simple packet dump, used for internal debugging.
2371 *
2372 * @param pMsg Pointer to the message to analyze and dump.
2373 */
2374static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg)
2375{
2376 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAnalyzeMBlk pMsg=%p\n"));
2377
2378 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
2379 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
2380 {
2381 PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
2382 size_t cbLen = MBLKL(pMsg) - sizeof(*pEthHdr);
2383 if (RTNetIPv4IsHdrValid(pIpHdr, cbLen, cbLen))
2384 {
2385 uint8_t *pb = pMsg->b_rptr;
2386 if (pIpHdr->ip_p == RTNETIPV4_PROT_ICMP)
2387 LogFlow((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
2388 else if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
2389 LogFlow((DEVICE_NAME ":TCP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
2390 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
2391 LogFlow((DEVICE_NAME ":UDP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
2392 }
2393 else
2394 {
2395 LogFlow((DEVICE_NAME ":Invalid IP header.\n"));
2396 return;
2397 }
2398 }
2399 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
2400 {
2401 PRTNETARPHDR pArpHdr = (PRTNETARPHDR)(pEthHdr + 1);
2402 LogFlow((DEVICE_NAME ":ARP Op=%d\n", pArpHdr->ar_oper));
2403 }
2404 else
2405 {
2406 LogFlow((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
2407 &pEthHdr->SrcMac));
2408 /* LogFlow((DEVICE_NAME ":%.*Vhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
2409 }
2410}
2411
2412
2413/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
2414bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
2415{
2416 vboxnetflt_stream_t *pStream = pThis->u.s.pvStream;
2417 return pStream->fPromisc;
2418}
2419
2420
2421void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
2422{
2423 LogFlow((DEVICE_NAME ":vboxNetFltPortOsGetMacAddress pThis=%p\n", pThis));
2424
2425 RTMAC EmptyMac;
2426 bzero(&EmptyMac, sizeof(EmptyMac));
2427 if (!bcmp(&pThis->u.s.Mac, &EmptyMac, sizeof(EmptyMac))) /* This should never happen... */
2428 {
2429 /* Bummer, Mac address is not copied yet. */
2430 LogRel((DEVICE_NAME ":vboxNetFltPortOsGetMacAddress: Mac address not cached yet!\n"));
2431 return;
2432 }
2433
2434 *pMac = pThis->u.s.Mac;
2435}
2436
2437
2438bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
2439{
2440 /*
2441 * MAC address change acknowledgements are intercepted on the read side
2442 * hence theoritically we are always update to date with any changes.
2443 */
2444 return pThis->u.s.Mac.au16[0] == pMac->au16[0]
2445 && pThis->u.s.Mac.au16[1] == pMac->au16[1]
2446 && pThis->u.s.Mac.au16[2] == pMac->au16[2];
2447}
2448
2449
2450void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
2451{
2452 LogFlow((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d\n", pThis, fActive));
2453
2454 /*
2455 * Enable/disable promiscuous mode.
2456 */
2457 vboxnetflt_stream_t *pStream = pThis->u.s.pvStream;
2458 Assert(pStream->Type == kIpStream);
2459 int rc = vboxNetFltSolarisPromiscReq(pStream->pReadQueue, fActive);
2460 if (VBOX_FAILURE(rc))
2461 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive failed to request promiscuous mode! rc=%d\n", rc));
2462}
2463
2464
2465int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
2466{
2467 /* Nothing to do here. */
2468 return VINF_SUCCESS;
2469}
2470
2471
2472int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
2473{
2474 /* Nothing to do here. */
2475 return VINF_SUCCESS;
2476}
2477
2478
2479void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
2480{
2481 LogFlow((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n"));
2482 vboxNetFltSolarisDetachFromInterface(pThis);
2483}
2484
2485
2486int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis)
2487{
2488 LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p\n"));
2489 return vboxNetFltSolarisAttachToInterface(pThis);
2490}
2491
2492
2493int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
2494{
2495 /*
2496 * Init. the solaris specific data.
2497 */
2498 pThis->u.s.pvStream = NULL;
2499 pThis->u.s.pvArpStream = NULL;
2500 bzero(&pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
2501 return VINF_SUCCESS;
2502}
2503
2504
2505bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
2506{
2507 /*
2508 * We don't support interface rediscovery on Solaris hosts because the
2509 * filter is very tightly bound to the stream.
2510 */
2511 return false;
2512}
2513
2514
2515int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
2516{
2517 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p pSG=%p fDst=%d\n", pThis, pSG, fDst));
2518
2519 vboxnetflt_stream_t *pStream = pThis->u.s.pvStream;
2520 queue_t *pReadQueue = pStream->pReadQueue;
2521 queue_t *pWriteQueue = WR(pReadQueue);
2522
2523 /*
2524 * Create a message block and send it down the wire (downstream).
2525 */
2526 if (fDst & INTNETTRUNKDIR_WIRE)
2527 {
2528 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
2529 if (RT_UNLIKELY(!pMsg))
2530 {
2531 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
2532 return VERR_NO_MEMORY;
2533 }
2534
2535 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_WIRE\n", pMsg));
2536 putnext(pWriteQueue, pMsg);
2537 }
2538
2539 /*
2540 * Create a message block and send it up the host stack (upstream).
2541 */
2542 if (fDst & INTNETTRUNKDIR_HOST)
2543 {
2544 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
2545 if (RT_UNLIKELY(!pMsg))
2546 {
2547 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
2548 return VERR_NO_MEMORY;
2549 }
2550
2551 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
2552 bool fArp = (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP));
2553
2554 /*
2555 * Construct a DL_UNITDATA_IND style message.
2556 */
2557 mblk_t *pDlpiMsg;
2558 int rc = vboxNetFltSolarisRawToUnitData(pMsg, &pDlpiMsg);
2559 if (VBOX_FAILURE(rc))
2560 {
2561 LogRel((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData failed! rc=%d\n", rc));
2562 freemsg(pMsg);
2563 return VERR_NO_MEMORY;
2564 }
2565 pMsg = pDlpiMsg;
2566
2567 if (fArp)
2568 {
2569 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST ARP\n"));
2570
2571 /*
2572 * Send message up ARP stream.
2573 */
2574 vboxnetflt_stream_t *pArpStream = pThis->u.s.pvArpStream;
2575 queue_t *pArpReadQueue = pArpStream->pReadQueue;
2576 putnext(pArpReadQueue, pMsg);
2577 }
2578 else
2579 {
2580 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST\n"));
2581
2582 /*
2583 * Send messages up IP stream.
2584 */
2585 putnext(pReadQueue, pMsg);
2586 }
2587 }
2588
2589 return VINF_SUCCESS;
2590}
2591
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette