VirtualBox

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

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

Solaris/vboxdrv/vboxflt: Fixed incorrect return value on failure on _init.

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

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