VirtualBox

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

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

Solaris/vboxnetflt: retain instance on recv and writes. Plus other bits.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 86.8 KB
 
1/* $Id: VBoxNetFlt-solaris.c 12531 2008-09-17 09:24:05Z 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 <iprt/string.h>
24#include <iprt/initterm.h>
25#include <iprt/assert.h>
26#include <iprt/alloca.h>
27#include <iprt/net.h>
28#include <iprt/mem.h>
29#include <iprt/thread.h>
30#include <iprt/spinlock.h>
31
32#include <inet/ip.h>
33#include <net/if.h>
34#include <sys/socket.h>
35#include <sys/kstr.h>
36#include <sys/file.h>
37#include <sys/sockio.h>
38#include <sys/strsubr.h>
39#include <sys/pathname.h>
40#include <sys/t_kuser.h>
41
42#include <sys/types.h>
43#include <sys/dlpi.h>
44#include <sys/types.h>
45#include <sys/param.h>
46#include <sys/ethernet.h>
47#include <sys/stat.h>
48#include <sys/stream.h>
49#include <sys/stropts.h>
50#include <sys/strsun.h>
51#include <sys/modctl.h>
52#include <sys/ddi.h>
53#include <sys/sunddi.h>
54#include <sys/sunldi.h>
55
56// Workaround for very strange define in sys/user.h
57// #define u (curproc->p_user) /* user is now part of proc structure */
58#ifdef u
59#undef u
60#endif
61
62#define VBOXNETFLT_OS_SPECFIC 1
63#include "../VBoxNetFltInternal.h"
64
65/*******************************************************************************
66* Defined Constants And Macros *
67*******************************************************************************/
68/** The module name. */
69#define DEVICE_NAME "vboxflt"
70/** The module descriptions as seen in 'modinfo'. */
71#define DEVICE_DESC_DRV "VirtualBox NetFilter Driver"
72#define DEVICE_DESC_MOD "VirtualBox NetFilter Module"
73
74/** @todo Remove the below hackery once done! */
75#if defined(DEBUG_ramshankar) && defined(LOG_ENABLED)
76# undef Log
77# define Log LogRel
78# undef LogFlow
79# define LogFlow LogRel
80#endif
81
82/** Dynamic module binding specific oddities. */
83#define VBOXNETFLT_IFNAME_LEN LIFNAMSIZ + 1
84
85
86/*******************************************************************************
87* Global Functions *
88*******************************************************************************/
89/**
90 * Stream Driver hooks.
91 */
92static int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
93static int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
94static int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
95
96/**
97 * Stream Module hooks.
98 */
99static int VBoxNetFltSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fFile, int fStream, cred_t *pCred);
100static int VBoxNetFltSolarisModClose(queue_t *pQueue, int fFile, cred_t *pCred);
101static int VBoxNetFltSolarisModReadPut(queue_t *pQueue, mblk_t *pMsg);
102static int VBoxNetFltSolarisModWritePut(queue_t *pQueue, mblk_t *pMsg);
103static int VBoxNetFltSolarisModWriteService(queue_t *pQueue);
104
105/**
106 * OS specific hooks invoked from common VBoxNetFlt ring-0.
107 */
108bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis);
109void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac);
110bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac);
111void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive);
112int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis);
113int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis);
114void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis);
115int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis);
116int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis);
117
118
119/*******************************************************************************
120* Structures and Typedefs *
121*******************************************************************************/
122/**
123 * Streams: module info.
124 */
125static struct module_info g_VBoxNetFltSolarisModInfo =
126{
127 0xbad, /* module id */
128 DEVICE_NAME,
129 0, /* min. packet size */
130 INFPSZ, /* max. packet size */
131 0, /* hi-water mask */
132 0 /* lo-water mask */
133};
134
135/**
136 * Streams: read queue hooks.
137 */
138static struct qinit g_VBoxNetFltSolarisReadQ =
139{
140 VBoxNetFltSolarisModReadPut,
141 NULL, /* service */
142 VBoxNetFltSolarisModOpen,
143 VBoxNetFltSolarisModClose,
144 NULL, /* admin (reserved) */
145 &g_VBoxNetFltSolarisModInfo,
146 NULL /* module stats */
147};
148
149/**
150 * Streams: write queue hooks.
151 */
152static struct qinit g_VBoxNetFltSolarisWriteQ =
153{
154 VBoxNetFltSolarisModWritePut,
155 VBoxNetFltSolarisModWriteService,
156 NULL, /* open */
157 NULL, /* close */
158 NULL, /* admin (reserved) */
159 &g_VBoxNetFltSolarisModInfo,
160 NULL /* module stats */
161};
162
163/**
164 * Streams: IO stream tab.
165 */
166static struct streamtab g_VBoxNetFltSolarisStreamTab =
167{
168 &g_VBoxNetFltSolarisReadQ,
169 &g_VBoxNetFltSolarisWriteQ,
170 NULL, /* muxread init */
171 NULL /* muxwrite init */
172};
173
174/**
175 * cb_ops: driver char/block entry points
176 */
177static struct cb_ops g_VBoxNetFltSolarisCbOps =
178{
179 nulldev, /* cb open */
180 nulldev, /* cb close */
181 nodev, /* b strategy */
182 nodev, /* b dump */
183 nodev, /* b print */
184 nodev, /* cb read */
185 nodev, /* cb write */
186 nodev, /* cb ioctl */
187 nodev, /* c devmap */
188 nodev, /* c mmap */
189 nodev, /* c segmap */
190 nochpoll, /* c poll */
191 ddi_prop_op, /* property ops */
192 &g_VBoxNetFltSolarisStreamTab,
193 D_NEW | D_MP | D_MTPERMOD, /* compat. flag */
194 CB_REV /* revision */
195};
196
197/**
198 * dev_ops: driver entry/exit and other ops.
199 */
200static struct dev_ops g_VBoxNetFltSolarisDevOps =
201{
202 DEVO_REV, /* driver build revision */
203 0, /* ref count */
204 VBoxNetFltSolarisGetInfo,
205 nulldev, /* identify */
206 nulldev, /* probe */
207 VBoxNetFltSolarisAttach,
208 VBoxNetFltSolarisDetach,
209 nodev, /* reset */
210 &g_VBoxNetFltSolarisCbOps,
211 (struct bus_ops *)0,
212 nodev /* power */
213};
214
215/**
216 * modldrv: export driver specifics to kernel
217 */
218static struct modldrv g_VBoxNetFltSolarisDriver =
219{
220 &mod_driverops, /* extern from kernel */
221 DEVICE_DESC_DRV,
222 &g_VBoxNetFltSolarisDevOps
223};
224
225/**
226 * fmodsw: streams module ops
227 */
228static struct fmodsw g_VBoxNetFltSolarisModOps =
229{
230 DEVICE_NAME,
231 &g_VBoxNetFltSolarisStreamTab,
232 D_NEW | D_MP | D_MTPERMOD
233};
234
235/**
236 * modlstrmod: streams module specifics to kernel
237 */
238static struct modlstrmod g_VBoxNetFltSolarisModule =
239{
240 &mod_strmodops, /* extern from kernel */
241 DEVICE_DESC_MOD,
242 &g_VBoxNetFltSolarisModOps
243};
244
245/**
246 * modlinkage: export install/remove/info to the kernel
247 */
248static struct modlinkage g_VBoxNetFltSolarisModLinkage =
249{
250 MODREV_1, /* loadable module system revision */
251 &g_VBoxNetFltSolarisDriver, /* streams driver framework */
252 &g_VBoxNetFltSolarisModule, /* streams module framework */
253 NULL /* terminate array of linkage structures */
254};
255
256struct vboxnetflt_state_t;
257
258/**
259 * vboxnetflt_dladdr_t: DL SAP address format
260 */
261typedef struct vboxnetflt_dladdr_t
262{
263 ether_addr_t Mac;
264 uint16_t SAP;
265} vboxnetflt_dladdr_t;
266
267#define VBOXNETFLT_DLADDRL sizeof(vboxnetflt_dladdr_t)
268
269/**
270 * which stream is this?
271 */
272typedef enum VBOXNETFLTSTREAMTYPE
273{
274 kUndefined = 0,
275 kIpStream = 0x1b,
276 kArpStream = 0xab
277} VBOXNETFLTSTREAMTYPE;
278
279/**
280 * vboxnetflt_stream_t: per-stream data
281 */
282typedef struct vboxnetflt_stream_t
283{
284 int DevMinor; /* minor device no. (for clone) */
285 queue_t *pReadQueue; /* read side queue */
286 queue_t *pArpReadQueue; /* ARP read queue */
287 struct vboxnetflt_state_t *pState; /* state associated with this queue */
288 struct vboxnetflt_stream_t *pNext; /* next stream in list */
289 bool fPromisc; /* cached promiscous value */
290 bool fRawMode; /* whether raw mode request was successful */
291 uint32_t ModeReqId; /* track MIOCTLs for swallowing our fake request acknowledgements */
292 t_uscalar_t UnAckPrim; /* unacknowledged primitive sent by this stream, again fake DL request tracking stuff */
293 PVBOXNETFLTINS pThis; /* the backend instance */
294 VBOXNETFLTSTREAMTYPE Type; /* the type of the stream Ip/Arp */
295} vboxnetflt_stream_t;
296
297/**
298 * vboxnetflt_state_t: per-driver data
299 */
300typedef struct vboxnetflt_state_t
301{
302 /** Global device info handle. */
303 dev_info_t *pDip;
304 /** The list of all opened streams. */
305 vboxnetflt_stream_t *pOpenedStreams;
306 /**
307 * pCurInstance is the currently VBox instance to be associated with the stream being created
308 * in ModOpen. This is just shared global data between the dynamic attach and the ModOpen procedure.
309 */
310 PVBOXNETFLTINS pCurInstance;
311 /** Goes along with pCurInstance to determine type of stream being opened/created. */
312 VBOXNETFLTSTREAMTYPE CurType;
313} vboxnetflt_state_t;
314
315
316/*******************************************************************************
317* Internal Functions *
318*******************************************************************************/
319static int vboxNetFltSolarisSetRawMode(queue_t *pQueue);
320static int vboxNetFltSolarisSetFastMode(queue_t *pQueue);
321
322static int vboxNetFltSolarisPhysAddrReq(queue_t *pQueue);
323static void vboxNetFltSolarisCachePhysAddr(PVBOXNETFLTINS pThis, mblk_t *pPhysAddrAckMsg);
324
325static int vboxNetFltSolarisUnitDataToRaw(PVBOXNETFLTINS pThis, mblk_t *pMsg, mblk_t **ppRawMsg);
326static int vboxNetFltSolarisRawToUnitData(mblk_t *pMsg, mblk_t **ppDlpiMsg);
327
328static mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst);
329static unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg);
330static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc);
331static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pMsg);
332static PVBOXNETFLTINS vboxNetFltSolarisFindInstance(vboxnetflt_stream_t *pStream);
333static mblk_t *vboxNetFltSolarisFixChecksums(mblk_t *pMsg);
334static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg);
335
336
337/*******************************************************************************
338* Global Variables *
339*******************************************************************************/
340/** The (common) global data. */
341static VBOXNETFLTGLOBALS g_VBoxNetFltSolarisGlobals;
342/** Global state. */
343static vboxnetflt_state_t g_VBoxNetFltSolarisState;
344/** GCC C++ hack. */
345unsigned __gxx_personality_v0 = 0xdecea5ed;
346/** Global Mutex protecting global state. */
347RTSEMFASTMUTEX g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
348
349
350/**
351 * Kernel entry points
352 */
353int _init(void)
354{
355 LogFlow((DEVICE_NAME ":_init\n"));
356
357 /*
358 * Prevent module autounloading.
359 */
360 modctl_t *pModCtl = mod_getctl(&g_VBoxNetFltSolarisModLinkage);
361 if (pModCtl)
362 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
363 else
364 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
365
366 /*
367 * Initialize IPRT.
368 */
369 int rc = RTR0Init(0);
370 if (RT_SUCCESS(rc))
371 {
372 /*
373 * Initialize Solaris specific globals here.
374 */
375 g_VBoxNetFltSolarisState.pOpenedStreams = NULL;
376 g_VBoxNetFltSolarisState.pCurInstance = NULL;
377 rc = RTSemFastMutexCreate(&g_VBoxNetFltSolarisMtx);
378 if (RT_SUCCESS(rc))
379 {
380 /*
381 * Initialize the globals and connect to the support driver.
382 *
383 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
384 * for establishing the connect to the support driver.
385 */
386 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
387 rc = vboxNetFltInitGlobals(&g_VBoxNetFltSolarisGlobals);
388 if (RT_SUCCESS(rc))
389 {
390 rc = mod_install(&g_VBoxNetFltSolarisModLinkage);
391 if (!rc)
392 return rc;
393
394 LogRel((DEVICE_NAME ":mod_install failed. rc=%d\n", rc));
395 vboxNetFltTryDeleteGlobals(&g_VBoxNetFltSolarisGlobals);
396 }
397 else
398 LogRel((DEVICE_NAME ":failed to initialize globals.\n"));
399
400 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
401 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
402 }
403 else
404 LogRel((DEVICE_NAME ":failed to create mutex.\n"));
405
406 RTR0Term();
407 }
408 else
409 LogRel((DEVICE_NAME ":failed to initialize IPRT (rc=%d)\n", rc));
410
411 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
412 return -1;
413}
414
415
416int _fini(void)
417{
418 int rc;
419 LogFlow((DEVICE_NAME ":_fini\n"));
420
421 /*
422 * Undo the work done during start (in reverse order).
423 */
424 rc = vboxNetFltTryDeleteGlobals(&g_VBoxNetFltSolarisGlobals);
425 if (RT_FAILURE(rc))
426 {
427 LogRel((DEVICE_NAME ":_fini - busy!\n"));
428 return EBUSY;
429 }
430
431 if (g_VBoxNetFltSolarisMtx != NIL_RTSEMFASTMUTEX)
432 {
433 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
434 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
435 }
436
437 RTR0Term();
438
439 return mod_remove(&g_VBoxNetFltSolarisModLinkage);
440}
441
442
443int _info(struct modinfo *pModInfo)
444{
445 LogFlow((DEVICE_NAME ":_info\n"));
446
447 int rc = mod_info(&g_VBoxNetFltSolarisModLinkage, pModInfo);
448
449 LogFlow((DEVICE_NAME ":_info returns %d\n", rc));
450 return rc;
451}
452
453
454/**
455 * Attach entry point, to attach a device to the system or resume it.
456 *
457 * @param pDip The module structure instance.
458 * @param enmCmd Operation type (attach/resume).
459 *
460 * @returns corresponding solaris error code.
461 */
462static int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
463{
464 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
465
466 switch (enmCmd)
467 {
468 case DDI_ATTACH:
469 {
470 int instance = ddi_get_instance(pDip);
471 int rc = ddi_create_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, CLONE_DEV);
472 if (rc == DDI_SUCCESS)
473 {
474 g_VBoxNetFltSolarisState.pDip = pDip;
475 ddi_report_dev(pDip);
476 return DDI_SUCCESS;
477 }
478 else
479 LogRel((DEVICE_NAME ":VBoxNetFltSolarisAttach failed to create minor node. rc%d\n", rc));
480 return DDI_FAILURE;
481 }
482
483 case DDI_RESUME:
484 {
485 /* Nothing to do here... */
486 return DDI_SUCCESS;
487 }
488 }
489 return DDI_FAILURE;
490}
491
492
493/**
494 * Detach entry point, to detach a device to the system or suspend it.
495 *
496 * @param pDip The module structure instance.
497 * @param enmCmd Operation type (detach/suspend).
498 *
499 * @returns corresponding solaris error code.
500 */
501static int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
502{
503 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
504
505 switch (enmCmd)
506 {
507 case DDI_DETACH:
508 {
509 int instance = ddi_get_instance(pDip);
510 ddi_remove_minor_node(pDip, NULL);
511 return DDI_SUCCESS;
512 }
513
514 case DDI_RESUME:
515 {
516 /* Nothing to do here... */
517 return DDI_SUCCESS;
518 }
519 }
520 return DDI_FAILURE;
521}
522
523
524/**
525 * Info entry point, called by solaris kernel for obtaining driver info.
526 *
527 * @param pDip The module structure instance (do not use).
528 * @param enmCmd Information request type.
529 * @param pvArg Type specific argument.
530 * @param ppvResult Where to store the requested info.
531 *
532 * @returns corresponding solaris error code.
533 */
534static int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppResult)
535{
536 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd,
537 getminor((dev_t)pvArg)));
538
539 switch (enmCmd)
540 {
541 case DDI_INFO_DEVT2DEVINFO:
542 {
543 *ppResult = g_VBoxNetFltSolarisState.pDip;
544 return DDI_SUCCESS;
545 }
546
547 case DDI_INFO_DEVT2INSTANCE:
548 {
549 int instance = getminor((dev_t)pvArg);
550 *ppResult = (void *)(uintptr_t)instance;
551 return DDI_SUCCESS;
552 }
553 }
554
555 return DDI_FAILURE;
556}
557
558
559/**
560 * Stream module open entry point, initializes the queue and allows streams processing.
561 *
562 * @param pQueue Pointer to the queue (cannot be NULL).
563 * @param pDev Pointer to the dev_t associated with the driver at the end of the stream.
564 * @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
565 * @param fStreamMode Stream open mode.
566 * @param pCred Pointer to user credentials.
567 *
568 * @returns corresponding solaris error code.
569 */
570static int VBoxNetFltSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fOpenMode, int fStreamMode, cred_t *pCred)
571{
572 Assert(pQueue);
573
574 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModOpen pQueue=%p pDev=%p fOpenMode=%d fStreamMode=%d\n", pQueue, pDev,
575 fOpenMode, fStreamMode));
576
577 /*
578 * Already open?
579 */
580 if (pQueue->q_ptr)
581 {
582 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen invalid open.\n"));
583 return ENOENT;
584 }
585
586 /*
587 * Check for the VirtualBox instance.
588 */
589 vboxnetflt_state_t *pState = &g_VBoxNetFltSolarisState;
590 if (RT_UNLIKELY(!pState->pCurInstance))
591 {
592 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to get VirtualBox instance.\n"));
593 return ENOENT;
594 }
595
596 /*
597 * Check VirtualBox stream type.
598 */
599 if (pState->CurType == kUndefined)
600 {
601 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed due to undefined VirtualBox open mode.\n"));
602 return ENOENT;
603 }
604
605 /*
606 * Get minor number. For clone opens provide a new dev_t.
607 */
608 minor_t DevMinor = 0;
609 vboxnetflt_stream_t *pStream = NULL;
610 vboxnetflt_stream_t **ppPrevStream = &pState->pOpenedStreams;
611 if (fStreamMode == CLONEOPEN)
612 {
613 for (; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
614 {
615 if (DevMinor < pStream->DevMinor)
616 break;
617 DevMinor++;
618 }
619 *pDev = makedevice(getmajor(*pDev), DevMinor);
620 }
621 else
622 DevMinor = getminor(*pDev);
623
624 /*
625 * Allocate & initialize per-stream data. Hook it into the (read and write) queue's module specific data.
626 */
627 pStream = RTMemAlloc(sizeof(*pStream));
628 if (RT_UNLIKELY(!pStream))
629 {
630 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to allocate stream data.\n"));
631 return ENOMEM;
632 }
633 pStream->DevMinor = DevMinor;
634 pStream->pReadQueue = pQueue;
635 pStream->pArpReadQueue = NULL;
636 pStream->pState = pState;
637 pStream->fPromisc = false;
638 pStream->fRawMode = false;
639
640 /*
641 * Pick up the current global VBOXNETFLTINS instance as
642 * the one that we will associate this stream with.
643 */
644 pStream->pThis = pState->pCurInstance;
645 pStream->Type = pState->CurType;
646 if (pState->CurType == kIpStream)
647 pState->pCurInstance->u.s.pvStream = pStream;
648 else
649 pState->pCurInstance->u.s.pvArpStream = pStream;
650
651 pStream->ModeReqId = 0;
652 pStream->UnAckPrim = 0;
653 pQueue->q_ptr = pStream;
654 WR(pQueue)->q_ptr = pStream;
655
656 /*
657 * Link it to the list of streams.
658 */
659 pStream->pNext = *ppPrevStream;
660 *ppPrevStream = pStream;
661
662 qprocson(pQueue);
663
664 /*
665 * Request the physical address (we cache the acknowledgement).
666 */
667 if (pStream->Type == kIpStream)
668 vboxNetFltSolarisPhysAddrReq(pStream->pReadQueue);
669
670 /*
671 * Enable raw mode.
672 */
673 if (pStream->Type == kIpStream)
674 vboxNetFltSolarisSetRawMode(pStream->pReadQueue);
675
676 pStream->pThis->fDisconnectedFromHost = false;
677
678 NOREF(fOpenMode);
679 NOREF(pCred);
680
681 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModOpen returns 0, DevMinor=%d pQueue=%p\n", DevMinor, pStream->pReadQueue));
682
683 return 0;
684}
685
686
687/**
688 * Stream module close entry point, undoes the work done on open and closes the stream.
689 *
690 * @param pQueue Pointer to the queue (cannot be NULL).
691 * @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
692 * @param pCred Pointer to user credentials.
693 *
694 * @returns corresponding solaris error code.
695 */
696static int VBoxNetFltSolarisModClose(queue_t *pQueue, int fOpenMode, cred_t *pCred)
697{
698 Assert(pQueue);
699
700 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModClose pQueue=%p fOpenMode=%d\n", pQueue, fOpenMode));
701
702 vboxnetflt_stream_t *pStream = NULL;
703 vboxnetflt_stream_t **ppPrevStream = NULL;
704 vboxnetflt_state_t *pState = NULL;
705
706 /*
707 * Get instance data.
708 */
709 pStream = (vboxnetflt_stream_t *)pQueue->q_ptr;
710 if (RT_UNLIKELY(!pStream))
711 {
712 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModClose failed to get stream.\n"));
713 return ENXIO;
714 }
715 pState = pStream->pState;
716 Assert(pState);
717
718 /*
719 * Enable native mode.
720 */
721 if (pStream->Type == kIpStream)
722 vboxNetFltSolarisSetFastMode(pStream->pReadQueue);
723
724 pStream->pThis->fDisconnectedFromHost = true;
725 qprocsoff(pQueue);
726
727 /*
728 * Unlink it from the list of streams.
729 */
730 for (ppPrevStream = &pState->pOpenedStreams; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
731 if (pStream == (vboxnetflt_stream_t *)pQueue->q_ptr)
732 break;
733 *ppPrevStream = pStream->pNext;
734
735 /*
736 * Delete the stream.
737 */
738 if (pStream->Type == kIpStream)
739 pStream->pThis->u.s.pvStream = NULL;
740 else
741 pStream->pThis->u.s.pvArpStream = NULL;
742 RTMemFree(pStream);
743 pQueue->q_ptr = NULL;
744 WR(pQueue)->q_ptr = NULL;
745
746 NOREF(fOpenMode);
747 NOREF(pCred);
748
749 return 0;
750}
751
752
753/**
754 * Read side put procedure for processing messages in the read queue.
755 *
756 * @param pQueue Pointer to the queue.
757 * @param pMsg Pointer to the message.
758 *
759 * @returns corresponding solaris error code.
760 */
761static int VBoxNetFltSolarisModReadPut(queue_t *pQueue, mblk_t *pMsg)
762{
763 if (!pMsg)
764 return 0;
765
766 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut pQueue=%p pMsg=%p\n"));
767
768 bool fSendUpstream = true;
769 bool fActive = false;
770 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
771 PVBOXNETFLTINS pThis = NULL;
772
773 /*
774 * In the unlikely case where VirtualBox crashed and this filter
775 * is somehow still in the host stream we must try not to panic the host.
776 */
777 if ( pStream
778 && pStream->Type == kIpStream
779 && pMsg)
780 {
781 pThis = vboxNetFltSolarisFindInstance(pStream);
782 if (RT_LIKELY(pThis))
783 {
784 /*
785 * Retain the instance if we're actively filtering.
786 */
787 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
788 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
789 fActive = ASMAtomicUoReadBool(&pThis->fActive);
790 if (fActive)
791 vboxNetFltRetain(pThis, true);
792 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
793
794 switch (DB_TYPE(pMsg))
795 {
796 case M_DATA:
797 {
798 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut M_DATA\n"));
799
800 if (fActive)
801 {
802 vboxNetFltSolarisRecv(pThis, pStream, pQueue, pMsg);
803 fSendUpstream = false;
804 }
805 break;
806 }
807
808 case M_PROTO:
809 case M_PCPROTO:
810 {
811 union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
812 t_uscalar_t Prim = pPrim->dl_primitive;
813
814 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO %d\n", Prim));
815 switch (Prim)
816 {
817 case DL_UNITDATA_IND:
818 {
819 /*
820 * I do not think control would come here... We convert all outgoing fast mode requests
821 * to raw mode; so I don't think we should really receive any fast mode replies.
822 */
823 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_UNITDATA_IND\n"));
824
825 if (fActive)
826 {
827 vboxNetFltSolarisRecv(pThis, pStream, pQueue, pMsg);
828 fSendUpstream = false;
829 }
830 break;
831 }
832
833 case DL_PHYS_ADDR_ACK:
834 {
835 vboxNetFltSolarisCachePhysAddr(pThis, pMsg);
836
837 /*
838 * Swallow our fake physical address request acknowledgement.
839 */
840 if (pStream->UnAckPrim == DL_PHYS_ADDR_REQ)
841 {
842 freemsg(pMsg);
843 fSendUpstream = false;
844 }
845 break;
846 }
847
848 case DL_OK_ACK:
849 {
850 dl_ok_ack_t *pOkAck = (dl_ok_ack_t *)pMsg->b_rptr;
851 if (pOkAck->dl_correct_primitive == DL_PROMISCON_REQ)
852 {
853 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO: DL_OK_ACK: fPromisc is ON.\n"));
854 pStream->fPromisc = true;
855 }
856 else if (pOkAck->dl_correct_primitive == DL_PROMISCOFF_REQ)
857 {
858 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO: DL_OK_ACK: fPromisc is OFF.\n"));
859 pStream->fPromisc = false;
860 }
861
862 /*
863 * Swallow our fake promiscous request acknowledgement.
864 */
865 if (pStream->UnAckPrim == pOkAck->dl_correct_primitive)
866 {
867 freemsg(pMsg);
868 fSendUpstream = false;
869 }
870 break;
871 }
872 }
873 break;
874 }
875
876 case M_IOCACK:
877 {
878 /*
879 * Swallow our fake raw/fast path mode request acknowledgement.
880 */
881 struct iocblk *pIOC = (struct iocblk *)pMsg->b_rptr;
882 if (pIOC->ioc_id == pStream->ModeReqId)
883 {
884 pStream->fRawMode = true;
885 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Mode acknowledgement. RawMode is %s\n",
886 pStream->fRawMode ? "ON" : "OFF"));
887
888 freemsg(pMsg);
889 fSendUpstream = false;
890 }
891 break;
892 }
893
894 case M_FLUSH:
895 {
896 /*
897 * We must support flushing queues.
898 */
899 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_FLUSH\n"));
900 if (*pMsg->b_rptr & FLUSHR)
901 flushq(pQueue, FLUSHALL);
902 break;
903 }
904 }
905 }
906 else
907 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Could not find VirtualBox instance!!\n"));
908 }
909
910 if ( fSendUpstream
911 && pMsg)
912 {
913 /*
914 * Pass foward high priority messages or when there's no flow control
915 * on an empty queue, otherwise queue them.
916 */
917 if ( queclass(pMsg) == QPCTL
918 || (pQueue->q_first == NULL && canputnext(pQueue)))
919 {
920 putnext(pQueue, pMsg);
921 }
922 else
923 putq(pQueue, pMsg);
924 }
925
926 if (fActive)
927 vboxNetFltRelease(pThis, true);
928
929 return 0;
930}
931
932
933/**
934 * Write side put procedure for processing messages in the write queue.
935 *
936 * @param pQueue Pointer to the queue.
937 * @param pMsg Pointer to the message.
938 *
939 * @returns corresponding solaris error code.
940 */
941static int VBoxNetFltSolarisModWritePut(queue_t *pQueue, mblk_t *pMsg)
942{
943 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut pQueue=%p pMsg=%p\n", pQueue, pMsg));
944
945 /*
946 * Check for the VirtualBox connection.
947 */
948 bool fSendDownstream = true;
949 bool fActive = false;
950 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
951 PVBOXNETFLTINS pThis = NULL;
952
953 /*
954 * In the unlikely case where VirtualBox crashed and this filter
955 * is somehow still in the host stream we must try not to panic the host.
956 */
957 if ( pStream
958 && pStream->Type == kIpStream
959 && pMsg)
960 {
961 pThis = vboxNetFltSolarisFindInstance(pStream);
962 if (RT_LIKELY(pThis))
963 {
964 /*
965 * Retain the instance if we're actively filtering.
966 */
967 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
968 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
969 fActive = ASMAtomicUoReadBool(&pThis->fActive);
970 if (fActive)
971 vboxNetFltRetain(pThis, true);
972 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
973
974 switch (DB_TYPE(pMsg))
975 {
976 case M_DATA:
977 {
978 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut M_DATA\n"));
979 break;
980 }
981
982 case M_PROTO:
983 case M_PCPROTO:
984 {
985 /*
986 * If we are not yet in raw mode; just pass through.
987 */
988 if (!pStream->fRawMode)
989 break;
990
991 /*
992 * Queue up other primitives to the service routine.
993 */
994 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut M_PROTO/M_PCPROTO\n"));
995
996 union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
997 t_uscalar_t Prim = pPrim->dl_primitive;
998 switch (Prim)
999 {
1000 case DL_UNITDATA_REQ:
1001 {
1002 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut DL_UNITDATA_REQ\n"));
1003 mblk_t *pRawMsg;
1004 int rc = vboxNetFltSolarisUnitDataToRaw(pThis, pMsg, &pRawMsg);
1005 if (RT_SUCCESS(rc))
1006 pMsg = pRawMsg;
1007 else
1008 fSendDownstream = false;
1009 break;
1010 }
1011
1012 default:
1013 {
1014 /*
1015 * Enqueue other DLPI primitives and service them later.
1016 */
1017 fSendDownstream = false;
1018 putq(pQueue, pMsg);
1019 break;
1020 }
1021 }
1022 break;
1023 }
1024
1025 case M_IOCTL:
1026 {
1027 struct iocblk *pIOC = (struct iocblk *)pMsg->b_rptr;
1028 if (pIOC->ioc_cmd == DL_IOC_HDR_INFO)
1029 {
1030 fSendDownstream = false;
1031
1032 /*
1033 * Some sanity checks.
1034 */
1035 if ( !pMsg->b_cont
1036 || (MBLKL(pMsg->b_cont) < sizeof(dl_unitdata_req_t) + VBOXNETFLT_DLADDRL)
1037 || (*((uint32_t *)pMsg->b_cont->b_rptr) != DL_UNITDATA_REQ))
1038 {
1039 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModWritePut: Invalid fast path request!\n"));
1040 miocnak(pQueue, pMsg, 0, EPROTO);
1041 break;
1042 }
1043
1044 dl_unitdata_req_t *pDlReq = (dl_unitdata_req_t *)pMsg->b_cont->b_rptr;
1045 size_t cbOffset = pDlReq->dl_dest_addr_offset;
1046 size_t cbAddr = pDlReq->dl_dest_addr_length;
1047 if ( !MBLKIN(pMsg->b_cont, cbOffset, cbAddr)
1048 || cbAddr != VBOXNETFLT_DLADDRL)
1049 {
1050 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModWritePut: Invalid header in fast path request!\n"));
1051 miocnak(pQueue, pMsg, 0, EPROTO);
1052 break;
1053 }
1054
1055 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_cont->b_rptr + cbOffset);
1056 mblk_t *pReplyMsg = allocb(sizeof(RTNETETHERHDR), BPRI_MED);
1057 if (RT_UNLIKELY(!pReplyMsg))
1058 {
1059 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModWritePut: Invalid header in fast path request!\n"));
1060 miocnak(pQueue, pMsg, 0, ENOMEM);
1061 break;
1062 }
1063
1064 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
1065 bcopy(&pDLSapAddr->Mac, &pEthHdr->DstMac, sizeof(RTMAC));
1066 bcopy(&pThis->u.s.Mac, &pEthHdr->SrcMac, sizeof(RTMAC));
1067 pEthHdr->EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
1068
1069 linkb(pMsg, pReplyMsg);
1070
1071 /*
1072 * Somebody is wanting fast path when we need raw mode.
1073 * Since we are evil, let's acknowledge the request ourselves!
1074 */
1075 miocack(pQueue, pMsg, msgsize(pMsg->b_cont), EINVAL);
1076 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut: Fast path request acknowledged.\n"));
1077 }
1078 break;
1079 }
1080
1081 case M_FLUSH:
1082 {
1083 /*
1084 * Canonical flush courtesy man qreply(9F) while we have a service routine.
1085 */
1086 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut M_FLUSH\n"));
1087 if (*pMsg->b_rptr & FLUSHW)
1088 {
1089 /*
1090 * Flush and mark as serviced.
1091 */
1092 flushq(pQueue, FLUSHALL);
1093 *pMsg->b_rptr &= ~FLUSHW;
1094 }
1095
1096 if (*pMsg->b_rptr & FLUSHR)
1097 {
1098 /*
1099 * Send the request upstream.
1100 */
1101 flushq(RD(pQueue), FLUSHALL);
1102 qreply(pQueue, pMsg);
1103 }
1104 else
1105 freemsg(pMsg);
1106
1107 break;
1108 }
1109 }
1110 }
1111 else
1112 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModWritePut: Could not find VirtualBox instance!!\n"));
1113 }
1114
1115 if ( fSendDownstream
1116 && pMsg)
1117 {
1118 /*
1119 * Pass foward high priority messages or when there's no flow control
1120 * on an empty queue, otherwise queue them.
1121 */
1122 if ( queclass(pMsg) == QPCTL
1123 || (pQueue->q_first == NULL && canputnext(pQueue)))
1124 {
1125 putnext(pQueue, pMsg);
1126 }
1127 else
1128 putq(pQueue, pMsg);
1129 }
1130
1131 if (fActive)
1132 vboxNetFltRelease(pThis, true);
1133
1134 return 0;
1135}
1136
1137
1138/**
1139 * Write side service procedure for deferred message processing on the write queue.
1140 *
1141 * @param pQueue Pointer to the queue.
1142 *
1143 * @returns corresponding solaris error code.
1144 */
1145static int VBoxNetFltSolarisModWriteService(queue_t *pQueue)
1146{
1147 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWriteService pQueue=%p\n", pQueue));
1148
1149 /*
1150 * Implment just the flow controlled service draining of the queue.
1151 * Nothing else to do here, we handle all the important stuff in the Put procedure.
1152 */
1153 mblk_t *pMsg;
1154 while (pMsg = getq(pQueue))
1155 {
1156 if (canputnext(pQueue))
1157 putnext(pQueue, pMsg);
1158 else
1159 {
1160 putbq(pQueue, pMsg);
1161 break;
1162 }
1163 }
1164
1165 return 0;
1166}
1167
1168
1169/**
1170 * Put the stream in raw mode.
1171 *
1172 * @returns VBox status code.
1173 * @param pQueue Pointer to the queue.
1174 */
1175static int vboxNetFltSolarisSetRawMode(queue_t *pQueue)
1176{
1177 LogFlow((DEVICE_NAME ":vboxNetFltSolarisSetRawMode pQueue=%p\n", pQueue));
1178
1179 mblk_t *pRawMsg = NULL;
1180 pRawMsg = mkiocb(DLIOCRAW);
1181 if (RT_UNLIKELY(!pRawMsg))
1182 return VERR_NO_MEMORY;
1183
1184 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
1185 struct iocblk *pIOC = (struct iocblk *)pRawMsg->b_rptr;
1186 pStream->ModeReqId = pIOC->ioc_id;
1187 pIOC->ioc_count = 0;
1188
1189 qreply(pQueue, pRawMsg);
1190 return VINF_SUCCESS;
1191}
1192
1193
1194/**
1195 * Put the stream back in fast path mode.
1196 *
1197 * @returns VBox status code.
1198 * @param pQueue Pointer to the queue.
1199 */
1200static int vboxNetFltSolarisSetFastMode(queue_t *pQueue)
1201{
1202 LogFlow((DEVICE_NAME ":vboxNetFltSolarisSetFastMode pQueue=%p\n", pQueue));
1203
1204 mblk_t *pFastMsg = mkiocb(DL_IOC_HDR_INFO);
1205 if (RT_UNLIKELY(!pFastMsg))
1206 return VERR_NO_MEMORY;
1207
1208 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
1209 struct iocblk *pIOC = (struct iocblk *)pFastMsg->b_rptr;
1210 pStream->ModeReqId = pIOC->ioc_id;
1211
1212 size_t cbReq = sizeof(dl_unitdata_req_t) + sizeof(vboxnetflt_dladdr_t);
1213 mblk_t *pDataReqMsg = allocb(cbReq, BPRI_MED);
1214 if (RT_UNLIKELY(!pDataReqMsg))
1215 return VERR_NO_MEMORY;
1216
1217 DB_TYPE(pDataReqMsg) = M_PROTO;
1218 dl_unitdata_req_t *pDataReq = (dl_unitdata_req_t *)pDataReqMsg->b_rptr;
1219 pDataReq->dl_primitive = DL_UNITDATA_REQ;
1220 pDataReq->dl_dest_addr_length = sizeof(vboxnetflt_dladdr_t);
1221 pDataReq->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
1222 pDataReq->dl_priority.dl_min = 0;
1223 pDataReq->dl_priority.dl_max = 0;
1224
1225 bzero(pDataReqMsg->b_rptr + sizeof(dl_unitdata_req_t), sizeof(vboxnetflt_dladdr_t));
1226 pDataReqMsg->b_wptr = pDataReqMsg->b_rptr + cbReq;
1227
1228 /*
1229 * Link the data format request message into the header ioctl message.
1230 */
1231 pFastMsg->b_cont = pDataReqMsg;
1232 pIOC->ioc_count = msgdsize(pDataReqMsg);
1233
1234 qreply(pQueue, pFastMsg);
1235 return VINF_SUCCESS;
1236}
1237
1238
1239/**
1240 * Send fake promiscous mode requests downstream.
1241 *
1242 * @param pQueue Pointer to the queue.
1243 * @param fPromisc Whether to enable promiscous mode or not.
1244 * @param PromiscLevel Promiscous level; DL_PROMISC_PHYS/SAP/MULTI.
1245 *
1246 * @returns VBox error code.
1247 */
1248static int vboxNetFltSolarisPromiscReq(queue_t *pQueue, bool fPromisc)
1249{
1250 LogFlow((DEVICE_NAME ":vboxNetFltSolarisPromiscReq pQueue=%p fPromisc=%d\n", pQueue, fPromisc));
1251
1252 t_uscalar_t Cmd;
1253 size_t cbReq = 0;
1254 if (fPromisc)
1255 {
1256 Cmd = DL_PROMISCON_REQ;
1257 cbReq = DL_PROMISCON_REQ_SIZE;
1258 }
1259 else
1260 {
1261 Cmd = DL_PROMISCOFF_REQ;
1262 cbReq = DL_PROMISCOFF_REQ_SIZE;
1263 }
1264
1265 mblk_t *pPromiscPhysMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1266 if (RT_UNLIKELY(!pPromiscPhysMsg))
1267 return VERR_NO_MEMORY;
1268
1269 mblk_t *pPromiscSapMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1270 if (RT_UNLIKELY(!pPromiscSapMsg))
1271 {
1272 freemsg(pPromiscPhysMsg);
1273 return VERR_NO_MEMORY;
1274 }
1275
1276 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
1277 pStream->UnAckPrim = Cmd;
1278
1279 if (fPromisc)
1280 {
1281 ((dl_promiscon_req_t *)pPromiscPhysMsg->b_rptr)->dl_level = DL_PROMISC_PHYS;
1282 ((dl_promiscon_req_t *)pPromiscSapMsg->b_rptr)->dl_level = DL_PROMISC_SAP;
1283 }
1284 else
1285 {
1286 ((dl_promiscoff_req_t *)pPromiscPhysMsg->b_rptr)->dl_level = DL_PROMISC_PHYS;
1287 ((dl_promiscoff_req_t *)pPromiscSapMsg->b_rptr)->dl_level = DL_PROMISC_SAP;
1288 }
1289
1290 qreply(pQueue, pPromiscPhysMsg);
1291 qreply(pQueue, pPromiscSapMsg);
1292
1293 return VINF_SUCCESS;
1294}
1295
1296
1297/**
1298 * Send a fake physical address request downstream.
1299 *
1300 * @returns VBox status code.
1301 * @param pQueue Pointer to the queue.
1302 * @param pMsg Pointer to the request message.
1303 */
1304static int vboxNetFltSolarisPhysAddrReq(queue_t *pQueue)
1305{
1306 LogFlow((DEVICE_NAME ":vboxNetFltSolarisPhysAddrReq pQueue=%p\n", pQueue));
1307
1308 t_uscalar_t Cmd = DL_PHYS_ADDR_REQ;
1309 size_t cbReq = DL_PHYS_ADDR_REQ_SIZE;
1310 mblk_t *pPhysAddrMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1311 if (RT_UNLIKELY(!pPhysAddrMsg))
1312 return VERR_NO_MEMORY;
1313
1314 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
1315 pStream->UnAckPrim = Cmd;
1316
1317 dl_phys_addr_req_t *pPhysAddrReq = (dl_phys_addr_req_t *)pPhysAddrMsg->b_rptr;
1318 pPhysAddrReq->dl_addr_type = DL_CURR_PHYS_ADDR;
1319
1320 qreply(pQueue, pPhysAddrMsg);
1321 return VERR_GENERAL_FAILURE;
1322}
1323
1324
1325/**
1326 * Cache the MAC address into the VirtualBox instance given a physical
1327 * address acknowledgement message.
1328 *
1329 * @param pThis The instance.
1330 * @param pMsg Pointer to the physical address acknowledgement message.
1331 */
1332static void vboxNetFltSolarisCachePhysAddr(PVBOXNETFLTINS pThis, mblk_t *pMsg)
1333{
1334 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr pThis=%p pMsg=%p\n", pThis, pMsg));
1335
1336 AssertCompile(sizeof(RTMAC) == ETHERADDRL);
1337 dl_phys_addr_ack_t *pPhysAddrAck = (dl_phys_addr_ack_t *)pMsg->b_rptr;
1338 if (pPhysAddrAck->dl_addr_length == sizeof(pThis->u.s.Mac))
1339 {
1340 bcopy(pMsg->b_rptr + pPhysAddrAck->dl_addr_offset, &pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
1341
1342 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr: DL_PHYS_ADDR_ACK: Mac=%.*Rhxs\n", sizeof(pThis->u.s.Mac),
1343 &pThis->u.s.Mac));
1344 }
1345}
1346
1347
1348/**
1349 * Opens the required device and returns the vnode_t associated with it.
1350 * We require this for the funny attach/detach routine.
1351 *
1352 * @returns VBox status code.
1353 * @param pszDev The device path.
1354 * @param ppVNode Where to store the vnode_t pointer associated with the opened device.
1355 * @param ppVNodeHeld Where to store the vnode_t required during closing of the device.
1356 * @param ppUser Open handle required while closing the device.
1357 */
1358static int vboxNetFltSolarisOpenDev(char *pszDev, vnode_t **ppVNode, vnode_t **ppVNodeHeld, TIUSER **ppUser)
1359{
1360 int rc;
1361 vnode_t *pVNodeHeld = NULL;
1362 rc = lookupname(pszDev, UIO_SYSSPACE, FOLLOW, NULLVPP, &pVNodeHeld);
1363 if (!rc)
1364 {
1365 TIUSER *pUser;
1366 rc = t_kopen((file_t *)NULL, pVNodeHeld->v_rdev, FREAD | FWRITE, &pUser, kcred);
1367 if (!rc)
1368 {
1369 *ppVNode = pUser->fp->f_vnode;
1370 *ppVNodeHeld = pVNodeHeld;
1371 *ppUser = pUser;
1372 return VINF_SUCCESS;
1373 }
1374 VN_RELE(pVNodeHeld);
1375 }
1376 return VERR_PATH_NOT_FOUND;
1377}
1378
1379
1380/**
1381 * Close the device opened using vboxNetFltSolarisOpenDev.
1382 *
1383 * @param pVNodeHeld Pointer to the held vnode of the device.
1384 * @param pUser Pointer to the file handle.
1385 */
1386static void vboxNetFltSolarisCloseDev(vnode_t *pVNodeHeld, TIUSER *pUser)
1387{
1388 t_kclose(pUser, 0);
1389 VN_RELE(pVNodeHeld);
1390}
1391
1392
1393/**
1394 * Get the logical interface flags from the stream.
1395 *
1396 * @returns VBox status code.
1397 * @param hDevice Layered device handle.
1398 * @param pInterface Pointer to the interface.
1399 */
1400static int vboxNetFltSolarisGetIfFlags(ldi_handle_t hDevice, struct lifreq *pInterface)
1401{
1402 struct strioctl IOCReq;
1403 int rc;
1404 int ret;
1405 IOCReq.ic_cmd = SIOCGLIFFLAGS;
1406 IOCReq.ic_timout = 40;
1407 IOCReq.ic_len = sizeof(struct lifreq);
1408 IOCReq.ic_dp = (caddr_t)pInterface;
1409 rc = ldi_ioctl(hDevice, I_STR, (intptr_t)&IOCReq, FKIOCTL, kcred, &ret);
1410 if (!rc)
1411 return VINF_SUCCESS;
1412
1413 return RTErrConvertFromErrno(rc);
1414}
1415
1416
1417/**
1418 * Sets the multiplexor ID from the interface.
1419 *
1420 * @returns VBox status code.
1421 * @param pVNode Pointer to the device vnode.
1422 * @param pInterface Pointer to the interface.
1423 */
1424static int vboxNetFltSolarisSetMuxId(vnode_t *pVNode, struct lifreq *pInterface)
1425{
1426 struct strioctl IOCReq;
1427 int rc;
1428 int ret;
1429 IOCReq.ic_cmd = SIOCSLIFMUXID;
1430 IOCReq.ic_timout = 40;
1431 IOCReq.ic_len = sizeof(struct lifreq);
1432 IOCReq.ic_dp = (caddr_t)pInterface;
1433
1434 rc = strioctl(pVNode, I_STR, (intptr_t)&IOCReq, 0, K_TO_K, kcred, &ret);
1435 if (!rc)
1436 return VINF_SUCCESS;
1437
1438 return RTErrConvertFromErrno(rc);
1439}
1440
1441
1442/**
1443 * Get the multiplexor file descriptor of the lower stream.
1444 *
1445 * @returns VBox status code.
1446 * @param MuxId The multiplexor ID.
1447 * @param pFd Where to store the lower stream file descriptor.
1448 */
1449static int vboxNetFltSolarisMuxIdToFd(vnode_t *pVNode, int MuxId, int *pFd)
1450{
1451 int ret;
1452 int rc = strioctl(pVNode, _I_MUXID2FD, (intptr_t)MuxId, 0, K_TO_K, kcred, &ret);
1453 if (!rc)
1454 {
1455 *pFd = ret;
1456 return VINF_SUCCESS;
1457 }
1458
1459 return RTErrConvertFromErrno(rc);
1460}
1461
1462
1463/**
1464 * Relinks the lower and the upper stream.
1465 *
1466 * @returns VBox status code.
1467 * @param pVNode Pointer to the device vnode.
1468 * @param pInterface Pointer to the interface.
1469 * @param IpMuxFd The IP multiplexor ID.
1470 * @param ArpMuxFd The ARP multiplexor ID.
1471 */
1472static int vboxNetFltSolarisRelink(vnode_t *pVNode, struct lifreq *pInterface, int IpMuxFd, int ArpMuxFd)
1473{
1474 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRelink: pVNode=%p pInterface=%p IpMuxFd=%d ArpMuxFd=%d\n", pVNode,
1475 pInterface, IpMuxFd, ArpMuxFd));
1476
1477 int NewIpMuxId;
1478 int NewArpMuxId;
1479 int rc = strioctl(pVNode, I_PLINK, (intptr_t)IpMuxFd, 0, K_TO_K, kcred, &NewIpMuxId);
1480 int rc2 = strioctl(pVNode, I_PLINK, (intptr_t)ArpMuxFd, 0, K_TO_K, kcred, &NewArpMuxId);
1481 if ( !rc
1482 && !rc2)
1483 {
1484 pInterface->lifr_ip_muxid = NewIpMuxId;
1485 pInterface->lifr_arp_muxid = NewArpMuxId;
1486 rc = vboxNetFltSolarisSetMuxId(pVNode, pInterface);
1487 if (RT_SUCCESS(rc))
1488 return VINF_SUCCESS;
1489
1490 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelink: failed to set new Mux Id.\n"));
1491 }
1492 else
1493 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelink: failed to link.\n"));
1494
1495 return VERR_GENERAL_FAILURE;
1496}
1497
1498
1499/**
1500 * Dynamically find the position on the host stack where to attach/detach ourselves.
1501 *
1502 * @returns VBox status code.
1503 * @param pVNode Pointer to the lower stream vnode.
1504 * @param pModPos Where to store the module position.
1505 */
1506static int vboxNetFltSolarisDetermineModPos(bool fAttach, vnode_t *pVNode, int *pModPos)
1507{
1508 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: fAttach=%d pVNode=%p pModPos=%p\n", fAttach, pVNode, pModPos));
1509
1510 int cMod;
1511 int rc = strioctl(pVNode, I_LIST, (intptr_t)NULL, 0, K_TO_K, kcred, &cMod);
1512 if (!rc)
1513 {
1514 if (cMod < 1)
1515 {
1516 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: too few modules on host interface. cMod=%d\n"));
1517 return VERR_OUT_OF_RANGE;
1518 }
1519
1520 /*
1521 * While attaching we make sure we are at the bottom most of the stack, excepting
1522 * the host driver.
1523 */
1524 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: cMod=%d\n", cMod));
1525 if (fAttach)
1526 {
1527 *pModPos = cMod - 1;
1528 return VINF_SUCCESS;
1529 }
1530
1531 /*
1532 * Detaching is a bit more complicated; since user could have altered the stack positions
1533 * we take the safe approach by finding our position.
1534 */
1535 struct str_list StrList;
1536 StrList.sl_nmods = cMod;
1537 StrList.sl_modlist = RTMemAllocZ(cMod * sizeof(struct str_list));
1538 if (RT_UNLIKELY(!StrList.sl_modlist))
1539 {
1540 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to alloc memory for StrList.\n"));
1541 return VERR_NO_MEMORY;
1542 }
1543
1544 /*
1545 * Get the list of all modules on the stack.
1546 */
1547 int ret;
1548 rc = strioctl(pVNode, I_LIST, (intptr_t)&StrList, 0, K_TO_K, kcred, &ret);
1549 if (!rc)
1550 {
1551 /*
1552 * Find our filter.
1553 */
1554 for (int i = 0; i < StrList.sl_nmods; i++)
1555 {
1556 if (!strcmp(DEVICE_NAME, StrList.sl_modlist[i].l_name))
1557 {
1558 LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: Success! Found %s at %d.\n", DEVICE_NAME, i));
1559 *pModPos = i;
1560 return VINF_SUCCESS;
1561 }
1562 }
1563
1564 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to find %s in the host stack.\n"));
1565 }
1566 else
1567 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get module information. rc=%d\n"));
1568 }
1569 else
1570 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get list of modules on host interface. rc=%d\n", rc));
1571 return VERR_GENERAL_FAILURE;
1572}
1573
1574
1575/**
1576 * Dynamically attaches this streams module on to the host stack.
1577 * As a side-effect, this streams also gets opened/closed during
1578 * the actual injection/ejection phase.
1579 *
1580 * @returns VBox status code.
1581 * @param pThis The instance.
1582 * @param fAttach Is this an attach or detach.
1583 */
1584static int vboxNetFltSolarisModSetup(PVBOXNETFLTINS pThis, bool fAttach)
1585{
1586 LogFlow(("vboxNetFltSolarisModSetup: pThis=%p (%s) fAttach=%s\n", pThis, pThis->szName, fAttach ? "true" : "false"));
1587
1588 /*
1589 * Statuatory Warning: Hackish code ahead.
1590 */
1591 if (strlen(pThis->szName) > VBOXNETFLT_IFNAME_LEN - 1)
1592 {
1593 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: interface name too long %s\n", pThis->szName));
1594 return VERR_INTNET_FLT_IF_NOT_FOUND;
1595 }
1596
1597 char *pszModName = DEVICE_NAME;
1598
1599 struct lifreq Interface;
1600 bzero(&Interface, sizeof(Interface));
1601 Interface.lifr_addr.ss_family = AF_INET;
1602 strncpy(Interface.lifr_name, pThis->szName, sizeof(Interface.lifr_name));
1603
1604 struct strmodconf StrMod;
1605 StrMod.mod_name = pszModName;
1606 StrMod.pos = -1; /* this is filled in later. */
1607
1608 struct strmodconf ArpStrMod;
1609 bcopy(&StrMod, &ArpStrMod, sizeof(StrMod));
1610
1611 int rc;
1612 int rc2;
1613 int ret;
1614 ldi_ident_t IPDevId = ldi_ident_from_anon();
1615 ldi_ident_t ARPDevId = ldi_ident_from_anon();
1616 ldi_handle_t IPDevHandle;
1617 ldi_handle_t UDPDevHandle;
1618 ldi_handle_t ARPDevHandle;
1619
1620 /*
1621 * Open the IP and ARP streams as layered devices.
1622 */
1623 rc = ldi_open_by_name(IP_DEV_NAME, FREAD | FWRITE, kcred, &IPDevHandle, IPDevId);
1624 ldi_ident_release(IPDevId);
1625 if (rc)
1626 {
1627 LogRel((DEVICE_NAME ":failed to open the IP stream on '%s'.\n", pThis->szName));
1628 return VERR_INTNET_FLT_IF_FAILED;
1629 }
1630
1631 rc = ldi_open_by_name("/dev/arp", FREAD | FWRITE, kcred, &ARPDevHandle, ARPDevId);
1632 ldi_ident_release(ARPDevId);
1633 if (rc)
1634 {
1635 LogRel((DEVICE_NAME ":failed to open the ARP stream on '%s'.\n", pThis->szName));
1636 ldi_close(IPDevHandle, FREAD | FWRITE, kcred);
1637 return VERR_INTNET_FLT_IF_FAILED;
1638 }
1639
1640 /*
1641 * Obtain the interface flags from IP.
1642 */
1643 rc = vboxNetFltSolarisGetIfFlags(IPDevHandle, &Interface);
1644 if (RT_SUCCESS(rc))
1645 {
1646 /*
1647 * Open the UDP stream. We sort of cheat here and obtain the vnode so that we can perform
1648 * things that are not possible from the layered interface.
1649 */
1650 vnode_t *pVNodeUDP = NULL;
1651 vnode_t *pVNodeUDPHeld = NULL;
1652 TIUSER *pUserUDP = NULL;
1653 rc = vboxNetFltSolarisOpenDev(UDP_DEV_NAME, &pVNodeUDP, &pVNodeUDPHeld, &pUserUDP);
1654 if (RT_SUCCESS(rc))
1655 {
1656 /*
1657 * Get the multiplexor IDs.
1658 */
1659 rc = ldi_ioctl(IPDevHandle, SIOCGLIFMUXID, (intptr_t)&Interface, FKIOCTL, kcred, &ret);
1660 if (!rc)
1661 {
1662 /*
1663 * Get the multiplex file descriptor to the lower streams. Generally this is lost
1664 * once a module is I_PLINK, we need to reobtain it for inserting/removing ourselves from the stack.
1665 */
1666 int IpMuxFd;
1667 int ArpMuxFd;
1668 rc = vboxNetFltSolarisMuxIdToFd(pVNodeUDP, Interface.lifr_ip_muxid, &IpMuxFd);
1669 rc2 = vboxNetFltSolarisMuxIdToFd(pVNodeUDP, Interface.lifr_arp_muxid, &ArpMuxFd);
1670 if ( RT_SUCCESS(rc)
1671 && RT_SUCCESS(rc2))
1672 {
1673 /*
1674 * We need to I_PUNLINK on these multiplexor IDs before we can start
1675 * operating on the lower stream as insertions are direct operations on the lower stream.
1676 */
1677 int ret;
1678 rc = strioctl(pVNodeUDP, I_PUNLINK, (intptr_t)Interface.lifr_ip_muxid, 0, K_TO_K, kcred, &ret);
1679 rc2 = strioctl(pVNodeUDP, I_PUNLINK, (intptr_t)Interface.lifr_arp_muxid, 0, K_TO_K, kcred, &ret);
1680 if ( !rc
1681 && !rc2)
1682 {
1683 /*
1684 * Obtain the vnode from the useless userland file descriptor.
1685 */
1686 file_t *pIpFile = getf(IpMuxFd);
1687 file_t *pArpFile = getf(ArpMuxFd);
1688 if ( pIpFile
1689 && pArpFile
1690 && pArpFile->f_vnode
1691 && pIpFile->f_vnode)
1692 {
1693 vnode_t *pVNodeIp = pIpFile->f_vnode;
1694 vnode_t *pVNodeArp = pArpFile->f_vnode;
1695
1696 /*
1697 * Find the position on the host stack for attaching/detaching ourselves.
1698 */
1699 rc = vboxNetFltSolarisDetermineModPos(fAttach, pVNodeIp, &StrMod.pos);
1700 rc2 = vboxNetFltSolarisDetermineModPos(fAttach, pVNodeArp, &ArpStrMod.pos);
1701 if ( RT_SUCCESS(rc)
1702 && RT_SUCCESS(rc2))
1703 {
1704 /*
1705 * Set global data which will be grabbed by ModOpen.
1706 * There is a known (though very unlikely) race here because
1707 * of the inability to pass user data while inserting.
1708 */
1709 g_VBoxNetFltSolarisState.pCurInstance = pThis;
1710 g_VBoxNetFltSolarisState.CurType = kIpStream;
1711
1712 /*
1713 * Inject/Eject from the host IP stack.
1714 */
1715 rc = strioctl(pVNodeIp, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K,
1716 kcred, &ret);
1717 if (!rc)
1718 {
1719 /*
1720 * Inject/Eject from the host ARP stack.
1721 */
1722 g_VBoxNetFltSolarisState.CurType = kArpStream;
1723 rc = strioctl(pVNodeArp, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&ArpStrMod, 0, K_TO_K,
1724 kcred, &ret);
1725 if (!rc)
1726 {
1727 g_VBoxNetFltSolarisState.pCurInstance = NULL;
1728 g_VBoxNetFltSolarisState.CurType = kUndefined;
1729
1730 /*
1731 * Our job's not yet over; we need to relink the upper and lower streams
1732 * otherwise we've pretty much screwed up the host interface.
1733 */
1734 rc = vboxNetFltSolarisRelink(pVNodeUDP, &Interface, IpMuxFd, ArpMuxFd);
1735 if (RT_SUCCESS(rc))
1736 {
1737 /*
1738 * Close the devices ONLY during the return from function case; otherwise
1739 * we end up close twice which is an instant kernel panic.
1740 */
1741 vboxNetFltSolarisCloseDev(pVNodeUDPHeld, pUserUDP);
1742 ldi_close(ARPDevHandle, FREAD | FWRITE, kcred);
1743 ldi_close(IPDevHandle, FREAD | FWRITE, kcred);
1744
1745 LogFlow((DEVICE_NAME ":vboxNetFltSolarisModSetup: Success! %s %s@(Ip:%d Arp:%d) "
1746 "%s interface %s\n", fAttach ? "Injected" : "Ejected", StrMod.mod_name,
1747 StrMod.pos, ArpStrMod.pos, fAttach ? "to" : "from", pThis->szName));
1748 return VINF_SUCCESS;
1749 }
1750 else
1751 {
1752 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: Relinking failed. Mode=%s rc=%d.\n",
1753 fAttach ? "inject" : "eject", rc));
1754 }
1755
1756 /*
1757 * Try failing gracefully during attach.
1758 */
1759 if (fAttach)
1760 strioctl(pVNodeIp, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
1761 }
1762 else
1763 {
1764 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to %s the ARP stack. rc=%d\n",
1765 fAttach ? "inject into" : "eject from", rc));
1766 }
1767
1768 if (fAttach)
1769 strioctl(pVNodeIp, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
1770
1771 vboxNetFltSolarisRelink(pVNodeUDP, &Interface, IpMuxFd, ArpMuxFd);
1772 }
1773 else
1774 {
1775 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to %s the IP stack. rc=%d\n",
1776 fAttach ? "inject into" : "eject from", rc));
1777 }
1778 }
1779 else
1780 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to find position. rc=%d rc2=%d\n", rc, rc2));
1781 }
1782 else
1783 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to get vnode from MuxFd.\n"));
1784 }
1785 else
1786 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to unlink upper stream rc=%d rc2=%d.\n", rc, rc2));
1787 }
1788 else
1789 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to get MuxFd from MuxId. rc=%d rc2=%d\n"));
1790 }
1791 else
1792 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to get Mux Ids. rc=%d\n", rc));
1793 vboxNetFltSolarisCloseDev(pVNodeUDPHeld, pUserUDP);
1794 }
1795 else
1796 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: failed to open UDP. rc=%d\n", rc));
1797 }
1798 else
1799 LogRel((DEVICE_NAME ":vboxNetFltSolarisModSetup: invalid interface '%s'.\n", pThis->szName));
1800
1801 ldi_close(ARPDevHandle, FREAD | FWRITE, kcred);
1802 ldi_close(IPDevHandle, FREAD | FWRITE, kcred);
1803
1804 return VERR_INTNET_FLT_IF_FAILED;
1805}
1806
1807
1808/**
1809 * Wrapper for attaching ourselves to the interface.
1810 *
1811 * @returns VBox status code.
1812 * @param pThis The instance.
1813 * @remarks Owns the globals mutex, so re-requesting it anytime during this phase
1814 * would panic the system e.g. in vboxNetFltSolarisFindInstance).
1815 */
1816static int vboxNetFltSolarisAttachToInterface(PVBOXNETFLTINS pThis)
1817{
1818 int rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
1819 AssertRC(rc);
1820
1821 rc = vboxNetFltSolarisModSetup(pThis, true);
1822
1823 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
1824 return rc;
1825}
1826
1827
1828/**
1829 * Wrapper for detaching ourselves from the interface.
1830 *
1831 * @returns VBox status code.
1832 * @param pThis The instance.
1833 * @remarks Owns the globals mutex, so re-requesting it anytime during this phase
1834 * would panic the system (e.g. in vboxNetFltSolarisFindInstance).
1835 */
1836static int vboxNetFltSolarisDetachFromInterface(PVBOXNETFLTINS pThis)
1837{
1838 int rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
1839 AssertRC(rc);
1840
1841 rc = vboxNetFltSolarisModSetup(pThis, false);
1842
1843 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
1844 return rc;
1845}
1846
1847
1848/**
1849 * Create a solaris message block from the SG list.
1850 *
1851 * @returns Solaris message block.
1852 * @param pThis The instance.
1853 * @param pSG Pointer to the scatter-gather list.
1854 */
1855static mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
1856{
1857 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG pThis=%p pSG=%p\n"));
1858
1859 mblk_t *pMsg = allocb(pSG->cbTotal, BPRI_MED);
1860 if (RT_UNLIKELY(!pMsg))
1861 {
1862 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed to alloc %d bytes for mblk_t.\n", pSG->cbTotal));
1863 return NULL;
1864 }
1865
1866 /*
1867 * Single buffer copy. Maybe later explore the
1868 * need/possibility for using a mblk_t chain rather.
1869 */
1870 for (unsigned i = 0; i < pSG->cSegsUsed; i++)
1871 {
1872 if (pSG->aSegs[i].pv)
1873 {
1874 bcopy(pSG->aSegs[i].pv, pMsg->b_wptr, pSG->aSegs[i].cb);
1875 pMsg->b_wptr += pSG->aSegs[i].cb;
1876 }
1877 }
1878 DB_TYPE(pMsg) = M_DATA;
1879 return pMsg;
1880}
1881
1882
1883/**
1884 * Calculate the number of segments required for this message block.
1885 *
1886 * @returns Number of segments.
1887 * @param pThis The instance
1888 * @param pMsg Pointer to the data message.
1889 */
1890static unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg)
1891{
1892 unsigned cSegs = 0;
1893 for (mblk_t *pCur = pMsg; pCur; pCur = pCur->b_cont)
1894 if (MBLKL(pCur))
1895 cSegs++;
1896
1897#ifdef PADD_RUNT_FRAMES_FROM_HOST
1898 if (msgdsize(pMsg) < 60)
1899 cSegs++;
1900#endif
1901
1902 NOREF(pThis);
1903 return RT_MAX(cSegs, 1);
1904}
1905
1906
1907/**
1908 * Initializes an SG list from the given message block.
1909 *
1910 * @returns VBox status code.
1911 * @param pThis The instance.
1912 * @param pMsg Pointer to the data message.
1913 The caller must ensure it's not a control message block.
1914 * @param pSG Pointer to the SG.
1915 * @param cSegs Number of segments in the SG.
1916 * This should match the number in the message block exactly!
1917 * @param fSrc The source of the message.
1918 */
1919static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
1920{
1921 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
1922
1923 pSG->pvOwnerData = NULL;
1924 pSG->pvUserData = NULL;
1925 pSG->pvUserData2 = NULL;
1926 pSG->cUsers = 1;
1927 pSG->cbTotal = 0;
1928 pSG->fFlags = INTNETSG_FLAGS_TEMP;
1929 pSG->cSegsAlloc = cSegs;
1930
1931 /*
1932 * Convert the message block to segments.
1933 */
1934 mblk_t *pCur = pMsg;
1935 unsigned iSeg = 0;
1936 while (pCur)
1937 {
1938 size_t cbSeg = MBLKL(pCur);
1939 if (cbSeg)
1940 {
1941 void *pvSeg = pCur->b_rptr;
1942 pSG->aSegs[iSeg].pv = pvSeg;
1943 pSG->aSegs[iSeg].cb = cbSeg;
1944 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
1945 pSG->cbTotal += cbSeg;
1946 iSeg++;
1947 }
1948 pCur = pCur->b_cont;
1949 }
1950 pSG->cSegsUsed = iSeg;
1951
1952#ifdef PADD_RUNT_FRAMES_FROM_HOST
1953 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
1954 {
1955 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pulling up to length.\n"));
1956
1957 static uint8_t const s_abZero[128] = {0};
1958 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
1959 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
1960 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
1961 pSG->cbTotal = 60;
1962 pSG->cSegsUsed++;
1963 }
1964#endif
1965
1966 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
1967 return VINF_SUCCESS;
1968}
1969
1970
1971/**
1972 * Converts raw mode M_DATA messages to M_PROTO DL_UNITDATA_IND format.
1973 *
1974 * @returns VBox status code.
1975 * @param pMsg Pointer to the raw message.
1976 * @param pDlpiMsg Where to store the M_PROTO message.
1977 *
1978 * @remarks The original raw message would be no longer valid and will be
1979 * linked as part of the new DLPI message. Callers must take care
1980 * not to use the raw message if this routine is successful.
1981 */
1982static int vboxNetFltSolarisRawToUnitData(mblk_t *pMsg, mblk_t **ppDlpiMsg)
1983{
1984 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData pMsg=%p\n", pMsg));
1985
1986 if (DB_TYPE(pMsg) != M_DATA)
1987 return VERR_NO_MEMORY;
1988
1989 size_t cbMsg = sizeof(dl_unitdata_ind_t) + 2 * sizeof(vboxnetflt_dladdr_t);
1990 mblk_t *pDlpiMsg = allocb(cbMsg, BPRI_MED);
1991 if (RT_UNLIKELY(!pDlpiMsg))
1992 return VERR_NO_MEMORY;
1993
1994 DB_TYPE(pDlpiMsg) = M_PROTO;
1995 dl_unitdata_ind_t *pDlpiData = (dl_unitdata_ind_t *)pDlpiMsg->b_rptr;
1996 pDlpiData->dl_primitive = DL_UNITDATA_IND;
1997 pDlpiData->dl_dest_addr_length = VBOXNETFLT_DLADDRL;
1998 pDlpiData->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
1999 pDlpiData->dl_src_addr_length = VBOXNETFLT_DLADDRL;
2000 pDlpiData->dl_src_addr_offset = VBOXNETFLT_DLADDRL + sizeof(dl_unitdata_ind_t);
2001
2002 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
2003
2004 vboxnetflt_dladdr_t *pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_dest_addr_offset);
2005 pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
2006 bcopy(&pEthHdr->DstMac, &pDlAddr->Mac, sizeof(RTMAC));
2007
2008 pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_src_addr_offset);
2009 pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
2010 bcopy(&pEthHdr->SrcMac, &pDlAddr->Mac, sizeof(RTMAC));
2011
2012 pDlpiMsg->b_wptr = pDlpiMsg->b_rptr + cbMsg;
2013
2014 /* Make the message point to the protocol header */
2015 pMsg->b_rptr += sizeof(RTNETETHERHDR);
2016
2017 pDlpiMsg->b_cont = pMsg;
2018 *ppDlpiMsg = pDlpiMsg;
2019 return VINF_SUCCESS;
2020}
2021
2022
2023/**
2024 * Converts DLPI M_PROTO messages to the raw mode M_DATA format.
2025 *
2026 * @returns VBox status code.
2027 * @param pMsg Pointer to the M_PROTO message.
2028 * @param ppRawMsg Where to store the converted message.
2029 *
2030 * @remarks If successful, the original pMsg is no longer valid, it will be deleted.
2031 * Callers must take care not to continue to use pMsg after a successful
2032 * call to this conversion routine.
2033 */
2034static int vboxNetFltSolarisUnitDataToRaw(PVBOXNETFLTINS pThis, mblk_t *pMsg, mblk_t **ppRawMsg)
2035{
2036 LogFlow((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw pMsg=%p\n", pMsg));
2037
2038 if ( !pMsg->b_cont
2039 || DB_TYPE(pMsg) != M_PROTO)
2040 {
2041 LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw invalid input message.\n"));
2042 return VERR_NET_PROTOCOL_ERROR;
2043 }
2044
2045 /*
2046 * Upstream consumers send/receive packets in the fast path mode.
2047 * We of course need to convert them into raw ethernet frames.
2048 */
2049 RTNETETHERHDR EthHdr;
2050 union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
2051 switch (pPrim->dl_primitive)
2052 {
2053 case DL_UNITDATA_IND:
2054 {
2055 /*
2056 * Receive side.
2057 */
2058 dl_unitdata_ind_t *pDlpiMsg = (dl_unitdata_ind_t *)pMsg->b_rptr;
2059 bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
2060 bcopy(pMsg->b_rptr + pDlpiMsg->dl_src_addr_offset, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
2061
2062 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
2063 EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
2064
2065 break;
2066 }
2067
2068 case DL_UNITDATA_REQ:
2069 {
2070 /*
2071 * Send side.
2072 */
2073 dl_unitdata_req_t *pDlpiMsg = (dl_unitdata_req_t *)pMsg->b_rptr;
2074
2075 bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
2076 bcopy(&pThis->u.s.Mac, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
2077
2078 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
2079 EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
2080
2081 break;
2082 }
2083
2084 default:
2085 {
2086 LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw Unknown M_PROTO. This shouldn't be happening!!"));
2087 return VERR_NET_PROTOCOL_ERROR;
2088 }
2089 }
2090
2091 /*
2092 * Let us just link it as a mblk_t chain rather than re-copy the entire message.
2093 * The vboxNetFltSolarisMBlkToSG function will handle chained mblk_t's.
2094 */
2095 size_t cbLen = sizeof(EthHdr);
2096 mblk_t *pEtherMsg = allocb(cbLen, BPRI_MED);
2097 if (RT_UNLIKELY(!pEtherMsg))
2098 return VERR_NO_MEMORY;
2099
2100 DB_TYPE(pEtherMsg) = M_DATA;
2101 bcopy(&EthHdr, pEtherMsg->b_wptr, sizeof(EthHdr));
2102 pEtherMsg->b_wptr += cbLen;
2103
2104 pEtherMsg->b_cont = pMsg->b_cont;
2105
2106 /*
2107 * Change the chained blocks to type M_DATA.
2108 */
2109 for (mblk_t *pTmp = pEtherMsg->b_cont; pTmp; pTmp = pTmp->b_cont)
2110 DB_TYPE(pTmp) = M_DATA;
2111
2112 pMsg->b_cont = NULL;
2113 freemsg(pMsg);
2114
2115 *ppRawMsg = pEtherMsg;
2116 return VINF_SUCCESS;
2117}
2118
2119
2120/**
2121 * Worker for routing messages from the wire or from the host.
2122 *
2123 * @returns VBox status code.
2124 * @param pThis The instance.
2125 * @param pStream Pointer to the stream.
2126 * @param pQueue Pointer to the queue.
2127 * @param pOrigMsg Pointer to the message.
2128 */
2129static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pOrigMsg)
2130{
2131 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRecv pThis=%p pOrigMsg=%p\n", pThis, pOrigMsg));
2132
2133 AssertCompile(sizeof(struct ether_header) == sizeof(RTNETETHERHDR));
2134 Assert(pStream->Type == kIpStream);
2135
2136 /*
2137 * Due to the asynchronous nature of streams we may get messages before the
2138 * raw mode is turned on, in this case just pass through.
2139 */
2140 if (!pStream->fRawMode)
2141 {
2142 LogFlow((DEVICE_NAME ":IP stream not yet in raw mode. Passing through packet.\n"));
2143 putnext(pQueue, pOrigMsg);
2144 return VINF_SUCCESS;
2145 }
2146
2147 /*
2148 * Make a copy as we will alter pMsg.
2149 */
2150 mblk_t *pMsg = copymsg(pOrigMsg);
2151
2152 /*
2153 * Sort out M_PROTO and M_DATA.
2154 */
2155 bool fOriginalIsRaw = true;
2156 if (DB_TYPE(pMsg) == M_PROTO)
2157 {
2158 fOriginalIsRaw = false;
2159 mblk_t *pRawMsg;
2160 int rc = vboxNetFltSolarisUnitDataToRaw(pThis, pMsg, &pRawMsg);
2161 if (RT_SUCCESS(rc))
2162 pMsg = pRawMsg;
2163 else
2164 {
2165 freemsg(pMsg);
2166 LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv invalid message!\n"));
2167 return VERR_GENERAL_FAILURE;
2168 }
2169 }
2170
2171 /*
2172 * Figure out the source of the packet based on the source Mac address.
2173 */
2174 /** @todo Is there a more fool-proof way to determine if the packet was indeed sent from the host?? */
2175 uint32_t fSrc = INTNETTRUNKDIR_WIRE;
2176 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
2177 if (vboxNetFltPortOsIsHostMac(pThis, &pEthHdr->SrcMac))
2178 fSrc = INTNETTRUNKDIR_HOST;
2179
2180 bool fChecksumAdjusted = false;
2181#if 1
2182 if (fSrc & INTNETTRUNKDIR_HOST)
2183 {
2184 mblk_t *pCorrectedMsg = vboxNetFltSolarisFixChecksums(pMsg);
2185 if (pCorrectedMsg)
2186 {
2187 fChecksumAdjusted = true;
2188 pMsg = pCorrectedMsg;
2189 }
2190 }
2191#endif
2192
2193 /*
2194 * Route all received packets into the internal network.
2195 */
2196 unsigned cSegs = vboxNetFltSolarisMBlkCalcSGSegs(pThis, pMsg);
2197 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
2198 int rc = vboxNetFltSolarisMBlkToSG(pThis, pMsg, pSG, cSegs, fSrc);
2199 if (RT_FAILURE(rc))
2200 {
2201 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG failed. rc=%d\n", rc));
2202 return rc;
2203 }
2204
2205 bool fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc);
2206
2207 /*
2208 * Drop messages consumed by the internal network.
2209 */
2210 if (fDropIt)
2211 {
2212 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRecv Packet consumed by internal network.\n"));
2213 freemsg(pOrigMsg);
2214 freemsg(pMsg);
2215 }
2216 else
2217 {
2218 /*
2219 * Packets from the host, push them up in raw mode.
2220 * Packets from the wire, we must push them in their original form
2221 * as upstream consumers expect this format.
2222 */
2223 if (fSrc & INTNETTRUNKDIR_HOST)
2224 {
2225 /* Raw packets with correct checksums, pass-through the original */
2226 if ( fOriginalIsRaw
2227 && !fChecksumAdjusted)
2228 {
2229 putnext(pQueue, pOrigMsg);
2230 }
2231 else /* For M_PROTO packets or checksum corrected raw packets, pass-through the raw */
2232 {
2233 putnext(pQueue, pMsg);
2234 pMsg = pOrigMsg; /* for the freemsg that follows */
2235 }
2236 }
2237 else /* INTNETTRUNKDIR_WIRE */
2238 {
2239 if (fOriginalIsRaw)
2240 pOrigMsg->b_rptr += sizeof(RTNETETHERHDR);
2241
2242 putnext(pQueue, pOrigMsg);
2243 }
2244
2245 freemsg(pMsg);
2246 }
2247
2248 return VINF_SUCCESS;
2249}
2250
2251
2252/**
2253 * Find the PVBOXNETFLTINS associated with a stream.
2254 *
2255 * @returns PVBOXNETFLTINS instance, or NULL if there's none.
2256 * @param pStream Pointer to the stream to search for.
2257 */
2258static PVBOXNETFLTINS vboxNetFltSolarisFindInstance(vboxnetflt_stream_t *pStream)
2259{
2260 if (!pStream)
2261 return NULL;
2262
2263 vboxnetflt_stream_t *pCur = g_VBoxNetFltSolarisState.pOpenedStreams;
2264 for (; pCur; pCur = pCur->pNext)
2265 if (pCur == pStream)
2266 return pCur->pThis;
2267
2268 return NULL;
2269}
2270
2271
2272/**
2273 * Finalize the message to be fed into the internal network.
2274 * Verifies and tries to fix checksums for TCP, UDP and IP.
2275 *
2276 * @returns Corrected message or NULL if no change was required.
2277 * @param pMsg Pointer to the message block.
2278 * This must not be DLPI linked messages, must be M_DATA.
2279 *
2280 * @remarks If this function returns a checksum adjusted message, the
2281 * passed in input message has been freed and should not be
2282 * referenced anymore by the caller.
2283 */
2284static mblk_t *vboxNetFltSolarisFixChecksums(mblk_t *pMsg)
2285{
2286 LogFlow((DEVICE_NAME ":vboxNetFltSolarisFixChecksums pMsg=%p\n"));
2287
2288 Assert(DB_TYPE(pMsg) == M_DATA);
2289
2290 if (MBLKL(pMsg) < sizeof(RTNETETHERHDR))
2291 {
2292 LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums Packet shorter than ethernet header size!\n"));
2293 return NULL;
2294 }
2295
2296 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
2297 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
2298 {
2299 /*
2300 * Check if we have a complete packet or being fed a chain.
2301 */
2302 size_t cbIpPacket = 0;
2303 mblk_t *pFullMsg = NULL;
2304 if (pMsg->b_cont)
2305 {
2306 LogFlow((DEVICE_NAME ":Chained mblk_t.\n"));
2307
2308 /*
2309 * Handle chain by making a packet copy to verify if the IP checksum is correct.
2310 * Contributions to calculating IP checksums from a chained message block with
2311 * odd/non-pulled up sizes are welcome.
2312 */
2313 size_t cbFullMsg = msgdsize(pMsg);
2314 mblk_t *pFullMsg = allocb(cbFullMsg, BPRI_MED);
2315 LogFlow((DEVICE_NAME ":msgdsize returns %d\n", cbFullMsg));
2316 if (RT_UNLIKELY(!pFullMsg))
2317 {
2318 LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums failed to alloc new message of %d bytes.\n", cbFullMsg));
2319 return false;
2320 }
2321
2322 for (mblk_t *pTmp = pMsg; pTmp; pTmp = pTmp->b_cont)
2323 {
2324 if (DB_TYPE(pTmp) == M_DATA)
2325 {
2326 bcopy(pTmp->b_rptr, pFullMsg->b_wptr, MBLKL(pTmp));
2327 pFullMsg->b_wptr += MBLKL(pTmp);
2328 }
2329 else
2330 LogFlow((DEVICE_NAME ":Not M_DATA.. this is really bad.\n"));
2331 }
2332
2333 DB_TYPE(pFullMsg) = M_DATA;
2334 pEthHdr = (PRTNETETHERHDR)pFullMsg->b_rptr;
2335 cbIpPacket = MBLKL(pFullMsg) - sizeof(RTNETETHERHDR);
2336 }
2337 else
2338 cbIpPacket = MBLKL(pMsg) - sizeof(RTNETETHERHDR);
2339
2340 /*
2341 * Check if the IP checksum is valid.
2342 */
2343 PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
2344 if (!RTNetIPv4IsHdrValid(pIpHdr, cbIpPacket, cbIpPacket))
2345 {
2346 LogFlow((DEVICE_NAME ":Invalid IP checksum detected. Trying to fix...\n"));
2347
2348 /*
2349 * Fix up TCP/UDP and IP checksums if they're incomplete/invalid.
2350 */
2351 if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
2352 {
2353 size_t cbTcpPacket = cbIpPacket - (pIpHdr->ip_hl << 2);
2354
2355 PRTNETTCP pTcpHdr = (PRTNETTCP)(pIpHdr + 1);
2356 if (!RTNetIPv4IsTCPValid(pIpHdr, pTcpHdr, cbTcpPacket, NULL, cbTcpPacket))
2357 {
2358 RTNetIPv4TCPChecksum(pIpHdr, pTcpHdr, NULL);
2359 LogFlow((DEVICE_NAME ":fixed TCP checkum.\n"));
2360 }
2361 else
2362 LogFlow((DEVICE_NAME ":valid TCP checksum invalid IP checksum...\n"));
2363 }
2364 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
2365 {
2366 size_t cbUdpPacket = cbIpPacket - (pIpHdr->ip_hl << 2);
2367
2368 PRTNETUDP pUdpHdr = (PRTNETUDP)(pIpHdr + 1);
2369 RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1);
2370
2371 LogFlow((DEVICE_NAME ":fixed UDP checksum.\n"));
2372 }
2373 else
2374 {
2375 LogFlow((DEVICE_NAME ":Non TCP/UDP protocol with invalid IP header!\n"));
2376 }
2377
2378 RTNetIPv4HdrChecksum(pIpHdr);
2379 LogFlow((DEVICE_NAME ":fixed IP checkum.\n"));
2380
2381 /*
2382 * If we made a copy and the checksum is corrected on the copy,
2383 * free the original, return the checksum fixed copy.
2384 */
2385 if (pFullMsg)
2386 {
2387 freemsg(pMsg);
2388 return pFullMsg;
2389 }
2390
2391 return pMsg;
2392 }
2393
2394 /*
2395 * If we made a copy and the checksum is NOT corrected, free the copy,
2396 * and return NULL.
2397 */
2398 if (pFullMsg)
2399 freemsg(pFullMsg);
2400 }
2401
2402 return NULL;
2403}
2404
2405
2406/**
2407 * Simple packet dump, used for internal debugging.
2408 *
2409 * @param pMsg Pointer to the message to analyze and dump.
2410 */
2411static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg)
2412{
2413 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAnalyzeMBlk pMsg=%p\n"));
2414
2415 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
2416 uint8_t *pb = pMsg->b_rptr;
2417 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
2418 {
2419 PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
2420 size_t cbLen = MBLKL(pMsg) - sizeof(*pEthHdr);
2421 if (RTNetIPv4IsHdrValid(pIpHdr, cbLen, cbLen))
2422 {
2423 if (pIpHdr->ip_p == RTNETIPV4_PROT_ICMP)
2424 LogFlow((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
2425 else if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
2426 LogFlow((DEVICE_NAME ":TCP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
2427 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
2428 LogFlow((DEVICE_NAME ":UDP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
2429 }
2430 else if (!pMsg->b_cont)
2431 {
2432 LogFlow((DEVICE_NAME ":Invalid IP header.\n"));
2433 }
2434 else
2435 {
2436 LogFlow((DEVICE_NAME ":Chained IP packet. Skipped validity check.\n"));
2437 }
2438 }
2439 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
2440 {
2441 PRTNETARPHDR pArpHdr = (PRTNETARPHDR)(pEthHdr + 1);
2442 LogFlow((DEVICE_NAME ":ARP Op=%d\n", pArpHdr->ar_oper));
2443 }
2444 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
2445 {
2446 LogFlow((DEVICE_NAME ":IPv6 D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
2447 }
2448 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_1)
2449 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_2)
2450 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_3))
2451 {
2452 LogFlow((DEVICE_NAME ":IPX packet.\n"));
2453 }
2454 else
2455 {
2456 LogFlow((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
2457 &pEthHdr->SrcMac));
2458 /* LogFlow((DEVICE_NAME ":%.*Vhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
2459 }
2460}
2461
2462
2463/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
2464bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
2465{
2466 vboxnetflt_stream_t *pStream = pThis->u.s.pvStream;
2467 if (pStream)
2468 return pStream->fPromisc;
2469
2470 LogRel((DEVICE_NAME ":vboxNetFltPortOsIsPromiscuous stream not found!!\n"));
2471 return false;
2472}
2473
2474
2475void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
2476{
2477 LogFlow((DEVICE_NAME ":vboxNetFltPortOsGetMacAddress pThis=%p\n", pThis));
2478
2479 RTMAC EmptyMac;
2480 bzero(&EmptyMac, sizeof(EmptyMac));
2481 if (!bcmp(&pThis->u.s.Mac, &EmptyMac, sizeof(EmptyMac))) /* This should never happen... */
2482 {
2483 /* Bummer, Mac address is not copied yet. */
2484 LogRel((DEVICE_NAME ":vboxNetFltPortOsGetMacAddress: Mac address not cached yet!\n"));
2485 return;
2486 }
2487
2488 *pMac = pThis->u.s.Mac;
2489}
2490
2491
2492bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
2493{
2494 /*
2495 * MAC address change acknowledgements are intercepted on the read side
2496 * hence theoritically we are always update to date with any changes.
2497 */
2498 return pThis->u.s.Mac.au16[0] == pMac->au16[0]
2499 && pThis->u.s.Mac.au16[1] == pMac->au16[1]
2500 && pThis->u.s.Mac.au16[2] == pMac->au16[2];
2501}
2502
2503
2504void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
2505{
2506 LogFlow((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d\n", pThis, fActive));
2507
2508 /*
2509 * Enable/disable promiscuous mode.
2510 */
2511 vboxnetflt_stream_t *pStream = pThis->u.s.pvStream;
2512 if (pStream)
2513 {
2514 int rc = vboxNetFltSolarisPromiscReq(pStream->pReadQueue, fActive);
2515 if (RT_FAILURE(rc))
2516 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive failed to request promiscuous mode! rc=%d\n", rc));
2517 }
2518 else
2519 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive stream not found!\n"));
2520}
2521
2522
2523int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
2524{
2525 /* Nothing to do here. */
2526 return VINF_SUCCESS;
2527}
2528
2529
2530int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
2531{
2532 /* Nothing to do here. */
2533 return VINF_SUCCESS;
2534}
2535
2536
2537void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
2538{
2539 LogFlow((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n"));
2540 vboxNetFltSolarisDetachFromInterface(pThis);
2541}
2542
2543
2544int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis)
2545{
2546 LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p\n"));
2547 return vboxNetFltSolarisAttachToInterface(pThis);
2548}
2549
2550
2551int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
2552{
2553 /*
2554 * Init. the solaris specific data.
2555 */
2556 pThis->u.s.pvStream = NULL;
2557 pThis->u.s.pvArpStream = NULL;
2558 bzero(&pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
2559 return VINF_SUCCESS;
2560}
2561
2562
2563bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
2564{
2565 /*
2566 * We don't support interface rediscovery on Solaris hosts because the
2567 * filter is very tightly bound to the stream.
2568 */
2569 return false;
2570}
2571
2572
2573int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
2574{
2575 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p pSG=%p fDst=%d\n", pThis, pSG, fDst));
2576
2577 vboxnetflt_stream_t *pStream = pThis->u.s.pvStream;
2578 queue_t *pReadQueue = pStream->pReadQueue;
2579 queue_t *pWriteQueue = WR(pReadQueue);
2580
2581 /*
2582 * Create a message block and send it down the wire (downstream).
2583 */
2584 if (fDst & INTNETTRUNKDIR_WIRE)
2585 {
2586 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
2587 if (RT_UNLIKELY(!pMsg))
2588 {
2589 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
2590 return VERR_NO_MEMORY;
2591 }
2592
2593 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_WIRE\n", pMsg));
2594 putnext(pWriteQueue, pMsg);
2595 }
2596
2597 /*
2598 * Create a message block and send it up the host stack (upstream).
2599 */
2600 if (fDst & INTNETTRUNKDIR_HOST)
2601 {
2602 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
2603 if (RT_UNLIKELY(!pMsg))
2604 {
2605 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
2606 return VERR_NO_MEMORY;
2607 }
2608
2609 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
2610 bool fArp = (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP));
2611
2612 /*
2613 * Construct a DL_UNITDATA_IND style message.
2614 */
2615 mblk_t *pDlpiMsg;
2616 int rc = vboxNetFltSolarisRawToUnitData(pMsg, &pDlpiMsg);
2617 if (RT_FAILURE(rc))
2618 {
2619 LogRel((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData failed! rc=%d\n", rc));
2620 freemsg(pMsg);
2621 return VERR_NO_MEMORY;
2622 }
2623 pMsg = pDlpiMsg;
2624
2625 if (fArp)
2626 {
2627 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST ARP\n"));
2628
2629 /*
2630 * Send message up ARP stream.
2631 */
2632 vboxnetflt_stream_t *pArpStream = pThis->u.s.pvArpStream;
2633 queue_t *pArpReadQueue = pArpStream->pReadQueue;
2634 putnext(pArpReadQueue, pMsg);
2635 }
2636 else
2637 {
2638 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST\n"));
2639
2640 /*
2641 * Send messages up IP stream.
2642 */
2643 putnext(pReadQueue, pMsg);
2644 }
2645 }
2646
2647 return VINF_SUCCESS;
2648}
2649
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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