VirtualBox

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

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

Solaris/VBoxNetFlt: cleanup.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 112.7 KB
 
1/* $Id: VBoxNetFlt-solaris.c 13787 2008-11-04 15:22:17Z 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 ourselves to the interface.
2142 *
2143 * @returns VBox status code.
2144 * @param pThis The instance.
2145 * @remarks Owns the globals mutex, so re-requesting it anytime during this phase
2146 * would panic the system e.g. in vboxNetFltSolarisFindInstance).
2147 */
2148static int vboxNetFltSolarisAttachToInterface(PVBOXNETFLTINS pThis)
2149{
2150 int rc = vboxNetFltSolarisOpenStream(pThis);
2151 if (RT_SUCCESS(rc))
2152 {
2153 rc = vboxNetFltSolarisAttachIp4(pThis, true /* fAttach */);
2154 if (RT_SUCCESS(rc))
2155 {
2156 vboxNetFltSolarisAttachIp6(pThis, true /* fAttach */);
2157 /* Ignore Ipv6 binding errors as it's optional. */
2158
2159 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, false);
2160 }
2161 else
2162 vboxNetFltSolarisCloseStream(pThis);
2163 }
2164 else
2165 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface vboxNetFltSolarisOpenStream failed rc=%Vrc\n", rc));
2166
2167 return rc;
2168}
2169
2170
2171/**
2172 * Wrapper for detaching ourselves from 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 vboxNetFltSolarisDetachFromInterface(PVBOXNETFLTINS pThis)
2180{
2181 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetachFromInterface pThis=%p\n", pThis));
2182
2183 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
2184 vboxNetFltSolarisCloseStream(pThis);
2185 int rc = vboxNetFltSolarisAttachIp4(pThis, false /* fAttach */);
2186 if (pThis->u.s.pvIp6Stream)
2187 rc = vboxNetFltSolarisAttachIp6(pThis, false /* fAttach */);
2188
2189 return rc;
2190}
2191
2192
2193/**
2194 * Create a solaris message block from the SG list.
2195 *
2196 * @returns Solaris message block.
2197 * @param pThis The instance.
2198 * @param pSG Pointer to the scatter-gather list.
2199 */
2200static mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
2201{
2202 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG pThis=%p pSG=%p\n"));
2203
2204 mblk_t *pMsg = allocb(pSG->cbTotal, BPRI_MED);
2205 if (RT_UNLIKELY(!pMsg))
2206 {
2207 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed to alloc %d bytes for mblk_t.\n", pSG->cbTotal));
2208 return NULL;
2209 }
2210
2211 /*
2212 * Single buffer copy. Maybe later explore the
2213 * need/possibility for using a mblk_t chain rather.
2214 */
2215 for (unsigned i = 0; i < pSG->cSegsUsed; i++)
2216 {
2217 if (pSG->aSegs[i].pv)
2218 {
2219 bcopy(pSG->aSegs[i].pv, pMsg->b_wptr, pSG->aSegs[i].cb);
2220 pMsg->b_wptr += pSG->aSegs[i].cb;
2221 }
2222 }
2223 DB_TYPE(pMsg) = M_DATA;
2224 return pMsg;
2225}
2226
2227
2228/**
2229 * Calculate the number of segments required for this message block.
2230 *
2231 * @returns Number of segments.
2232 * @param pThis The instance
2233 * @param pMsg Pointer to the data message.
2234 */
2235static unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg)
2236{
2237 unsigned cSegs = 0;
2238 for (mblk_t *pCur = pMsg; pCur; pCur = pCur->b_cont)
2239 if (MBLKL(pCur))
2240 cSegs++;
2241
2242#ifdef PADD_RUNT_FRAMES_FROM_HOST
2243 if (msgdsize(pMsg) < 60)
2244 cSegs++;
2245#endif
2246
2247 NOREF(pThis);
2248 return RT_MAX(cSegs, 1);
2249}
2250
2251
2252/**
2253 * Initializes an SG list from the given message block.
2254 *
2255 * @returns VBox status code.
2256 * @param pThis The instance.
2257 * @param pMsg Pointer to the data message.
2258 The caller must ensure it's not a control message block.
2259 * @param pSG Pointer to the SG.
2260 * @param cSegs Number of segments in the SG.
2261 * This should match the number in the message block exactly!
2262 * @param fSrc The source of the message.
2263 */
2264static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
2265{
2266 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
2267
2268 pSG->pvOwnerData = NULL;
2269 pSG->pvUserData = NULL;
2270 pSG->pvUserData2 = NULL;
2271 pSG->cUsers = 1;
2272 pSG->cbTotal = 0;
2273 pSG->fFlags = INTNETSG_FLAGS_TEMP;
2274 pSG->cSegsAlloc = cSegs;
2275
2276 /*
2277 * Convert the message block to segments.
2278 */
2279 mblk_t *pCur = pMsg;
2280 unsigned iSeg = 0;
2281 while (pCur)
2282 {
2283 size_t cbSeg = MBLKL(pCur);
2284 if (cbSeg)
2285 {
2286 void *pvSeg = pCur->b_rptr;
2287 pSG->aSegs[iSeg].pv = pvSeg;
2288 pSG->aSegs[iSeg].cb = cbSeg;
2289 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
2290 pSG->cbTotal += cbSeg;
2291 iSeg++;
2292 }
2293 pCur = pCur->b_cont;
2294 }
2295 pSG->cSegsUsed = iSeg;
2296
2297#ifdef PADD_RUNT_FRAMES_FROM_HOST
2298 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
2299 {
2300 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pulling up to length.\n"));
2301
2302 static uint8_t const s_abZero[128] = {0};
2303 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
2304 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
2305 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
2306 pSG->cbTotal = 60;
2307 pSG->cSegsUsed++;
2308 }
2309#endif
2310
2311 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
2312 return VINF_SUCCESS;
2313}
2314
2315
2316/**
2317 * Converts raw mode M_DATA messages to M_PROTO DL_UNITDATA_IND format.
2318 *
2319 * @returns VBox status code.
2320 * @param pMsg Pointer to the raw message.
2321 * @param pDlpiMsg Where to store the M_PROTO message.
2322 *
2323 * @remarks The original raw message would be no longer valid and will be
2324 * linked as part of the new DLPI message. Callers must take care
2325 * not to use the raw message if this routine is successful.
2326 */
2327static int vboxNetFltSolarisRawToUnitData(mblk_t *pMsg, mblk_t **ppDlpiMsg)
2328{
2329 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData pMsg=%p\n", pMsg));
2330
2331 if (DB_TYPE(pMsg) != M_DATA)
2332 return VERR_NO_MEMORY;
2333
2334 size_t cbMsg = sizeof(dl_unitdata_ind_t) + 2 * sizeof(vboxnetflt_dladdr_t);
2335 mblk_t *pDlpiMsg = allocb(cbMsg, BPRI_MED);
2336 if (RT_UNLIKELY(!pDlpiMsg))
2337 return VERR_NO_MEMORY;
2338
2339 DB_TYPE(pDlpiMsg) = M_PROTO;
2340 dl_unitdata_ind_t *pDlpiData = (dl_unitdata_ind_t *)pDlpiMsg->b_rptr;
2341 pDlpiData->dl_primitive = DL_UNITDATA_IND;
2342 pDlpiData->dl_dest_addr_length = VBOXNETFLT_DLADDRL;
2343 pDlpiData->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
2344 pDlpiData->dl_src_addr_length = VBOXNETFLT_DLADDRL;
2345 pDlpiData->dl_src_addr_offset = VBOXNETFLT_DLADDRL + sizeof(dl_unitdata_ind_t);
2346
2347 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
2348
2349 vboxnetflt_dladdr_t *pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_dest_addr_offset);
2350 pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
2351 bcopy(&pEthHdr->DstMac, &pDlAddr->Mac, sizeof(RTMAC));
2352
2353 pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_src_addr_offset);
2354 pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
2355 bcopy(&pEthHdr->SrcMac, &pDlAddr->Mac, sizeof(RTMAC));
2356
2357 pDlpiMsg->b_wptr = pDlpiMsg->b_rptr + cbMsg;
2358
2359 /* Make the message point to the protocol header */
2360 pMsg->b_rptr += sizeof(RTNETETHERHDR);
2361
2362 pDlpiMsg->b_cont = pMsg;
2363 *ppDlpiMsg = pDlpiMsg;
2364 return VINF_SUCCESS;
2365}
2366
2367
2368/**
2369 * Converts DLPI M_PROTO messages to the raw mode M_DATA format.
2370 *
2371 * @returns VBox status code.
2372 * @param pMsg Pointer to the M_PROTO message.
2373 * @param ppRawMsg Where to store the converted message.
2374 *
2375 * @remarks If successful, the original pMsg is no longer valid, it will be deleted.
2376 * Callers must take care not to continue to use pMsg after a successful
2377 * call to this conversion routine.
2378 */
2379static int vboxNetFltSolarisUnitDataToRaw(PVBOXNETFLTINS pThis, mblk_t *pMsg, mblk_t **ppRawMsg)
2380{
2381 LogFlow((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw pMsg=%p\n", pMsg));
2382
2383 if ( !pMsg->b_cont
2384 || DB_TYPE(pMsg) != M_PROTO)
2385 {
2386 LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw invalid input message.\n"));
2387 return VERR_NET_PROTOCOL_ERROR;
2388 }
2389
2390 /*
2391 * Upstream consumers send/receive packets in the fast path mode.
2392 * We of course need to convert them into raw ethernet frames.
2393 */
2394 RTNETETHERHDR EthHdr;
2395 union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
2396 switch (pPrim->dl_primitive)
2397 {
2398 case DL_UNITDATA_IND:
2399 {
2400 /*
2401 * Receive side.
2402 */
2403 dl_unitdata_ind_t *pDlpiMsg = (dl_unitdata_ind_t *)pMsg->b_rptr;
2404 bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
2405 bcopy(pMsg->b_rptr + pDlpiMsg->dl_src_addr_offset, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
2406
2407 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
2408 EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
2409
2410 break;
2411 }
2412
2413 case DL_UNITDATA_REQ:
2414 {
2415 /*
2416 * Send side.
2417 */
2418 dl_unitdata_req_t *pDlpiMsg = (dl_unitdata_req_t *)pMsg->b_rptr;
2419
2420 bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
2421 bcopy(&pThis->u.s.Mac, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
2422
2423 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
2424 EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
2425
2426 break;
2427 }
2428
2429 default:
2430 {
2431 LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw Unknown M_PROTO. This shouldn't be happening!!"));
2432 return VERR_NET_PROTOCOL_ERROR;
2433 }
2434 }
2435
2436 /*
2437 * Let us just link it as a mblk_t chain rather than re-copy the entire message.
2438 * The vboxNetFltSolarisMBlkToSG function will handle chained mblk_t's.
2439 */
2440 size_t cbLen = sizeof(EthHdr);
2441 mblk_t *pEtherMsg = allocb(cbLen, BPRI_MED);
2442 if (RT_UNLIKELY(!pEtherMsg))
2443 return VERR_NO_MEMORY;
2444
2445 DB_TYPE(pEtherMsg) = M_DATA;
2446 bcopy(&EthHdr, pEtherMsg->b_wptr, sizeof(EthHdr));
2447 pEtherMsg->b_wptr += cbLen;
2448
2449 pEtherMsg->b_cont = pMsg->b_cont;
2450
2451 /*
2452 * Change the chained blocks to type M_DATA.
2453 */
2454 for (mblk_t *pTmp = pEtherMsg->b_cont; pTmp; pTmp = pTmp->b_cont)
2455 DB_TYPE(pTmp) = M_DATA;
2456
2457 pMsg->b_cont = NULL;
2458 freemsg(pMsg);
2459
2460 *ppRawMsg = pEtherMsg;
2461 return VINF_SUCCESS;
2462}
2463
2464
2465/**
2466 * Initializes a packet identifier.
2467 *
2468 * @param pTag Pointer to the packed identifier.
2469 * @param pMsg Pointer to the message to be identified.
2470 *
2471 * @remarks Warning!!! This function assumes 'pMsg' is an unchained message.
2472 */
2473static inline void vboxNetFltSolarisInitPacketId(PVBOXNETFLTPACKETID pTag, mblk_t *pMsg)
2474{
2475 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
2476 size_t cbMsg = MBLKL(pMsg);
2477
2478 pTag->cbPacket = cbMsg;
2479 pTag->Checksum = RTCrc32(pMsg->b_rptr, cbMsg);
2480 bcopy(&pEthHdr->SrcMac, &pTag->SrcMac, sizeof(RTMAC));
2481 bcopy(&pEthHdr->DstMac, &pTag->DstMac, sizeof(RTMAC));
2482}
2483
2484
2485/**
2486 * Queues a packet for loopback elimination.
2487 *
2488 * @returns VBox status code.
2489 * @param pThis The instance.
2490 * @param pPromiscStream Pointer to the promiscuous stream.
2491 * @param pMsg Pointer to the message.
2492 * @remarks Warning!! Assumes caller has taken care of any locking necessary.
2493 */
2494static int vboxNetFltSolarisQueueLoopback(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg)
2495{
2496 Assert(pThis);
2497 Assert(pMsg);
2498 Assert(DB_TYPE(pMsg) == M_DATA);
2499 Assert(pPromiscStream);
2500
2501 LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback pThis=%p pPromiscStream=%p pMsg=%p\n", pThis, pPromiscStream, pMsg));
2502
2503 if (RT_UNLIKELY(pMsg->b_cont))
2504 {
2505 /*
2506 * We don't currently make chained messages in on Xmit
2507 * so this only needs to be supported when we do that.
2508 */
2509 return VERR_NOT_SUPPORTED;
2510 }
2511
2512 size_t cbMsg = MBLKL(pMsg);
2513 if (RT_UNLIKELY(cbMsg < sizeof(RTNETETHERHDR)))
2514 return VERR_NET_MSG_SIZE;
2515
2516 int rc = RTSemFastMutexRequest(pThis->u.s.hFastMtx);
2517 AssertRCReturn(rc, rc);
2518
2519 PVBOXNETFLTPACKETID pCur = NULL;
2520 if (pPromiscStream->cLoopback < VBOXNETFLT_LOOPBACK_SIZE
2521 || ( pPromiscStream->pHead
2522 && pPromiscStream->pHead->cbPacket == 0))
2523 {
2524 do
2525 {
2526 if (!pPromiscStream->pHead)
2527 {
2528 pCur = RTMemAlloc(sizeof(VBOXNETFLTPACKETID));
2529 if (RT_UNLIKELY(!pCur))
2530 {
2531 rc = VERR_NO_MEMORY;
2532 break;
2533 }
2534
2535 vboxNetFltSolarisInitPacketId(pCur, pMsg);
2536
2537 pCur->pNext = NULL;
2538 pPromiscStream->pHead = pCur;
2539 pPromiscStream->pTail = pCur;
2540 pPromiscStream->cLoopback++;
2541
2542 LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback initialized head. checksum=%u.\n",
2543 pPromiscStream->pHead->Checksum));
2544 break;
2545 }
2546 else if ( pPromiscStream->pHead
2547 && pPromiscStream->pHead->cbPacket == 0)
2548 {
2549 pCur = pPromiscStream->pHead;
2550 vboxNetFltSolarisInitPacketId(pCur, pMsg);
2551
2552 LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback re-used head checksum=%u cLoopback=%d.\n",
2553 pCur->Checksum, pPromiscStream->cLoopback));
2554 break;
2555 }
2556 else
2557 {
2558 pCur = RTMemAlloc(sizeof(VBOXNETFLTPACKETID));
2559 if (RT_UNLIKELY(!pCur))
2560 {
2561 rc = VERR_NO_MEMORY;
2562 break;
2563 }
2564
2565 vboxNetFltSolarisInitPacketId(pCur, pMsg);
2566
2567 pCur->pNext = pPromiscStream->pHead;
2568 pPromiscStream->pHead = pCur;
2569 pPromiscStream->cLoopback++;
2570
2571 LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback added head checksum=%u cLoopback=%d.\n", pCur->Checksum,
2572 pPromiscStream->cLoopback));
2573 break;
2574 }
2575 } while (0);
2576 }
2577 else
2578 {
2579 /*
2580 * Maximum loopback queue size reached. Re-use tail as head.
2581 */
2582 Assert(pPromiscStream->pHead);
2583 Assert(pPromiscStream->pTail);
2584
2585 /*
2586 * Find tail's previous item.
2587 */
2588 PVBOXNETFLTPACKETID pPrev = NULL;
2589 pCur = pPromiscStream->pHead;
2590
2591 /** @todo consider if this is worth switching to a double linked list... */
2592 while (pCur != pPromiscStream->pTail)
2593 {
2594 pPrev = pCur;
2595 pCur = pCur->pNext;
2596 }
2597
2598 pPromiscStream->pTail = pPrev;
2599 pPromiscStream->pTail->pNext = NULL;
2600 pCur->pNext = pPromiscStream->pHead;
2601 pPromiscStream->pHead = pCur;
2602
2603 vboxNetFltSolarisInitPacketId(pCur, pMsg);
2604 LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback recycled tail!! checksum=%u cLoopback=%d\n", pCur->Checksum,
2605 pPromiscStream->cLoopback));
2606 }
2607
2608 RTSemFastMutexRelease(pThis->u.s.hFastMtx);
2609
2610 return rc;
2611}
2612
2613
2614/**
2615 * Checks if the packet is enqueued for loopback as our own packet.
2616 *
2617 * @returns If it's our packet, returns true after dequeuing it, otherwise false.
2618 * @param pThis The instance.
2619 * @param pPromiscStream Pointer to the promiscuous stream.
2620 * @param pMsg Pointer to the message.
2621 */
2622static bool vboxNetFltSolarisIsOurMBlk(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg)
2623{
2624 Assert(pThis);
2625 Assert(pPromiscStream);
2626 Assert(pMsg);
2627 Assert(DB_TYPE(pMsg) == M_DATA);
2628
2629 LogFlow((DEVICE_NAME ":vboxNetFltSolarisIsOurMBlk pThis=%p pMsg=%p\n", pThis, pMsg));
2630
2631 if (pMsg->b_cont)
2632 {
2633 /** Handle this when Xmit makes chained messages */
2634 return false;
2635 }
2636
2637 size_t cbMsg = MBLKL(pMsg);
2638 if (cbMsg < sizeof(RTNETETHERHDR))
2639 return false;
2640
2641 int rc = RTSemFastMutexRequest(pThis->u.s.hFastMtx);
2642 AssertRCReturn(rc, rc);
2643
2644 PVBOXNETFLTPACKETID pPrev = NULL;
2645 PVBOXNETFLTPACKETID pCur = pPromiscStream->pHead;
2646 bool fIsOurPacket = false;
2647 while (pCur)
2648 {
2649 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
2650 if ( pCur->cbPacket != cbMsg
2651 || pCur->SrcMac.au8[0] != pEthHdr->SrcMac.au8[0]
2652 || pCur->SrcMac.au8[1] != pEthHdr->SrcMac.au8[1]
2653 || pCur->SrcMac.au8[2] != pEthHdr->SrcMac.au8[2]
2654 || pCur->SrcMac.au8[3] != pEthHdr->SrcMac.au8[3]
2655 || pCur->SrcMac.au8[4] != pEthHdr->SrcMac.au8[4]
2656 || pCur->SrcMac.au8[5] != pEthHdr->SrcMac.au8[5]
2657 || pCur->DstMac.au8[0] != pEthHdr->DstMac.au8[0]
2658 || pCur->DstMac.au8[1] != pEthHdr->DstMac.au8[1]
2659 || pCur->DstMac.au8[2] != pEthHdr->DstMac.au8[2]
2660 || pCur->DstMac.au8[3] != pEthHdr->DstMac.au8[3]
2661 || pCur->DstMac.au8[4] != pEthHdr->DstMac.au8[4]
2662 || pCur->DstMac.au8[5] != pEthHdr->DstMac.au8[5])
2663 {
2664 pPrev = pCur;
2665 pCur = pCur->pNext;
2666 continue;
2667 }
2668
2669 uint16_t Checksum = RTCrc32(pMsg->b_rptr, cbMsg);
2670 if (pCur->Checksum != Checksum)
2671 {
2672 pPrev = pCur;
2673 pCur = pCur->pNext;
2674 continue;
2675 }
2676
2677 /*
2678 * Yes, it really is our own packet, mark it as handled
2679 * and move it as a "free slot" to the head and return success.
2680 */
2681 pCur->cbPacket = 0;
2682 if (pPrev)
2683 {
2684 if (!pCur->pNext)
2685 pPromiscStream->pTail = pPrev;
2686
2687 pPrev->pNext = pCur->pNext;
2688 pCur->pNext = pPromiscStream->pHead;
2689 pPromiscStream->pHead = pCur;
2690 }
2691 fIsOurPacket = true;
2692
2693 LogFlow((DEVICE_NAME ":vboxNetFltSolarisIsOurMBlk found packet %p Checksum=%u cLoopback=%d\n", pMsg, Checksum,
2694 pPromiscStream->cLoopback));
2695 break;
2696 }
2697
2698 RTSemFastMutexRelease(pThis->u.s.hFastMtx);
2699 return fIsOurPacket;
2700}
2701
2702
2703/**
2704 * Worker for routing messages from the wire or from the host.
2705 *
2706 * @returns VBox status code.
2707 * @param pThis The instance.
2708 * @param pStream Pointer to the stream.
2709 * @param pQueue Pointer to the queue.
2710 * @param pOrigMsg Pointer to the message.
2711 */
2712static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pMsg)
2713{
2714 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRecv pThis=%p pMsg=%p\n", pThis, pMsg));
2715
2716 AssertCompile(sizeof(struct ether_header) == sizeof(RTNETETHERHDR));
2717 Assert(pStream->Type == kPromiscStream);
2718
2719 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvPromiscStream);
2720 if (RT_UNLIKELY(!pPromiscStream))
2721 {
2722 freemsg(pMsg);
2723 LogRel((DEVICE_NAME ":Promiscuous stream missing!! Failing to receive packet.\n"));
2724 return VERR_INVALID_POINTER;
2725 }
2726
2727 /*
2728 * Don't loopback packets we transmit to the wire.
2729 */
2730 /** @todo maybe we need not check for loopback for INTNETTRUNKDIR_HOST case? */
2731 if (vboxNetFltSolarisIsOurMBlk(pThis, pPromiscStream, pMsg))
2732 {
2733 LogFlow((DEVICE_NAME ":Avoiding packet loopback.\n"));
2734 freemsg(pMsg);
2735 return VINF_SUCCESS;
2736 }
2737
2738 /*
2739 * Figure out the source of the packet based on the source Mac address.
2740 */
2741 uint32_t fSrc = INTNETTRUNKDIR_WIRE;
2742 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
2743 if (vboxNetFltPortOsIsHostMac(pThis, &pEthHdr->SrcMac))
2744 fSrc = INTNETTRUNKDIR_HOST;
2745
2746 /*
2747 * Afaik; we no longer need to worry about incorrect checksums because we now use
2748 * a dedicated stream and don't intercept packets under IP/ARP which might be doing
2749 * checksum offloading.
2750 */
2751#if 0
2752 if (fSrc & INTNETTRUNKDIR_HOST)
2753 {
2754 mblk_t *pCorrectedMsg = vboxNetFltSolarisFixChecksums(pMsg);
2755 if (pCorrectedMsg)
2756 pMsg = pCorrectedMsg;
2757 }
2758 vboxNetFltSolarisAnalyzeMBlk(pMsg);
2759#endif
2760
2761 /*
2762 * Route all received packets into the internal network.
2763 */
2764 unsigned cSegs = vboxNetFltSolarisMBlkCalcSGSegs(pThis, pMsg);
2765 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
2766 int rc = vboxNetFltSolarisMBlkToSG(pThis, pMsg, pSG, cSegs, fSrc);
2767 if (RT_SUCCESS(rc))
2768 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc);
2769 else
2770 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG failed. rc=%d\n", rc));
2771
2772 freemsg(pMsg);
2773 return VINF_SUCCESS;
2774}
2775
2776
2777/**
2778 * Find the PVBOXNETFLTINS associated with a stream.
2779 *
2780 * @returns PVBOXNETFLTINS instance, or NULL if there's none.
2781 * @param pStream Pointer to the stream to search for.
2782 */
2783static PVBOXNETFLTINS vboxNetFltSolarisFindInstance(vboxnetflt_stream_t *pStream)
2784{
2785 if (!pStream)
2786 return NULL;
2787
2788 vboxnetflt_stream_t *pCur = g_VBoxNetFltSolarisStreams;
2789 for (; pCur; pCur = pCur->pNext)
2790 if (pCur == pStream)
2791 return pCur->pThis;
2792
2793 return NULL;
2794}
2795
2796
2797/**
2798 * Finalize the message to be fed into the internal network.
2799 * Verifies and tries to fix checksums for TCP, UDP and IP.
2800 *
2801 * @returns Corrected message or NULL if no change was required.
2802 * @param pMsg Pointer to the message block.
2803 * This must not be DLPI linked messages, must be M_DATA.
2804 *
2805 * @remarks If this function returns a checksum adjusted message, the
2806 * passed in input message has been freed and should not be
2807 * referenced anymore by the caller.
2808 */
2809static mblk_t *vboxNetFltSolarisFixChecksums(mblk_t *pMsg)
2810{
2811 LogFlow((DEVICE_NAME ":vboxNetFltSolarisFixChecksums pMsg=%p\n"));
2812
2813 Assert(DB_TYPE(pMsg) == M_DATA);
2814
2815 if (MBLKL(pMsg) < sizeof(RTNETETHERHDR))
2816 {
2817 LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums Packet shorter than ethernet header size!\n"));
2818 return NULL;
2819 }
2820
2821 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
2822 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
2823 {
2824 /*
2825 * Check if we have a complete packet or being fed a chain.
2826 */
2827 size_t cbIpPacket = 0;
2828 mblk_t *pFullMsg = NULL;
2829 if (pMsg->b_cont)
2830 {
2831 LogFlow((DEVICE_NAME ":Chained mblk_t.\n"));
2832
2833 /*
2834 * Handle chain by making a packet copy to verify if the IP checksum is correct.
2835 * Contributions to calculating IP checksums from a chained message block with
2836 * odd/non-pulled up sizes are welcome.
2837 */
2838 size_t cbFullMsg = msgdsize(pMsg);
2839 mblk_t *pFullMsg = allocb(cbFullMsg, BPRI_MED);
2840 LogFlow((DEVICE_NAME ":msgdsize returns %d\n", cbFullMsg));
2841 if (RT_UNLIKELY(!pFullMsg))
2842 {
2843 LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums failed to alloc new message of %d bytes.\n", cbFullMsg));
2844 return NULL;
2845 }
2846
2847 for (mblk_t *pTmp = pMsg; pTmp; pTmp = pTmp->b_cont)
2848 {
2849 if (DB_TYPE(pTmp) == M_DATA)
2850 {
2851 bcopy(pTmp->b_rptr, pFullMsg->b_wptr, MBLKL(pTmp));
2852 pFullMsg->b_wptr += MBLKL(pTmp);
2853 }
2854 }
2855
2856 DB_TYPE(pFullMsg) = M_DATA;
2857 pEthHdr = (PRTNETETHERHDR)pFullMsg->b_rptr;
2858 cbIpPacket = MBLKL(pFullMsg) - sizeof(RTNETETHERHDR);
2859 }
2860 else
2861 cbIpPacket = MBLKL(pMsg) - sizeof(RTNETETHERHDR);
2862
2863 /*
2864 * Check if the IP checksum is valid.
2865 */
2866 uint8_t *pbProtocol = (uint8_t *)(pEthHdr + 1);
2867 PRTNETIPV4 pIpHdr = (PRTNETIPV4)pbProtocol;
2868 size_t cbPayload = cbIpPacket - (pIpHdr->ip_hl << 2);
2869 bool fChecksumAdjusted = false;
2870 if (RTNetIPv4IsHdrValid(pIpHdr, cbPayload, cbPayload))
2871 {
2872 pbProtocol += (pIpHdr->ip_hl << 2);
2873
2874 /*
2875 * Fix up TCP/UDP and IP checksums if they're incomplete/invalid.
2876 */
2877 if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
2878 {
2879 PRTNETTCP pTcpHdr = (PRTNETTCP)pbProtocol;
2880 uint16_t TcpChecksum = RTNetIPv4TCPChecksum(pIpHdr, pTcpHdr, NULL);
2881 if (pTcpHdr->th_sum != TcpChecksum)
2882 {
2883 pTcpHdr->th_sum = TcpChecksum;
2884 fChecksumAdjusted = true;
2885 LogFlow((DEVICE_NAME ":fixed TCP checksum.\n"));
2886 }
2887 }
2888 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
2889 {
2890 PRTNETUDP pUdpHdr = (PRTNETUDP)pbProtocol;
2891 uint16_t UdpChecksum = RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1);
2892
2893 if (pUdpHdr->uh_sum != UdpChecksum)
2894 {
2895 pUdpHdr->uh_sum = UdpChecksum;
2896 fChecksumAdjusted = true;
2897 LogFlow((DEVICE_NAME ":Fixed UDP checksum."));
2898 }
2899 }
2900 }
2901
2902 if (fChecksumAdjusted)
2903 {
2904 /*
2905 * If we made a copy and the checksum is corrected on the copy,
2906 * free the original, return the checksum fixed copy.
2907 */
2908 if (pFullMsg)
2909 {
2910 freemsg(pMsg);
2911 return pFullMsg;
2912 }
2913
2914 return pMsg;
2915 }
2916
2917 /*
2918 * If we made a copy and the checksum is NOT corrected, free the copy,
2919 * and return NULL.
2920 */
2921 if (pFullMsg)
2922 freemsg(pFullMsg);
2923
2924 return NULL;
2925 }
2926
2927 return NULL;
2928}
2929
2930
2931/**
2932 * Simple packet dump, used for internal debugging.
2933 *
2934 * @param pMsg Pointer to the message to analyze and dump.
2935 */
2936static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg)
2937{
2938 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAnalyzeMBlk pMsg=%p\n", pMsg));
2939
2940 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
2941 uint8_t *pb = pMsg->b_rptr;
2942 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
2943 {
2944 PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
2945 size_t cbLen = MBLKL(pMsg) - sizeof(*pEthHdr);
2946 if (!pMsg->b_cont)
2947 {
2948 if (pIpHdr->ip_p == RTNETIPV4_PROT_ICMP)
2949 LogFlow((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
2950 else if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
2951 LogFlow((DEVICE_NAME ":TCP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
2952 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
2953 {
2954 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint32_t *)pIpHdr + pIpHdr->ip_hl);
2955 if ( RT_BE2H_U16(pUdpHdr->uh_sport) == 67
2956 && RT_BE2H_U16(pUdpHdr->uh_dport) == 68)
2957 {
2958 LogRel((DEVICE_NAME ":UDP bootp ack D=%.6Rhxs S=%.6Rhxs UDP_CheckSum=%04x Computex=%04x\n", pb, pb + 6,
2959 RT_BE2H_U16(pUdpHdr->uh_sum), RT_BE2H_U16(RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1))));
2960 }
2961 }
2962 }
2963 else
2964 {
2965 LogFlow((DEVICE_NAME ":Chained IP packet. Skipping validity check.\n"));
2966 }
2967 }
2968 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
2969 {
2970 PRTNETARPHDR pArpHdr = (PRTNETARPHDR)(pEthHdr + 1);
2971 LogFlow((DEVICE_NAME ":ARP Op=%d\n", pArpHdr->ar_oper));
2972 }
2973 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
2974 {
2975 LogFlow((DEVICE_NAME ":IPv6 D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
2976 }
2977 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_1)
2978 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_2)
2979 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_3))
2980 {
2981 LogFlow((DEVICE_NAME ":IPX packet.\n"));
2982 }
2983 else
2984 {
2985 LogFlow((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
2986 &pEthHdr->SrcMac));
2987 /* LogFlow((DEVICE_NAME ":%.*Vhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
2988 }
2989}
2990
2991
2992/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
2993bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
2994{
2995 /*
2996 * There is no easy way of obtaining the global host side promiscuous counter.
2997 * Currently we just return false.
2998 */
2999 return false;
3000}
3001
3002
3003void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
3004{
3005 LogFlow((DEVICE_NAME ":vboxNetFltPortOsGetMacAddress pThis=%p\n", pThis));
3006 *pMac = pThis->u.s.Mac;
3007}
3008
3009
3010bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
3011{
3012 /*
3013 * MAC address change acknowledgements are intercepted on the read side
3014 * hence theoritically we are always update to date with any changes.
3015 */
3016 return pThis->u.s.Mac.au16[0] == pMac->au16[0]
3017 && pThis->u.s.Mac.au16[1] == pMac->au16[1]
3018 && pThis->u.s.Mac.au16[2] == pMac->au16[2];
3019}
3020
3021
3022void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
3023{
3024 LogFlow((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d\n", pThis, fActive));
3025
3026 /*
3027 * Enable/disable promiscuous mode.
3028 */
3029 vboxnetflt_stream_t *pStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvPromiscStream);
3030 if (pStream)
3031 {
3032 if (pStream->pReadQueue)
3033 {
3034 int rc = vboxNetFltSolarisPromiscReq(pStream->pReadQueue, fActive);
3035 if (RT_FAILURE(rc))
3036 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive failed to request promiscuous mode! rc=%d\n", rc));
3037 }
3038 else
3039 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive queue not found!\n"));
3040 }
3041 else
3042 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive stream not found!\n"));
3043}
3044
3045
3046int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
3047{
3048 LogFlow((DEVICE_NAME ":vboxNetFltOsDisconnectIt pThis=%p\n", pThis));
3049
3050 vboxNetFltSolarisDetachFromInterface(pThis);
3051
3052 if (pThis->u.s.hFastMtx != NIL_RTSEMFASTMUTEX)
3053 {
3054 RTSemFastMutexDestroy(pThis->u.s.hFastMtx);
3055 pThis->u.s.hFastMtx = NIL_RTSEMFASTMUTEX;
3056 }
3057 return VINF_SUCCESS;
3058}
3059
3060
3061int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
3062{
3063 /* Nothing to do here. */
3064 return VINF_SUCCESS;
3065}
3066
3067
3068void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
3069{
3070 LogFlow((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n", pThis));
3071 /* Nothing to do here. */
3072}
3073
3074
3075int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis)
3076{
3077 LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p\n"));
3078
3079 /*
3080 * Mutex used for loopback lockouts.
3081 */
3082 int rc = RTSemFastMutexCreate(&pThis->u.s.hFastMtx);
3083 if (RT_SUCCESS(rc))
3084 {
3085 rc = vboxNetFltSolarisAttachToInterface(pThis);
3086 if (RT_SUCCESS(rc))
3087 return rc;
3088
3089 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed. rc=%Vrc\n", rc));
3090 RTSemFastMutexDestroy(pThis->u.s.hFastMtx);
3091 pThis->u.s.hFastMtx = NIL_RTSEMFASTMUTEX;
3092 }
3093
3094 return rc;
3095}
3096
3097
3098int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
3099{
3100 /*
3101 * Init. the solaris specific data.
3102 */
3103 pThis->u.s.pvIp4Stream = NULL;
3104 pThis->u.s.pvIp6Stream = NULL;
3105 pThis->u.s.pvArpStream = NULL;
3106 pThis->u.s.pvPromiscStream = NULL;
3107 pThis->u.s.hFastMtx = NIL_RTSEMFASTMUTEX;
3108 bzero(&pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
3109 return VINF_SUCCESS;
3110}
3111
3112
3113bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
3114{
3115 /*
3116 * We don't support interface rediscovery on Solaris hosts because the
3117 * filter is very tightly bound to the stream.
3118 */
3119 return false;
3120}
3121
3122
3123int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
3124{
3125 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p pSG=%p fDst=%d\n", pThis, pSG, fDst));
3126
3127 int rc = VINF_SUCCESS;
3128 if (fDst & INTNETTRUNKDIR_WIRE)
3129 {
3130#ifdef VBOXNETFLT_SOLARIS_USE_NETINFO
3131 /*
3132 * @todo try find a way for IPFilter to accept ethernet frames (currently silently drops them).
3133 */
3134 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
3135 if (RT_LIKELY(pMsg))
3136 {
3137 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
3138 unsigned uProtocol;
3139 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
3140 uProtocol = AF_INET6;
3141 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
3142 uProtocol = AF_INET;
3143
3144 /*
3145 * Queue out using netinfo.
3146 */
3147 netstack_t *pNetStack = netstack_get_current();
3148 if (pNetStack)
3149 {
3150 net_data_t pNetData = net_lookup_impl(NHF_INET, pNetStack);
3151 if (pNetData)
3152 {
3153 phy_if_t pInterface = net_phylookup(pNetData, pThis->szName);
3154 if (pInterface)
3155 {
3156 net_inject_t InjectData;
3157 InjectData.ni_packet = pMsg;
3158 InjectData.ni_physical = pInterface;
3159 bzero(&InjectData.ni_addr, sizeof(InjectData.ni_addr));
3160 InjectData.ni_addr.ss_family = uProtocol;
3161
3162 /*
3163 * Queue out rather than direct out transmission.
3164 */
3165 int rc = net_inject(pNetData, NI_QUEUE_OUT, &InjectData);
3166 if (!rc)
3167 rc = VINF_SUCCESS;
3168 else
3169 {
3170 LogRel((DEVICE_NAME ":queuing IP packet for transmission failed. rc=%d\n", rc));
3171 rc = VERR_NET_IO_ERROR;
3172 }
3173 }
3174 else
3175 {
3176 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit failed to lookup physical interface.\n"));
3177 rc = VERR_NET_IO_ERROR;
3178 }
3179 }
3180 else
3181 {
3182 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit failed to get IP hooks.\n"));
3183 rc = VERR_NET_IO_ERROR;
3184 }
3185 netstack_rele(pNetStack);
3186 }
3187 else
3188 {
3189 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit failed to get current net stack.\n"));
3190 rc = VERR_NET_IO_ERROR;
3191 }
3192 }
3193 else
3194 {
3195 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
3196 rc = VERR_NO_MEMORY;
3197 }
3198#else
3199 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvPromiscStream);
3200 if (RT_LIKELY(pPromiscStream))
3201 {
3202 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
3203 if (RT_LIKELY(pMsg))
3204 {
3205 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_WIRE\n"));
3206
3207 vboxNetFltSolarisQueueLoopback(pThis, pPromiscStream, pMsg);
3208 putnext(WR(pPromiscStream->Stream.pReadQueue), pMsg);
3209 }
3210 else
3211 {
3212 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
3213 rc = VERR_NO_MEMORY;
3214 }
3215 }
3216#endif
3217 }
3218
3219 if (fDst & INTNETTRUNKDIR_HOST)
3220 {
3221 /*
3222 * For unplumbed interfaces we would not be bound to IP or ARP.
3223 * We either bind to both or neither; so atomic reading one should be sufficient.
3224 */
3225 vboxnetflt_stream_t *pIp4Stream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvIp4Stream);
3226 if (!pIp4Stream)
3227 return rc;
3228
3229 /*
3230 * Create a message block and send it up the host stack (upstream).
3231 */
3232 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
3233 if (RT_LIKELY(pMsg))
3234 {
3235 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
3236
3237 /*
3238 * Send message up ARP stream.
3239 */
3240 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
3241 {
3242 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST ARP\n"));
3243
3244 vboxnetflt_stream_t *pArpStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvArpStream);
3245 if (pArpStream)
3246 {
3247 /*
3248 * Construct a DL_UNITDATA_IND style message for ARP as it doesn't understand fast path.
3249 */
3250 mblk_t *pDlpiMsg;
3251 int rc = vboxNetFltSolarisRawToUnitData(pMsg, &pDlpiMsg);
3252 if (RT_SUCCESS(rc))
3253 {
3254 pMsg = pDlpiMsg;
3255
3256 queue_t *pArpReadQueue = pArpStream->pReadQueue;
3257 putnext(pArpReadQueue, pMsg);
3258 }
3259 else
3260 {
3261 LogRel((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData failed!\n"));
3262 freemsg(pMsg);
3263 rc = VERR_NO_MEMORY;
3264 }
3265 }
3266 else
3267 freemsg(pMsg); /* Should really never happen... */
3268 }
3269 else
3270 {
3271 vboxnetflt_stream_t *pIp6Stream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvIp6Stream);
3272 if ( pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6)
3273 && pIp6Stream)
3274 {
3275 /*
3276 * Send messages up IPv6 stream.
3277 */
3278 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST IPv6\n"));
3279
3280 pMsg->b_rptr += sizeof(RTNETETHERHDR);
3281 queue_t *pIp6ReadQueue = pIp6Stream->pReadQueue;
3282 putnext(pIp6ReadQueue, pMsg);
3283 }
3284 else
3285 {
3286 /*
3287 * Send messages up IPv4 stream.
3288 */
3289 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST IPv4\n"));
3290
3291 pMsg->b_rptr += sizeof(RTNETETHERHDR);
3292 queue_t *pIp4ReadQueue = pIp4Stream->pReadQueue;
3293 putnext(pIp4ReadQueue, pMsg);
3294 }
3295 }
3296 }
3297 else
3298 {
3299 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed.\n"));
3300 rc = VERR_NO_MEMORY;
3301 }
3302 }
3303
3304 return rc;
3305}
3306
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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