VirtualBox

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

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

Solaris/VBoxNetFlt: unused.

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

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