VirtualBox

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

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

Solaris/VBoxNetFlt: compile time scope fix.

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

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