VirtualBox

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

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

Solaris/VBoxNetFlt: fixed crash with kcred deallocation behind our back.

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

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