VirtualBox

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

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

Solaris/VBoxNetFlt: netinfo.

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

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