VirtualBox

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

Last change on this file since 36876 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

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

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