VirtualBox

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

Last change on this file since 13306 was 13137, checked in by vboxsync, 16 years ago

Solaris/VBoxNetFlt: Fixed a rarely triggered but deadly bug in loopback handling.

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

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