VirtualBox

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

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

Solaris/VBoxNetFlt: removed NETINFO deadcode.

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