VirtualBox

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

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

Solaris/VBoxNetFlt: Teardown time race fixes.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 113.2 KB
 
1/* $Id: VBoxNetFlt-solaris.c 13769 2008-11-03 19:13:51Z 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/** The list of all opened streams. */
370vboxnetflt_stream_t *g_VBoxNetFltSolarisStreams;
371
372/**
373 * g_VBoxNetFltInstance is the current PVBOXNETFLTINS to be associated with the stream being created
374 * in ModOpen. This is just shared global data between the dynamic attach and the ModOpen procedure.
375 */
376PVBOXNETFLTINS volatile g_VBoxNetFltSolarisInstance;
377
378/** Goes along with the instance to determine type of stream being opened/created. */
379VBOXNETFLTSTREAMTYPE volatile g_VBoxNetFltSolarisStreamType;
380
381/** GCC C++ hack. */
382unsigned __gxx_personality_v0 = 0xdecea5ed;
383
384
385/**
386 * Kernel entry points
387 */
388int _init(void)
389{
390 LogFlow((DEVICE_NAME ":_init\n"));
391
392 /*
393 * Prevent module autounloading.
394 */
395 modctl_t *pModCtl = mod_getctl(&g_VBoxNetFltSolarisModLinkage);
396 if (pModCtl)
397 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
398 else
399 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
400
401 /*
402 * Initialize IPRT.
403 */
404 int rc = RTR0Init(0);
405 if (RT_SUCCESS(rc))
406 {
407 /*
408 * Initialize Solaris specific globals here.
409 */
410 g_VBoxNetFltSolarisStreams = NULL;
411 g_VBoxNetFltSolarisInstance = NULL;
412
413 /*
414 * Initialize the globals and connect to the support driver.
415 *
416 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
417 * for establishing the connect to the support driver.
418 */
419 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
420 rc = vboxNetFltInitGlobals(&g_VBoxNetFltSolarisGlobals);
421 if (RT_SUCCESS(rc))
422 {
423 rc = mod_install(&g_VBoxNetFltSolarisModLinkage);
424 if (!rc)
425 return rc;
426
427 LogRel((DEVICE_NAME ":mod_install failed. rc=%d\n", rc));
428 vboxNetFltTryDeleteGlobals(&g_VBoxNetFltSolarisGlobals);
429 }
430 else
431 LogRel((DEVICE_NAME ":failed to initialize globals.\n"));
432
433 RTR0Term();
434 }
435 else
436 LogRel((DEVICE_NAME ":failed to initialize IPRT (rc=%d)\n", rc));
437
438 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
439 return -1;
440}
441
442
443int _fini(void)
444{
445 int rc;
446 LogFlow((DEVICE_NAME ":_fini\n"));
447
448 /*
449 * Undo the work done during start (in reverse order).
450 */
451 rc = vboxNetFltTryDeleteGlobals(&g_VBoxNetFltSolarisGlobals);
452 if (RT_FAILURE(rc))
453 {
454 LogRel((DEVICE_NAME ":_fini - busy!\n"));
455 return EBUSY;
456 }
457
458 RTR0Term();
459
460 return mod_remove(&g_VBoxNetFltSolarisModLinkage);
461}
462
463
464int _info(struct modinfo *pModInfo)
465{
466 LogFlow((DEVICE_NAME ":_info\n"));
467
468 int rc = mod_info(&g_VBoxNetFltSolarisModLinkage, pModInfo);
469
470 LogFlow((DEVICE_NAME ":_info returns %d\n", rc));
471 return rc;
472}
473
474
475/**
476 * Attach entry point, to attach a device to the system or resume it.
477 *
478 * @param pDip The module structure instance.
479 * @param enmCmd Operation type (attach/resume).
480 *
481 * @returns corresponding solaris error code.
482 */
483static int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
484{
485 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
486
487 switch (enmCmd)
488 {
489 case DDI_ATTACH:
490 {
491 int instance = ddi_get_instance(pDip);
492 int rc = ddi_create_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, CLONE_DEV);
493 if (rc == DDI_SUCCESS)
494 {
495 g_pVBoxNetFltSolarisDip = pDip;
496 ddi_report_dev(pDip);
497 return DDI_SUCCESS;
498 }
499 else
500 LogRel((DEVICE_NAME ":VBoxNetFltSolarisAttach failed to create minor node. rc%d\n", rc));
501 return DDI_FAILURE;
502 }
503
504 case DDI_RESUME:
505 {
506 /* Nothing to do here... */
507 return DDI_SUCCESS;
508 }
509 }
510 return DDI_FAILURE;
511}
512
513
514/**
515 * Detach entry point, to detach a device to the system or suspend it.
516 *
517 * @param pDip The module structure instance.
518 * @param enmCmd Operation type (detach/suspend).
519 *
520 * @returns corresponding solaris error code.
521 */
522static int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
523{
524 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
525
526 switch (enmCmd)
527 {
528 case DDI_DETACH:
529 {
530 int instance = ddi_get_instance(pDip);
531 ddi_remove_minor_node(pDip, NULL);
532 return DDI_SUCCESS;
533 }
534
535 case DDI_RESUME:
536 {
537 /* Nothing to do here... */
538 return DDI_SUCCESS;
539 }
540 }
541 return DDI_FAILURE;
542}
543
544
545/**
546 * Info entry point, called by solaris kernel for obtaining driver info.
547 *
548 * @param pDip The module structure instance (do not use).
549 * @param enmCmd Information request type.
550 * @param pvArg Type specific argument.
551 * @param ppvResult Where to store the requested info.
552 *
553 * @returns corresponding solaris error code.
554 */
555static int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppResult)
556{
557 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd,
558 getminor((dev_t)pvArg)));
559
560 switch (enmCmd)
561 {
562 case DDI_INFO_DEVT2DEVINFO:
563 {
564 *ppResult = g_pVBoxNetFltSolarisDip;
565 return DDI_SUCCESS;
566 }
567
568 case DDI_INFO_DEVT2INSTANCE:
569 {
570 int instance = getminor((dev_t)pvArg);
571 *ppResult = (void *)(uintptr_t)instance;
572 return DDI_SUCCESS;
573 }
574 }
575
576 return DDI_FAILURE;
577}
578
579
580/**
581 * Stream module open entry point, initializes the queue and allows streams processing.
582 *
583 * @param pQueue Pointer to the queue (cannot be NULL).
584 * @param pDev Pointer to the dev_t associated with the driver at the end of the stream.
585 * @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
586 * @param fStreamMode Stream open mode.
587 * @param pCred Pointer to user credentials.
588 *
589 * @returns corresponding solaris error code.
590 */
591static int VBoxNetFltSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fOpenMode, int fStreamMode, cred_t *pCred)
592{
593 Assert(pQueue);
594
595 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModOpen pQueue=%p pDev=%p fOpenMode=%d fStreamMode=%d\n", pQueue, pDev,
596 fOpenMode, fStreamMode));
597
598 /*
599 * Already open?
600 */
601 if (pQueue->q_ptr)
602 {
603 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen invalid open.\n"));
604 return ENOENT;
605 }
606
607 /*
608 * Check for the VirtualBox instance.
609 */
610 PVBOXNETFLTINS pThis = g_VBoxNetFltSolarisInstance;
611 if (!pThis)
612 {
613 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to get VirtualBox instance.\n"));
614 return ENOENT;
615 }
616
617 /*
618 * Check VirtualBox stream type.
619 */
620 if (g_VBoxNetFltSolarisStreamType == kUndefined)
621 {
622 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed due to undefined VirtualBox open mode.\n"));
623 return ENOENT;
624 }
625
626 /*
627 * Get minor number. For clone opens provide a new dev_t.
628 */
629 minor_t DevMinor = 0;
630 vboxnetflt_stream_t *pStream = NULL;
631 vboxnetflt_stream_t **ppPrevStream = &g_VBoxNetFltSolarisStreams;
632 if (fStreamMode == CLONEOPEN)
633 {
634 for (; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
635 {
636 if (DevMinor < pStream->DevMinor)
637 break;
638 DevMinor++;
639 }
640 *pDev = makedevice(getmajor(*pDev), DevMinor);
641 }
642 else
643 DevMinor = getminor(*pDev);
644
645 if (g_VBoxNetFltSolarisStreamType == kPromiscStream)
646 {
647 vboxnetflt_promisc_stream_t *pPromiscStream = RTMemAlloc(sizeof(vboxnetflt_promisc_stream_t));
648 if (RT_UNLIKELY(!pPromiscStream))
649 {
650 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to allocate promiscuous stream data.\n"));
651 return ENOMEM;
652 }
653
654 pPromiscStream->fPromisc = false;
655 pPromiscStream->fRawMode = false;
656 pPromiscStream->ModeReqId = 0;
657 pPromiscStream->pHead = NULL;
658 pPromiscStream->pTail = NULL;
659 pPromiscStream->cLoopback = 0;
660 pStream = (vboxnetflt_stream_t *)pPromiscStream;
661 }
662 else
663 {
664 /*
665 * Allocate & initialize per-stream data. Hook it into the (read and write) queue's module specific data.
666 */
667 pStream = RTMemAlloc(sizeof(vboxnetflt_stream_t));
668 if (RT_UNLIKELY(!pStream))
669 {
670 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to allocate stream data.\n"));
671 return ENOMEM;
672 }
673 }
674 pStream->DevMinor = DevMinor;
675 pStream->pReadQueue = pQueue;
676
677 /*
678 * Pick up the current global VBOXNETFLTINS instance as
679 * the one that we will associate this stream with.
680 */
681 ASMAtomicUoWritePtr((void * volatile *)&pStream->pThis, pThis);
682 pStream->Type = g_VBoxNetFltSolarisStreamType;
683 switch (pStream->Type)
684 {
685 case kIp4Stream: ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pvIp4Stream, pStream); break;
686 case kIp6Stream: ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pvIp6Stream, pStream); break;
687 case kArpStream: ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pvArpStream, pStream); break;
688 case kPromiscStream: ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pvPromiscStream, pStream); break;
689 default: /* Heh. */
690 {
691 AssertRelease(pStream->Type);
692 break;
693 }
694 }
695
696 pQueue->q_ptr = pStream;
697 WR(pQueue)->q_ptr = pStream;
698
699 /*
700 * Link it to the list of streams.
701 */
702 pStream->pNext = *ppPrevStream;
703 *ppPrevStream = pStream;
704
705 qprocson(pQueue);
706
707 /*
708 * Don't hold the spinlocks across putnext calls as it could
709 * (and does mostly) re-enter the put procedure on the same thread.
710 */
711 if (pStream->Type == kPromiscStream)
712 {
713 vboxnetflt_promisc_stream_t *pPromiscStream = (vboxnetflt_promisc_stream_t *)pStream;
714
715 /*
716 * Bind to SAP 0 (DL_ETHER).
717 * Note: We don't support DL_TPR (token passing ring) SAP as that is unnecessary asynchronous
718 * work to get DL_INFO_REQ acknowledgements and determine SAP based on the Mac Type etc.
719 * Besides TPR doesn't really exist anymore practically as far as I know.
720 */
721 int rc = vboxNetFltSolarisBindReq(pStream->pReadQueue, 0 /* SAP */);
722 if (RT_LIKELY(RT_SUCCESS(rc)))
723 {
724 /*
725 * Request the physical address (we cache the acknowledgement).
726 */
727 /** @todo take a look at DLPI notifications additionally for these things. */
728 rc = vboxNetFltSolarisPhysAddrReq(pStream->pReadQueue);
729 if (RT_LIKELY(RT_SUCCESS(rc)))
730 {
731 /*
732 * Ask for DLPI link notifications, don't bother check for errors here.
733 */
734 vboxNetFltSolarisNotifyReq(pStream->pReadQueue);
735
736 /*
737 * Enable raw mode.
738 */
739 rc = vboxNetFltSolarisSetRawMode(pPromiscStream);
740 if (RT_FAILURE(rc))
741 LogRel((DEVICE_NAME ":vboxNetFltSolarisSetRawMode failed rc=%Vrc.\n", rc));
742 }
743 else
744 LogRel((DEVICE_NAME ":vboxNetFltSolarisSetRawMode failed rc=%Vrc.\n", rc));
745 }
746 else
747 LogRel((DEVICE_NAME ":vboxNetFltSolarisBindReq failed rc=%Vrc.\n", rc));
748 }
749
750 NOREF(fOpenMode);
751 NOREF(pCred);
752
753 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModOpen returns 0, DevMinor=%d pQueue=%p\n", DevMinor, pStream->pReadQueue));
754
755 return 0;
756}
757
758
759/**
760 * Stream module close entry point, undoes the work done on open and closes the stream.
761 *
762 * @param pQueue Pointer to the queue (cannot be NULL).
763 * @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
764 * @param pCred Pointer to user credentials.
765 *
766 * @returns corresponding solaris error code.
767 */
768static int VBoxNetFltSolarisModClose(queue_t *pQueue, int fOpenMode, cred_t *pCred)
769{
770 Assert(pQueue);
771
772 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModClose pQueue=%p fOpenMode=%d\n", pQueue, fOpenMode));
773
774 vboxnetflt_stream_t *pStream = NULL;
775 vboxnetflt_stream_t **ppPrevStream = NULL;
776
777 /*
778 * Get instance data.
779 */
780 pStream = (vboxnetflt_stream_t *)pQueue->q_ptr;
781 if (RT_UNLIKELY(!pStream))
782 {
783 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModClose failed to get stream.\n"));
784 return ENXIO;
785 }
786
787 if (pStream->Type == kPromiscStream)
788 {
789 flushq(pQueue, FLUSHALL);
790 flushq(WR(pQueue), FLUSHALL);
791 }
792
793 qprocsoff(pQueue);
794
795 if (pStream->Type == kPromiscStream)
796 {
797 vboxnetflt_promisc_stream_t *pPromiscStream = (vboxnetflt_promisc_stream_t *)pStream;
798
799 int rc = RTSemFastMutexRequest(pStream->pThis->u.s.hFastMtx);
800 AssertRCReturn(rc, rc);
801
802 /*
803 * Free-up loopback buffers.
804 */
805 PVBOXNETFLTPACKETID pCur = pPromiscStream->pHead;
806 while (pCur)
807 {
808 PVBOXNETFLTPACKETID pNext = pCur->pNext;
809 RTMemFree(pCur);
810 pCur = pNext;
811 }
812 pPromiscStream->pHead = NULL;
813 pPromiscStream->pTail = NULL;
814 pPromiscStream->cLoopback = 0;
815
816 RTSemFastMutexRelease(pStream->pThis->u.s.hFastMtx);
817 }
818
819 /*
820 * Unlink it from the list of streams.
821 */
822 for (ppPrevStream = &g_VBoxNetFltSolarisStreams; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
823 if (pStream == (vboxnetflt_stream_t *)pQueue->q_ptr)
824 break;
825 *ppPrevStream = pStream->pNext;
826
827 /*
828 * Delete the stream.
829 */
830 switch (pStream->Type)
831 {
832 case kIp4Stream: ASMAtomicUoWritePtr(pStream->pThis->u.s.pvIp4Stream, NULL); break;
833 case kIp6Stream: ASMAtomicUoWritePtr(pStream->pThis->u.s.pvIp6Stream, NULL); break;
834 case kArpStream: ASMAtomicUoWritePtr(pStream->pThis->u.s.pvArpStream, NULL); break;
835 case kPromiscStream: ASMAtomicUoWritePtr(pStream->pThis->u.s.pvPromiscStream, NULL); break;
836 default: /* Heh. */
837 {
838 AssertRelease(pStream->Type);
839 break;
840 }
841 }
842
843 vboxNetFltRelease(pStream->pThis, false /* fBusy */);
844 RTMemFree(pStream);
845 pQueue->q_ptr = NULL;
846 WR(pQueue)->q_ptr = NULL;
847
848 NOREF(fOpenMode);
849 NOREF(pCred);
850
851 return 0;
852}
853
854
855/**
856 * Read side put procedure for processing messages in the read queue.
857 *
858 * @param pQueue Pointer to the queue.
859 * @param pMsg Pointer to the message.
860 *
861 * @returns corresponding solaris error code.
862 */
863static int VBoxNetFltSolarisModReadPut(queue_t *pQueue, mblk_t *pMsg)
864{
865 if (!pMsg)
866 return 0;
867
868 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut pQueue=%p pMsg=%p\n", pQueue, pMsg));
869
870 bool fSendUpstream = true;
871 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
872 PVBOXNETFLTINS pThis = NULL;
873
874 /*
875 * In the unlikely case where VirtualBox crashed and this filter
876 * is somehow still in the host stream we must try not to panic the host.
877 */
878 if ( pStream
879 && pStream->Type == kPromiscStream)
880 {
881 pThis = ASMAtomicUoReadPtr((void * volatile *)&pStream->pThis);
882 if (RT_LIKELY(pThis))
883 {
884 /*
885 * Retain the instance if we're filtering regardless of we are active or not
886 * The reason being even when we are inactive we reference the instance (e.g
887 * the promiscuous OFF acknowledgement case).
888 */
889 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
890 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
891 const bool fActive = ASMAtomicUoReadBool(&pThis->fActive);
892 vboxNetFltRetain(pThis, true /* fBusy */);
893 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
894
895 vboxnetflt_promisc_stream_t *pPromiscStream = (vboxnetflt_promisc_stream_t *)pStream;
896
897 switch (DB_TYPE(pMsg))
898 {
899 case M_DATA:
900 {
901 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut M_DATA\n"));
902
903 if ( fActive
904 && pPromiscStream->fRawMode)
905 {
906 vboxNetFltSolarisRecv(pThis, pStream, pQueue, pMsg);
907 fSendUpstream = false;
908 }
909 break;
910 }
911
912 case M_PROTO:
913 case M_PCPROTO:
914 {
915 union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
916 t_uscalar_t Prim = pPrim->dl_primitive;
917
918 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO %d\n", Prim));
919 switch (Prim)
920 {
921 case DL_NOTIFY_IND:
922 {
923 if (MBLKL(pMsg) < DL_NOTIFY_IND_SIZE)
924 {
925 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Invalid notification size; expected>=%d got=%d\n",
926 DL_NOTIFY_IND_SIZE, MBLKL(pMsg)));
927 fSendUpstream = false;
928 break;
929 }
930
931 dl_notify_ind_t *pNotifyInd = (dl_notify_ind_t *)pMsg->b_rptr;
932 switch (pNotifyInd->dl_notification)
933 {
934 case DL_NOTE_PHYS_ADDR:
935 {
936 if (pNotifyInd->dl_data != DL_CURR_PHYS_ADDR)
937 break;
938
939 size_t cOffset = pNotifyInd->dl_addr_offset;
940 size_t cbAddr = pNotifyInd->dl_addr_length;
941
942 if (!cOffset || !cbAddr)
943 {
944 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_PHYS_ADDR. Invalid offset/addr.\n"));
945 fSendUpstream = false;
946 break;
947 }
948
949 bcopy(pMsg->b_rptr + cOffset, &pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
950 fSendUpstream = false;
951 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_PHYS_ADDR. New Mac=%.*Rhxs\n",
952 sizeof(pThis->u.s.Mac), &pThis->u.s.Mac));
953 break;
954 }
955
956 case DL_NOTE_LINK_UP:
957 {
958 const bool fDisconnected = ASMAtomicUoReadBool(&pThis->fActive);
959 if (fDisconnected)
960 {
961 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, false);
962 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_LINK_UP.\n"));
963 }
964 fSendUpstream = false;
965 break;
966 }
967
968 case DL_NOTE_LINK_DOWN:
969 {
970 const bool fDisconnected = ASMAtomicUoReadBool(&pThis->fActive);
971 if (!fDisconnected)
972 {
973 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
974 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_LINK_DOWN.\n"));
975 }
976 fSendUpstream = false;
977 break;
978 }
979 }
980 break;
981 }
982
983 case DL_BIND_ACK:
984 {
985 /*
986 * Swallow our bind request acknowledgement.
987 */
988 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_BIND_ACK. Bound to requested SAP!\n"));
989 freemsg(pMsg);
990 fSendUpstream = false;
991 break;
992 }
993
994 case DL_PHYS_ADDR_ACK:
995 {
996 /*
997 * Swallow our physical address request acknowledgement.
998 */
999 vboxNetFltSolarisCachePhysAddr(pThis, pMsg);
1000 freemsg(pMsg);
1001 fSendUpstream = false;
1002 break;
1003 }
1004
1005 case DL_OK_ACK:
1006 {
1007 /*
1008 * Swallow our fake promiscous request acknowledgement.
1009 */
1010 dl_ok_ack_t *pOkAck = (dl_ok_ack_t *)pMsg->b_rptr;
1011 if (pOkAck->dl_correct_primitive == DL_PROMISCON_REQ)
1012 {
1013 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO: DL_OK_ACK: fPromisc is ON.\n"));
1014 pPromiscStream->fPromisc = true;
1015 }
1016 else if (pOkAck->dl_correct_primitive == DL_PROMISCOFF_REQ)
1017 {
1018 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO: DL_OK_ACK: fPromisc is OFF.\n"));
1019 pPromiscStream->fPromisc = false;
1020 }
1021
1022 freemsg(pMsg);
1023 fSendUpstream = false;
1024 break;
1025 }
1026 }
1027 break;
1028 }
1029
1030 case M_IOCACK:
1031 {
1032 /*
1033 * Swallow our fake raw/fast path mode request acknowledgement.
1034 */
1035 struct iocblk *pIOC = (struct iocblk *)pMsg->b_rptr;
1036 if (pIOC->ioc_id == pPromiscStream->ModeReqId)
1037 {
1038 pPromiscStream->fRawMode = true;
1039 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Mode acknowledgement. RawMode is %s\n",
1040 pPromiscStream->fRawMode ? "ON" : "OFF"));
1041
1042 freemsg(pMsg);
1043 fSendUpstream = false;
1044 }
1045 break;
1046 }
1047
1048 case M_FLUSH:
1049 {
1050 /*
1051 * We must support flushing queues.
1052 */
1053 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_FLUSH\n"));
1054 if (*pMsg->b_rptr & FLUSHR)
1055 flushq(pQueue, FLUSHALL);
1056 break;
1057 }
1058 }
1059
1060 vboxNetFltRelease(pThis, true /* fBusy */);
1061 }
1062 else
1063 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Could not find VirtualBox instance!!\n"));
1064 }
1065
1066 if (fSendUpstream)
1067 {
1068 /*
1069 * Pass foward messages when adjacent module can receive, otherwise queue them.
1070 */
1071 if (canputnext(pQueue))
1072 putnext(pQueue, pMsg);
1073 else
1074 putbq(pQueue, pMsg);
1075 }
1076
1077 return 0;
1078}
1079
1080
1081/**
1082 * Write side put procedure for processing messages in the write queue.
1083 *
1084 * @param pQueue Pointer to the queue.
1085 * @param pMsg Pointer to the message.
1086 *
1087 * @returns corresponding solaris error code.
1088 */
1089static int VBoxNetFltSolarisModWritePut(queue_t *pQueue, mblk_t *pMsg)
1090{
1091 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut pQueue=%p pMsg=%p\n", pQueue, pMsg));
1092
1093 if (pMsg)
1094 {
1095 /*
1096 * Pass foward messages when adjacent module can receive, otherwise queue them.
1097 */
1098 if (canputnext(pQueue))
1099 putnext(pQueue, pMsg);
1100 else
1101 putbq(pQueue, pMsg);
1102 }
1103
1104 return 0;
1105}
1106
1107
1108/**
1109 * Write side service procedure for deferred message processing on the write queue.
1110 *
1111 * @param pQueue Pointer to the queue.
1112 *
1113 * @returns corresponding solaris error code.
1114 */
1115static int VBoxNetFltSolarisModWriteService(queue_t *pQueue)
1116{
1117 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWriteService pQueue=%p\n", pQueue));
1118
1119 /*
1120 * Implement just the flow controlled service draining of the queue.
1121 * Nothing else to do here, we handle all the important stuff in the Put procedure.
1122 */
1123 mblk_t *pMsg;
1124 while (pMsg = getq(pQueue))
1125 {
1126 if (canputnext(pQueue))
1127 putnext(pQueue, pMsg);
1128 else
1129 {
1130 putbq(pQueue, pMsg);
1131 break;
1132 }
1133 }
1134
1135 return 0;
1136}
1137
1138
1139/**
1140 * Put the stream in raw mode.
1141 *
1142 * @returns VBox status code.
1143 * @param pQueue Pointer to the queue.
1144 */
1145static int vboxNetFltSolarisSetRawMode(vboxnetflt_promisc_stream_t *pPromiscStream)
1146{
1147 LogFlow((DEVICE_NAME ":vboxNetFltSolarisSetRawMode pPromiscStream=%p\n", pPromiscStream));
1148
1149 mblk_t *pRawMsg = NULL;
1150 pRawMsg = mkiocb(DLIOCRAW);
1151 if (RT_UNLIKELY(!pRawMsg))
1152 return VERR_NO_MEMORY;
1153
1154 queue_t *pQueue = pPromiscStream->Stream.pReadQueue;
1155 if (!pQueue)
1156 return VERR_INVALID_POINTER;
1157
1158 struct iocblk *pIOC = (struct iocblk *)pRawMsg->b_rptr;
1159 pPromiscStream->ModeReqId = pIOC->ioc_id;
1160 pIOC->ioc_count = 0;
1161
1162 qreply(pQueue, pRawMsg);
1163 return VINF_SUCCESS;
1164}
1165
1166
1167#if 0
1168/**
1169 * Put the stream back in fast path mode.
1170 *
1171 * @returns VBox status code.
1172 * @param pQueue Pointer to the queue.
1173 */
1174static int vboxNetFltSolarisSetFastMode(queue_t *pQueue)
1175{
1176 LogFlow((DEVICE_NAME ":vboxNetFltSolarisSetFastMode pQueue=%p\n", pQueue));
1177
1178 mblk_t *pFastMsg = mkiocb(DL_IOC_HDR_INFO);
1179 if (RT_UNLIKELY(!pFastMsg))
1180 return VERR_NO_MEMORY;
1181
1182 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
1183 struct iocblk *pIOC = (struct iocblk *)pFastMsg->b_rptr;
1184 pStream->ModeReqId = pIOC->ioc_id;
1185
1186 size_t cbReq = sizeof(dl_unitdata_req_t) + sizeof(vboxnetflt_dladdr_t);
1187 mblk_t *pDataReqMsg = allocb(cbReq, BPRI_MED);
1188 if (RT_UNLIKELY(!pDataReqMsg))
1189 return VERR_NO_MEMORY;
1190
1191 DB_TYPE(pDataReqMsg) = M_PROTO;
1192 dl_unitdata_req_t *pDataReq = (dl_unitdata_req_t *)pDataReqMsg->b_rptr;
1193 pDataReq->dl_primitive = DL_UNITDATA_REQ;
1194 pDataReq->dl_dest_addr_length = sizeof(vboxnetflt_dladdr_t);
1195 pDataReq->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
1196 pDataReq->dl_priority.dl_min = 0;
1197 pDataReq->dl_priority.dl_max = 0;
1198
1199 bzero(pDataReqMsg->b_rptr + sizeof(dl_unitdata_req_t), sizeof(vboxnetflt_dladdr_t));
1200 pDataReqMsg->b_wptr = pDataReqMsg->b_rptr + cbReq;
1201
1202 /*
1203 * Link the data format request message into the header ioctl message.
1204 */
1205 pFastMsg->b_cont = pDataReqMsg;
1206 pIOC->ioc_count = msgdsize(pDataReqMsg);
1207
1208 qreply(pQueue, pFastMsg);
1209 return VINF_SUCCESS;
1210}
1211#endif
1212
1213
1214/**
1215 * Send fake promiscous mode requests downstream.
1216 *
1217 * @param pQueue Pointer to the queue.
1218 * @param fPromisc Whether to enable promiscous mode or not.
1219 * @param PromiscLevel Promiscous level; DL_PROMISC_PHYS/SAP/MULTI.
1220 *
1221 * @returns VBox error code.
1222 */
1223static int vboxNetFltSolarisPromiscReq(queue_t *pQueue, bool fPromisc)
1224{
1225 LogFlow((DEVICE_NAME ":vboxNetFltSolarisPromiscReq pQueue=%p fPromisc=%d\n", pQueue, fPromisc));
1226
1227 t_uscalar_t Cmd;
1228 size_t cbReq = 0;
1229 if (fPromisc)
1230 {
1231 Cmd = DL_PROMISCON_REQ;
1232 cbReq = DL_PROMISCON_REQ_SIZE;
1233 }
1234 else
1235 {
1236 Cmd = DL_PROMISCOFF_REQ;
1237 cbReq = DL_PROMISCOFF_REQ_SIZE;
1238 }
1239
1240 mblk_t *pPromiscPhysMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1241 if (RT_UNLIKELY(!pPromiscPhysMsg))
1242 return VERR_NO_MEMORY;
1243
1244 mblk_t *pPromiscSapMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1245 if (RT_UNLIKELY(!pPromiscSapMsg))
1246 {
1247 freemsg(pPromiscPhysMsg);
1248 return VERR_NO_MEMORY;
1249 }
1250
1251 if (fPromisc)
1252 {
1253 ((dl_promiscon_req_t *)pPromiscPhysMsg->b_rptr)->dl_level = DL_PROMISC_PHYS;
1254 ((dl_promiscon_req_t *)pPromiscSapMsg->b_rptr)->dl_level = DL_PROMISC_SAP;
1255 }
1256 else
1257 {
1258 ((dl_promiscoff_req_t *)pPromiscPhysMsg->b_rptr)->dl_level = DL_PROMISC_PHYS;
1259 ((dl_promiscoff_req_t *)pPromiscSapMsg->b_rptr)->dl_level = DL_PROMISC_SAP;
1260 }
1261
1262 qreply(pQueue, pPromiscPhysMsg);
1263 qreply(pQueue, pPromiscSapMsg);
1264
1265 return VINF_SUCCESS;
1266}
1267
1268
1269/**
1270 * Send a fake physical address request downstream.
1271 *
1272 * @returns VBox status code.
1273 * @param pQueue Pointer to the queue.
1274 * @param pMsg Pointer to the request message.
1275 */
1276static int vboxNetFltSolarisPhysAddrReq(queue_t *pQueue)
1277{
1278 LogFlow((DEVICE_NAME ":vboxNetFltSolarisPhysAddrReq pQueue=%p\n", pQueue));
1279
1280 t_uscalar_t Cmd = DL_PHYS_ADDR_REQ;
1281 size_t cbReq = DL_PHYS_ADDR_REQ_SIZE;
1282 mblk_t *pPhysAddrMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1283 if (RT_UNLIKELY(!pPhysAddrMsg))
1284 return VERR_NO_MEMORY;
1285
1286 dl_phys_addr_req_t *pPhysAddrReq = (dl_phys_addr_req_t *)pPhysAddrMsg->b_rptr;
1287 pPhysAddrReq->dl_addr_type = DL_CURR_PHYS_ADDR;
1288
1289 qreply(pQueue, pPhysAddrMsg);
1290 return VINF_SUCCESS;
1291}
1292
1293
1294/**
1295 * Cache the MAC address into the VirtualBox instance given a physical
1296 * address acknowledgement message.
1297 *
1298 * @param pThis The instance.
1299 * @param pMsg Pointer to the physical address acknowledgement message.
1300 */
1301static void vboxNetFltSolarisCachePhysAddr(PVBOXNETFLTINS pThis, mblk_t *pMsg)
1302{
1303 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr pThis=%p pMsg=%p\n", pThis, pMsg));
1304
1305 AssertCompile(sizeof(RTMAC) == ETHERADDRL);
1306 dl_phys_addr_ack_t *pPhysAddrAck = (dl_phys_addr_ack_t *)pMsg->b_rptr;
1307 if (pPhysAddrAck->dl_addr_length == sizeof(pThis->u.s.Mac))
1308 {
1309 bcopy(pMsg->b_rptr + pPhysAddrAck->dl_addr_offset, &pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
1310
1311 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr: DL_PHYS_ADDR_ACK: Mac=%.*Rhxs\n", sizeof(pThis->u.s.Mac),
1312 &pThis->u.s.Mac));
1313 }
1314 else
1315 {
1316 LogRel((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr: Invalid address size. expected=%d got=%d\n", ETHERADDRL,
1317 pPhysAddrAck->dl_addr_length));
1318 }
1319}
1320
1321
1322/**
1323 * Prepare DLPI bind request to a SAP.
1324 *
1325 * @returns VBox status code.
1326 * @param pQueue Pointer to the queue.
1327 * @param SAP The SAP to bind the stream to.
1328 */
1329static int vboxNetFltSolarisBindReq(queue_t *pQueue, int SAP)
1330{
1331 LogFlow((DEVICE_NAME ":vboxNetFltSolarisBindReq SAP=%d\n", SAP));
1332
1333 mblk_t *pBindMsg = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ);
1334 if (RT_UNLIKELY(!pBindMsg))
1335 return VERR_NO_MEMORY;
1336
1337 dl_bind_req_t *pBindReq = (dl_bind_req_t *)pBindMsg->b_rptr;
1338 pBindReq->dl_sap = SAP;
1339 pBindReq->dl_max_conind = 0;
1340 pBindReq->dl_conn_mgmt = 0;
1341 pBindReq->dl_xidtest_flg = 0;
1342 pBindReq->dl_service_mode = DL_CLDLS;
1343
1344 qreply(pQueue, pBindMsg);
1345 return VINF_SUCCESS;
1346}
1347
1348
1349/**
1350 * Prepare DLPI notifications request.
1351 *
1352 * @returns VBox status code.
1353 * @param pQueue Pointer to the queue.
1354 */
1355static int vboxNetFltSolarisNotifyReq(queue_t *pQueue)
1356{
1357 LogFlow((DEVICE_NAME ":vboxNetFltSolarisNotifyReq\n"));
1358
1359 mblk_t *pNotifyMsg = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, DL_NOTIFY_REQ);
1360 if (RT_UNLIKELY(!pNotifyMsg))
1361 return VERR_NO_MEMORY;
1362
1363 dl_notify_req_t *pNotifyReq = (dl_notify_req_t *)pNotifyMsg->b_rptr;
1364 pNotifyReq->dl_notifications = DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_PHYS_ADDR;
1365
1366 qreply(pQueue, pNotifyMsg);
1367 return VINF_SUCCESS;
1368}
1369
1370
1371/**
1372 * Opens the required device and returns the vnode_t associated with it.
1373 * We require this for the funny attach/detach routine.
1374 *
1375 * @returns VBox status code.
1376 * @param pszDev The device path.
1377 * @param ppVNode Where to store the vnode_t pointer associated with the opened device.
1378 * @param ppVNodeHeld Where to store the vnode_t required during closing of the device.
1379 * @param ppUser Open handle required while closing the device.
1380 */
1381static int vboxNetFltSolarisOpenDev(char *pszDev, vnode_t **ppVNode, vnode_t **ppVNodeHeld, TIUSER **ppUser)
1382{
1383 int rc;
1384 vnode_t *pVNodeHeld = NULL;
1385 rc = lookupname(pszDev, UIO_SYSSPACE, FOLLOW, NULLVPP, &pVNodeHeld);
1386 if (!rc)
1387 {
1388 TIUSER *pUser;
1389 rc = t_kopen((file_t *)NULL, pVNodeHeld->v_rdev, FREAD | FWRITE, &pUser, kcred);
1390 if (!rc)
1391 {
1392 *ppVNode = pUser->fp->f_vnode;
1393 *ppVNodeHeld = pVNodeHeld;
1394 *ppUser = pUser;
1395 return VINF_SUCCESS;
1396 }
1397 VN_RELE(pVNodeHeld);
1398 }
1399 return VERR_PATH_NOT_FOUND;
1400}
1401
1402
1403/**
1404 * Close the device opened using vboxNetFltSolarisOpenDev.
1405 *
1406 * @param pVNodeHeld Pointer to the held vnode of the device.
1407 * @param pUser Pointer to the file handle.
1408 */
1409static void vboxNetFltSolarisCloseDev(vnode_t *pVNodeHeld, TIUSER *pUser)
1410{
1411 t_kclose(pUser, 0);
1412 VN_RELE(pVNodeHeld);
1413}
1414
1415
1416/**
1417 * Get the logical interface flags from the stream.
1418 *
1419 * @returns VBox status code.
1420 * @param hDevice Layered device handle.
1421 * @param pInterface Pointer to the interface.
1422 */
1423static int vboxNetFltSolarisGetIfFlags(ldi_handle_t hDevice, struct lifreq *pInterface)
1424{
1425 struct strioctl IOCReq;
1426 int rc;
1427 int ret;
1428 IOCReq.ic_cmd = SIOCGLIFFLAGS;
1429 IOCReq.ic_timout = 40;
1430 IOCReq.ic_len = sizeof(struct lifreq);
1431 IOCReq.ic_dp = (caddr_t)pInterface;
1432 rc = ldi_ioctl(hDevice, I_STR, (intptr_t)&IOCReq, FKIOCTL, kcred, &ret);
1433 if (!rc)
1434 return VINF_SUCCESS;
1435
1436 return RTErrConvertFromErrno(rc);
1437}
1438
1439
1440/**
1441 * Sets the multiplexor ID from the interface.
1442 *
1443 * @returns VBox status code.
1444 * @param pVNode Pointer to the device vnode.
1445 * @param pInterface Pointer to the interface.
1446 */
1447static int vboxNetFltSolarisSetMuxId(vnode_t *pVNode, struct lifreq *pInterface)
1448{
1449 struct strioctl IOCReq;
1450 int rc;
1451 int ret;
1452 IOCReq.ic_cmd = SIOCSLIFMUXID;
1453 IOCReq.ic_timout = 40;
1454 IOCReq.ic_len = sizeof(struct lifreq);
1455 IOCReq.ic_dp = (caddr_t)pInterface;
1456
1457 rc = strioctl(pVNode, I_STR, (intptr_t)&IOCReq, 0, K_TO_K, kcred, &ret);
1458 if (!rc)
1459 return VINF_SUCCESS;
1460
1461 return RTErrConvertFromErrno(rc);
1462}
1463
1464
1465/**
1466 * Get the multiplexor file descriptor of the lower stream.
1467 *
1468 * @returns VBox status code.
1469 * @param MuxId The multiplexor ID.
1470 * @param pFd Where to store the lower stream file descriptor.
1471 */
1472static int vboxNetFltSolarisMuxIdToFd(vnode_t *pVNode, int MuxId, int *pFd)
1473{
1474 int ret;
1475 int rc = strioctl(pVNode, _I_MUXID2FD, (intptr_t)MuxId, 0, K_TO_K, kcred, &ret);
1476 if (!rc)
1477 {
1478 *pFd = ret;
1479 return VINF_SUCCESS;
1480 }
1481
1482 return RTErrConvertFromErrno(rc);
1483}
1484
1485
1486/**
1487 * Relinks the lower and the upper IPv4 stream.
1488 *
1489 * @returns VBox status code.
1490 * @param pVNode Pointer to the device vnode.
1491 * @param pInterface Pointer to the interface.
1492 * @param IpMuxFd The IP multiplexor ID.
1493 * @param ArpMuxFd The ARP multiplexor ID.
1494 */
1495static int vboxNetFltSolarisRelinkIp4(vnode_t *pVNode, struct lifreq *pInterface, int IpMuxFd, int ArpMuxFd)
1496{
1497 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: pVNode=%p pInterface=%p IpMuxFd=%d ArpMuxFd=%d\n", pVNode,
1498 pInterface, IpMuxFd, ArpMuxFd));
1499
1500 int NewIpMuxId;
1501 int NewArpMuxId;
1502 int rc = strioctl(pVNode, I_PLINK, (intptr_t)IpMuxFd, 0, K_TO_K, kcred, &NewIpMuxId);
1503 int rc2 = strioctl(pVNode, I_PLINK, (intptr_t)ArpMuxFd, 0, K_TO_K, kcred, &NewArpMuxId);
1504 if ( !rc
1505 && !rc2)
1506 {
1507 pInterface->lifr_ip_muxid = NewIpMuxId;
1508 pInterface->lifr_arp_muxid = NewArpMuxId;
1509 rc = vboxNetFltSolarisSetMuxId(pVNode, pInterface);
1510 if (RT_SUCCESS(rc))
1511 return VINF_SUCCESS;
1512
1513 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: failed to set new Mux Id.\n"));
1514 }
1515 else
1516 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: failed to link.\n"));
1517
1518 return VERR_GENERAL_FAILURE;
1519}
1520
1521
1522/**
1523 * Relinks the lower and the upper IPv6 stream.
1524 *
1525 * @returns VBox status code.
1526 * @param pVNode Pointer to the device vnode.
1527 * @param pInterface Pointer to the interface.
1528 * @param Ip6MuxFd The IPv6 multiplexor ID.
1529 */
1530static int vboxNetFltSolarisRelinkIp6(vnode_t *pVNode, struct lifreq *pInterface, int Ip6MuxFd)
1531{
1532 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: pVNode=%p pInterface=%p Ip6MuxFd=%d\n", pVNode, pInterface, Ip6MuxFd));
1533
1534 int NewIp6MuxId;
1535 int rc = strioctl(pVNode, I_PLINK, (intptr_t)Ip6MuxFd, 0, K_TO_K, kcred, &NewIp6MuxId);
1536 if (!rc)
1537 {
1538 pInterface->lifr_ip_muxid = NewIp6MuxId;
1539 rc = vboxNetFltSolarisSetMuxId(pVNode, pInterface);
1540 if (RT_SUCCESS(rc))
1541 return VINF_SUCCESS;
1542
1543 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: failed to set new Mux Id.\n"));
1544 }
1545 else
1546 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: failed to link.\n"));
1547
1548 return VERR_GENERAL_FAILURE;
1549}
1550
1551
1552/**
1553 * Dynamically find the position on the host stack where to attach/detach ourselves.
1554 *
1555 * @returns VBox status code.
1556 * @param pVNode Pointer to the lower stream vnode.
1557 * @param pModPos Where to store the module position.
1558 */
1559static int vboxNetFltSolarisDetermineModPos(bool fAttach, vnode_t *pVNode, int *pModPos)
1560{
1561 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: fAttach=%d pVNode=%p pModPos=%p\n", fAttach, pVNode, pModPos));
1562
1563 int cMod;
1564 int rc = strioctl(pVNode, I_LIST, (intptr_t)NULL, 0, K_TO_K, kcred, &cMod);
1565 if (!rc)
1566 {
1567 if (cMod < 1)
1568 {
1569 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: too few modules on host interface. cMod=%d\n"));
1570 return VERR_OUT_OF_RANGE;
1571 }
1572
1573 /*
1574 * While attaching we make sure we are at the bottom most of the stack, excepting
1575 * the host driver.
1576 */
1577 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: cMod=%d\n", cMod));
1578 if (fAttach)
1579 {
1580 *pModPos = cMod - 1;
1581 return VINF_SUCCESS;
1582 }
1583
1584 /*
1585 * Detaching is a bit more complicated; since user could have altered the stack positions
1586 * we take the safe approach by finding our position.
1587 */
1588 struct str_list StrList;
1589 StrList.sl_nmods = cMod;
1590 StrList.sl_modlist = RTMemAllocZ(cMod * sizeof(struct str_list));
1591 if (RT_UNLIKELY(!StrList.sl_modlist))
1592 {
1593 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to alloc memory for StrList.\n"));
1594 return VERR_NO_MEMORY;
1595 }
1596
1597 /*
1598 * Get the list of all modules on the stack.
1599 */
1600 int ret;
1601 rc = strioctl(pVNode, I_LIST, (intptr_t)&StrList, 0, K_TO_K, kcred, &ret);
1602 if (!rc)
1603 {
1604 /*
1605 * Find our filter.
1606 */
1607 for (int i = 0; i < StrList.sl_nmods; i++)
1608 {
1609 if (!strcmp(DEVICE_NAME, StrList.sl_modlist[i].l_name))
1610 {
1611 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: Success! Found %s at %d.\n", DEVICE_NAME, i));
1612 *pModPos = i;
1613 RTMemFree(StrList.sl_modlist);
1614 return VINF_SUCCESS;
1615 }
1616 }
1617
1618 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to find %s in the host stack.\n"));
1619 }
1620 else
1621 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get module information. rc=%d\n"));
1622
1623 RTMemFree(StrList.sl_modlist);
1624 }
1625 else
1626 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get list of modules on host interface. rc=%d\n", rc));
1627 return VERR_GENERAL_FAILURE;
1628}
1629
1630
1631/**
1632 * Opens up dedicated stream on top of the interface.
1633 * As a side-effect, the stream gets opened during
1634 * the I_PUSH phase.
1635 *
1636 * @param pThis The instance.
1637 */
1638static int vboxNetFltSolarisOpenStream(PVBOXNETFLTINS pThis)
1639{
1640 ldi_ident_t DevId;
1641 DevId = ldi_ident_from_anon();
1642 int ret;
1643
1644 /** @todo support DLPI style 2.*/
1645 /*
1646 * Try style-1 open first.
1647 */
1648 char szDev[128];
1649 RTStrPrintf(szDev, sizeof(szDev), "/dev/net/%s", pThis->szName);
1650 int rc = ldi_open_by_name(szDev, FREAD | FWRITE, kcred, &pThis->u.s.hIface, DevId);
1651 if ( rc
1652 && rc == ENODEV) /* ENODEV is returned when resolvepath fails, not ENOENT */
1653 {
1654 /*
1655 * Fallback to non-ClearView style-1 open.
1656 */
1657 RTStrPrintf(szDev, sizeof(szDev), "/dev/%s", pThis->szName);
1658 rc = ldi_open_by_name(szDev, FREAD | FWRITE, kcred, &pThis->u.s.hIface, DevId);
1659 }
1660
1661 ldi_ident_release(DevId);
1662 if (rc)
1663 {
1664 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to open '%s' rc=%d\n", szDev, rc));
1665 return VERR_INTNET_FLT_IF_FAILED;
1666 }
1667
1668 rc = ldi_ioctl(pThis->u.s.hIface, I_FIND, (intptr_t)DEVICE_NAME, FKIOCTL, kcred, &ret);
1669 if (!rc)
1670 {
1671 if (!ret)
1672 {
1673 g_VBoxNetFltSolarisInstance = pThis;
1674 g_VBoxNetFltSolarisStreamType = kPromiscStream;
1675
1676 rc = ldi_ioctl(pThis->u.s.hIface, I_PUSH, (intptr_t)DEVICE_NAME, FKIOCTL, kcred, &ret);
1677
1678 g_VBoxNetFltSolarisInstance = NULL;
1679 g_VBoxNetFltSolarisStreamType = kUndefined;
1680
1681 if (!rc)
1682 return VINF_SUCCESS;
1683
1684 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to push filter onto host interface '%s'\n", pThis->szName));
1685 }
1686 else
1687 return VINF_SUCCESS;
1688 }
1689 else
1690 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to search for filter in interface '%s'.\n", pThis->szName));
1691
1692 return VERR_INTNET_FLT_IF_FAILED;
1693}
1694
1695
1696/**
1697 * Closes the interface, thereby closing the dedicated stream.
1698 *
1699 * @param pThis The instance.
1700 */
1701static void vboxNetFltSolarisCloseStream(PVBOXNETFLTINS pThis)
1702{
1703 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCloseStream pThis=%p\n"));
1704
1705 vboxNetFltRetain(pThis, false /* fBusy */);
1706
1707 ldi_close(pThis->u.s.hIface, FREAD | FWRITE, kcred);
1708}
1709
1710
1711/**
1712 * Dynamically attach under IPv4 and ARP streams on the host stack.
1713 *
1714 * @returns VBox status code.
1715 * @param pThis The instance.
1716 * @param fAttach Is this an attach or detach.
1717 */
1718static int vboxNetFltSolarisAttachIp4(PVBOXNETFLTINS pThis, bool fAttach)
1719{
1720 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachIp4 pThis=%p fAttach=%d\n", pThis, fAttach));
1721
1722 /*
1723 * Statuatory Warning: Hackish code ahead.
1724 */
1725 char *pszModName = DEVICE_NAME;
1726
1727 struct lifreq Ip4Interface;
1728 bzero(&Ip4Interface, sizeof(Ip4Interface));
1729 Ip4Interface.lifr_addr.ss_family = AF_INET;
1730 strncpy(Ip4Interface.lifr_name, pThis->szName, sizeof(Ip4Interface.lifr_name));
1731
1732 struct strmodconf StrMod;
1733 StrMod.mod_name = pszModName;
1734 StrMod.pos = -1; /* this is filled in later. */
1735
1736 struct strmodconf ArpStrMod;
1737 bcopy(&StrMod, &ArpStrMod, sizeof(StrMod));
1738
1739 int rc;
1740 int rc2;
1741 int ret;
1742 ldi_ident_t DeviceIdent = ldi_ident_from_anon();
1743 ldi_handle_t Ip4DevHandle;
1744 ldi_handle_t ArpDevHandle;
1745
1746 /*
1747 * Open the IP and ARP streams as layered devices.
1748 */
1749 rc = ldi_open_by_name(IP_DEV_NAME, FREAD | FWRITE, kcred, &Ip4DevHandle, DeviceIdent);
1750 if (rc)
1751 {
1752 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open the IP stream on '%s'.\n", pThis->szName));
1753 ldi_ident_release(DeviceIdent);
1754 return VERR_INTNET_FLT_IF_FAILED;
1755 }
1756
1757 rc = ldi_open_by_name("/dev/arp", FREAD | FWRITE, kcred, &ArpDevHandle, DeviceIdent);
1758 if (rc)
1759 {
1760 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open the ARP stream on '%s'.\n", pThis->szName));
1761 ldi_ident_release(DeviceIdent);
1762 ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
1763 return VERR_INTNET_FLT_IF_FAILED;
1764 }
1765
1766 ldi_ident_release(DeviceIdent);
1767
1768 /*
1769 * Obtain the interface flags from IPv4.
1770 */
1771 rc = vboxNetFltSolarisGetIfFlags(Ip4DevHandle, &Ip4Interface);
1772 if (RT_SUCCESS(rc))
1773 {
1774 /*
1775 * Open the UDP stream. We sort of cheat here and obtain the vnode so that we can perform
1776 * things that are not possible from the layered interface.
1777 */
1778 vnode_t *pUdp4VNode = NULL;
1779 vnode_t *pUdp4VNodeHeld = NULL;
1780 TIUSER *pUdp4User = NULL;
1781 rc = vboxNetFltSolarisOpenDev(UDP_DEV_NAME, &pUdp4VNode, &pUdp4VNodeHeld, &pUdp4User);
1782 if (RT_SUCCESS(rc))
1783 {
1784 /*
1785 * Get the multiplexor IDs.
1786 */
1787 rc = ldi_ioctl(Ip4DevHandle, SIOCGLIFMUXID, (intptr_t)&Ip4Interface, FKIOCTL, kcred, &ret);
1788 if (!rc)
1789 {
1790 /*
1791 * Get the multiplex file descriptor to the lower streams. Generally this is lost
1792 * once a module is I_PLINK, we need to reobtain it for inserting/removing ourselves from the stack.
1793 */
1794 int Ip4MuxFd;
1795 int ArpMuxFd;
1796 rc = vboxNetFltSolarisMuxIdToFd(pUdp4VNode, Ip4Interface.lifr_ip_muxid, &Ip4MuxFd);
1797 rc2 = vboxNetFltSolarisMuxIdToFd(pUdp4VNode, Ip4Interface.lifr_arp_muxid, &ArpMuxFd);
1798 if ( RT_SUCCESS(rc)
1799 && RT_SUCCESS(rc2))
1800 {
1801 /*
1802 * We need to I_PUNLINK on these multiplexor IDs before we can start
1803 * operating on the lower stream as insertions are direct operations on the lower stream.
1804 */
1805 int ret;
1806 rc = strioctl(pUdp4VNode, I_PUNLINK, (intptr_t)Ip4Interface.lifr_ip_muxid, 0, K_TO_K, kcred, &ret);
1807 rc2 = strioctl(pUdp4VNode, I_PUNLINK, (intptr_t)Ip4Interface.lifr_arp_muxid, 0, K_TO_K, kcred, &ret);
1808 if ( !rc
1809 && !rc2)
1810 {
1811 /*
1812 * Obtain the vnode from the useless userland file descriptor.
1813 */
1814 file_t *pIpFile = getf(Ip4MuxFd);
1815 file_t *pArpFile = getf(ArpMuxFd);
1816 if ( pIpFile
1817 && pArpFile
1818 && pArpFile->f_vnode
1819 && pIpFile->f_vnode)
1820 {
1821 vnode_t *pIp4VNode = pIpFile->f_vnode;
1822 vnode_t *pArpVNode = pArpFile->f_vnode;
1823
1824 /*
1825 * Find the position on the host stack for attaching/detaching ourselves.
1826 */
1827 rc = vboxNetFltSolarisDetermineModPos(fAttach, pIp4VNode, &StrMod.pos);
1828 rc2 = vboxNetFltSolarisDetermineModPos(fAttach, pArpVNode, &ArpStrMod.pos);
1829 if ( RT_SUCCESS(rc)
1830 && RT_SUCCESS(rc2))
1831 {
1832 /*
1833 * Set global data which will be grabbed by ModOpen.
1834 * There is a known (though very unlikely) race here because
1835 * of the inability to pass user data while inserting.
1836 */
1837 g_VBoxNetFltSolarisInstance = pThis;
1838 g_VBoxNetFltSolarisStreamType = kIp4Stream;
1839
1840 /*
1841 * Inject/Eject from the host IP stack.
1842 */
1843 if (!fAttach)
1844 vboxNetFltRetain(pThis, false /* fBusy */);
1845 rc = strioctl(pIp4VNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K,
1846 kcred, &ret);
1847 if (!rc)
1848 {
1849 if (!fAttach)
1850 vboxNetFltRetain(pThis, false /* fBusy */);
1851
1852 /*
1853 * Inject/Eject from the host ARP stack.
1854 */
1855 g_VBoxNetFltSolarisStreamType = kArpStream;
1856 rc = strioctl(pArpVNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&ArpStrMod, 0, K_TO_K,
1857 kcred, &ret);
1858 if (!rc)
1859 {
1860 g_VBoxNetFltSolarisInstance = NULL;
1861 g_VBoxNetFltSolarisStreamType = kUndefined;
1862
1863 /*
1864 * Our job's not yet over; we need to relink the upper and lower streams
1865 * otherwise we've pretty much screwed up the host interface.
1866 */
1867 rc = vboxNetFltSolarisRelinkIp4(pUdp4VNode, &Ip4Interface, Ip4MuxFd, ArpMuxFd);
1868 if (RT_SUCCESS(rc))
1869 {
1870 /*
1871 * Close the devices ONLY during the return from function case; otherwise
1872 * we end up close twice which is an instant kernel panic.
1873 */
1874 vboxNetFltSolarisCloseDev(pUdp4VNodeHeld, pUdp4User);
1875 ldi_close(ArpDevHandle, FREAD | FWRITE, kcred);
1876 ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
1877
1878 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Success! %s %s@(IPv4:%d Arp:%d) "
1879 "%s interface %s\n", fAttach ? "Injected" : "Ejected", StrMod.mod_name,
1880 StrMod.pos, ArpStrMod.pos, fAttach ? "to" : "from", pThis->szName));
1881 return VINF_SUCCESS;
1882 }
1883 else
1884 {
1885 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Relinking failed. Mode=%s rc=%d.\n",
1886 fAttach ? "inject" : "eject", rc));
1887 }
1888
1889 /*
1890 * Try failing gracefully during attach.
1891 */
1892 if (fAttach)
1893 strioctl(pIp4VNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
1894 }
1895 else
1896 {
1897 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to %s the ARP stack. rc=%d\n",
1898 fAttach ? "inject into" : "eject from", rc));
1899 if (!fAttach)
1900 vboxNetFltRelease(pThis, false /* fBusy */);
1901 }
1902
1903 if (fAttach)
1904 strioctl(pIp4VNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
1905
1906 vboxNetFltSolarisRelinkIp4(pUdp4VNode, &Ip4Interface, Ip4MuxFd, ArpMuxFd);
1907 }
1908 else
1909 {
1910 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to %s the IP stack. rc=%d\n",
1911 fAttach ? "inject into" : "eject from", rc));
1912 if (!fAttach)
1913 vboxNetFltRelease(pThis, false /* fBusy */);
1914 }
1915 }
1916 else
1917 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to find position. rc=%d rc2=%d\n", rc, rc2));
1918 }
1919 else
1920 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get vnode from MuxFd.\n"));
1921 }
1922 else
1923 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to unlink upper stream rc=%d rc2=%d.\n", rc, rc2));
1924 }
1925 else
1926 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get MuxFd from MuxId. rc=%d rc2=%d\n"));
1927 }
1928 else
1929 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get Mux Ids. rc=%d\n", rc));
1930 vboxNetFltSolarisCloseDev(pUdp4VNodeHeld, pUdp4User);
1931 }
1932 else
1933 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open UDP. rc=%d\n", rc));
1934 }
1935 else
1936 {
1937 /*
1938 * This would happen for interfaces that are not plumbed.
1939 */
1940 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Warning: seems '%s' is unplumbed.\n", pThis->szName));
1941 rc = VINF_SUCCESS;
1942 }
1943
1944 ldi_close(ArpDevHandle, FREAD | FWRITE, kcred);
1945 ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
1946
1947 if (RT_SUCCESS(rc))
1948 return rc;
1949
1950 return VERR_INTNET_FLT_IF_FAILED;
1951}
1952
1953
1954/**
1955 * Dynamically attach under IPv6 on the host stack.
1956 *
1957 * @returns VBox status code.
1958 * @param pThis The instance.
1959 * @param fAttach Is this an attach or detach.
1960 */
1961static int vboxNetFltSolarisAttachIp6(PVBOXNETFLTINS pThis, bool fAttach)
1962{
1963 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachIp6 pThis=%p fAttach=%d\n", pThis, fAttach));
1964
1965 /*
1966 * Statuatory Warning: Hackish code ahead.
1967 */
1968 char *pszModName = DEVICE_NAME;
1969
1970 struct lifreq Ip6Interface;
1971 bzero(&Ip6Interface, sizeof(Ip6Interface));
1972 Ip6Interface.lifr_addr.ss_family = AF_INET6;
1973 strncpy(Ip6Interface.lifr_name, pThis->szName, sizeof(Ip6Interface.lifr_name));
1974
1975 struct strmodconf StrMod;
1976 StrMod.mod_name = pszModName;
1977 StrMod.pos = -1; /* this is filled in later. */
1978
1979 int rc;
1980 int rc2;
1981 int ret;
1982 ldi_ident_t DeviceIdent = ldi_ident_from_anon();
1983 ldi_handle_t Ip6DevHandle;
1984 ldi_handle_t Udp6DevHandle;
1985
1986 /*
1987 * Open the IPv6 stream as a layered devices.
1988 */
1989 rc = ldi_open_by_name(IP6_DEV_NAME, FREAD | FWRITE, kcred, &Ip6DevHandle, DeviceIdent);
1990 ldi_ident_release(DeviceIdent);
1991 if (rc)
1992 {
1993 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to open the IPv6 stream on '%s'.\n", pThis->szName));
1994 return VERR_INTNET_FLT_IF_FAILED;
1995 }
1996
1997 /*
1998 * Obtain the interface flags from IPv6.
1999 */
2000 rc = vboxNetFltSolarisGetIfFlags(Ip6DevHandle, &Ip6Interface);
2001 if (RT_SUCCESS(rc))
2002 {
2003 /*
2004 * Open the UDP stream. We sort of cheat here and obtain the vnode so that we can perform
2005 * things that are not possible from the layered interface.
2006 */
2007 vnode_t *pUdp6VNode = NULL;
2008 vnode_t *pUdp6VNodeHeld = NULL;
2009 TIUSER *pUdp6User = NULL;
2010 rc = vboxNetFltSolarisOpenDev(UDP6_DEV_NAME, &pUdp6VNode, &pUdp6VNodeHeld, &pUdp6User);
2011 if (RT_SUCCESS(rc))
2012 {
2013 /*
2014 * Get the multiplexor IDs.
2015 */
2016 rc = ldi_ioctl(Ip6DevHandle, SIOCGLIFMUXID, (intptr_t)&Ip6Interface, FKIOCTL, kcred, &ret);
2017 if (!rc)
2018 {
2019 /*
2020 * Get the multiplex file descriptor to the lower streams. Generally this is lost
2021 * once a module is I_PLINK, we need to reobtain it for inserting/removing ourselves from the stack.
2022 */
2023 int Ip6MuxFd;
2024 rc = vboxNetFltSolarisMuxIdToFd(pUdp6VNode, Ip6Interface.lifr_ip_muxid, &Ip6MuxFd);
2025 if (RT_SUCCESS(rc))
2026 {
2027 /*
2028 * We need to I_PUNLINK on these multiplexor IDs before we can start
2029 * operating on the lower stream as insertions are direct operations on the lower stream.
2030 */
2031 int ret;
2032 rc = strioctl(pUdp6VNode, I_PUNLINK, (intptr_t)Ip6Interface.lifr_ip_muxid, 0, K_TO_K, kcred, &ret);
2033 if (!rc)
2034 {
2035 /*
2036 * Obtain the vnode from the useless userland file descriptor.
2037 */
2038 file_t *pIpFile = getf(Ip6MuxFd);
2039 if ( pIpFile
2040 && pIpFile->f_vnode)
2041 {
2042 vnode_t *pIp6VNode = pIpFile->f_vnode;
2043
2044 /*
2045 * Find the position on the host stack for attaching/detaching ourselves.
2046 */
2047 rc = vboxNetFltSolarisDetermineModPos(fAttach, pIp6VNode, &StrMod.pos);
2048 if (RT_SUCCESS(rc))
2049 {
2050 /*
2051 * Set global data which will be grabbed by ModOpen.
2052 * There is a known (though very unlikely) race here because
2053 * of the inability to pass user data while inserting.
2054 */
2055 g_VBoxNetFltSolarisInstance = pThis;
2056 g_VBoxNetFltSolarisStreamType = kIp6Stream;
2057
2058 if (!fAttach)
2059 vboxNetFltRetain(pThis, false /* fBusy */);
2060
2061 /*
2062 * Inject/Eject from the host IPv6 stack.
2063 */
2064 rc = strioctl(pIp6VNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K,
2065 kcred, &ret);
2066 if (!rc)
2067 {
2068 g_VBoxNetFltSolarisInstance = NULL;
2069 g_VBoxNetFltSolarisStreamType = kUndefined;
2070
2071 /*
2072 * Our job's not yet over; we need to relink the upper and lower streams
2073 * otherwise we've pretty much screwed up the host interface.
2074 */
2075 rc = vboxNetFltSolarisRelinkIp6(pUdp6VNode, &Ip6Interface, Ip6MuxFd);
2076 if (RT_SUCCESS(rc))
2077 {
2078 /*
2079 * Close the devices ONLY during the return from function case; otherwise
2080 * we end up close twice which is an instant kernel panic.
2081 */
2082 vboxNetFltSolarisCloseDev(pUdp6VNodeHeld, pUdp6User);
2083 ldi_close(Ip6DevHandle, FREAD | FWRITE, kcred);
2084
2085 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: Success! %s %s@(IPv6:%d) "
2086 "%s interface %s\n", fAttach ? "Injected" : "Ejected", StrMod.mod_name,
2087 StrMod.pos, fAttach ? "to" : "from", pThis->szName));
2088 return VINF_SUCCESS;
2089 }
2090 else
2091 {
2092 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: Relinking failed. Mode=%s rc=%d.\n",
2093 fAttach ? "inject" : "eject", rc));
2094 }
2095
2096 if (fAttach)
2097 strioctl(pIp6VNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
2098
2099 vboxNetFltSolarisRelinkIp6(pUdp6VNode, &Ip6Interface, Ip6MuxFd);
2100 }
2101 else
2102 {
2103 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to %s the IP stack. rc=%d\n",
2104 fAttach ? "inject into" : "eject from", rc));
2105 if (!fAttach)
2106 vboxNetFltRelease(pThis, false /* fBusy */);
2107 }
2108 }
2109 else
2110 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to find position. rc=%d rc2=%d\n", rc, rc2));
2111 }
2112 else
2113 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get vnode from MuxFd.\n"));
2114 }
2115 else
2116 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to unlink upper stream rc=%d rc2=%d.\n", rc, rc2));
2117 }
2118 else
2119 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get MuxFd from MuxId. rc=%d rc2=%d\n"));
2120 }
2121 else
2122 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get Mux Ids. rc=%d\n", rc));
2123 vboxNetFltSolarisCloseDev(pUdp6VNodeHeld, pUdp6User);
2124 }
2125 else
2126 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to open UDP. rc=%d\n", rc));
2127 }
2128 else
2129 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get IPv6 flags.\n", pThis->szName));
2130
2131 ldi_close(Ip6DevHandle, FREAD | FWRITE, kcred);
2132
2133 if (RT_SUCCESS(rc))
2134 return rc;
2135
2136 return VERR_INTNET_FLT_IF_FAILED;
2137}
2138
2139
2140/**
2141 * Wrapper for attaching our module to the specificed stream on the host stack.
2142 * As a side-effect, the streams also gets opened/closed during the actual injection/ejection phase.
2143 *
2144 * @returns VBox status code.
2145 * @param pThis The instance.
2146 * @param fAttach Is this an attach or detach.
2147 * @param StreamType Identifies the host stream the module be inject/ejected.
2148 */
2149static int vboxNetFltSolarisModSetup(PVBOXNETFLTINS pThis, bool fAttach, VBOXNETFLTSTREAMTYPE StreamType)
2150{
2151 LogFlow(("vboxNetFltSolarisModSetup: pThis=%p (%s) fAttach=%s StreamType=%d\n", pThis, pThis->szName,
2152 fAttach ? "true" : "false", StreamType));
2153
2154 switch (StreamType)
2155 {
2156 case kIp4Stream:
2157 case kArpStream:
2158 return vboxNetFltSolarisAttachIp4(pThis, fAttach);
2159
2160 case kIp6Stream:
2161 return vboxNetFltSolarisAttachIp6(pThis, fAttach);
2162
2163 default:
2164 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: Invalid stream type %d\n", StreamType));
2165 return VERR_INTNET_FLT_IF_FAILED;
2166 }
2167}
2168
2169
2170
2171/**
2172 * Wrapper for attaching ourselves to the interface.
2173 *
2174 * @returns VBox status code.
2175 * @param pThis The instance.
2176 * @remarks Owns the globals mutex, so re-requesting it anytime during this phase
2177 * would panic the system e.g. in vboxNetFltSolarisFindInstance).
2178 */
2179static int vboxNetFltSolarisAttachToInterface(PVBOXNETFLTINS pThis)
2180{
2181 int rc = vboxNetFltSolarisOpenStream(pThis);
2182 if (RT_SUCCESS(rc))
2183 {
2184 rc = vboxNetFltSolarisModSetup(pThis, true, kIp4Stream);
2185 if (RT_SUCCESS(rc))
2186 {
2187 vboxNetFltSolarisModSetup(pThis, true, kIp6Stream);
2188 /* Ignore Ipv6 binding errors as it's optional. */
2189
2190 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, false);
2191 }
2192 else
2193 vboxNetFltSolarisCloseStream(pThis);
2194 }
2195 else
2196 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface vboxNetFltSolarisOpenStream failed rc=%Vrc\n", rc));
2197
2198 return rc;
2199}
2200
2201
2202/**
2203 * Wrapper for detaching ourselves from the interface.
2204 *
2205 * @returns VBox status code.
2206 * @param pThis The instance.
2207 * @remarks Owns the globals mutex, so re-requesting it anytime during this phase
2208 * would panic the system (e.g. in vboxNetFltSolarisFindInstance).
2209 */
2210static int vboxNetFltSolarisDetachFromInterface(PVBOXNETFLTINS pThis)
2211{
2212 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetachFromInterface pThis=%p\n", pThis));
2213
2214 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
2215 vboxNetFltSolarisCloseStream(pThis);
2216 int rc = vboxNetFltSolarisModSetup(pThis, false, kIp4Stream);
2217 if (pThis->u.s.pvIp6Stream)
2218 rc = vboxNetFltSolarisModSetup(pThis, false, kIp6Stream);
2219
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 LogFlow((DEVICE_NAME ":vboxNetFltOsDisconnectIt pThis=%p\n", pThis));
3080
3081 vboxNetFltSolarisDetachFromInterface(pThis);
3082
3083 if (pThis->u.s.hFastMtx != NIL_RTSEMFASTMUTEX)
3084 {
3085 RTSemFastMutexDestroy(pThis->u.s.hFastMtx);
3086 pThis->u.s.hFastMtx = NIL_RTSEMFASTMUTEX;
3087 }
3088 return VINF_SUCCESS;
3089}
3090
3091
3092int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
3093{
3094 /* Nothing to do here. */
3095 return VINF_SUCCESS;
3096}
3097
3098
3099void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
3100{
3101 LogFlow((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n", pThis));
3102 /* Nothing to do here. */
3103}
3104
3105
3106int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis)
3107{
3108 LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p\n"));
3109
3110 /*
3111 * Mutex used for loopback lockouts.
3112 */
3113 int rc = RTSemFastMutexCreate(&pThis->u.s.hFastMtx);
3114 if (RT_SUCCESS(rc))
3115 {
3116 rc = vboxNetFltSolarisAttachToInterface(pThis);
3117 if (RT_SUCCESS(rc))
3118 return rc;
3119
3120 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed. rc=%Vrc\n", rc));
3121 RTSemFastMutexDestroy(pThis->u.s.hFastMtx);
3122 pThis->u.s.hFastMtx = NIL_RTSEMFASTMUTEX;
3123 }
3124
3125 return rc;
3126}
3127
3128
3129int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
3130{
3131 /*
3132 * Init. the solaris specific data.
3133 */
3134 pThis->u.s.pvIp4Stream = NULL;
3135 pThis->u.s.pvIp6Stream = NULL;
3136 pThis->u.s.pvArpStream = NULL;
3137 pThis->u.s.pvPromiscStream = NULL;
3138 pThis->u.s.hFastMtx = NIL_RTSEMFASTMUTEX;
3139 bzero(&pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
3140 return VINF_SUCCESS;
3141}
3142
3143
3144bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
3145{
3146 /*
3147 * We don't support interface rediscovery on Solaris hosts because the
3148 * filter is very tightly bound to the stream.
3149 */
3150 return false;
3151}
3152
3153
3154int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
3155{
3156 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p pSG=%p fDst=%d\n", pThis, pSG, fDst));
3157
3158 int rc = VINF_SUCCESS;
3159 if (fDst & INTNETTRUNKDIR_WIRE)
3160 {
3161#ifdef VBOXNETFLT_SOLARIS_USE_NETINFO
3162 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
3163 if (RT_LIKELY(pMsg))
3164 {
3165 netstack_t *pNetStack = netstack_get_current();
3166 if (pNetStack)
3167 {
3168 net_data_t pNetData = net_lookup_impl(NHF_INET, pNetStack);
3169 if (pNetData)
3170 {
3171 phy_if_t pInterface = net_phylookup(pNetData, pThis->szName);
3172 if (pInterface)
3173 {
3174 net_inject_t InjectData;
3175 InjectData.ni_packet = pMsg;
3176 InjectData.ni_physical = pInterface;
3177 bzero(&InjectData.ni_addr, sizeof(InjectData.ni_addr));
3178 InjectData.ni_addr.ss_family = AF_INET;
3179
3180 /*
3181 * Queue out rather than direct out transmission.
3182 */
3183 int rc = net_inject(pNetData, NI_QUEUE_OUT, &InjectData);
3184 if (!rc)
3185 rc = VINF_SUCCESS;
3186 else
3187 {
3188 LogRel((DEVICE_NAME ":queuing IP packet for transmission failed. rc=%d\n", rc));
3189 rc = VERR_NET_IO_ERROR;
3190 }
3191 }
3192 else
3193 {
3194 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit failed to lookup physical interface.\n"));
3195 rc = VERR_NET_IO_ERROR;
3196 }
3197 }
3198 else
3199 {
3200 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit failed to get IP hooks.\n"));
3201 rc = VERR_NET_IO_ERROR;
3202 }
3203 netstack_rele(pNetStack);
3204 }
3205 else
3206 {
3207 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit failed to get current net stack.\n"));
3208 rc = VERR_NET_IO_ERROR;
3209 }
3210 }
3211 else
3212 {
3213 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
3214 rc = VERR_NO_MEMORY;
3215 }
3216#else
3217 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvPromiscStream);
3218 if (RT_LIKELY(pPromiscStream))
3219 {
3220 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
3221 if (RT_LIKELY(pMsg))
3222 {
3223 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_WIRE\n"));
3224
3225 vboxNetFltSolarisQueueLoopback(pThis, pPromiscStream, pMsg);
3226 putnext(WR(pPromiscStream->Stream.pReadQueue), pMsg);
3227 }
3228 else
3229 {
3230 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
3231 rc = VERR_NO_MEMORY;
3232 }
3233 }
3234#endif
3235
3236 }
3237
3238 if (fDst & INTNETTRUNKDIR_HOST)
3239 {
3240 /*
3241 * For unplumbed interfaces we would not be bound to IP or ARP.
3242 * We either bind to both or neither; so atomic reading one should be sufficient.
3243 */
3244 vboxnetflt_stream_t *pIp4Stream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvIp4Stream);
3245 if (!pIp4Stream)
3246 return rc;
3247
3248 /*
3249 * Create a message block and send it up the host stack (upstream).
3250 */
3251 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
3252 if (RT_LIKELY(pMsg))
3253 {
3254 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
3255
3256 /*
3257 * Send message up ARP stream.
3258 */
3259 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
3260 {
3261 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST ARP\n"));
3262
3263 vboxnetflt_stream_t *pArpStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvArpStream);
3264 if (pArpStream)
3265 {
3266 /*
3267 * Construct a DL_UNITDATA_IND style message for ARP as it doesn't understand fast path.
3268 */
3269 mblk_t *pDlpiMsg;
3270 int rc = vboxNetFltSolarisRawToUnitData(pMsg, &pDlpiMsg);
3271 if (RT_SUCCESS(rc))
3272 {
3273 pMsg = pDlpiMsg;
3274
3275 queue_t *pArpReadQueue = pArpStream->pReadQueue;
3276 putnext(pArpReadQueue, pMsg);
3277 }
3278 else
3279 {
3280 LogRel((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData failed!\n"));
3281 freemsg(pMsg);
3282 rc = VERR_NO_MEMORY;
3283 }
3284 }
3285 else
3286 freemsg(pMsg); /* Should really never happen... */
3287 }
3288 else
3289 {
3290 vboxnetflt_stream_t *pIp6Stream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvIp6Stream);
3291 if ( pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6)
3292 && pIp6Stream)
3293 {
3294 /*
3295 * Send messages up IPv6 stream.
3296 */
3297 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST IPv6\n"));
3298
3299 pMsg->b_rptr += sizeof(RTNETETHERHDR);
3300 queue_t *pIp6ReadQueue = pIp6Stream->pReadQueue;
3301 putnext(pIp6ReadQueue, 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 }
3316 else
3317 {
3318 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed.\n"));
3319 rc = VERR_NO_MEMORY;
3320 }
3321 }
3322
3323 return rc;
3324}
3325
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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