VirtualBox

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

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

Solaris/VBoxNetFlt: paranoia.

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

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