VirtualBox

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

Last change on this file since 94887 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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