VirtualBox

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

Last change on this file since 32619 was 31847, checked in by vboxsync, 14 years ago

iprt: removed crc32.h and crc64.h, use crc.h instead.

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