VirtualBox

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

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

Solaris/driver versions: Added versions for NetFlt and the Guest driver. Cleared up incorrect comments in VBoxNetFlt regarding vanity names and PPA hacks.

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

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