VirtualBox

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

Last change on this file since 14789 was 14280, checked in by vboxsync, 16 years ago

Solaris/VBoxNetFlt: minor bits.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette