VirtualBox

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

最後變更 在這個檔案從13875是 13875,由 vboxsync 提交於 16 年 前

Solaris/VBoxNetFlt: attempt to fix recursive mutex enters on other modules probably caused due to high priority messages being queued up by us.

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

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