VirtualBox

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

Last change on this file since 32767 was 32716, checked in by vboxsync, 14 years ago

Solaris/VBoxNetFlt: fix deadlock with PromiscReq and ModWritePut (#5262)

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