VirtualBox

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

Last change on this file since 62745 was 62490, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 139.7 KB
Line 
1/* $Id: VBoxNetFlt-solaris.c 62490 2016-07-22 18:41:49Z vboxsync $ */
2/** @file
3 * VBoxNetFlt - Network Filter Driver (Host), Solaris Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008-2016 Oracle Corporation
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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
32#include <VBox/log.h>
33#include <VBox/err.h>
34#include <VBox/intnetinline.h>
35#include <VBox/version.h>
36#include <iprt/string.h>
37#include <iprt/initterm.h>
38#include <iprt/assert.h>
39#include <iprt/alloca.h>
40#include <iprt/net.h>
41#include <iprt/mem.h>
42#include <iprt/thread.h>
43#include <iprt/spinlock.h>
44#include <iprt/crc.h>
45#include <iprt/err.h>
46#include <iprt/ctype.h>
47#define VBOXNETFLT_SOLARIS_IPV6_POLLING
48#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
49# include <iprt/timer.h>
50# include <iprt/time.h>
51#endif
52
53#include <inet/ip.h>
54#include <net/if.h>
55#include <sys/socket.h>
56#include <sys/kstr.h>
57#include <sys/file.h>
58#include <sys/sockio.h>
59#include <sys/strsubr.h>
60#include <sys/pathname.h>
61#include <sys/t_kuser.h>
62
63#include <sys/types.h>
64#include <sys/dlpi.h>
65#include <sys/types.h>
66#include <sys/time.h>
67#include <sys/param.h>
68#include <sys/ethernet.h>
69#include <sys/stat.h>
70#include <sys/stream.h>
71#include <sys/stropts.h>
72#include <sys/strsun.h>
73#include <sys/modctl.h>
74#include <sys/ddi.h>
75#include <sys/sunddi.h>
76#include <sys/sunldi.h>
77#include <sys/ctf_api.h>
78
79// Workaround for very strange define in sys/user.h
80// #define u (curproc->p_user) /* user is now part of proc structure */
81#ifdef u
82#undef u
83#endif
84
85#define VBOXNETFLT_OS_SPECFIC 1
86#include "../VBoxNetFltInternal.h"
87
88
89/*********************************************************************************************************************************
90* Defined Constants And Macros *
91*********************************************************************************************************************************/
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#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
99/** Driver properties */
100# define VBOXNETFLT_IP6POLLINTERVAL "ipv6-pollinterval"
101#endif
102
103/** Maximum loopback packet queue size per interface */
104#define VBOXNETFLT_LOOPBACK_SIZE 32
105
106/** VLAN tag masking, should probably be in IPRT? */
107#define VLAN_ID(vlan) (((vlan) >> 0) & 0x0fffu)
108#define VLAN_CFI(vlan) (((vlan) >> 12) & 0x0001u)
109#define VLAN_PRI(vlan) (((vlan) >> 13) & 0x0007u)
110#define VLAN_TAG(pri,cfi,vid) (((pri) << 13) | ((cfi) << 12) | ((vid) << 0))
111
112typedef struct VLANHEADER
113{
114 uint16_t Type;
115 uint16_t Data;
116} VLANHEADER;
117typedef struct VLANHEADER *PVLANHEADER;
118
119
120/*********************************************************************************************************************************
121* Global Functions *
122*********************************************************************************************************************************/
123/**
124 * Stream Driver hooks.
125 */
126static int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppvResult);
127static int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
128static int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
129static int VBoxNetFltSolarisQuiesceNotNeeded(dev_info_t *pDip);
130
131/**
132 * Stream Module hooks.
133 */
134static int VBoxNetFltSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fFile, int fStream, cred_t *pCred);
135static int VBoxNetFltSolarisModClose(queue_t *pQueue, int fFile, cred_t *pCred);
136static int VBoxNetFltSolarisModReadPut(queue_t *pQueue, mblk_t *pMsg);
137static int VBoxNetFltSolarisModWritePut(queue_t *pQueue, mblk_t *pMsg);
138
139
140/*********************************************************************************************************************************
141* Structures and Typedefs *
142*********************************************************************************************************************************/
143/**
144 * Streams: module info.
145 */
146static struct module_info g_VBoxNetFltSolarisModInfo =
147{
148 0xbad, /* module id */
149 DEVICE_NAME,
150 0, /* min. packet size */
151 INFPSZ, /* max. packet size */
152 0, /* hi-water mark */
153 0 /* lo-water mark */
154};
155
156/**
157 * Streams: read queue hooks.
158 */
159static struct qinit g_VBoxNetFltSolarisReadQ =
160{
161 VBoxNetFltSolarisModReadPut,
162 NULL, /* service */
163 VBoxNetFltSolarisModOpen,
164 VBoxNetFltSolarisModClose,
165 NULL, /* admin (reserved) */
166 &g_VBoxNetFltSolarisModInfo,
167 NULL /* module stats */
168};
169
170/**
171 * Streams: write queue hooks.
172 */
173static struct qinit g_VBoxNetFltSolarisWriteQ =
174{
175 VBoxNetFltSolarisModWritePut,
176 NULL, /* service */
177 NULL, /* open */
178 NULL, /* close */
179 NULL, /* admin (reserved) */
180 &g_VBoxNetFltSolarisModInfo,
181 NULL /* module stats */
182};
183
184/**
185 * Streams: IO stream tab.
186 */
187static struct streamtab g_VBoxNetFltSolarisStreamTab =
188{
189 &g_VBoxNetFltSolarisReadQ,
190 &g_VBoxNetFltSolarisWriteQ,
191 NULL, /* muxread init */
192 NULL /* muxwrite init */
193};
194
195/**
196 * cb_ops: driver char/block entry points
197 */
198static struct cb_ops g_VBoxNetFltSolarisCbOps =
199{
200 nulldev, /* cb open */
201 nulldev, /* cb close */
202 nodev, /* b strategy */
203 nodev, /* b dump */
204 nodev, /* b print */
205 nodev, /* cb read */
206 nodev, /* cb write */
207 nodev, /* cb ioctl */
208 nodev, /* c devmap */
209 nodev, /* c mmap */
210 nodev, /* c segmap */
211 nochpoll, /* c poll */
212 ddi_prop_op, /* property ops */
213 &g_VBoxNetFltSolarisStreamTab,
214 D_NEW | D_MP | D_MTQPAIR | D_MTOUTPERIM | D_MTOCEXCL, /* compat. flag */
215 CB_REV /* revision */
216};
217
218/**
219 * dev_ops: driver entry/exit and other ops.
220 */
221static struct dev_ops g_VBoxNetFltSolarisDevOps =
222{
223 DEVO_REV, /* driver build revision */
224 0, /* ref count */
225 VBoxNetFltSolarisGetInfo,
226 nulldev, /* identify */
227 nulldev, /* probe */
228 VBoxNetFltSolarisAttach,
229 VBoxNetFltSolarisDetach,
230 nodev, /* reset */
231 &g_VBoxNetFltSolarisCbOps,
232 (struct bus_ops *)0,
233 nodev, /* power */
234 VBoxNetFltSolarisQuiesceNotNeeded
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" RT_XSTR(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 | D_MTOUTPERIM | D_MTOCEXCL
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" RT_XSTR(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 {
274 &g_VBoxNetFltSolarisDriver, /* streams driver framework */
275 &g_VBoxNetFltSolarisModule, /* streams module framework */
276 NULL /* terminate array of linkage structures */
277 }
278};
279
280struct vboxnetflt_state_t;
281
282/**
283 * vboxnetflt_dladdr_t: DL SAP address format
284 */
285typedef struct vboxnetflt_dladdr_t
286{
287 ether_addr_t Mac;
288 uint16_t SAP;
289} vboxnetflt_dladdr_t;
290
291#define VBOXNETFLT_DLADDRL sizeof(vboxnetflt_dladdr_t)
292
293/**
294 * which stream is this?
295 */
296typedef enum VBOXNETFLTSTREAMTYPE
297{
298 kUndefined = 0,
299 kIp4Stream = 0x1b,
300 kIp6Stream = 0xcc,
301 kArpStream = 0xab,
302 kPromiscStream = 0xdf
303} VBOXNETFLTSTREAMTYPE;
304
305/**
306 * loopback packet identifier
307 */
308typedef struct VBOXNETFLTPACKETID
309{
310 struct VBOXNETFLTPACKETID *pNext;
311 uint16_t cbPacket;
312 uint16_t Checksum;
313 RTMAC SrcMac;
314 RTMAC DstMac;
315} VBOXNETFLTPACKETID;
316typedef struct VBOXNETFLTPACKETID *PVBOXNETFLTPACKETID;
317
318/**
319 * vboxnetflt_stream_t: per-stream data (multiple streams per interface)
320 */
321typedef struct vboxnetflt_stream_t
322{
323 int DevMinor; /* minor device no. (for clone) */
324 queue_t *pReadQueue; /* read side queue */
325 struct vboxnetflt_stream_t *pNext; /* next stream in list */
326 PVBOXNETFLTINS volatile pThis; /* the backend instance */
327 VBOXNETFLTSTREAMTYPE Type; /* the type of the stream */
328} vboxnetflt_stream_t;
329
330/**
331 * vboxnetflt_promisc_stream_t: per-interface dedicated stream data
332 */
333typedef struct vboxnetflt_promisc_stream_t
334{
335 vboxnetflt_stream_t Stream; /* dedicated/promiscuous stream */
336 bool fPromisc; /* cached promiscuous value */
337 bool fRawMode; /* whether raw mode request was successful */
338 uint32_t ModeReqId; /* track MIOCTLs for swallowing our fake request acknowledgements */
339#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
340 PRTTIMER pIp6Timer; /* ipv6 stream poll timer for dynamic ipv6 stream attachment */
341#endif
342 size_t cLoopback; /* loopback queue size list */
343 timeout_id_t volatile TimeoutId; /* timeout id of promisc. req */
344 PVBOXNETFLTPACKETID pHead; /* loopback packet identifier head */
345 PVBOXNETFLTPACKETID pTail; /* loopback packet identifier tail */
346} vboxnetflt_promisc_stream_t;
347
348typedef struct vboxnetflt_promisc_params_t
349{
350 PVBOXNETFLTINS pThis; /* the backend instance */
351 bool fPromiscOn; /* whether promiscuous req. on or off */
352} vboxnetflt_promisc_params_t;
353
354
355/*********************************************************************************************************************************
356* Internal Functions *
357*********************************************************************************************************************************/
358static int vboxNetFltSolarisSetRawMode(vboxnetflt_promisc_stream_t *pPromiscStream);
359/* static int vboxNetFltSolarisSetFastMode(queue_t *pQueue); */
360
361static int vboxNetFltSolarisPhysAddrReq(queue_t *pQueue);
362static void vboxNetFltSolarisCachePhysAddr(PVBOXNETFLTINS pThis, mblk_t *pPhysAddrAckMsg);
363static int vboxNetFltSolarisBindReq(queue_t *pQueue, int SAP);
364static int vboxNetFltSolarisNotifyReq(queue_t *pQueue);
365
366/* static int vboxNetFltSolarisUnitDataToRaw(PVBOXNETFLTINS pThis, mblk_t *pMsg, mblk_t **ppRawMsg); */
367static int vboxNetFltSolarisRawToUnitData(mblk_t *pMsg, mblk_t **ppDlpiMsg);
368
369static inline void vboxNetFltSolarisInitPacketId(PVBOXNETFLTPACKETID pTag, mblk_t *pMsg);
370static int vboxNetFltSolarisQueueLoopback(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg);
371static bool vboxNetFltSolarisIsOurMBlk(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg);
372
373static mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst);
374static unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg);
375static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc);
376static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pMsg);
377/* static mblk_t *vboxNetFltSolarisFixChecksums(mblk_t *pMsg); */
378/* static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg); */
379
380
381/*********************************************************************************************************************************
382* Global Variables *
383*********************************************************************************************************************************/
384/** Global device info handle. */
385static dev_info_t *g_pVBoxNetFltSolarisDip = NULL;
386
387/** The (common) global data. */
388static VBOXNETFLTGLOBALS g_VBoxNetFltSolarisGlobals;
389
390/** The list of all opened streams. */
391vboxnetflt_stream_t *g_VBoxNetFltSolarisStreams = NULL;
392
393/** Global mutex protecting open/close. */
394static RTSEMFASTMUTEX g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
395
396/** Global credentials using during open/close. */
397static cred_t *g_pVBoxNetFltSolarisCred = NULL;
398
399/**
400 * g_VBoxNetFltInstance is the current PVBOXNETFLTINS to be associated with the stream being created
401 * in ModOpen. This is just shared global data between the dynamic attach and the ModOpen procedure.
402 */
403PVBOXNETFLTINS volatile g_VBoxNetFltSolarisInstance = NULL;
404
405/** Goes along with the instance to determine type of stream being opened/created. */
406VBOXNETFLTSTREAMTYPE volatile g_VBoxNetFltSolarisStreamType = kUndefined;
407
408#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
409/** Global IPv6 polling interval */
410static int g_VBoxNetFltSolarisPollInterval = -1;
411#endif
412
413static int s_off_vnode = -1;
414#define VNODE_FOR_FILE_T(filetpointer) (*(struct vnode **)((char *)(filetpointer) + s_off_vnode))
415
416
417static int
418vboxNetFltSolarisCtfGetMemberOffset(ctf_file_t *pCtfFile, const char *pszStruct, const char *pszMember, int *pOffset)
419{
420 AssertReturn(pCtfFile, VERR_INVALID_PARAMETER);
421 AssertReturn(pszStruct, VERR_INVALID_PARAMETER);
422 AssertReturn(pszMember, VERR_INVALID_PARAMETER);
423 AssertReturn(pOffset, VERR_INVALID_PARAMETER);
424
425 ctf_id_t TypeId = ctf_lookup_by_name(pCtfFile, pszStruct);
426 if (TypeId != CTF_ERR)
427 {
428 ctf_membinfo_t MemberInfo;
429 bzero(&MemberInfo, sizeof(MemberInfo));
430 if (ctf_member_info(pCtfFile, TypeId, pszMember, &MemberInfo) != CTF_ERR)
431 {
432 *pOffset = (MemberInfo.ctm_offset >> 3);
433 LogRel((DEVICE_NAME ":%s::%s at %d\n", pszStruct, pszMember, *pOffset));
434 return VINF_SUCCESS;
435 }
436 else
437 LogRel((DEVICE_NAME ":ctf_member_info failed for struct %s member %s\n", pszStruct, pszMember));
438 }
439 else
440 LogRel((DEVICE_NAME ":ctf_lookup_by_name failed for struct %s\n", pszStruct));
441
442 return VERR_NOT_FOUND;
443}
444
445
446static int
447vboxNetFltSolarisProbeCtf(void)
448{
449 /*
450 * CTF probing for fluid f_vnode member in file_t.
451 */
452 int rc = VERR_INTERNAL_ERROR;
453 modctl_t *pModCtl = mod_hold_by_name("genunix");
454 if (pModCtl)
455 {
456 int err;
457 mutex_enter(&mod_lock);
458 ctf_file_t *pCtfFile = ctf_modopen(pModCtl->mod_mp, &err);
459 mutex_exit(&mod_lock);
460 if (pCtfFile)
461 {
462 rc = vboxNetFltSolarisCtfGetMemberOffset(pCtfFile, "file_t", "f_vnode", &s_off_vnode);
463 ctf_close(pCtfFile);
464 }
465 else
466 LogRel((DEVICE_NAME ":ctf_modopen failed. err=%d\n", err));
467
468 mod_release_mod(pModCtl);
469 }
470 else
471 LogRel((DEVICE_NAME ":mod_hold_by_name failed.\n"));
472
473 return rc;
474}
475
476
477/**
478 * Kernel entry points
479 */
480int _init(void)
481{
482 LogFunc((DEVICE_NAME ":_init\n"));
483
484 /*
485 * Prevent module autounloading.
486 */
487 modctl_t *pModCtl = mod_getctl(&g_VBoxNetFltSolarisModLinkage);
488 if (pModCtl)
489 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
490 else
491 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
492
493 /*
494 * Initialize IPRT.
495 */
496 int rc = RTR0Init(0);
497 if (RT_SUCCESS(rc))
498 {
499 rc = vboxNetFltSolarisProbeCtf();
500 if (RT_SUCCESS(rc))
501 {
502 /*
503 * Initialize Solaris specific globals here.
504 */
505 g_VBoxNetFltSolarisStreams = NULL;
506 g_VBoxNetFltSolarisInstance = NULL;
507 g_pVBoxNetFltSolarisCred = crdup(kcred);
508 if (RT_LIKELY(g_pVBoxNetFltSolarisCred))
509 {
510 rc = RTSemFastMutexCreate(&g_VBoxNetFltSolarisMtx);
511 if (RT_SUCCESS(rc))
512 {
513 /*
514 * Initialize the globals and connect to the support driver.
515 *
516 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
517 * for establishing the connect to the support driver.
518 */
519 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
520 rc = vboxNetFltInitGlobalsAndIdc(&g_VBoxNetFltSolarisGlobals);
521 if (RT_SUCCESS(rc))
522 {
523 rc = mod_install(&g_VBoxNetFltSolarisModLinkage);
524 if (!rc)
525 return rc;
526
527 LogRel((DEVICE_NAME ":mod_install failed. rc=%d\n", rc));
528 vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltSolarisGlobals);
529 }
530 else
531 LogRel((DEVICE_NAME ":failed to initialize globals.\n"));
532
533 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
534 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
535 }
536 }
537 else
538 {
539 LogRel((DEVICE_NAME ":failed to allocate credentials.\n"));
540 rc = VERR_NO_MEMORY;
541 }
542 }
543 else
544 LogRel((DEVICE_NAME ":vboxNetFltSolarisProbeCtf failed. rc=%d\n", rc));
545
546 RTR0Term();
547 }
548 else
549 LogRel((DEVICE_NAME ":failed to initialize IPRT (rc=%d)\n", rc));
550
551 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
552 return RTErrConvertToErrno(rc);
553}
554
555
556int _fini(void)
557{
558 int rc;
559 LogFunc((DEVICE_NAME ":_fini\n"));
560
561 /*
562 * Undo the work done during start (in reverse order).
563 */
564 rc = vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltSolarisGlobals);
565 if (RT_FAILURE(rc))
566 {
567 LogRel((DEVICE_NAME ":_fini - busy!\n"));
568 return EBUSY;
569 }
570
571 rc = mod_remove(&g_VBoxNetFltSolarisModLinkage);
572 if (!rc)
573 {
574 if (g_pVBoxNetFltSolarisCred)
575 {
576 crfree(g_pVBoxNetFltSolarisCred);
577 g_pVBoxNetFltSolarisCred = NULL;
578 }
579
580 if (g_VBoxNetFltSolarisMtx != NIL_RTSEMFASTMUTEX)
581 {
582 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
583 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
584 }
585
586 RTR0Term();
587 }
588
589 return rc;
590}
591
592
593int _info(struct modinfo *pModInfo)
594{
595 LogFunc((DEVICE_NAME ":_info\n"));
596
597 int rc = mod_info(&g_VBoxNetFltSolarisModLinkage, pModInfo);
598
599 Log((DEVICE_NAME ":_info returns %d\n", rc));
600 return rc;
601}
602
603
604/**
605 * Attach entry point, to attach a device to the system or resume it.
606 *
607 * @param pDip The module structure instance.
608 * @param enmCmd Operation type (attach/resume).
609 *
610 * @returns corresponding solaris error code.
611 */
612static int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
613{
614 LogFunc((DEVICE_NAME ":VBoxNetFltSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
615
616 switch (enmCmd)
617 {
618 case DDI_ATTACH:
619 {
620 int instance = ddi_get_instance(pDip);
621 int rc = ddi_create_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, CLONE_DEV);
622 if (rc == DDI_SUCCESS)
623 {
624 g_pVBoxNetFltSolarisDip = pDip;
625#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
626 /*
627 * Get the user prop. for polling interval.
628 */
629 int Interval = ddi_getprop(DDI_DEV_T_ANY, pDip, DDI_PROP_DONTPASS, VBOXNETFLT_IP6POLLINTERVAL, -1 /* default */);
630 if (Interval == -1)
631 Log((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: no poll interval property specified. Skipping Ipv6 polling.\n"));
632 else if (Interval < 1 || Interval > 120)
633 {
634 LogRel((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Invalid polling interval %d. Expected between 1 and 120 secs.\n",
635 Interval));
636 Interval = -1;
637 }
638
639 g_VBoxNetFltSolarisPollInterval = Interval;
640#endif
641 ddi_report_dev(pDip);
642 return DDI_SUCCESS;
643 }
644 else
645 LogRel((DEVICE_NAME ":VBoxNetFltSolarisAttach failed to create minor node. rc%d\n", rc));
646 return DDI_FAILURE;
647 }
648
649 case DDI_RESUME:
650 {
651 /* Nothing to do here... */
652 return DDI_SUCCESS;
653 }
654
655 /* case DDI_PM_RESUME: */
656 default:
657 return DDI_FAILURE;
658 }
659}
660
661
662/**
663 * Detach entry point, to detach a device to the system or suspend it.
664 *
665 * @param pDip The module structure instance.
666 * @param enmCmd Operation type (detach/suspend).
667 *
668 * @returns corresponding solaris error code.
669 */
670static int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
671{
672 LogFunc((DEVICE_NAME ":VBoxNetFltSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
673
674 switch (enmCmd)
675 {
676 case DDI_DETACH:
677 {
678 ddi_remove_minor_node(pDip, NULL);
679 return DDI_SUCCESS;
680 }
681
682 case DDI_RESUME:
683 {
684 /* Nothing to do here... */
685 return DDI_SUCCESS;
686 }
687
688 /* case DDI_PM_SUSPEND: */
689 /* case DDI_HOT_PLUG_DETACH: */
690 default:
691 return DDI_FAILURE;
692 }
693}
694
695
696/**
697 * Quiesce not-needed entry point, as Solaris 10 doesn't have any
698 * ddi_quiesce_not_needed() function.
699 *
700 * @param pDip The module structure instance.
701 *
702 * @return corresponding solaris error code.
703 */
704static int VBoxNetFltSolarisQuiesceNotNeeded(dev_info_t *pDip)
705{
706 return DDI_SUCCESS;
707}
708
709
710/**
711 * Info entry point, called by solaris kernel for obtaining driver info.
712 *
713 * @param pDip The module structure instance (do not use).
714 * @param enmCmd Information request type.
715 * @param pvArg Type specific argument.
716 * @param ppvResult Where to store the requested info.
717 *
718 * @returns corresponding solaris error code.
719 */
720static int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppvResult)
721{
722 LogFunc((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd,
723 getminor((dev_t)pvArg)));
724
725 switch (enmCmd)
726 {
727 case DDI_INFO_DEVT2DEVINFO:
728 {
729 *ppvResult = g_pVBoxNetFltSolarisDip;
730 return DDI_SUCCESS;
731 }
732
733 case DDI_INFO_DEVT2INSTANCE:
734 {
735 int instance = getminor((dev_t)pvArg);
736 *ppvResult = (void *)(uintptr_t)instance;
737 return DDI_SUCCESS;
738 }
739 }
740
741 return DDI_FAILURE;
742}
743
744
745/**
746 * Stream module open entry point, initializes the queue and allows streams processing.
747 *
748 * @param pQueue Pointer to the read queue (cannot be NULL).
749 * @param pDev Pointer to the dev_t associated with the driver at the end of the stream.
750 * @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
751 * @param fStreamMode Stream open mode.
752 * @param pCred Pointer to user credentials.
753 *
754 * @returns corresponding solaris error code.
755 */
756static int VBoxNetFltSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fOpenMode, int fStreamMode, cred_t *pCred)
757{
758 Assert(pQueue);
759
760 LogFunc((DEVICE_NAME ":VBoxNetFltSolarisModOpen pQueue=%p pDev=%p fOpenMode=%d fStreamMode=%d\n", pQueue, pDev,
761 fOpenMode, fStreamMode));
762
763 /*
764 * Already open?
765 */
766 if (pQueue->q_ptr)
767 {
768 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen invalid open.\n"));
769 return ENOENT;
770 }
771
772 /*
773 * Check that the request was initiated by our code.
774 *
775 * This ASSUMES that crdup() will return a copy with a unique address and
776 * not do any kind of clever pooling. This check will when combined with
777 * g_VBoxNetFltSolarisMtx prevent races and that the instance gets
778 * associated with the wrong streams.
779 */
780 if (pCred != g_pVBoxNetFltSolarisCred)
781 {
782 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen invalid credentials.\n"));
783 return EACCES;
784 }
785
786 /*
787 * Check for the VirtualBox instance.
788 */
789 PVBOXNETFLTINS pThis = g_VBoxNetFltSolarisInstance;
790 if (!pThis)
791 {
792 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to get VirtualBox instance.\n"));
793 return ENOENT;
794 }
795
796 /*
797 * Check VirtualBox stream type.
798 */
799 if ( g_VBoxNetFltSolarisStreamType != kPromiscStream
800 && g_VBoxNetFltSolarisStreamType != kArpStream
801 && g_VBoxNetFltSolarisStreamType != kIp6Stream
802 && g_VBoxNetFltSolarisStreamType != kIp4Stream)
803 {
804 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed due to undefined VirtualBox open mode. Type=%d\n",
805 g_VBoxNetFltSolarisStreamType));
806 return ENOENT;
807 }
808
809 /*
810 * Get minor number. For clone opens provide a new dev_t.
811 */
812 minor_t DevMinor = 0;
813 vboxnetflt_stream_t *pStream = NULL;
814 vboxnetflt_stream_t **ppPrevStream = &g_VBoxNetFltSolarisStreams;
815 if (fStreamMode == CLONEOPEN)
816 {
817 for (; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
818 {
819 if (DevMinor < pStream->DevMinor)
820 break;
821 DevMinor++;
822 }
823 *pDev = makedevice(getmajor(*pDev), DevMinor);
824 }
825 else
826 DevMinor = getminor(*pDev);
827
828 if (g_VBoxNetFltSolarisStreamType == kPromiscStream)
829 {
830 vboxnetflt_promisc_stream_t *pPromiscStream = RTMemAlloc(sizeof(vboxnetflt_promisc_stream_t));
831 if (RT_UNLIKELY(!pPromiscStream))
832 {
833 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to allocate promiscuous stream data.\n"));
834 return ENOMEM;
835 }
836
837 pPromiscStream->fPromisc = false;
838 pPromiscStream->fRawMode = false;
839 pPromiscStream->ModeReqId = 0;
840 pPromiscStream->pHead = NULL;
841 pPromiscStream->pTail = NULL;
842 pPromiscStream->cLoopback = 0;
843 pPromiscStream->TimeoutId = 0;
844#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
845 pPromiscStream->pIp6Timer = NULL;
846#endif
847 pStream = (vboxnetflt_stream_t *)pPromiscStream;
848 }
849 else
850 {
851 /*
852 * Allocate & initialize per-stream data. Hook it into the (read and write) queue's module specific data.
853 */
854 pStream = RTMemAlloc(sizeof(vboxnetflt_stream_t));
855 if (RT_UNLIKELY(!pStream))
856 {
857 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to allocate stream data.\n"));
858 return ENOMEM;
859 }
860 }
861 pStream->DevMinor = DevMinor;
862 pStream->pReadQueue = pQueue;
863
864 /*
865 * Pick up the current global VBOXNETFLTINS instance as
866 * the one that we will associate this stream with.
867 */
868 ASMAtomicUoWritePtr(&pStream->pThis, pThis);
869 pStream->Type = g_VBoxNetFltSolarisStreamType;
870 switch (pStream->Type)
871 {
872 case kIp4Stream: ASMAtomicUoWritePtr((void**)&pThis->u.s.pIp4Stream, pStream); break;
873 case kIp6Stream: ASMAtomicUoWritePtr((void**)&pThis->u.s.pIp6Stream, pStream); break;
874 case kArpStream: ASMAtomicUoWritePtr((void**)&pThis->u.s.pArpStream, pStream); break;
875 case kPromiscStream: ASMAtomicUoWritePtr((void**)&pThis->u.s.pPromiscStream, pStream); break;
876 default: /* Heh. */
877 {
878 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen huh!? Invalid stream type %d\n", pStream->Type));
879 RTMemFree(pStream);
880 return EINVAL;
881 }
882 }
883
884 pQueue->q_ptr = pStream;
885 WR(pQueue)->q_ptr = pStream;
886
887 /*
888 * Link it to the list of streams.
889 */
890 pStream->pNext = *ppPrevStream;
891 *ppPrevStream = pStream;
892
893 /*
894 * Increment IntNet reference count for this stream.
895 */
896 vboxNetFltRetain(pThis, false /* fBusy */);
897
898 qprocson(pQueue);
899
900 /*
901 * Don't hold the spinlocks across putnext calls as it could
902 * (and does mostly) re-enter the put procedure on the same thread.
903 */
904 if (pStream->Type == kPromiscStream)
905 {
906 vboxnetflt_promisc_stream_t *pPromiscStream = (vboxnetflt_promisc_stream_t *)pStream;
907
908 /*
909 * Bind to SAP 0 (DL_ETHER).
910 * Note: We don't support DL_TPR (token passing ring) SAP as that is unnecessary asynchronous
911 * work to get DL_INFO_REQ acknowledgements and determine SAP based on the Mac Type etc.
912 * Besides TPR doesn't really exist anymore practically as far as I know.
913 */
914 int rc = vboxNetFltSolarisBindReq(pStream->pReadQueue, 0 /* SAP */);
915 if (RT_LIKELY(RT_SUCCESS(rc)))
916 {
917 /*
918 * Request the physical address (we cache the acknowledgement).
919 */
920 rc = vboxNetFltSolarisPhysAddrReq(pStream->pReadQueue);
921 if (RT_LIKELY(RT_SUCCESS(rc)))
922 {
923 /*
924 * Ask for DLPI link notifications, don't bother check for errors here.
925 */
926 vboxNetFltSolarisNotifyReq(pStream->pReadQueue);
927
928 /*
929 * Enable raw mode.
930 */
931 rc = vboxNetFltSolarisSetRawMode(pPromiscStream);
932 if (RT_FAILURE(rc))
933 LogRel((DEVICE_NAME ":vboxNetFltSolarisSetRawMode failed rc=%Rrc.\n", rc));
934 }
935 else
936 LogRel((DEVICE_NAME ":vboxNetFltSolarisSetRawMode failed rc=%Rrc.\n", rc));
937 }
938 else
939 LogRel((DEVICE_NAME ":vboxNetFltSolarisBindReq failed rc=%Rrc.\n", rc));
940 }
941
942 NOREF(fOpenMode);
943
944 Log((DEVICE_NAME ":VBoxNetFltSolarisModOpen returns 0, DevMinor=%d pQueue=%p\n", DevMinor, pStream->pReadQueue));
945
946 return 0;
947}
948
949
950/**
951 * Stream module close entry point, undoes the work done on open and closes the stream.
952 *
953 * @param pQueue Pointer to the read queue (cannot be NULL).
954 * @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
955 * @param pCred Pointer to user credentials.
956 *
957 * @returns corresponding solaris error code.
958 */
959static int VBoxNetFltSolarisModClose(queue_t *pQueue, int fOpenMode, cred_t *pCred)
960{
961 Assert(pQueue);
962
963 LogFunc((DEVICE_NAME ":VBoxNetFltSolarisModClose pQueue=%p fOpenMode=%d\n", pQueue, fOpenMode));
964
965 vboxnetflt_stream_t *pStream = NULL;
966 vboxnetflt_stream_t **ppPrevStream = NULL;
967
968 /*
969 * Get instance data.
970 */
971 pStream = (vboxnetflt_stream_t *)pQueue->q_ptr;
972 if (RT_UNLIKELY(!pStream))
973 {
974 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModClose failed to get stream.\n"));
975 return ENXIO;
976 }
977
978 if (pStream->Type == kPromiscStream)
979 {
980 /*
981 * If there are any timeout scheduled, we need to make sure they are cancelled.
982 */
983 vboxnetflt_promisc_stream_t *pPromiscStream = (vboxnetflt_promisc_stream_t *)pStream;
984 timeout_id_t TimeoutId = ASMAtomicReadPtr(&pPromiscStream->TimeoutId);
985 if (TimeoutId)
986 {
987 quntimeout(WR(pPromiscStream->Stream.pReadQueue), TimeoutId);
988 ASMAtomicWritePtr(&pPromiscStream->TimeoutId, NULL);
989 }
990
991 flushq(pQueue, FLUSHALL);
992 flushq(WR(pQueue), FLUSHALL);
993 }
994
995 qprocsoff(pQueue);
996
997 if (pStream->Type == kPromiscStream)
998 {
999 vboxnetflt_promisc_stream_t *pPromiscStream = (vboxnetflt_promisc_stream_t *)pStream;
1000
1001 mutex_enter(&pStream->pThis->u.s.hMtx);
1002
1003 /*
1004 * Free-up loopback buffers.
1005 */
1006 PVBOXNETFLTPACKETID pCur = pPromiscStream->pHead;
1007 while (pCur)
1008 {
1009 PVBOXNETFLTPACKETID pNext = pCur->pNext;
1010 RTMemFree(pCur);
1011 pCur = pNext;
1012 }
1013 pPromiscStream->pHead = NULL;
1014 pPromiscStream->pTail = NULL;
1015 pPromiscStream->cLoopback = 0;
1016
1017#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
1018 /*
1019 * Sheer paranoia.
1020 */
1021 if (pPromiscStream->pIp6Timer != NULL)
1022 {
1023 RTTimerStop(pPromiscStream->pIp6Timer);
1024 RTTimerDestroy(pPromiscStream->pIp6Timer);
1025 ASMAtomicUoWriteNullPtr(&pPromiscStream->pIp6Timer);
1026 }
1027#endif
1028
1029 mutex_exit(&pStream->pThis->u.s.hMtx);
1030 }
1031
1032 /*
1033 * Unlink it from the list of streams.
1034 */
1035 for (ppPrevStream = &g_VBoxNetFltSolarisStreams; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
1036 if (pStream == (vboxnetflt_stream_t *)pQueue->q_ptr)
1037 break;
1038 *ppPrevStream = pStream->pNext;
1039
1040 /*
1041 * Delete the stream.
1042 */
1043 switch (pStream->Type)
1044 {
1045 case kIp4Stream: ASMAtomicUoWriteNullPtr(&pStream->pThis->u.s.pIp4Stream); break;
1046 case kIp6Stream: ASMAtomicUoWriteNullPtr(&pStream->pThis->u.s.pIp6Stream); break;
1047 case kArpStream: ASMAtomicUoWriteNullPtr(&pStream->pThis->u.s.pArpStream); break;
1048 case kPromiscStream: ASMAtomicUoWriteNullPtr(&pStream->pThis->u.s.pPromiscStream); break;
1049 default: /* Heh. */
1050 {
1051 AssertRelease(pStream->Type);
1052 break;
1053 }
1054 }
1055
1056 /*
1057 * Decrement IntNet reference count for this stream.
1058 */
1059 vboxNetFltRelease(pStream->pThis, false /* fBusy */);
1060
1061 RTMemFree(pStream);
1062 pQueue->q_ptr = NULL;
1063 WR(pQueue)->q_ptr = NULL;
1064
1065 NOREF(fOpenMode);
1066 NOREF(pCred);
1067
1068 return 0;
1069}
1070
1071
1072/**
1073 * Read side put procedure for processing messages in the read queue.
1074 * All streams, bound and unbound share this read procedure.
1075 *
1076 * @param pQueue Pointer to the read queue.
1077 * @param pMsg Pointer to the message.
1078 *
1079 * @returns corresponding solaris error code.
1080 */
1081static int VBoxNetFltSolarisModReadPut(queue_t *pQueue, mblk_t *pMsg)
1082{
1083 if (!pMsg)
1084 return 0;
1085
1086 LogFunc((DEVICE_NAME ":VBoxNetFltSolarisModReadPut pQueue=%p pMsg=%p\n", pQueue, pMsg));
1087
1088 bool fSendUpstream = true;
1089 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
1090 PVBOXNETFLTINS pThis = NULL;
1091
1092 /*
1093 * In the unlikely case where VirtualBox crashed and this filter
1094 * is somehow still in the host stream we must try not to panic the host.
1095 */
1096 if ( pStream
1097 && pStream->Type == kPromiscStream)
1098 {
1099 fSendUpstream = false;
1100 pThis = ASMAtomicUoReadPtrT(&pStream->pThis, PVBOXNETFLTINS);
1101 if (RT_LIKELY(pThis))
1102 {
1103 /*
1104 * Retain the instance if we're filtering regardless of we are active or not
1105 * The reason being even when we are inactive we reference the instance (e.g
1106 * the promiscuous OFF acknowledgement case).
1107 */
1108 RTSpinlockAcquire(pThis->hSpinlock);
1109 const bool fActive = pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE;
1110 vboxNetFltRetain(pThis, true /* fBusy */);
1111 RTSpinlockRelease(pThis->hSpinlock);
1112
1113 vboxnetflt_promisc_stream_t *pPromiscStream = (vboxnetflt_promisc_stream_t *)pStream;
1114
1115 switch (DB_TYPE(pMsg))
1116 {
1117 case M_DATA:
1118 {
1119 Log((DEVICE_NAME ":VBoxNetFltSolarisModReadPut M_DATA\n"));
1120
1121 if ( fActive
1122 && pPromiscStream->fRawMode)
1123 {
1124 vboxNetFltSolarisRecv(pThis, pStream, pQueue, pMsg);
1125 }
1126 break;
1127 }
1128
1129 case M_PROTO:
1130 case M_PCPROTO:
1131 {
1132 union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
1133 t_uscalar_t Prim = pPrim->dl_primitive;
1134
1135 Log((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO %d\n", Prim));
1136 switch (Prim)
1137 {
1138 case DL_NOTIFY_IND:
1139 {
1140 if (MBLKL(pMsg) < DL_NOTIFY_IND_SIZE)
1141 {
1142 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Invalid notification size; expected>=%d"
1143 " got=%d\n", DL_NOTIFY_IND_SIZE, MBLKL(pMsg)));
1144 break;
1145 }
1146
1147 dl_notify_ind_t *pNotifyInd = (dl_notify_ind_t *)pMsg->b_rptr;
1148 switch (pNotifyInd->dl_notification)
1149 {
1150 case DL_NOTE_PHYS_ADDR:
1151 {
1152 if (pNotifyInd->dl_data != DL_CURR_PHYS_ADDR)
1153 break;
1154
1155 size_t cOffset = pNotifyInd->dl_addr_offset;
1156 size_t cbAddr = pNotifyInd->dl_addr_length;
1157
1158 if (!cOffset || !cbAddr)
1159 {
1160 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_PHYS_ADDR."
1161 "Invalid offset/addr.\n"));
1162 fSendUpstream = false;
1163 break;
1164 }
1165
1166 bcopy(pMsg->b_rptr + cOffset, &pThis->u.s.MacAddr, sizeof(pThis->u.s.MacAddr));
1167 Log((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_PHYS_ADDR. New Mac=%.*Rhxs\n",
1168 sizeof(pThis->u.s.MacAddr), &pThis->u.s.MacAddr));
1169 break;
1170 }
1171
1172 case DL_NOTE_LINK_UP:
1173 {
1174 if (ASMAtomicXchgBool(&pThis->fDisconnectedFromHost, false))
1175 Log((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_LINK_UP.\n"));
1176 break;
1177 }
1178
1179 case DL_NOTE_LINK_DOWN:
1180 {
1181 if (!ASMAtomicXchgBool(&pThis->fDisconnectedFromHost, true))
1182 Log((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_LINK_DOWN.\n"));
1183 break;
1184 }
1185 }
1186 break;
1187 }
1188
1189 case DL_BIND_ACK:
1190 {
1191 /*
1192 * Swallow our bind request acknowledgement.
1193 */
1194 Log((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_BIND_ACK. Bound to requested SAP!\n"));
1195 break;
1196 }
1197
1198 case DL_PHYS_ADDR_ACK:
1199 {
1200 /*
1201 * Swallow our physical address request acknowledgement.
1202 */
1203 vboxNetFltSolarisCachePhysAddr(pThis, pMsg);
1204 break;
1205 }
1206
1207 case DL_OK_ACK:
1208 {
1209 /*
1210 * Swallow our fake promiscuous request acknowledgement.
1211 */
1212 dl_ok_ack_t *pOkAck = (dl_ok_ack_t *)pMsg->b_rptr;
1213 if (pOkAck->dl_correct_primitive == DL_PROMISCON_REQ)
1214 {
1215 Log((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO: DL_OK_ACK: fPromisc is ON.\n"));
1216 pPromiscStream->fPromisc = true;
1217 }
1218 else if (pOkAck->dl_correct_primitive == DL_PROMISCOFF_REQ)
1219 {
1220 Log((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO: DL_OK_ACK: fPromisc is OFF.\n"));
1221 pPromiscStream->fPromisc = false;
1222 }
1223 break;
1224 }
1225 }
1226 break;
1227 }
1228
1229 case M_IOCACK:
1230 {
1231 /*
1232 * Swallow our fake raw/fast path mode request acknowledgement.
1233 */
1234 struct iocblk *pIOC = (struct iocblk *)pMsg->b_rptr;
1235 if (pIOC->ioc_id == pPromiscStream->ModeReqId)
1236 {
1237 pPromiscStream->fRawMode = true;
1238 Log((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Mode acknowledgement. RawMode is %s\n",
1239 pPromiscStream->fRawMode ? "ON" : "OFF"));
1240 }
1241 break;
1242 }
1243
1244 case M_IOCNAK:
1245 {
1246 /*
1247 * Swallow our fake raw/fast path mode request not acknowledged.
1248 */
1249 struct iocblk *pIOC = (struct iocblk *)pMsg->b_rptr;
1250 if (pIOC->ioc_id == pPromiscStream->ModeReqId)
1251 {
1252 pPromiscStream->fRawMode = false;
1253 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: WARNING! Mode not acknowledged. RawMode is %s\n",
1254 pPromiscStream->fRawMode ? "ON" : "OFF"));
1255 }
1256 break;
1257 }
1258
1259 case M_FLUSH:
1260 {
1261 /*
1262 * We must support flushing queues.
1263 */
1264 Log((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_FLUSH\n"));
1265 if (*pMsg->b_rptr & FLUSHR)
1266 flushq(pQueue, FLUSHALL);
1267 break;
1268 }
1269 }
1270
1271 vboxNetFltRelease(pThis, true /* fBusy */);
1272 }
1273 else
1274 LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Could not find VirtualBox instance!!\n"));
1275 }
1276
1277 if (fSendUpstream)
1278 {
1279 /*
1280 * Don't queue up things here, can cause bad things to happen when the system
1281 * is under heavy loads and we need to jam across high priority messages which
1282 * if it's not done properly will end up in an infinite loop.
1283 */
1284 putnext(pQueue, pMsg);
1285 }
1286 else
1287 {
1288 /*
1289 * We need to free up the message if we don't pass it through.
1290 */
1291 freemsg(pMsg);
1292 }
1293
1294 return 0;
1295}
1296
1297
1298/**
1299 * Write side put procedure for processing messages in the write queue.
1300 * All streams, bound and unbound share this write procedure.
1301 *
1302 * @param pQueue Pointer to the write queue.
1303 * @param pMsg Pointer to the message.
1304 *
1305 * @returns corresponding solaris error code.
1306 */
1307static int VBoxNetFltSolarisModWritePut(queue_t *pQueue, mblk_t *pMsg)
1308{
1309 LogFunc((DEVICE_NAME ":VBoxNetFltSolarisModWritePut pQueue=%p pMsg=%p\n", pQueue, pMsg));
1310
1311 putnext(pQueue, pMsg);
1312 return 0;
1313}
1314
1315
1316/**
1317 * Put the stream in raw mode.
1318 *
1319 * @returns VBox status code.
1320 * @param pPromiscStream Pointer to the read queue.
1321 */
1322static int vboxNetFltSolarisSetRawMode(vboxnetflt_promisc_stream_t *pPromiscStream)
1323{
1324 LogFunc((DEVICE_NAME ":vboxNetFltSolarisSetRawMode pPromiscStream=%p\n", pPromiscStream));
1325
1326 mblk_t *pRawMsg = NULL;
1327 pRawMsg = mkiocb(DLIOCRAW);
1328 if (RT_UNLIKELY(!pRawMsg))
1329 return VERR_NO_MEMORY;
1330
1331 queue_t *pQueue = pPromiscStream->Stream.pReadQueue;
1332 if (!pQueue)
1333 return VERR_INVALID_POINTER;
1334
1335 struct iocblk *pIOC = (struct iocblk *)pRawMsg->b_rptr;
1336 pPromiscStream->ModeReqId = pIOC->ioc_id;
1337 pIOC->ioc_count = 0;
1338
1339 qreply(pQueue, pRawMsg);
1340 return VINF_SUCCESS;
1341}
1342
1343
1344#if 0
1345/**
1346 * Put the stream back in fast path mode.
1347 *
1348 * @returns VBox status code.
1349 * @param pQueue Pointer to the read queue.
1350 */
1351static int vboxNetFltSolarisSetFastMode(queue_t *pQueue)
1352{
1353 LogFunc((DEVICE_NAME ":vboxNetFltSolarisSetFastMode pQueue=%p\n", pQueue));
1354
1355 mblk_t *pFastMsg = mkiocb(DL_IOC_HDR_INFO);
1356 if (RT_UNLIKELY(!pFastMsg))
1357 return VERR_NO_MEMORY;
1358
1359 vboxnetflt_stream_t *pStream = pQueue->q_ptr;
1360 struct iocblk *pIOC = (struct iocblk *)pFastMsg->b_rptr;
1361 pStream->ModeReqId = pIOC->ioc_id;
1362
1363 size_t cbReq = sizeof(dl_unitdata_req_t) + sizeof(vboxnetflt_dladdr_t);
1364 mblk_t *pDataReqMsg = allocb(cbReq, BPRI_MED);
1365 if (RT_UNLIKELY(!pDataReqMsg))
1366 return VERR_NO_MEMORY;
1367
1368 DB_TYPE(pDataReqMsg) = M_PROTO;
1369 dl_unitdata_req_t *pDataReq = (dl_unitdata_req_t *)pDataReqMsg->b_rptr;
1370 pDataReq->dl_primitive = DL_UNITDATA_REQ;
1371 pDataReq->dl_dest_addr_length = sizeof(vboxnetflt_dladdr_t);
1372 pDataReq->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
1373 pDataReq->dl_priority.dl_min = 0;
1374 pDataReq->dl_priority.dl_max = 0;
1375
1376 bzero(pDataReqMsg->b_rptr + sizeof(dl_unitdata_req_t), sizeof(vboxnetflt_dladdr_t));
1377 pDataReqMsg->b_wptr = pDataReqMsg->b_rptr + cbReq;
1378
1379 /*
1380 * Link the data format request message into the header ioctl message.
1381 */
1382 pFastMsg->b_cont = pDataReqMsg;
1383 pIOC->ioc_count = msgdsize(pDataReqMsg);
1384
1385 qreply(pQueue, pFastMsg);
1386 return VINF_SUCCESS;
1387}
1388#endif
1389
1390
1391/**
1392 * Callback function for qwriter to send promiscuous request messages
1393 * downstream.
1394 *
1395 * @param pQueue Pointer to the write queue.
1396 * @param fPromisc Whether to send promiscuous ON or OFF requests.
1397 *
1398 * @returns VBox status code.
1399 */
1400static int vboxNetFltSolarisPromiscReq(queue_t *pQueue, bool fPromisc)
1401{
1402 LogFunc((DEVICE_NAME ":vboxNetFltSolarisPromiscReq pQueue=%p fPromisc=%d\n", pQueue, fPromisc));
1403
1404 t_uscalar_t Cmd;
1405 size_t cbReq = 0;
1406 if (fPromisc)
1407 {
1408 Cmd = DL_PROMISCON_REQ;
1409 cbReq = DL_PROMISCON_REQ_SIZE;
1410 }
1411 else
1412 {
1413 Cmd = DL_PROMISCOFF_REQ;
1414 cbReq = DL_PROMISCOFF_REQ_SIZE;
1415 }
1416
1417 mblk_t *pPromiscPhysMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1418 if (RT_UNLIKELY(!pPromiscPhysMsg))
1419 return VERR_NO_MEMORY;
1420
1421 mblk_t *pPromiscSapMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1422 if (RT_UNLIKELY(!pPromiscSapMsg))
1423 {
1424 freemsg(pPromiscPhysMsg);
1425 return VERR_NO_MEMORY;
1426 }
1427
1428 if (fPromisc)
1429 {
1430 ((dl_promiscon_req_t *)pPromiscPhysMsg->b_rptr)->dl_level = DL_PROMISC_PHYS;
1431 ((dl_promiscon_req_t *)pPromiscSapMsg->b_rptr)->dl_level = DL_PROMISC_SAP;
1432 }
1433 else
1434 {
1435 ((dl_promiscoff_req_t *)pPromiscPhysMsg->b_rptr)->dl_level = DL_PROMISC_PHYS;
1436 ((dl_promiscoff_req_t *)pPromiscSapMsg->b_rptr)->dl_level = DL_PROMISC_SAP;
1437 }
1438
1439 putnext(pQueue, pPromiscPhysMsg);
1440 putnext(pQueue, pPromiscSapMsg);
1441
1442 return VINF_SUCCESS;
1443}
1444
1445
1446/**
1447 * Callback wrapper for qwriter() to safely send promiscuous requests. This is
1448 * called at the outer perimeter with exclusive lock held.
1449 *
1450 * @param pQueue Pointer to the write queue.
1451 * @param pMsg A one byte message indicates a Promisc ON, otherwise
1452 * a promiscuous OFF request. See
1453 * vboxNetFltSolarisPromiscReqWrap().
1454 */
1455static void vboxNetFltSolarisPromiscReqWrapExcl(queue_t *pQueue, mblk_t *pMsg)
1456{
1457 /*
1458 * Paranoia.
1459 */
1460 AssertReturnVoid(pQueue);
1461 if (RT_UNLIKELY(!pMsg))
1462 LogRel((DEVICE_NAME ":VBoxNetFltSolarisPromiscReqWrapExcl pQueue=%p missing message!\n", pQueue));
1463
1464 bool fPromisc = (MBLKL(pMsg) == 1);
1465 freemsg(pMsg);
1466 pMsg = NULL;
1467 int rc = vboxNetFltSolarisPromiscReq(pQueue, fPromisc);
1468 if (RT_FAILURE(rc))
1469 LogRel((DEVICE_NAME ":VBoxNetFltSolarisPromiscReqWrapExcl vboxNetFltSolarisPromiscReq failed. rc=%d\n", rc));
1470}
1471
1472
1473/**
1474 * Callback wrapper for qtimeout() to safely send promiscuous requests. This is
1475 * called at the inner perimeter with shared lock.
1476 *
1477 * @param pvData Pointer to vboxnetflt_promisc_params_t. See
1478 * vboxNetFltPortOsSetActive().
1479 */
1480static void vboxNetFltSolarisPromiscReqWrap(void *pvData)
1481{
1482 vboxnetflt_promisc_params_t *pParams = pvData;
1483 if (RT_LIKELY(pParams))
1484 {
1485 PVBOXNETFLTINS pThis = pParams->pThis;
1486 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream,
1487 vboxnetflt_promisc_stream_t *);
1488 if ( pPromiscStream
1489 && pPromiscStream->Stream.pReadQueue)
1490 {
1491 /*
1492 * Use size of message to indicate to qwriter callback whether it must send
1493 * promiscuous On or Off messages. This is ugly but easier and more efficient than
1494 * scheduling two separate qwriter callbacks with prepared messages to putnext.
1495 */
1496 size_t cbMsg = pParams->fPromiscOn ? 1 : 2;
1497 mblk_t *pMsg = allocb(cbMsg, BPRI_HI);
1498 if (RT_UNLIKELY(!pMsg))
1499 {
1500 LogRel((DEVICE_NAME ":Failed to alloc message of %u bytes\n", cbMsg));
1501 return;
1502 }
1503
1504 /*
1505 * Move the data pointer so we can use MBLKL, as MBLKSIZE gets the db_lim which is
1506 * always aligned.
1507 */
1508 pMsg->b_wptr += cbMsg;
1509
1510 /*
1511 * Upgrade inner perimeter lock to exclusive outer perimeter lock and
1512 * then call putnext while we are at the outer perimeter.
1513 */
1514 qwriter(WR(pPromiscStream->Stream.pReadQueue), pMsg, vboxNetFltSolarisPromiscReqWrapExcl, PERIM_OUTER);
1515 ASMAtomicWritePtr(&pPromiscStream->TimeoutId, NULL);
1516 }
1517 RTMemFree(pParams);
1518 }
1519}
1520
1521
1522/**
1523 * Send a fake physical address request downstream.
1524 *
1525 * @returns VBox status code.
1526 * @param pQueue Pointer to the read queue.
1527 */
1528static int vboxNetFltSolarisPhysAddrReq(queue_t *pQueue)
1529{
1530 LogFunc((DEVICE_NAME ":vboxNetFltSolarisPhysAddrReq pQueue=%p\n", pQueue));
1531
1532 t_uscalar_t Cmd = DL_PHYS_ADDR_REQ;
1533 size_t cbReq = DL_PHYS_ADDR_REQ_SIZE;
1534 mblk_t *pPhysAddrMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
1535 if (RT_UNLIKELY(!pPhysAddrMsg))
1536 return VERR_NO_MEMORY;
1537
1538 dl_phys_addr_req_t *pPhysAddrReq = (dl_phys_addr_req_t *)pPhysAddrMsg->b_rptr;
1539 pPhysAddrReq->dl_addr_type = DL_CURR_PHYS_ADDR;
1540
1541 qreply(pQueue, pPhysAddrMsg);
1542 return VINF_SUCCESS;
1543}
1544
1545
1546/**
1547 * Cache the MAC address into the VirtualBox instance given a physical
1548 * address acknowledgement message.
1549 *
1550 * @param pThis The instance.
1551 * @param pMsg Pointer to the physical address acknowledgement message.
1552 */
1553static void vboxNetFltSolarisCachePhysAddr(PVBOXNETFLTINS pThis, mblk_t *pMsg)
1554{
1555 LogFunc((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr pThis=%p pMsg=%p\n", pThis, pMsg));
1556
1557 AssertCompile(sizeof(RTMAC) == ETHERADDRL);
1558 dl_phys_addr_ack_t *pPhysAddrAck = (dl_phys_addr_ack_t *)pMsg->b_rptr;
1559 if (pPhysAddrAck->dl_addr_length == sizeof(pThis->u.s.MacAddr))
1560 {
1561 bcopy(pMsg->b_rptr + pPhysAddrAck->dl_addr_offset, &pThis->u.s.MacAddr, sizeof(pThis->u.s.MacAddr));
1562
1563 Log((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr: DL_PHYS_ADDR_ACK: Mac=%.*Rhxs\n",
1564 sizeof(pThis->u.s.MacAddr), &pThis->u.s.MacAddr));
1565
1566 if (vboxNetFltTryRetainBusyNotDisconnected(pThis))
1567 {
1568 Assert(pThis->pSwitchPort);
1569 if (pThis->pSwitchPort)
1570 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
1571 vboxNetFltRelease(pThis, true /*fBusy*/);
1572 }
1573 }
1574 else
1575 {
1576 LogRel((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr: Invalid address size. expected=%d got=%d\n", ETHERADDRL,
1577 pPhysAddrAck->dl_addr_length));
1578 }
1579}
1580
1581
1582/**
1583 * Prepare DLPI bind request to a SAP.
1584 *
1585 * @returns VBox status code.
1586 * @param pQueue Pointer to the read queue.
1587 * @param SAP The SAP to bind the stream to.
1588 */
1589static int vboxNetFltSolarisBindReq(queue_t *pQueue, int SAP)
1590{
1591 LogFunc((DEVICE_NAME ":vboxNetFltSolarisBindReq SAP=%d\n", SAP));
1592
1593 mblk_t *pBindMsg = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ);
1594 if (RT_UNLIKELY(!pBindMsg))
1595 return VERR_NO_MEMORY;
1596
1597 dl_bind_req_t *pBindReq = (dl_bind_req_t *)pBindMsg->b_rptr;
1598 pBindReq->dl_sap = SAP;
1599 pBindReq->dl_max_conind = 0;
1600 pBindReq->dl_conn_mgmt = 0;
1601 pBindReq->dl_xidtest_flg = 0;
1602 pBindReq->dl_service_mode = DL_CLDLS;
1603
1604 qreply(pQueue, pBindMsg);
1605 return VINF_SUCCESS;
1606}
1607
1608
1609/**
1610 * Prepare DLPI notifications request.
1611 *
1612 * @returns VBox status code.
1613 * @param pQueue Pointer to the read queue.
1614 */
1615static int vboxNetFltSolarisNotifyReq(queue_t *pQueue)
1616{
1617 LogFunc((DEVICE_NAME ":vboxNetFltSolarisNotifyReq\n"));
1618
1619 mblk_t *pNotifyMsg = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, DL_NOTIFY_REQ);
1620 if (RT_UNLIKELY(!pNotifyMsg))
1621 return VERR_NO_MEMORY;
1622
1623 dl_notify_req_t *pNotifyReq = (dl_notify_req_t *)pNotifyMsg->b_rptr;
1624 pNotifyReq->dl_notifications = DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_PHYS_ADDR;
1625
1626 qreply(pQueue, pNotifyMsg);
1627 return VINF_SUCCESS;
1628}
1629
1630
1631/**
1632 * Opens the required device and returns the vnode_t associated with it.
1633 * We require this for the funny attach/detach routine.
1634 *
1635 * @returns VBox status code.
1636 * @param pszDev The device path.
1637 * @param ppVNode Where to store the vnode_t pointer associated with the opened device.
1638 * @param ppVNodeHeld Where to store the vnode_t required during closing of the device.
1639 * @param ppUser Open handle required while closing the device.
1640 */
1641static int vboxNetFltSolarisOpenDev(char *pszDev, vnode_t **ppVNode, vnode_t **ppVNodeHeld, TIUSER **ppUser)
1642{
1643 int rc;
1644 vnode_t *pVNodeHeld = NULL;
1645 rc = lookupname(pszDev, UIO_SYSSPACE, FOLLOW, NULLVPP, &pVNodeHeld);
1646 if ( !rc
1647 && pVNodeHeld)
1648 {
1649 TIUSER *pUser;
1650 rc = t_kopen((file_t *)NULL, pVNodeHeld->v_rdev, FREAD | FWRITE, &pUser, kcred);
1651 if (!rc)
1652 {
1653 if ( pUser
1654 && pUser->fp
1655 && VNODE_FOR_FILE_T(pUser->fp))
1656 {
1657 *ppVNode = VNODE_FOR_FILE_T(pUser->fp);
1658 *ppVNodeHeld = pVNodeHeld;
1659 *ppUser = pUser;
1660 return VINF_SUCCESS;
1661 }
1662 else
1663 {
1664 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenDev failed. pUser=%p fp=%p f_vnode=%p\n", pUser,
1665 pUser ? pUser->fp : NULL, pUser && pUser->fp ? VNODE_FOR_FILE_T(pUser->fp) : NULL));
1666 }
1667
1668 if (pUser)
1669 t_kclose(pUser, 0);
1670 }
1671 else
1672 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenDev t_kopen failed. rc=%d\n", rc));
1673
1674 VN_RELE(pVNodeHeld);
1675 }
1676 else
1677 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenDev lookupname failed. rc=%d pVNodeHeld=%p\n", rc, pVNodeHeld));
1678
1679 return VERR_PATH_NOT_FOUND;
1680}
1681
1682
1683/**
1684 * Close the device opened using vboxNetFltSolarisOpenDev.
1685 *
1686 * @param pVNodeHeld Pointer to the held vnode of the device.
1687 * @param pUser Pointer to the file handle.
1688 */
1689static void vboxNetFltSolarisCloseDev(vnode_t *pVNodeHeld, TIUSER *pUser)
1690{
1691 t_kclose(pUser, 0);
1692 VN_RELE(pVNodeHeld);
1693}
1694
1695
1696/**
1697 * Set the DLPI style-2 PPA via an attach request, Synchronous.
1698 * Waits for request acknowledgement and verifies the result.
1699 *
1700 * @returns VBox status code.
1701 * @param hDevice Layered device handle.
1702 * @param PPA Physical Point of Attachment (PPA) number.
1703 */
1704static int vboxNetFltSolarisAttachReq(ldi_handle_t hDevice, int PPA)
1705{
1706 int rc;
1707 mblk_t *pAttachMsg = mexchange(NULL, NULL, DL_ATTACH_REQ_SIZE, M_PROTO, DL_ATTACH_REQ);
1708 if (RT_UNLIKELY(!pAttachMsg))
1709 return VERR_NO_MEMORY;
1710
1711 dl_attach_req_t *pAttachReq = (dl_attach_req_t *)pAttachMsg->b_rptr;
1712 pAttachReq->dl_ppa = PPA;
1713
1714 rc = ldi_putmsg(hDevice, pAttachMsg);
1715 if (!rc)
1716 {
1717 rc = ldi_getmsg(hDevice, &pAttachMsg, NULL);
1718 if (!rc)
1719 {
1720 /*
1721 * Verify if the attach succeeded.
1722 */
1723 size_t cbMsg = MBLKL(pAttachMsg);
1724 if (cbMsg >= sizeof(t_uscalar_t))
1725 {
1726 union DL_primitives *pPrim = (union DL_primitives *)pAttachMsg->b_rptr;
1727 t_uscalar_t AckPrim = pPrim->dl_primitive;
1728
1729 if ( AckPrim == DL_OK_ACK /* Success! */
1730 && cbMsg == DL_OK_ACK_SIZE)
1731 {
1732 rc = VINF_SUCCESS;
1733 }
1734 else if ( AckPrim == DL_ERROR_ACK /* Error Ack. */
1735 && cbMsg == DL_ERROR_ACK_SIZE)
1736 {
1737 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachReq ldi_getmsg succeeded, but unsupported op.\n"));
1738 rc = VERR_NOT_SUPPORTED;
1739 }
1740 else /* Garbled reply */
1741 {
1742 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachReq ldi_getmsg succeeded, but invalid op."
1743 " expected %d recvd %d\n", DL_OK_ACK, AckPrim));
1744 rc = VERR_INVALID_FUNCTION;
1745 }
1746 }
1747 else
1748 {
1749 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachReq ldi_getmsg succeeded, but invalid size %d expected %d\n", cbMsg,
1750 DL_OK_ACK_SIZE));
1751 rc = VERR_INVALID_FUNCTION;
1752 }
1753 }
1754 else
1755 {
1756 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachReq ldi_getmsg failed. rc=%d\n", rc));
1757 rc = VERR_INVALID_FUNCTION;
1758 }
1759 }
1760 else
1761 {
1762 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachReq ldi_putmsg failed. rc=%d\n", rc));
1763 rc = VERR_UNRESOLVED_ERROR;
1764 }
1765
1766 freemsg(pAttachMsg);
1767 return rc;
1768}
1769
1770
1771/**
1772 * Get the logical interface flags from the stream.
1773 *
1774 * @returns VBox status code.
1775 * @param hDevice Layered device handle.
1776 * @param pInterface Pointer to the interface.
1777 */
1778static int vboxNetFltSolarisGetIfFlags(ldi_handle_t hDevice, struct lifreq *pInterface)
1779{
1780 struct strioctl IOCReq;
1781 int rc;
1782 int ret;
1783 IOCReq.ic_cmd = SIOCGLIFFLAGS;
1784 IOCReq.ic_timout = 40;
1785 IOCReq.ic_len = sizeof(struct lifreq);
1786 IOCReq.ic_dp = (caddr_t)pInterface;
1787 rc = ldi_ioctl(hDevice, I_STR, (intptr_t)&IOCReq, FKIOCTL, kcred, &ret);
1788 if (!rc)
1789 return VINF_SUCCESS;
1790
1791 return RTErrConvertFromErrno(rc);
1792}
1793
1794
1795/**
1796 * Sets the multiplexor ID from the interface.
1797 *
1798 * @returns VBox status code.
1799 * @param pVNode Pointer to the device vnode.
1800 * @param pInterface Pointer to the interface.
1801 */
1802static int vboxNetFltSolarisSetMuxId(vnode_t *pVNode, struct lifreq *pInterface)
1803{
1804 struct strioctl IOCReq;
1805 int rc;
1806 int ret;
1807 IOCReq.ic_cmd = SIOCSLIFMUXID;
1808 IOCReq.ic_timout = 40;
1809 IOCReq.ic_len = sizeof(struct lifreq);
1810 IOCReq.ic_dp = (caddr_t)pInterface;
1811
1812 rc = strioctl(pVNode, I_STR, (intptr_t)&IOCReq, 0, K_TO_K, kcred, &ret);
1813 if (!rc)
1814 return VINF_SUCCESS;
1815
1816 return RTErrConvertFromErrno(rc);
1817}
1818
1819
1820/**
1821 * Get the multiplexor file descriptor of the lower stream.
1822 *
1823 * @returns VBox status code.
1824 * @param pVNode Pointer to the device vnode.
1825 * @param MuxId The multiplexor ID.
1826 * @param pFd Where to store the lower stream file descriptor.
1827 */
1828static int vboxNetFltSolarisMuxIdToFd(vnode_t *pVNode, int MuxId, int *pFd)
1829{
1830 int ret;
1831 int rc = strioctl(pVNode, _I_MUXID2FD, (intptr_t)MuxId, 0, K_TO_K, kcred, &ret);
1832 if (!rc)
1833 {
1834 *pFd = ret;
1835 return VINF_SUCCESS;
1836 }
1837
1838 return RTErrConvertFromErrno(rc);
1839}
1840
1841
1842/**
1843 * Relinks the lower and the upper IPv4 stream.
1844 *
1845 * @returns VBox status code.
1846 * @param pVNode Pointer to the device vnode.
1847 * @param pInterface Pointer to the interface.
1848 * @param IpMuxFd The IP multiplexor ID.
1849 * @param ArpMuxFd The ARP multiplexor ID.
1850 */
1851static int vboxNetFltSolarisRelinkIp4(vnode_t *pVNode, struct lifreq *pInterface, int IpMuxFd, int ArpMuxFd)
1852{
1853 LogFunc((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: pVNode=%p pInterface=%p IpMuxFd=%d ArpMuxFd=%d\n", pVNode,
1854 pInterface, IpMuxFd, ArpMuxFd));
1855
1856 int NewIpMuxId;
1857 int NewArpMuxId;
1858 int rc = strioctl(pVNode, I_PLINK, (intptr_t)IpMuxFd, 0, K_TO_K, kcred, &NewIpMuxId);
1859 int rc2 = strioctl(pVNode, I_PLINK, (intptr_t)ArpMuxFd, 0, K_TO_K, kcred, &NewArpMuxId);
1860 if ( !rc
1861 && !rc2)
1862 {
1863 pInterface->lifr_ip_muxid = NewIpMuxId;
1864 pInterface->lifr_arp_muxid = NewArpMuxId;
1865 rc = vboxNetFltSolarisSetMuxId(pVNode, pInterface);
1866 if (RT_SUCCESS(rc))
1867 return VINF_SUCCESS;
1868
1869 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: failed to set new Mux Id.\n"));
1870 }
1871 else
1872 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: failed to link.\n"));
1873
1874 return VERR_GENERAL_FAILURE;
1875}
1876
1877
1878/**
1879 * Relinks the lower and the upper IPv6 stream.
1880 *
1881 * @returns VBox status code.
1882 * @param pVNode Pointer to the device vnode.
1883 * @param pInterface Pointer to the interface.
1884 * @param Ip6MuxFd The IPv6 multiplexor ID.
1885 */
1886static int vboxNetFltSolarisRelinkIp6(vnode_t *pVNode, struct lifreq *pInterface, int Ip6MuxFd)
1887{
1888 LogFunc((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: pVNode=%p pInterface=%p Ip6MuxFd=%d\n", pVNode, pInterface, Ip6MuxFd));
1889
1890 int NewIp6MuxId;
1891 int rc = strioctl(pVNode, I_PLINK, (intptr_t)Ip6MuxFd, 0, K_TO_K, kcred, &NewIp6MuxId);
1892 if (!rc)
1893 {
1894 pInterface->lifr_ip_muxid = NewIp6MuxId;
1895 rc = vboxNetFltSolarisSetMuxId(pVNode, pInterface);
1896 if (RT_SUCCESS(rc))
1897 return VINF_SUCCESS;
1898
1899 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: failed to set new Mux Id.\n"));
1900 }
1901 else
1902 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: failed to link.\n"));
1903
1904 return VERR_GENERAL_FAILURE;
1905}
1906
1907
1908/**
1909 * Dynamically find the position on the host stack where to attach/detach ourselves.
1910 *
1911 * @returns VBox status code.
1912 * @param fAttach Is this an attach or detach.
1913 * @param pVNode Pointer to the lower stream vnode.
1914 * @param pModPos Where to store the module position.
1915 */
1916static int vboxNetFltSolarisDetermineModPos(bool fAttach, vnode_t *pVNode, int *pModPos)
1917{
1918 LogFunc((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: fAttach=%d pVNode=%p pModPos=%p\n", fAttach, pVNode, pModPos));
1919
1920 int cMod;
1921 int rc = strioctl(pVNode, I_LIST, (intptr_t)NULL, 0, K_TO_K, kcred, &cMod);
1922 if (!rc)
1923 {
1924 if (cMod < 1)
1925 {
1926 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: too few modules on host interface. cMod=%d\n"));
1927 return VERR_OUT_OF_RANGE;
1928 }
1929
1930 /*
1931 * While attaching we make sure we are at the bottom most of the stack, excepting
1932 * the host driver.
1933 */
1934 Log((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: cMod=%d\n", cMod));
1935 if (fAttach)
1936 {
1937 *pModPos = cMod - 1;
1938 return VINF_SUCCESS;
1939 }
1940
1941 /*
1942 * Detaching is a bit more complicated; since user could have altered the stack positions
1943 * we take the safe approach by finding our position.
1944 */
1945 struct str_list StrList;
1946 StrList.sl_nmods = cMod;
1947 StrList.sl_modlist = RTMemAllocZ(cMod * sizeof(struct str_list));
1948 if (RT_UNLIKELY(!StrList.sl_modlist))
1949 {
1950 Log((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to alloc memory for StrList.\n"));
1951 return VERR_NO_MEMORY;
1952 }
1953
1954 /*
1955 * Get the list of all modules on the stack.
1956 */
1957 int ret;
1958 rc = strioctl(pVNode, I_LIST, (intptr_t)&StrList, 0, K_TO_K, kcred, &ret);
1959 if (!rc)
1960 {
1961 /*
1962 * Find our filter.
1963 */
1964 for (int i = 0; i < StrList.sl_nmods; i++)
1965 {
1966 if (!strcmp(DEVICE_NAME, StrList.sl_modlist[i].l_name))
1967 {
1968 Log((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: Success! Found %s at %d.\n", DEVICE_NAME, i));
1969 *pModPos = i;
1970 RTMemFree(StrList.sl_modlist);
1971 return VINF_SUCCESS;
1972 }
1973 }
1974
1975 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to find %s in the host stack.\n", DEVICE_NAME));
1976 }
1977 else
1978 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get module information. rc=%d\n"));
1979
1980 RTMemFree(StrList.sl_modlist);
1981 }
1982 else
1983 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get list of modules on host interface. rc=%d\n", rc));
1984 return VERR_GENERAL_FAILURE;
1985}
1986
1987
1988/**
1989 * Opens up the DLPI style 2 link that requires explicit PPA attach
1990 * phase.
1991 *
1992 * @returns VBox status code.
1993 * @param pThis The instance.
1994 * @param pDevId Where to store the opened LDI device id.
1995 */
1996static int vboxNetFltSolarisOpenStyle2(PVBOXNETFLTINS pThis, ldi_ident_t *pDevId)
1997{
1998 /*
1999 * Strip out PPA from the device name, eg: "ce3".
2000 */
2001 char *pszDev = RTStrDup(pThis->szName);
2002 if (!pszDev)
2003 return VERR_NO_MEMORY;
2004
2005 char *pszEnd = strchr(pszDev, '\0');
2006 while (--pszEnd > pszDev)
2007 if (!RT_C_IS_DIGIT(*pszEnd))
2008 break;
2009 pszEnd++;
2010
2011 int rc = VERR_GENERAL_FAILURE;
2012 long PPA = -1;
2013 if ( pszEnd
2014 && ddi_strtol(pszEnd, NULL, 10, &PPA) == 0)
2015 {
2016 *pszEnd = '\0';
2017 char szDev[128];
2018 RTStrPrintf(szDev, sizeof(szDev), "/dev/%s", pszDev);
2019
2020 /*
2021 * Try open the device as DPLI style 2.
2022 */
2023 rc = ldi_open_by_name(szDev, FREAD | FWRITE, kcred, &pThis->u.s.hIface, *pDevId);
2024 if (!rc)
2025 {
2026 /*
2027 * Attach the PPA explictly.
2028 */
2029 rc = vboxNetFltSolarisAttachReq(pThis->u.s.hIface, (int)PPA);
2030 if (RT_SUCCESS(rc))
2031 {
2032 RTStrFree(pszDev);
2033 return rc;
2034 }
2035
2036 ldi_close(pThis->u.s.hIface, FREAD | FWRITE, kcred);
2037 pThis->u.s.hIface = NULL;
2038 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStyle2 dl_attach failed. rc=%d szDev=%s PPA=%d rc=%d\n", rc, szDev, PPA));
2039 }
2040 else
2041 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStyle2 Failed to open. rc=%d szDev=%s PPA=%d\n", rc, szDev, PPA));
2042 }
2043 else
2044 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStyle2 Failed to construct PPA. pszDev=%s pszEnd=%s.\n", pszDev, pszEnd));
2045
2046 RTStrFree(pszDev);
2047 return VERR_INTNET_FLT_IF_FAILED;
2048}
2049
2050
2051/**
2052 * Opens up dedicated stream on top of the interface.
2053 * As a side-effect, the stream gets opened during
2054 * the I_PUSH phase.
2055 *
2056 * @param pThis The instance.
2057 */
2058static int vboxNetFltSolarisOpenStream(PVBOXNETFLTINS pThis)
2059{
2060 ldi_ident_t DevId;
2061 DevId = ldi_ident_from_anon();
2062 int ret;
2063
2064 /*
2065 * Figure out if this is a VLAN interface or not based on the interface name.
2066 * Only works for the VLAN PPA-hack based names. See @bugref{4854} for details.
2067 */
2068 char *pszEnd = strchr(pThis->szName, '\0');
2069 while (--pszEnd > pThis->szName)
2070 if (!RT_C_IS_DIGIT(*pszEnd))
2071 break;
2072 pszEnd++;
2073 uint32_t PPA = RTStrToUInt32(pszEnd);
2074 if (PPA > 1000)
2075 {
2076 pThis->u.s.fVLAN = true;
2077 LogRel((DEVICE_NAME ": %s detected as VLAN interface with VID=%u.\n", pThis->szName, PPA / 1000U));
2078 }
2079
2080 /*
2081 * Try style-1 open first.
2082 */
2083 char szDev[128];
2084 RTStrPrintf(szDev, sizeof(szDev), "/dev/net/%s", pThis->szName);
2085 int rc = ldi_open_by_name(szDev, FREAD | FWRITE, kcred, &pThis->u.s.hIface, DevId);
2086 if ( rc
2087 && rc == ENODEV) /* ENODEV is returned when resolvepath fails, not ENOENT */
2088 {
2089 /*
2090 * Fallback to non-ClearView style-1 open.
2091 */
2092 RTStrPrintf(szDev, sizeof(szDev), "/dev/%s", pThis->szName);
2093 rc = ldi_open_by_name(szDev, FREAD | FWRITE, kcred, &pThis->u.s.hIface, DevId);
2094 }
2095
2096 if (rc)
2097 {
2098 /*
2099 * Try DLPI style 2.
2100 */
2101 rc = vboxNetFltSolarisOpenStyle2(pThis, &DevId);
2102 if (RT_FAILURE(rc))
2103 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream vboxNetFltSolarisOpenStyle2 failed. rc=%d\n", rc));
2104 else
2105 rc = 0;
2106 }
2107
2108 ldi_ident_release(DevId);
2109 if (rc)
2110 {
2111 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to open '%s' rc=%d pszName='%s'\n", szDev, rc, pThis->szName));
2112 return VERR_INTNET_FLT_IF_FAILED;
2113 }
2114
2115 rc = ldi_ioctl(pThis->u.s.hIface, I_FIND, (intptr_t)DEVICE_NAME, FKIOCTL, kcred, &ret);
2116 if (!rc)
2117 {
2118 if (!ret)
2119 {
2120 if (RT_LIKELY(g_pVBoxNetFltSolarisCred)) /* Paranoia */
2121 {
2122 rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
2123 AssertRCReturn(rc, rc);
2124
2125 g_VBoxNetFltSolarisInstance = pThis;
2126 g_VBoxNetFltSolarisStreamType = kPromiscStream;
2127
2128 rc = ldi_ioctl(pThis->u.s.hIface, I_PUSH, (intptr_t)DEVICE_NAME, FKIOCTL, g_pVBoxNetFltSolarisCred, &ret);
2129
2130 g_VBoxNetFltSolarisInstance = NULL;
2131 g_VBoxNetFltSolarisStreamType = kUndefined;
2132
2133 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
2134 }
2135 else
2136 {
2137 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream huh!? Missing credentials.\n"));
2138 rc = VERR_INVALID_POINTER;
2139 }
2140
2141 if (!rc)
2142 return VINF_SUCCESS;
2143
2144 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to push filter onto host interface '%s'\n", pThis->szName));
2145 }
2146 else
2147 return VINF_SUCCESS;
2148 }
2149 else
2150 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to search for filter in interface '%s'.\n", pThis->szName));
2151
2152 ldi_close(pThis->u.s.hIface, FREAD | FWRITE, kcred);
2153 pThis->u.s.hIface = NULL;
2154
2155 return VERR_INTNET_FLT_IF_FAILED;
2156}
2157
2158
2159/**
2160 * Closes the interface, thereby closing the dedicated stream.
2161 *
2162 * @param pThis The instance.
2163 */
2164static void vboxNetFltSolarisCloseStream(PVBOXNETFLTINS pThis)
2165{
2166 LogFunc((DEVICE_NAME ":vboxNetFltSolarisCloseStream pThis=%p\n"));
2167
2168 if (pThis->u.s.hIface)
2169 {
2170 ldi_close(pThis->u.s.hIface, FREAD | FWRITE, kcred);
2171 pThis->u.s.hIface = NULL;
2172 }
2173}
2174
2175
2176/**
2177 * Dynamically attach under IPv4 and ARP streams on the host stack.
2178 *
2179 * @returns VBox status code.
2180 * @param pThis The instance.
2181 * @param fAttach Is this an attach or detach.
2182 */
2183static int vboxNetFltSolarisAttachIp4(PVBOXNETFLTINS pThis, bool fAttach)
2184{
2185 LogFunc((DEVICE_NAME ":vboxNetFltSolarisAttachIp4 pThis=%p fAttach=%d\n", pThis, fAttach));
2186
2187 /*
2188 * Statutory Warning: Hackish code ahead.
2189 */
2190 char *pszModName = DEVICE_NAME;
2191
2192 struct lifreq Ip4Interface;
2193 bzero(&Ip4Interface, sizeof(Ip4Interface));
2194 Ip4Interface.lifr_addr.ss_family = AF_INET;
2195 strncpy(Ip4Interface.lifr_name, pThis->szName, sizeof(Ip4Interface.lifr_name));
2196
2197 struct strmodconf StrMod;
2198 StrMod.mod_name = pszModName;
2199 StrMod.pos = -1; /* this is filled in later. */
2200
2201 struct strmodconf ArpStrMod;
2202 bcopy(&StrMod, &ArpStrMod, sizeof(StrMod));
2203
2204 int rc;
2205 int rc2;
2206 int ret;
2207 ldi_ident_t DeviceIdent = ldi_ident_from_anon();
2208 ldi_handle_t Ip4DevHandle;
2209 ldi_handle_t ArpDevHandle;
2210
2211 /*
2212 * Open the IP and ARP streams as layered devices.
2213 */
2214 rc = ldi_open_by_name(IP_DEV_NAME, FREAD | FWRITE, kcred, &Ip4DevHandle, DeviceIdent);
2215 if (rc)
2216 {
2217 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open the IP stream on '%s'.\n", pThis->szName));
2218 ldi_ident_release(DeviceIdent);
2219 return VERR_INTNET_FLT_IF_FAILED;
2220 }
2221
2222 rc = ldi_open_by_name("/dev/arp", FREAD | FWRITE, kcred, &ArpDevHandle, DeviceIdent);
2223 if (rc)
2224 {
2225 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open the ARP stream on '%s'.\n", pThis->szName));
2226 ldi_ident_release(DeviceIdent);
2227 ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
2228 return VERR_INTNET_FLT_IF_FAILED;
2229 }
2230
2231 ldi_ident_release(DeviceIdent);
2232
2233 /*
2234 * Obtain the interface flags from IPv4.
2235 */
2236 rc = vboxNetFltSolarisGetIfFlags(Ip4DevHandle, &Ip4Interface);
2237 if (RT_SUCCESS(rc))
2238 {
2239 /*
2240 * Open the UDP stream. We sort of cheat here and obtain the vnode so that we can perform
2241 * things that are not possible from the layered interface.
2242 */
2243 vnode_t *pUdp4VNode = NULL;
2244 vnode_t *pUdp4VNodeHeld = NULL;
2245 TIUSER *pUdp4User = NULL;
2246 rc = vboxNetFltSolarisOpenDev(UDP_DEV_NAME, &pUdp4VNode, &pUdp4VNodeHeld, &pUdp4User);
2247 if (RT_SUCCESS(rc))
2248 {
2249 /*
2250 * Get the multiplexor IDs.
2251 */
2252 rc = ldi_ioctl(Ip4DevHandle, SIOCGLIFMUXID, (intptr_t)&Ip4Interface, FKIOCTL, kcred, &ret);
2253 if (!rc)
2254 {
2255 /*
2256 * Get the multiplex file descriptor to the lower streams. Generally this is lost
2257 * once a module is I_PLINK, we need to reobtain it for inserting/removing ourselves from the stack.
2258 */
2259 int Ip4MuxFd;
2260 int ArpMuxFd;
2261 rc = vboxNetFltSolarisMuxIdToFd(pUdp4VNode, Ip4Interface.lifr_ip_muxid, &Ip4MuxFd);
2262 rc2 = vboxNetFltSolarisMuxIdToFd(pUdp4VNode, Ip4Interface.lifr_arp_muxid, &ArpMuxFd);
2263 if ( RT_SUCCESS(rc)
2264 && RT_SUCCESS(rc2))
2265 {
2266 /*
2267 * We need to I_PUNLINK on these multiplexor IDs before we can start
2268 * operating on the lower stream as insertions are direct operations on the lower stream.
2269 */
2270 rc = strioctl(pUdp4VNode, I_PUNLINK, (intptr_t)Ip4Interface.lifr_ip_muxid, 0, K_TO_K, kcred, &ret);
2271 rc2 = strioctl(pUdp4VNode, I_PUNLINK, (intptr_t)Ip4Interface.lifr_arp_muxid, 0, K_TO_K, kcred, &ret);
2272 if ( !rc
2273 && !rc2)
2274 {
2275 /*
2276 * Obtain the vnode from the useless userland file descriptor.
2277 */
2278 file_t *pIpFile = getf(Ip4MuxFd);
2279 file_t *pArpFile = getf(ArpMuxFd);
2280 if ( pIpFile
2281 && pArpFile
2282 && VNODE_FOR_FILE_T(pArpFile)
2283 && VNODE_FOR_FILE_T(pIpFile))
2284 {
2285 vnode_t *pIp4VNode = VNODE_FOR_FILE_T(pIpFile);
2286 vnode_t *pArpVNode = VNODE_FOR_FILE_T(pArpFile);
2287
2288 /*
2289 * Find the position on the host stack for attaching/detaching ourselves.
2290 */
2291 rc = vboxNetFltSolarisDetermineModPos(fAttach, pIp4VNode, &StrMod.pos);
2292 rc2 = vboxNetFltSolarisDetermineModPos(fAttach, pArpVNode, &ArpStrMod.pos);
2293 if ( RT_SUCCESS(rc)
2294 && RT_SUCCESS(rc2))
2295 {
2296 /*
2297 * Inject/Eject from the host IP stack.
2298 */
2299
2300 /*
2301 * Set global data which will be grabbed by ModOpen.
2302 * There is a known (though very unlikely) race here because
2303 * of the inability to pass user data while inserting.
2304 */
2305 rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
2306 AssertRCReturn(rc, rc);
2307
2308 if (fAttach)
2309 {
2310 g_VBoxNetFltSolarisInstance = pThis;
2311 g_VBoxNetFltSolarisStreamType = kIp4Stream;
2312 }
2313
2314 rc = strioctl(pIp4VNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K,
2315 g_pVBoxNetFltSolarisCred, &ret);
2316
2317 if (fAttach)
2318 {
2319 g_VBoxNetFltSolarisInstance = NULL;
2320 g_VBoxNetFltSolarisStreamType = kUndefined;
2321 }
2322
2323 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
2324
2325 if (!rc)
2326 {
2327 /*
2328 * Inject/Eject from the host ARP stack.
2329 */
2330 rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
2331 AssertRCReturn(rc, rc);
2332
2333 if (fAttach)
2334 {
2335 g_VBoxNetFltSolarisInstance = pThis;
2336 g_VBoxNetFltSolarisStreamType = kArpStream;
2337 }
2338
2339 rc = strioctl(pArpVNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&ArpStrMod, 0, K_TO_K,
2340 g_pVBoxNetFltSolarisCred, &ret);
2341
2342 if (fAttach)
2343 {
2344 g_VBoxNetFltSolarisInstance = NULL;
2345 g_VBoxNetFltSolarisStreamType = kUndefined;
2346 }
2347
2348 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
2349
2350 if (!rc)
2351 {
2352 /*
2353 * Our job's not yet over; we need to relink the upper and lower streams
2354 * otherwise we've pretty much screwed up the host interface.
2355 */
2356 rc = vboxNetFltSolarisRelinkIp4(pUdp4VNode, &Ip4Interface, Ip4MuxFd, ArpMuxFd);
2357 if (RT_SUCCESS(rc))
2358 {
2359 /*
2360 * Close the devices ONLY during the return from function case; otherwise
2361 * we end up close twice which is an instant kernel panic.
2362 */
2363 vboxNetFltSolarisCloseDev(pUdp4VNodeHeld, pUdp4User);
2364 ldi_close(ArpDevHandle, FREAD | FWRITE, kcred);
2365 ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
2366 releasef(Ip4MuxFd);
2367 releasef(ArpMuxFd);
2368
2369 Log((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Success! %s %s@(IPv4:%d Arp:%d) "
2370 "%s interface %s\n", fAttach ? "Injected" : "Ejected", StrMod.mod_name,
2371 StrMod.pos, ArpStrMod.pos, fAttach ? "to" : "from", pThis->szName));
2372 return VINF_SUCCESS;
2373 }
2374 else
2375 {
2376 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Relinking failed. Mode=%s rc=%d.\n",
2377 fAttach ? "inject" : "eject", rc));
2378 }
2379
2380 /*
2381 * Try failing gracefully during attach.
2382 */
2383 if (fAttach)
2384 strioctl(pArpVNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
2385 }
2386 else
2387 {
2388 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to %s the ARP stack. rc=%d\n",
2389 fAttach ? "inject into" : "eject from", rc));
2390 }
2391
2392 if (fAttach)
2393 strioctl(pIp4VNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
2394
2395 vboxNetFltSolarisRelinkIp4(pUdp4VNode, &Ip4Interface, Ip4MuxFd, ArpMuxFd);
2396 }
2397 else
2398 {
2399 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to %s the IP stack. rc=%d\n",
2400 fAttach ? "inject into" : "eject from", rc));
2401 }
2402 }
2403 else
2404 {
2405 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to find position. rc=%d rc2=%d\n", rc,
2406 rc2));
2407 }
2408
2409 releasef(Ip4MuxFd);
2410 releasef(ArpMuxFd);
2411 }
2412 else
2413 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get vnode from MuxFd.\n"));
2414 }
2415 else
2416 {
2417 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to unlink upper stream rc=%d rc2=%d.\n", rc,
2418 rc2));
2419 }
2420 }
2421 else
2422 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get MuxFd from MuxId. rc=%d rc2=%d\n", rc, rc2));
2423 }
2424 else
2425 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get Mux Ids. rc=%d\n", rc));
2426 vboxNetFltSolarisCloseDev(pUdp4VNodeHeld, pUdp4User);
2427 }
2428 else
2429 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open UDP. rc=%d\n", rc));
2430
2431 rc = VERR_INTNET_FLT_IF_FAILED;
2432 }
2433 else
2434 {
2435 /*
2436 * This would happen for interfaces that are not plumbed.
2437 */
2438 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Warning: seems '%s' is unplumbed.\n", pThis->szName));
2439 rc = VINF_SUCCESS;
2440 }
2441
2442 ldi_close(ArpDevHandle, FREAD | FWRITE, kcred);
2443 ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
2444
2445 return rc;
2446}
2447
2448
2449/**
2450 * Dynamically attach under IPv6 on the host stack.
2451 *
2452 * @returns VBox status code.
2453 * @param pThis The instance.
2454 * @param fAttach Is this an attach or detach.
2455 */
2456static int vboxNetFltSolarisAttachIp6(PVBOXNETFLTINS pThis, bool fAttach)
2457{
2458 LogFunc((DEVICE_NAME ":vboxNetFltSolarisAttachIp6 pThis=%p fAttach=%d\n", pThis, fAttach));
2459
2460 /*
2461 * Statutory Warning: Hackish code ahead.
2462 */
2463 char *pszModName = DEVICE_NAME;
2464
2465 struct lifreq Ip6Interface;
2466 bzero(&Ip6Interface, sizeof(Ip6Interface));
2467 Ip6Interface.lifr_addr.ss_family = AF_INET6;
2468 strncpy(Ip6Interface.lifr_name, pThis->szName, sizeof(Ip6Interface.lifr_name));
2469
2470 struct strmodconf StrMod;
2471 StrMod.mod_name = pszModName;
2472 StrMod.pos = -1; /* this is filled in later. */
2473
2474 int rc;
2475 int ret;
2476 ldi_ident_t DeviceIdent = ldi_ident_from_anon();
2477 ldi_handle_t Ip6DevHandle;
2478
2479 /*
2480 * Open the IPv6 stream as a layered devices.
2481 */
2482 rc = ldi_open_by_name(IP6_DEV_NAME, FREAD | FWRITE, kcred, &Ip6DevHandle, DeviceIdent);
2483 ldi_ident_release(DeviceIdent);
2484 if (rc)
2485 {
2486 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to open the IPv6 stream on '%s'.\n", pThis->szName));
2487 return VERR_INTNET_FLT_IF_FAILED;
2488 }
2489
2490 /*
2491 * Obtain the interface flags from IPv6.
2492 */
2493 rc = vboxNetFltSolarisGetIfFlags(Ip6DevHandle, &Ip6Interface);
2494 if (RT_SUCCESS(rc))
2495 {
2496 /*
2497 * Open the UDP stream. We sort of cheat here and obtain the vnode so that we can perform
2498 * things that are not possible from the layered interface.
2499 */
2500 vnode_t *pUdp6VNode = NULL;
2501 vnode_t *pUdp6VNodeHeld = NULL;
2502 TIUSER *pUdp6User = NULL;
2503 rc = vboxNetFltSolarisOpenDev(UDP6_DEV_NAME, &pUdp6VNode, &pUdp6VNodeHeld, &pUdp6User);
2504 if (RT_SUCCESS(rc))
2505 {
2506 /*
2507 * Get the multiplexor IDs.
2508 */
2509 rc = ldi_ioctl(Ip6DevHandle, SIOCGLIFMUXID, (intptr_t)&Ip6Interface, FKIOCTL, kcred, &ret);
2510 if (!rc)
2511 {
2512 /*
2513 * Get the multiplex file descriptor to the lower streams. Generally this is lost
2514 * once a module is I_PLINK, we need to reobtain it for inserting/removing ourselves from the stack.
2515 */
2516 int Ip6MuxFd;
2517 rc = vboxNetFltSolarisMuxIdToFd(pUdp6VNode, Ip6Interface.lifr_ip_muxid, &Ip6MuxFd);
2518 if (RT_SUCCESS(rc))
2519 {
2520 /*
2521 * We need to I_PUNLINK on these multiplexor IDs before we can start
2522 * operating on the lower stream as insertions are direct operations on the lower stream.
2523 */
2524 rc = strioctl(pUdp6VNode, I_PUNLINK, (intptr_t)Ip6Interface.lifr_ip_muxid, 0, K_TO_K, kcred, &ret);
2525 if (!rc)
2526 {
2527 /*
2528 * Obtain the vnode from the useless userland file descriptor.
2529 */
2530 file_t *pIpFile = getf(Ip6MuxFd);
2531 if ( pIpFile
2532 && VNODE_FOR_FILE_T(pIpFile))
2533 {
2534 vnode_t *pIp6VNode = VNODE_FOR_FILE_T(pIpFile);
2535
2536 /*
2537 * Find the position on the host stack for attaching/detaching ourselves.
2538 */
2539 rc = vboxNetFltSolarisDetermineModPos(fAttach, pIp6VNode, &StrMod.pos);
2540 if (RT_SUCCESS(rc))
2541 {
2542 /*
2543 * Set global data which will be grabbed by ModOpen.
2544 * There is a known (though very unlikely) race here because
2545 * of the inability to pass user data while inserting.
2546 */
2547 rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
2548 AssertRCReturn(rc, rc);
2549
2550 if (fAttach)
2551 {
2552 g_VBoxNetFltSolarisInstance = pThis;
2553 g_VBoxNetFltSolarisStreamType = kIp6Stream;
2554 }
2555
2556 /*
2557 * Inject/Eject from the host IPv6 stack.
2558 */
2559 rc = strioctl(pIp6VNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K,
2560 g_pVBoxNetFltSolarisCred, &ret);
2561
2562 if (fAttach)
2563 {
2564 g_VBoxNetFltSolarisInstance = NULL;
2565 g_VBoxNetFltSolarisStreamType = kUndefined;
2566 }
2567
2568 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
2569
2570 if (!rc)
2571 {
2572 /*
2573 * Our job's not yet over; we need to relink the upper and lower streams
2574 * otherwise we've pretty much screwed up the host interface.
2575 */
2576 rc = vboxNetFltSolarisRelinkIp6(pUdp6VNode, &Ip6Interface, Ip6MuxFd);
2577 if (RT_SUCCESS(rc))
2578 {
2579 /*
2580 * Close the devices ONLY during the return from function case; otherwise
2581 * we end up close twice which is an instant kernel panic.
2582 */
2583 vboxNetFltSolarisCloseDev(pUdp6VNodeHeld, pUdp6User);
2584 ldi_close(Ip6DevHandle, FREAD | FWRITE, kcred);
2585 releasef(Ip6MuxFd);
2586
2587 Log((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: Success! %s %s@(IPv6:%d) "
2588 "%s interface %s\n", fAttach ? "Injected" : "Ejected", StrMod.mod_name,
2589 StrMod.pos, fAttach ? "to" : "from", pThis->szName));
2590 return VINF_SUCCESS;
2591 }
2592 else
2593 {
2594 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: Relinking failed. Mode=%s rc=%d.\n",
2595 fAttach ? "inject" : "eject", rc));
2596 }
2597
2598 if (fAttach)
2599 strioctl(pIp6VNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
2600
2601 vboxNetFltSolarisRelinkIp6(pUdp6VNode, &Ip6Interface, Ip6MuxFd);
2602 }
2603 else
2604 {
2605 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to %s the IP stack. rc=%d\n",
2606 fAttach ? "inject into" : "eject from", rc));
2607 }
2608 }
2609 else
2610 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to find position. rc=%d\n", rc));
2611
2612 releasef(Ip6MuxFd);
2613 }
2614 else
2615 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get vnode from MuxFd.\n"));
2616 }
2617 else
2618 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to unlink upper stream rc=%d.\n", rc));
2619 }
2620 else
2621 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get MuxFd from MuxId. rc=%d\n", rc));
2622 }
2623 else
2624 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get Mux Ids. rc=%d\n", rc));
2625
2626 vboxNetFltSolarisCloseDev(pUdp6VNodeHeld, pUdp6User);
2627 }
2628 else
2629 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to open UDP. rc=%d\n", rc));
2630
2631 rc = VERR_INTNET_FLT_IF_FAILED;
2632 }
2633 else
2634 {
2635 Log((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get IPv6 flags.\n", pThis->szName));
2636 rc = VERR_INTNET_FLT_IF_NOT_FOUND;
2637 }
2638
2639 ldi_close(Ip6DevHandle, FREAD | FWRITE, kcred);
2640
2641 return rc;
2642}
2643
2644
2645#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
2646/**
2647 * Ipv6 dynamic attachment timer callback to attach to the Ipv6 stream if needed.
2648 *
2649 * @param pTimer Pointer to the timer.
2650 * @param pvData Opaque pointer to the instance.
2651 * @param iTick Timer tick (unused).
2652 */
2653static void vboxNetFltSolarispIp6Timer(PRTTIMER pTimer, void *pvData, uint64_t iTick)
2654{
2655 LogFunc((DEVICE_NAME ":vboxNetFltSolarispIp6Timer pTimer=%p pvData=%p\n", pTimer, pvData));
2656
2657 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvData;
2658 if ( RT_LIKELY(pThis)
2659 && RT_LIKELY(pTimer))
2660 {
2661 vboxnetflt_stream_t *pIp6Stream = ASMAtomicUoReadPtrT(&pThis->u.s.pIp6Stream, vboxnetflt_stream_t *);
2662 bool fIp6Attaching = ASMAtomicUoReadBool(&pThis->u.s.fAttaching);
2663 if ( !pIp6Stream
2664 && !fIp6Attaching)
2665 {
2666 int rc = RTSemFastMutexRequest(pThis->u.s.hPollMtx);
2667 if (RT_SUCCESS(rc))
2668 {
2669 ASMAtomicUoWriteBool(&pThis->u.s.fAttaching, true);
2670
2671 vboxNetFltSolarisAttachIp6(pThis, true /* fAttach */);
2672
2673 ASMAtomicUoWriteBool(&pThis->u.s.fAttaching, false);
2674 RTSemFastMutexRelease(pThis->u.s.hPollMtx);
2675 }
2676 else
2677 LogRel((DEVICE_NAME ":vboxNetFltSolarispIp6Timer failed to obtain mutex. rc=%Rrc\n", rc));
2678 }
2679 }
2680
2681 NOREF(iTick);
2682}
2683
2684
2685/**
2686 * Setups up a kernel timer based on the driver property for attaching to IPv6 stream
2687 * whenever the stream gets plumbed for the interface.
2688 *
2689 * @returns VBox status code.
2690 * @param pThis The instance.
2691 */
2692static int vboxNetFltSolarisSetupIp6Polling(PVBOXNETFLTINS pThis)
2693{
2694 LogFunc((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling pThis=%p\n", pThis));
2695
2696 int rc = VERR_GENERAL_FAILURE;
2697 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream, vboxnetflt_promisc_stream_t *);
2698 if (RT_LIKELY(pPromiscStream))
2699 {
2700 if (RT_LIKELY(pPromiscStream->pIp6Timer == NULL))
2701 {
2702 /*
2703 * Validate IPv6 polling interval.
2704 */
2705 int Interval = g_VBoxNetFltSolarisPollInterval;
2706 if (Interval < 1 || Interval > 120)
2707 {
2708 LogRel((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Invalid polling interval %d. Expected between"
2709 " 1 and 120 secs.\n", Interval));
2710 return VERR_INVALID_PARAMETER;
2711 }
2712
2713 /*
2714 * Setup kernel poll timer.
2715 */
2716 rc = RTTimerCreateEx(&pPromiscStream->pIp6Timer, Interval * (uint64_t)1000000000, RTTIMER_FLAGS_CPU_ANY,
2717 vboxNetFltSolarispIp6Timer, (void *)pThis);
2718 if (RT_SUCCESS(rc))
2719 {
2720 rc = RTTimerStart(pPromiscStream->pIp6Timer, 10 * (uint64_t)1000000000 /* 10 seconds to blastoff */);
2721 Log((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Ipv6 %d second timer begins firing in 10 seconds.\n",
2722 Interval));
2723 }
2724 else
2725 LogRel((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Failed to create timer. rc=%d\n", rc));
2726 }
2727 else
2728 {
2729 LogRel((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Polling already started.\n"));
2730 rc = VINF_SUCCESS;
2731 }
2732 }
2733 return rc;
2734}
2735#endif
2736
2737/**
2738 * Wrapper for detaching ourselves from the interface.
2739 *
2740 * @returns VBox status code.
2741 * @param pThis The instance.
2742 * @remarks Owns the globals mutex, so re-requesting it anytime during this phase
2743 * would panic the system (e.g. in vboxNetFltSolarisFindInstance).
2744 */
2745static int vboxNetFltSolarisDetachFromInterface(PVBOXNETFLTINS pThis)
2746{
2747 LogFunc((DEVICE_NAME ":vboxNetFltSolarisDetachFromInterface pThis=%p\n", pThis));
2748
2749 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
2750 vboxNetFltSolarisCloseStream(pThis);
2751 int rc = VINF_SUCCESS;
2752 if (pThis->u.s.pIp4Stream)
2753 rc = vboxNetFltSolarisAttachIp4(pThis, false /* fAttach */);
2754 if (pThis->u.s.pIp6Stream)
2755 rc = vboxNetFltSolarisAttachIp6(pThis, false /* fAttach */);
2756
2757#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
2758 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream, vboxnetflt_promisc_stream_t *);
2759 if ( pPromiscStream
2760 && pPromiscStream->pIp6Timer == NULL)
2761 {
2762 RTTimerStop(pPromiscStream->pIp6Timer);
2763 RTTimerDestroy(pPromiscStream->pIp6Timer);
2764 ASMAtomicUoWriteNullPtr(&pPromiscStream->pIp6Timer);
2765 }
2766#endif
2767
2768 return rc;
2769}
2770
2771
2772/**
2773 * Wrapper for attaching ourselves to the interface.
2774 *
2775 * @returns VBox status code.
2776 * @param pThis The instance.
2777 */
2778static int vboxNetFltSolarisAttachToInterface(PVBOXNETFLTINS pThis)
2779{
2780 LogFunc((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface pThis=%p\n", pThis));
2781
2782 /*
2783 * Since this is asynchronous streams injection, let the attach succeed before we can start
2784 * processing the stream.
2785 */
2786 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
2787 int rc = vboxNetFltSolarisOpenStream(pThis);
2788 if (RT_SUCCESS(rc))
2789 {
2790 rc = vboxNetFltSolarisAttachIp4(pThis, true /* fAttach */);
2791 if (RT_SUCCESS(rc))
2792 {
2793 /*
2794 * Ipv6 attaching is optional and can fail. We don't bother to bring down the whole
2795 * attach process just if Ipv6 interface is unavailable.
2796 */
2797 int rc2 = vboxNetFltSolarisAttachIp6(pThis, true /* fAttach */);
2798
2799#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
2800 /*
2801 * If Ip6 interface is not plumbed and an Ip6 polling interval is specified, we need
2802 * to begin polling to attach on the Ip6 interface whenever it comes up.
2803 */
2804 if ( rc2 == VERR_INTNET_FLT_IF_NOT_FOUND
2805 && g_VBoxNetFltSolarisPollInterval != -1)
2806 {
2807 int rc3 = vboxNetFltSolarisSetupIp6Polling(pThis);
2808 if (RT_FAILURE(rc3))
2809 {
2810 /*
2811 * If we failed to setup Ip6 polling, warn in the release log and continue.
2812 */
2813 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface IPv6 polling inactive. rc=%Rrc\n", rc3));
2814 }
2815 }
2816#endif
2817
2818 /*
2819 * Report promiscuousness and capabilities.
2820 */
2821 if (vboxNetFltTryRetainBusyNotDisconnected(pThis))
2822 {
2823 Assert(pThis->pSwitchPort);
2824 /** @todo There is no easy way of obtaining the global host side promiscuous
2825 * counter. Currently we just return false. */
2826 pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, false);
2827 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
2828 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
2829 vboxNetFltRelease(pThis, true /*fBusy*/);
2830 }
2831
2832 /*
2833 * Ipv4 is successful, and maybe Ipv6, we're ready for transfers.
2834 */
2835 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, false);
2836
2837 return VINF_SUCCESS;
2838 }
2839
2840 vboxNetFltSolarisCloseStream(pThis);
2841 }
2842 else
2843 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface vboxNetFltSolarisOpenStream failed rc=%Rrc\n", rc));
2844
2845 return rc;
2846}
2847
2848
2849/**
2850 * Create a solaris message block from the SG list.
2851 *
2852 * @returns Solaris message block.
2853 * @param pThis The instance.
2854 * @param pSG Pointer to the scatter-gather list.
2855 * @param fDst The destination mask, INTNETTRUNKDIR_XXX. Ignored.
2856 */
2857static mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
2858{
2859 LogFunc((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG pThis=%p pSG=%p\n", pThis, pSG));
2860
2861 mblk_t *pMsg = allocb(pSG->cbTotal, BPRI_MED);
2862 if (RT_UNLIKELY(!pMsg))
2863 {
2864 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed to alloc %d bytes for mblk_t.\n", pSG->cbTotal));
2865 return NULL;
2866 }
2867
2868 /*
2869 * Single buffer copy. Maybe later explore the
2870 * need/possibility for using a mblk_t chain rather.
2871 */
2872 for (unsigned i = 0; i < pSG->cSegsUsed; i++)
2873 {
2874 if (pSG->aSegs[i].pv)
2875 {
2876 bcopy(pSG->aSegs[i].pv, pMsg->b_wptr, pSG->aSegs[i].cb);
2877 pMsg->b_wptr += pSG->aSegs[i].cb;
2878 }
2879 }
2880 DB_TYPE(pMsg) = M_DATA;
2881 return pMsg;
2882}
2883
2884
2885/**
2886 * Calculate the number of segments required for this message block.
2887 *
2888 * @returns Number of segments.
2889 * @param pThis The instance
2890 * @param pMsg Pointer to the data message.
2891 */
2892static unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg)
2893{
2894 unsigned cSegs = 0;
2895 for (mblk_t *pCur = pMsg; pCur; pCur = pCur->b_cont)
2896 if (MBLKL(pCur))
2897 cSegs++;
2898
2899#ifdef PADD_RUNT_FRAMES_FROM_HOST
2900 if (msgdsize(pMsg) < 60)
2901 cSegs++;
2902#endif
2903
2904 NOREF(pThis);
2905 return RT_MAX(cSegs, 1);
2906}
2907
2908
2909/**
2910 * Initializes an SG list from the given message block.
2911 *
2912 * @returns VBox status code.
2913 * @param pThis The instance.
2914 * @param pMsg Pointer to the data message.
2915 The caller must ensure it's not a control message block.
2916 * @param pSG Pointer to the SG.
2917 * @param cSegs Number of segments in the SG.
2918 * This should match the number in the message block exactly!
2919 * @param fSrc The source of the message.
2920 */
2921static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
2922{
2923 LogFunc((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
2924
2925 /*
2926 * Convert the message block to segments. Work INTNETSG::cbTotal.
2927 */
2928 IntNetSgInitTempSegs(pSG, 0 /*cbTotal*/, cSegs, 0 /*cSegsUsed*/);
2929 mblk_t *pCur = pMsg;
2930 unsigned iSeg = 0;
2931 while (pCur)
2932 {
2933 size_t cbSeg = MBLKL(pCur);
2934 if (cbSeg)
2935 {
2936 void *pvSeg = pCur->b_rptr;
2937 pSG->aSegs[iSeg].pv = pvSeg;
2938 pSG->aSegs[iSeg].cb = cbSeg;
2939 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
2940 pSG->cbTotal += cbSeg;
2941 iSeg++;
2942 }
2943 pCur = pCur->b_cont;
2944 }
2945 pSG->cSegsUsed = iSeg;
2946
2947#ifdef PADD_RUNT_FRAMES_FROM_HOST
2948 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
2949 {
2950 Log((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pulling up to length.\n"));
2951
2952 static uint8_t const s_abZero[128] = {0};
2953 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
2954 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
2955 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
2956 pSG->cbTotal = 60;
2957 pSG->cSegsUsed++;
2958 Assert(iSeg + 1 < cSegs);
2959 }
2960#endif
2961
2962 Log((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
2963 return VINF_SUCCESS;
2964}
2965
2966
2967/**
2968 * Converts raw mode M_DATA messages to M_PROTO DL_UNITDATA_IND format.
2969 *
2970 * @returns VBox status code.
2971 * @param pMsg Pointer to the raw message.
2972 * @param ppDlpiMsg Where to store the M_PROTO message.
2973 *
2974 * @remarks The original raw message would be no longer valid and will be
2975 * linked as part of the new DLPI message. Callers must take care
2976 * not to use the raw message if this routine is successful.
2977 */
2978static int vboxNetFltSolarisRawToUnitData(mblk_t *pMsg, mblk_t **ppDlpiMsg)
2979{
2980 LogFunc((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData pMsg=%p\n", pMsg));
2981
2982 if (DB_TYPE(pMsg) != M_DATA)
2983 return VERR_NO_MEMORY;
2984
2985 size_t cbMsg = sizeof(dl_unitdata_ind_t) + 2 * sizeof(vboxnetflt_dladdr_t);
2986 mblk_t *pDlpiMsg = allocb(cbMsg, BPRI_MED);
2987 if (RT_UNLIKELY(!pDlpiMsg))
2988 return VERR_NO_MEMORY;
2989
2990 DB_TYPE(pDlpiMsg) = M_PROTO;
2991 dl_unitdata_ind_t *pDlpiData = (dl_unitdata_ind_t *)pDlpiMsg->b_rptr;
2992 pDlpiData->dl_primitive = DL_UNITDATA_IND;
2993 pDlpiData->dl_dest_addr_length = VBOXNETFLT_DLADDRL;
2994 pDlpiData->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
2995 pDlpiData->dl_src_addr_length = VBOXNETFLT_DLADDRL;
2996 pDlpiData->dl_src_addr_offset = VBOXNETFLT_DLADDRL + sizeof(dl_unitdata_ind_t);
2997
2998 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
2999
3000 vboxnetflt_dladdr_t *pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_dest_addr_offset);
3001 pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
3002 bcopy(&pEthHdr->DstMac, &pDlAddr->Mac, sizeof(RTMAC));
3003
3004 pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_src_addr_offset);
3005 pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
3006 bcopy(&pEthHdr->SrcMac, &pDlAddr->Mac, sizeof(RTMAC));
3007
3008 pDlpiMsg->b_wptr = pDlpiMsg->b_rptr + cbMsg;
3009
3010 /* Make the message point to the protocol header */
3011 pMsg->b_rptr += sizeof(RTNETETHERHDR);
3012
3013 pDlpiMsg->b_cont = pMsg;
3014 *ppDlpiMsg = pDlpiMsg;
3015 return VINF_SUCCESS;
3016}
3017
3018#if 0
3019/**
3020 * Converts DLPI M_PROTO messages to the raw mode M_DATA format.
3021 *
3022 * @returns VBox status code.
3023 * @param pMsg Pointer to the M_PROTO message.
3024 * @param ppRawMsg Where to store the converted message.
3025 *
3026 * @remarks If successful, the original pMsg is no longer valid, it will be deleted.
3027 * Callers must take care not to continue to use pMsg after a successful
3028 * call to this conversion routine.
3029 */
3030static int vboxNetFltSolarisUnitDataToRaw(PVBOXNETFLTINS pThis, mblk_t *pMsg, mblk_t **ppRawMsg)
3031{
3032 LogFunc((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw pMsg=%p\n", pMsg));
3033
3034 if ( !pMsg->b_cont
3035 || DB_TYPE(pMsg) != M_PROTO)
3036 {
3037 LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw invalid input message.\n"));
3038 return VERR_NET_PROTOCOL_ERROR;
3039 }
3040
3041 /*
3042 * Upstream consumers send/receive packets in the fast path mode.
3043 * We of course need to convert them into raw ethernet frames.
3044 */
3045 RTNETETHERHDR EthHdr;
3046 union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
3047 switch (pPrim->dl_primitive)
3048 {
3049 case DL_UNITDATA_IND:
3050 {
3051 /*
3052 * Receive side.
3053 */
3054 dl_unitdata_ind_t *pDlpiMsg = (dl_unitdata_ind_t *)pMsg->b_rptr;
3055 bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
3056 bcopy(pMsg->b_rptr + pDlpiMsg->dl_src_addr_offset, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
3057
3058 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
3059 EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
3060
3061 break;
3062 }
3063
3064 case DL_UNITDATA_REQ:
3065 {
3066 /*
3067 * Send side.
3068 */
3069 dl_unitdata_req_t *pDlpiMsg = (dl_unitdata_req_t *)pMsg->b_rptr;
3070
3071 bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
3072 bcopy(&pThis->u.s.MacAddr, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
3073
3074 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
3075 EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
3076
3077 break;
3078 }
3079
3080 default:
3081 {
3082 LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw Unknown M_PROTO. This shouldn't be happening!!"));
3083 return VERR_NET_PROTOCOL_ERROR;
3084 }
3085 }
3086
3087 /*
3088 * Let us just link it as a mblk_t chain rather than re-copy the entire message.
3089 * The vboxNetFltSolarisMBlkToSG function will handle chained mblk_t's.
3090 */
3091 size_t cbLen = sizeof(EthHdr);
3092 mblk_t *pEtherMsg = allocb(cbLen, BPRI_MED);
3093 if (RT_UNLIKELY(!pEtherMsg))
3094 return VERR_NO_MEMORY;
3095
3096 DB_TYPE(pEtherMsg) = M_DATA;
3097 bcopy(&EthHdr, pEtherMsg->b_wptr, sizeof(EthHdr));
3098 pEtherMsg->b_wptr += cbLen;
3099
3100 pEtherMsg->b_cont = pMsg->b_cont;
3101
3102 /*
3103 * Change the chained blocks to type M_DATA.
3104 */
3105 for (mblk_t *pTmp = pEtherMsg->b_cont; pTmp; pTmp = pTmp->b_cont)
3106 DB_TYPE(pTmp) = M_DATA;
3107
3108 pMsg->b_cont = NULL;
3109 freemsg(pMsg);
3110
3111 *ppRawMsg = pEtherMsg;
3112 return VINF_SUCCESS;
3113}
3114#endif
3115
3116/**
3117 * Initializes a packet identifier.
3118 *
3119 * @param pTag Pointer to the packed identifier.
3120 * @param pMsg Pointer to the message to be identified.
3121 *
3122 * @remarks Warning!!! This function assumes 'pMsg' is an unchained message.
3123 */
3124static inline void vboxNetFltSolarisInitPacketId(PVBOXNETFLTPACKETID pTag, mblk_t *pMsg)
3125{
3126 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
3127 size_t cbMsg = MBLKL(pMsg);
3128
3129 pTag->cbPacket = cbMsg;
3130 pTag->Checksum = RTCrc32(pMsg->b_rptr, cbMsg);
3131 bcopy(&pEthHdr->SrcMac, &pTag->SrcMac, sizeof(RTMAC));
3132 bcopy(&pEthHdr->DstMac, &pTag->DstMac, sizeof(RTMAC));
3133}
3134
3135
3136/**
3137 * Queues a packet for loopback elimination.
3138 *
3139 * @returns VBox status code.
3140 * @param pThis The instance.
3141 * @param pPromiscStream Pointer to the promiscuous stream.
3142 * @param pMsg Pointer to the message.
3143 */
3144static int vboxNetFltSolarisQueueLoopback(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg)
3145{
3146 Assert(pThis);
3147 Assert(pMsg);
3148 Assert(DB_TYPE(pMsg) == M_DATA);
3149 Assert(pPromiscStream);
3150
3151 LogFunc((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback pThis=%p pPromiscStream=%p pMsg=%p\n", pThis, pPromiscStream, pMsg));
3152
3153 if (RT_UNLIKELY(pMsg->b_cont))
3154 {
3155 /*
3156 * We don't currently make chained messages in on Xmit
3157 * so this only needs to be supported when we do that.
3158 */
3159 return VERR_NOT_SUPPORTED;
3160 }
3161
3162 size_t cbMsg = MBLKL(pMsg);
3163 if (RT_UNLIKELY(cbMsg < sizeof(RTNETETHERHDR)))
3164 return VERR_NET_MSG_SIZE;
3165
3166 int rc = VINF_SUCCESS;
3167 mutex_enter(&pThis->u.s.hMtx);
3168
3169 PVBOXNETFLTPACKETID pCur = NULL;
3170 if (pPromiscStream->cLoopback < VBOXNETFLT_LOOPBACK_SIZE
3171 || ( pPromiscStream->pHead
3172 && pPromiscStream->pHead->cbPacket == 0))
3173 {
3174 do
3175 {
3176 if (!pPromiscStream->pHead)
3177 {
3178 pCur = RTMemAlloc(sizeof(VBOXNETFLTPACKETID));
3179 if (RT_UNLIKELY(!pCur))
3180 {
3181 rc = VERR_NO_MEMORY;
3182 break;
3183 }
3184
3185 vboxNetFltSolarisInitPacketId(pCur, pMsg);
3186
3187 pCur->pNext = NULL;
3188 pPromiscStream->pHead = pCur;
3189 pPromiscStream->pTail = pCur;
3190 pPromiscStream->cLoopback++;
3191
3192 Log((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback initialized head. checksum=%u.\n",
3193 pPromiscStream->pHead->Checksum));
3194 break;
3195 }
3196 else if ( pPromiscStream->pHead
3197 && pPromiscStream->pHead->cbPacket == 0)
3198 {
3199 pCur = pPromiscStream->pHead;
3200 vboxNetFltSolarisInitPacketId(pCur, pMsg);
3201
3202 Log((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback re-used head checksum=%u cLoopback=%d.\n",
3203 pCur->Checksum, pPromiscStream->cLoopback));
3204 break;
3205 }
3206 else
3207 {
3208 pCur = RTMemAlloc(sizeof(VBOXNETFLTPACKETID));
3209 if (RT_UNLIKELY(!pCur))
3210 {
3211 rc = VERR_NO_MEMORY;
3212 break;
3213 }
3214
3215 vboxNetFltSolarisInitPacketId(pCur, pMsg);
3216
3217 pCur->pNext = pPromiscStream->pHead;
3218 pPromiscStream->pHead = pCur;
3219 pPromiscStream->cLoopback++;
3220
3221 Log((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback added head checksum=%u cLoopback=%d.\n", pCur->Checksum,
3222 pPromiscStream->cLoopback));
3223 break;
3224 }
3225 } while (0);
3226 }
3227 else
3228 {
3229 /*
3230 * Maximum loopback queue size reached. Re-use tail as head.
3231 */
3232 Assert(pPromiscStream->pHead);
3233 Assert(pPromiscStream->pTail);
3234
3235 /*
3236 * Find tail's previous item.
3237 */
3238 PVBOXNETFLTPACKETID pPrev = NULL;
3239 pCur = pPromiscStream->pHead;
3240
3241 /** @todo consider if this is worth switching to a double linked list... */
3242 while (pCur != pPromiscStream->pTail)
3243 {
3244 pPrev = pCur;
3245 pCur = pCur->pNext;
3246 }
3247
3248 pPromiscStream->pTail = pPrev;
3249 pPromiscStream->pTail->pNext = NULL;
3250 pCur->pNext = pPromiscStream->pHead;
3251 pPromiscStream->pHead = pCur;
3252
3253 vboxNetFltSolarisInitPacketId(pCur, pMsg);
3254 Log((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback recycled tail!! checksum=%u cLoopback=%d\n", pCur->Checksum,
3255 pPromiscStream->cLoopback));
3256 }
3257
3258 mutex_exit(&pThis->u.s.hMtx);
3259
3260 return rc;
3261}
3262
3263
3264/**
3265 * Checks if the packet is enqueued for loopback as our own packet.
3266 *
3267 * @returns If it's our packet, returns true after dequeuing it, otherwise false.
3268 * @param pThis The instance.
3269 * @param pPromiscStream Pointer to the promiscuous stream.
3270 * @param pMsg Pointer to the message.
3271 */
3272static bool vboxNetFltSolarisIsOurMBlk(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg)
3273{
3274 Assert(pThis);
3275 Assert(pPromiscStream);
3276 Assert(pMsg);
3277 Assert(DB_TYPE(pMsg) == M_DATA);
3278
3279 LogFunc((DEVICE_NAME ":vboxNetFltSolarisIsOurMBlk pThis=%p pMsg=%p\n", pThis, pMsg));
3280
3281 if (pMsg->b_cont)
3282 {
3283 /** Handle this when Xmit makes chained messages */
3284 return false;
3285 }
3286
3287 size_t cbMsg = MBLKL(pMsg);
3288 if (cbMsg < sizeof(RTNETETHERHDR))
3289 return false;
3290
3291 mutex_enter(&pThis->u.s.hMtx);
3292
3293 PVBOXNETFLTPACKETID pPrev = NULL;
3294 PVBOXNETFLTPACKETID pCur = pPromiscStream->pHead;
3295 bool fIsOurPacket = false;
3296 while (pCur)
3297 {
3298 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
3299 if ( pCur->cbPacket != cbMsg
3300 || pCur->SrcMac.au8[0] != pEthHdr->SrcMac.au8[0]
3301 || pCur->SrcMac.au8[1] != pEthHdr->SrcMac.au8[1]
3302 || pCur->SrcMac.au8[2] != pEthHdr->SrcMac.au8[2]
3303 || pCur->SrcMac.au8[3] != pEthHdr->SrcMac.au8[3]
3304 || pCur->SrcMac.au8[4] != pEthHdr->SrcMac.au8[4]
3305 || pCur->SrcMac.au8[5] != pEthHdr->SrcMac.au8[5]
3306 || pCur->DstMac.au8[0] != pEthHdr->DstMac.au8[0]
3307 || pCur->DstMac.au8[1] != pEthHdr->DstMac.au8[1]
3308 || pCur->DstMac.au8[2] != pEthHdr->DstMac.au8[2]
3309 || pCur->DstMac.au8[3] != pEthHdr->DstMac.au8[3]
3310 || pCur->DstMac.au8[4] != pEthHdr->DstMac.au8[4]
3311 || pCur->DstMac.au8[5] != pEthHdr->DstMac.au8[5])
3312 {
3313 pPrev = pCur;
3314 pCur = pCur->pNext;
3315 continue;
3316 }
3317
3318 uint16_t Checksum = RTCrc32(pMsg->b_rptr, cbMsg);
3319 if (pCur->Checksum != Checksum)
3320 {
3321 pPrev = pCur;
3322 pCur = pCur->pNext;
3323 continue;
3324 }
3325
3326 /*
3327 * Yes, it really is our own packet, mark it as handled
3328 * and move it as a "free slot" to the head and return success.
3329 */
3330 pCur->cbPacket = 0;
3331 if (pPrev)
3332 {
3333 if (!pCur->pNext)
3334 pPromiscStream->pTail = pPrev;
3335
3336 pPrev->pNext = pCur->pNext;
3337 pCur->pNext = pPromiscStream->pHead;
3338 pPromiscStream->pHead = pCur;
3339 }
3340 fIsOurPacket = true;
3341
3342 Log((DEVICE_NAME ":vboxNetFltSolarisIsOurMBlk found packet %p Checksum=%u cLoopback=%d\n", pMsg, Checksum,
3343 pPromiscStream->cLoopback));
3344 break;
3345 }
3346
3347 Log((DEVICE_NAME ":vboxNetFltSolarisIsOurMBlk returns %d.\n", fIsOurPacket));
3348 mutex_exit(&pThis->u.s.hMtx);
3349 return fIsOurPacket;
3350}
3351
3352
3353/**
3354 * Helper.
3355 */
3356DECLINLINE(bool) vboxNetFltPortSolarisIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
3357{
3358 /*
3359 * MAC address change acknowledgements are intercepted on the read side
3360 * hence theoretically we are always update to date with any changes.
3361 */
3362 return pThis->u.s.MacAddr.au16[0] == pMac->au16[0]
3363 && pThis->u.s.MacAddr.au16[1] == pMac->au16[1]
3364 && pThis->u.s.MacAddr.au16[2] == pMac->au16[2];
3365}
3366
3367
3368/**
3369 * Worker for routing messages from the wire or from the host.
3370 *
3371 * @returns VBox status code.
3372 * @param pThis The instance.
3373 * @param pStream Pointer to the stream.
3374 * @param pQueue Pointer to the read queue.
3375 * @param pMsg Pointer to the message.
3376 */
3377static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pMsg)
3378{
3379 LogFunc((DEVICE_NAME ":vboxNetFltSolarisRecv pThis=%p pMsg=%p\n", pThis, pMsg));
3380
3381 AssertCompile(sizeof(struct ether_header) == sizeof(RTNETETHERHDR));
3382 Assert(pStream->Type == kPromiscStream);
3383
3384 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream, vboxnetflt_promisc_stream_t *);
3385 if (RT_UNLIKELY(!pPromiscStream))
3386 {
3387 LogRel((DEVICE_NAME ":Promiscuous stream missing!! Failing to receive packet.\n"));
3388 return VERR_INVALID_POINTER;
3389 }
3390
3391 /*
3392 * Paranoia...
3393 */
3394 if (RT_UNLIKELY(MBLKL(pMsg) < sizeof(RTNETETHERHDR)))
3395 {
3396 size_t cbMsg = msgdsize(pMsg);
3397 if (cbMsg < sizeof(RTNETETHERHDR))
3398 {
3399 LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv %s: packet too small. Dropping packet.\n", pThis->szName));
3400 return VINF_SUCCESS;
3401 }
3402
3403 mblk_t *pFullMsg = msgpullup(pMsg, -1 /* all data blocks */);
3404 if (pFullMsg)
3405 {
3406 freemsg(pMsg);
3407 pMsg = pFullMsg;
3408 }
3409 else
3410 {
3411 LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv msgpullup failed.\n"));
3412 return VERR_NO_MEMORY;
3413 }
3414 }
3415
3416 /*
3417 * Don't loopback packets we transmit to the wire.
3418 */
3419 if (vboxNetFltSolarisIsOurMBlk(pThis, pPromiscStream, pMsg))
3420 {
3421 Log((DEVICE_NAME ":Avoiding packet loopback.\n"));
3422 return VINF_SUCCESS;
3423 }
3424
3425 /*
3426 * Figure out the source of the packet based on the source Mac address.
3427 */
3428 uint32_t fSrc = INTNETTRUNKDIR_WIRE;
3429 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
3430 if (vboxNetFltPortSolarisIsHostMac(pThis, &pEthHdr->SrcMac))
3431 fSrc = INTNETTRUNKDIR_HOST;
3432
3433 /*
3434 * Afaik; we no longer need to worry about incorrect checksums because we now use
3435 * a dedicated stream and don't intercept packets under IP/ARP which might be doing
3436 * checksum offloading.
3437 */
3438#if 0
3439 if (fSrc & INTNETTRUNKDIR_HOST)
3440 {
3441 mblk_t *pCorrectedMsg = vboxNetFltSolarisFixChecksums(pMsg);
3442 if (pCorrectedMsg)
3443 pMsg = pCorrectedMsg;
3444 }
3445 vboxNetFltSolarisAnalyzeMBlk(pMsg);
3446#endif
3447
3448 /*
3449 * Solaris raw mode streams for priority-tagged VLAN does not strip the VLAN tag.
3450 * It zero's the VLAN-Id but keeps the tag intact as part of the Ethernet header.
3451 * We need to manually strip these tags out or the guests might get confused.
3452 */
3453 bool fCopied = false;
3454 bool fTagged = false;
3455 if ( pThis->u.s.fVLAN
3456 && pPromiscStream->fRawMode)
3457 {
3458 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_VLAN))
3459 {
3460 if (msgdsize(pMsg) > sizeof(RTNETETHERHDR) + sizeof(VLANHEADER))
3461 {
3462 if (pMsg->b_cont)
3463 {
3464 mblk_t *pFullMsg = msgpullup(pMsg, -1 /* all data blocks */);
3465 if (pFullMsg)
3466 {
3467 /* Original pMsg will be freed by the caller */
3468 pMsg = pFullMsg;
3469 fCopied = true;
3470 }
3471 else
3472 {
3473 LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv msgpullup failed.\n"));
3474 return VERR_NO_MEMORY;
3475 }
3476 }
3477
3478 PVLANHEADER pVlanHdr = (PVLANHEADER)(pMsg->b_rptr + sizeof(RTNETETHERHDR) - sizeof(pEthHdr->EtherType));
3479 Log((DEVICE_NAME ":Recv VLAN Pcp=%u Cfi=%u Id=%u\n", VLAN_PRI(RT_BE2H_U16(pVlanHdr->Data)),
3480 VLAN_CFI(RT_BE2H_U16(pVlanHdr->Data)), VLAN_ID(RT_BE2H_U16(pVlanHdr->Data))));
3481 if ( VLAN_PRI(RT_BE2H_U16(pVlanHdr->Data)) > 0
3482 && VLAN_ID(RT_BE2H_U16(pVlanHdr->Data)) == 0)
3483 {
3484 /*
3485 * Create new Ethernet header with stripped VLAN tag.
3486 */
3487 size_t cbEthPrefix = sizeof(RTNETETHERHDR) - sizeof(pEthHdr->EtherType);
3488 mblk_t *pStrippedMsg = allocb(cbEthPrefix, BPRI_MED);
3489 if (RT_LIKELY(pStrippedMsg))
3490 {
3491 fTagged = true;
3492
3493 /*
3494 * Copy ethernet header excluding the ethertype.
3495 */
3496 bcopy(pMsg->b_rptr, pStrippedMsg->b_wptr, cbEthPrefix);
3497 pStrippedMsg->b_wptr += cbEthPrefix;
3498
3499 /*
3500 * Link the rest of the message (ethertype + data, skipping VLAN header).
3501 */
3502 pMsg->b_rptr += cbEthPrefix + sizeof(VLANHEADER);
3503 pStrippedMsg->b_cont = pMsg;
3504 pMsg = pStrippedMsg;
3505 Log((DEVICE_NAME ":Stripped VLAN tag.\n"));
3506 }
3507 else
3508 {
3509 LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv insufficient memory for creating VLAN stripped packet"
3510 " cbMsg=%u.\n", cbEthPrefix));
3511 if (fCopied)
3512 freemsg(pMsg);
3513 return VERR_NO_MEMORY;
3514 }
3515 }
3516 }
3517 }
3518 }
3519
3520 /*
3521 * Route all received packets into the internal network.
3522 */
3523 unsigned cSegs = vboxNetFltSolarisMBlkCalcSGSegs(pThis, pMsg);
3524 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
3525 int rc = vboxNetFltSolarisMBlkToSG(pThis, pMsg, pSG, cSegs, fSrc);
3526 if (RT_SUCCESS(rc))
3527 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc);
3528 else
3529 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG failed. rc=%d\n", rc));
3530
3531 /*
3532 * If we've allocated the prefix before the VLAN tag in a new message, free that.
3533 */
3534 if (fTagged)
3535 {
3536 mblk_t *pTagMsg = pMsg->b_cont;
3537 pMsg->b_cont = NULL; /* b_cont could be the message from the caller or a copy we made (fCopied) */
3538 freemsg(pMsg);
3539 pMsg = pTagMsg;
3540 }
3541
3542 /*
3543 * If we made an extra copy for VLAN stripping, we need to free that ourselves.
3544 */
3545 if (fCopied)
3546 freemsg(pMsg);
3547
3548 return VINF_SUCCESS;
3549}
3550
3551#if 0
3552/**
3553 * Finalize the message to be fed into the internal network.
3554 * Verifies and tries to fix checksums for TCP, UDP and IP.
3555 *
3556 * @returns Corrected message or NULL if no change was required.
3557 * @param pMsg Pointer to the message block.
3558 * This must not be DLPI linked messages, must be M_DATA.
3559 *
3560 * @remarks If this function returns a checksum adjusted message, the
3561 * passed in input message has been freed and should not be
3562 * referenced anymore by the caller.
3563 */
3564static mblk_t *vboxNetFltSolarisFixChecksums(mblk_t *pMsg)
3565{
3566 LogFunc((DEVICE_NAME ":vboxNetFltSolarisFixChecksums pMsg=%p\n"));
3567
3568 Assert(DB_TYPE(pMsg) == M_DATA);
3569
3570 if (MBLKL(pMsg) < sizeof(RTNETETHERHDR))
3571 {
3572 LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums Packet shorter than ethernet header size!\n"));
3573 return NULL;
3574 }
3575
3576 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
3577 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
3578 {
3579 /*
3580 * Check if we have a complete packet or being fed a chain.
3581 */
3582 size_t cbIpPacket = 0;
3583 mblk_t *pFullMsg = NULL;
3584 if (pMsg->b_cont)
3585 {
3586 Log((DEVICE_NAME ":Chained mblk_t.\n"));
3587
3588 /*
3589 * Handle chain by making a packet copy to verify if the IP checksum is correct.
3590 * Contributions to calculating IP checksums from a chained message block with
3591 * odd/non-pulled up sizes are welcome.
3592 */
3593 size_t cbFullMsg = msgdsize(pMsg);
3594 mblk_t *pFullMsg = allocb(cbFullMsg, BPRI_MED);
3595 Log((DEVICE_NAME ":msgdsize returns %d\n", cbFullMsg));
3596 if (RT_UNLIKELY(!pFullMsg))
3597 {
3598 LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums failed to alloc new message of %d bytes.\n", cbFullMsg));
3599 return NULL;
3600 }
3601
3602 for (mblk_t *pTmp = pMsg; pTmp; pTmp = pTmp->b_cont)
3603 {
3604 if (DB_TYPE(pTmp) == M_DATA)
3605 {
3606 bcopy(pTmp->b_rptr, pFullMsg->b_wptr, MBLKL(pTmp));
3607 pFullMsg->b_wptr += MBLKL(pTmp);
3608 }
3609 }
3610
3611 DB_TYPE(pFullMsg) = M_DATA;
3612 pEthHdr = (PRTNETETHERHDR)pFullMsg->b_rptr;
3613 cbIpPacket = MBLKL(pFullMsg) - sizeof(RTNETETHERHDR);
3614 }
3615 else
3616 cbIpPacket = MBLKL(pMsg) - sizeof(RTNETETHERHDR);
3617
3618 /*
3619 * Check if the IP checksum is valid.
3620 */
3621 uint8_t *pbProtocol = (uint8_t *)(pEthHdr + 1);
3622 PRTNETIPV4 pIpHdr = (PRTNETIPV4)pbProtocol;
3623 size_t cbPayload = cbIpPacket - (pIpHdr->ip_hl << 2);
3624 bool fChecksumAdjusted = false;
3625 if (RTNetIPv4IsHdrValid(pIpHdr, cbPayload, cbPayload))
3626 {
3627 pbProtocol += (pIpHdr->ip_hl << 2);
3628
3629 /*
3630 * Fix up TCP/UDP and IP checksums if they're incomplete/invalid.
3631 */
3632 if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
3633 {
3634 PRTNETTCP pTcpHdr = (PRTNETTCP)pbProtocol;
3635 uint16_t TcpChecksum = RTNetIPv4TCPChecksum(pIpHdr, pTcpHdr, NULL);
3636 if (pTcpHdr->th_sum != TcpChecksum)
3637 {
3638 pTcpHdr->th_sum = TcpChecksum;
3639 fChecksumAdjusted = true;
3640 Log((DEVICE_NAME ":fixed TCP checksum.\n"));
3641 }
3642 }
3643 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
3644 {
3645 PRTNETUDP pUdpHdr = (PRTNETUDP)pbProtocol;
3646 uint16_t UdpChecksum = RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1);
3647
3648 if (pUdpHdr->uh_sum != UdpChecksum)
3649 {
3650 pUdpHdr->uh_sum = UdpChecksum;
3651 fChecksumAdjusted = true;
3652 Log((DEVICE_NAME ":Fixed UDP checksum."));
3653 }
3654 }
3655 }
3656
3657 if (fChecksumAdjusted)
3658 {
3659 /*
3660 * If we made a copy and the checksum is corrected on the copy,
3661 * free the original, return the checksum fixed copy.
3662 */
3663 if (pFullMsg)
3664 {
3665 freemsg(pMsg);
3666 return pFullMsg;
3667 }
3668
3669 return pMsg;
3670 }
3671
3672 /*
3673 * If we made a copy and the checksum is NOT corrected, free the copy,
3674 * and return NULL.
3675 */
3676 if (pFullMsg)
3677 freemsg(pFullMsg);
3678
3679 return NULL;
3680 }
3681
3682 return NULL;
3683}
3684
3685
3686/**
3687 * Simple packet dump, used for internal debugging.
3688 *
3689 * @param pMsg Pointer to the message to analyze and dump.
3690 */
3691static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg)
3692{
3693 LogFunc((DEVICE_NAME ":vboxNetFltSolarisAnalyzeMBlk pMsg=%p\n", pMsg));
3694
3695 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
3696 uint8_t *pb = pMsg->b_rptr;
3697 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
3698 {
3699 PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
3700 size_t cbLen = MBLKL(pMsg) - sizeof(*pEthHdr);
3701 if (!pMsg->b_cont)
3702 {
3703 if (pIpHdr->ip_p == RTNETIPV4_PROT_ICMP)
3704 LogRel((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
3705 else if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
3706 LogRel((DEVICE_NAME ":TCP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
3707 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
3708 {
3709 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint32_t *)pIpHdr + pIpHdr->ip_hl);
3710 if ( RT_BE2H_U16(pUdpHdr->uh_sport) == 67
3711 && RT_BE2H_U16(pUdpHdr->uh_dport) == 68)
3712 {
3713 LogRel((DEVICE_NAME ":UDP bootp ack D=%.6Rhxs S=%.6Rhxs UDP_CheckSum=%04x Computex=%04x\n", pb, pb + 6,
3714 RT_BE2H_U16(pUdpHdr->uh_sum), RT_BE2H_U16(RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1))));
3715 }
3716 }
3717 }
3718 else
3719 {
3720 Log((DEVICE_NAME ":Chained IP packet. Skipping validity check.\n"));
3721 }
3722 }
3723 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_VLAN))
3724 {
3725 PVLANHEADER pVlanHdr = (PVLANHEADER)(pMsg->b_rptr + sizeof(RTNETETHERHDR) - sizeof(pEthHdr->EtherType));
3726 LogRel((DEVICE_NAME ":VLAN Pcp=%u Cfi=%u Id=%u\n", VLAN_PRI(RT_BE2H_U16(pVlanHdr->Data)),
3727 VLAN_CFI(RT_BE2H_U16(pVlanHdr->Data)), VLAN_ID(RT_BE2H_U16(pVlanHdr->Data))));
3728 LogRel((DEVICE_NAME "%.*Rhxd\n", sizeof(VLANHEADER), pVlanHdr));
3729 }
3730 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
3731 {
3732 PRTNETARPHDR pArpHdr = (PRTNETARPHDR)(pEthHdr + 1);
3733 LogRel((DEVICE_NAME ":ARP Op=%d\n", pArpHdr->ar_oper));
3734 }
3735 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
3736 {
3737 LogRel((DEVICE_NAME ":IPv6 D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
3738 }
3739 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_1)
3740 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_2)
3741 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_3))
3742 {
3743 LogRel((DEVICE_NAME ":IPX packet.\n"));
3744 }
3745 else
3746 {
3747 LogRel((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
3748 &pEthHdr->SrcMac));
3749 /* Log((DEVICE_NAME ":%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
3750 }
3751}
3752#endif
3753
3754
3755/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
3756
3757
3758
3759void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
3760{
3761 LogFunc((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d\n", pThis, fActive));
3762
3763 /*
3764 * Enable/disable promiscuous mode.
3765 */
3766 vboxnetflt_promisc_params_t *pData = RTMemAllocZ(sizeof(vboxnetflt_promisc_params_t));
3767 if (RT_LIKELY(pData))
3768 {
3769 /*
3770 * See @bugref{5262} as to why we need to do all this qtimeout/qwriter tricks.
3771 */
3772 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream,
3773 vboxnetflt_promisc_stream_t *);
3774 if ( pPromiscStream
3775 && pPromiscStream->Stream.pReadQueue)
3776 {
3777 pData->pThis = pThis;
3778 pData->fPromiscOn = fActive;
3779 if (ASMAtomicReadPtr(&pPromiscStream->TimeoutId))
3780 quntimeout(WR(pPromiscStream->Stream.pReadQueue), pPromiscStream->TimeoutId);
3781 timeout_id_t TimeoutId = qtimeout(WR(pPromiscStream->Stream.pReadQueue), vboxNetFltSolarisPromiscReqWrap,
3782 pData, 1 /* ticks */);
3783 ASMAtomicWritePtr(&pPromiscStream->TimeoutId, TimeoutId);
3784 return; /* pData will be freed by vboxNetFltSolarisPromiscReqWrap() */
3785 }
3786 else
3787 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d missing stream!\n", pThis, fActive));
3788 RTMemFree(pData);
3789 }
3790 else
3791 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive out of memory!\n"));
3792}
3793
3794
3795int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
3796{
3797 LogFunc((DEVICE_NAME ":vboxNetFltOsDisconnectIt pThis=%p\n", pThis));
3798
3799 vboxNetFltSolarisDetachFromInterface(pThis);
3800
3801 return VINF_SUCCESS;
3802}
3803
3804
3805int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
3806{
3807 /* Nothing to do here. */
3808 return VINF_SUCCESS;
3809}
3810
3811
3812void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
3813{
3814 LogFunc((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n", pThis));
3815
3816 mutex_destroy(&pThis->u.s.hMtx);
3817
3818#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
3819 if (pThis->u.s.hPollMtx != NIL_RTSEMFASTMUTEX)
3820 {
3821 RTSemFastMutexDestroy(pThis->u.s.hPollMtx);
3822 pThis->u.s.hPollMtx = NIL_RTSEMFASTMUTEX;
3823 }
3824#endif
3825
3826}
3827
3828
3829int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
3830{
3831 LogFunc((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p\n"));
3832
3833 /*
3834 * Mutex used for loopback lockouts.
3835 */
3836 int rc = VINF_SUCCESS;
3837 mutex_init(&pThis->u.s.hMtx, NULL /* name */, MUTEX_DRIVER, NULL /* cookie */);
3838#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
3839 rc = RTSemFastMutexCreate(&pThis->u.s.hPollMtx);
3840 if (RT_SUCCESS(rc))
3841 {
3842#endif
3843 rc = vboxNetFltSolarisAttachToInterface(pThis);
3844 if (RT_SUCCESS(rc))
3845 return rc;
3846
3847 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed. rc=%Rrc\n", rc));
3848
3849#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
3850 RTSemFastMutexDestroy(pThis->u.s.hPollMtx);
3851 pThis->u.s.hPollMtx = NIL_RTSEMFASTMUTEX;
3852 }
3853 else
3854 LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to create poll mutex. rc=%Rrc\n", rc));
3855#endif
3856
3857 mutex_destroy(&pThis->u.s.hMtx);
3858
3859 NOREF(pvContext);
3860 return rc;
3861}
3862
3863
3864int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
3865{
3866 /*
3867 * Init. the solaris specific data.
3868 */
3869 pThis->u.s.hIface = NULL;
3870 pThis->u.s.pIp4Stream = NULL;
3871 pThis->u.s.pIp6Stream = NULL;
3872 pThis->u.s.pArpStream = NULL;
3873 pThis->u.s.pPromiscStream = NULL;
3874 pThis->u.s.fAttaching = false;
3875 pThis->u.s.fVLAN = false;
3876#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
3877 pThis->u.s.hPollMtx = NIL_RTSEMFASTMUTEX;
3878#endif
3879 bzero(&pThis->u.s.MacAddr, sizeof(pThis->u.s.MacAddr));
3880 return VINF_SUCCESS;
3881}
3882
3883
3884bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
3885{
3886 /*
3887 * We don't support interface rediscovery on Solaris hosts because the
3888 * filter is very tightly bound to the stream.
3889 */
3890 return false;
3891}
3892
3893
3894void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
3895{
3896 NOREF(pThis); NOREF(pvIfData); NOREF(pMac);
3897}
3898
3899
3900int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
3901{
3902 /* Nothing to do */
3903 NOREF(pThis); NOREF(pvIf); NOREF(ppvIfData);
3904 return VINF_SUCCESS;
3905}
3906
3907
3908int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
3909{
3910 /* Nothing to do */
3911 NOREF(pThis); NOREF(pvIfData);
3912 return VINF_SUCCESS;
3913}
3914
3915
3916int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
3917{
3918 NOREF(pvIfData);
3919 LogFunc((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p pSG=%p fDst=%d\n", pThis, pSG, fDst));
3920
3921 int rc = VINF_SUCCESS;
3922 if (fDst & INTNETTRUNKDIR_WIRE)
3923 {
3924 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream,
3925 vboxnetflt_promisc_stream_t *);
3926 if (RT_LIKELY(pPromiscStream))
3927 {
3928 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
3929 if (RT_LIKELY(pMsg))
3930 {
3931 Log((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_WIRE\n"));
3932
3933 vboxNetFltSolarisQueueLoopback(pThis, pPromiscStream, pMsg);
3934 putnext(WR(pPromiscStream->Stream.pReadQueue), pMsg);
3935 }
3936 else
3937 {
3938 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
3939 return VERR_NO_MEMORY;
3940 }
3941 }
3942 }
3943
3944 if (fDst & INTNETTRUNKDIR_HOST)
3945 {
3946 /*
3947 * For unplumbed interfaces we would not be bound to IP or ARP.
3948 * We either bind to both or neither; so atomic reading one should be sufficient.
3949 */
3950 vboxnetflt_stream_t *pIp4Stream = ASMAtomicUoReadPtrT(&pThis->u.s.pIp4Stream, vboxnetflt_stream_t *);
3951 if (!pIp4Stream)
3952 return rc;
3953
3954 /*
3955 * Create a message block and send it up the host stack (upstream).
3956 */
3957 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
3958 if (RT_LIKELY(pMsg))
3959 {
3960 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
3961
3962 /*
3963 * Send message up ARP stream.
3964 */
3965 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
3966 {
3967 Log((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST ARP\n"));
3968
3969 vboxnetflt_stream_t *pArpStream = ASMAtomicUoReadPtrT(&pThis->u.s.pArpStream, vboxnetflt_stream_t *);
3970 if (pArpStream)
3971 {
3972 /*
3973 * Construct a DL_UNITDATA_IND style message for ARP as it doesn't understand fast path.
3974 */
3975 mblk_t *pDlpiMsg;
3976 rc = vboxNetFltSolarisRawToUnitData(pMsg, &pDlpiMsg);
3977 if (RT_SUCCESS(rc))
3978 {
3979 pMsg = pDlpiMsg;
3980
3981 queue_t *pArpReadQueue = pArpStream->pReadQueue;
3982 putnext(pArpReadQueue, pMsg);
3983 }
3984 else
3985 {
3986 LogRel((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData failed!\n"));
3987 freemsg(pMsg);
3988 rc = VERR_NO_MEMORY;
3989 }
3990 }
3991 else
3992 freemsg(pMsg); /* Should really never happen... */
3993 }
3994 else
3995 {
3996 vboxnetflt_stream_t *pIp6Stream = ASMAtomicUoReadPtrT(&pThis->u.s.pIp6Stream, vboxnetflt_stream_t *);
3997 if ( pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6)
3998 && pIp6Stream)
3999 {
4000 /*
4001 * Send messages up IPv6 stream.
4002 */
4003 Log((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST IPv6\n"));
4004
4005 pMsg->b_rptr += sizeof(RTNETETHERHDR);
4006 queue_t *pIp6ReadQueue = pIp6Stream->pReadQueue;
4007 putnext(pIp6ReadQueue, pMsg);
4008 }
4009 else
4010 {
4011 /*
4012 * Send messages up IPv4 stream.
4013 */
4014 Log((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST IPv4\n"));
4015
4016 pMsg->b_rptr += sizeof(RTNETETHERHDR);
4017 queue_t *pIp4ReadQueue = pIp4Stream->pReadQueue;
4018 putnext(pIp4ReadQueue, pMsg);
4019 }
4020 }
4021 }
4022 else
4023 {
4024 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed.\n"));
4025 rc = VERR_NO_MEMORY;
4026 }
4027 }
4028
4029 return rc;
4030}
4031
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