VirtualBox

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

Last change on this file since 23301 was 23301, checked in by vboxsync, 15 years ago

VBoxNetFlt-solaris.c: be bolder in the claims wrt pCred/g_pVBoxNetFltSolarisCred.

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