VirtualBox

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

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

IntNet: Added Interface, Interface private data passing for per-interface based VBoxNetFlt.

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