VirtualBox

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

Last change on this file since 12209 was 12209, checked in by vboxsync, 16 years ago

Solaris/vboxnetflt: No rediscovery.

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

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