VirtualBox

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

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

IntNet,VBoxNetFlt: Cleaned up the locking protocol between IntNet and NetFlt. Eleminated the out-bound trunk lock that IntNet always took when calling NetFlt.

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