VirtualBox

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

Last change on this file since 105745 was 98807, checked in by vboxsync, 21 months ago

Some small Solaris-specific build warning fixes:

Main/Console: Remove a duplicate 'HRESULT hrc' declaration (flagged as
'warning: declaration of ‘hrc’ shadows a previous local [-Wshadow]').

Main/PerformanceSolaris: Move global variable ‘g_fNotReported’ behind
'if ARCH_BITS == 32' as it's only used in 32-bit mode (flagged as
'warning: ‘g_fNotReported’ defined but not used [-Wunused-variable]').

HostDrivers/VBoxNetFlt: The vboxNetFltSolarisMuxIdToFd() routine calls
the Solaris STREAMS kernel routine strioctl() which only sets the
seventh argument (int *rvalp) upon success. vboxNetFltSolarisMuxIdToFd()
passes in an 'int *pFd' argument for this returned value and logically
only sets it upon success. The subsequent code ignores 'pFd' upon
failure but the compiler isn't smart enough to figure that out so add in
an initialization for '*pFd' (flagged as 'warning: ‘Ip6MuxFd’ may be used
uninitialized [-Wmaybe-uninitialized]' and similarly for 'Ip4MuxFd' and
'ArpMuxFd').

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