VirtualBox

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

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

Solaris/VBoxNetFlt: #3183 DLPI style 2 support (disabled, untested).

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

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