VirtualBox

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

Last change on this file since 96586 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 140.0 KB
Line 
1/* $Id: VBoxNetFlt-solaris.c 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * VBoxNetFlt - Network Filter Driver (Host), Solaris Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008-2022 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 int rc = strioctl(pVNode, _I_MUXID2FD, (intptr_t)MuxId, 0, K_TO_K, kcred, &ret);
1841 if (!rc)
1842 {
1843 *pFd = ret;
1844 return VINF_SUCCESS;
1845 }
1846
1847 return RTErrConvertFromErrno(rc);
1848}
1849
1850
1851/**
1852 * Relinks the lower and the upper IPv4 stream.
1853 *
1854 * @returns VBox status code.
1855 * @param pVNode Pointer to the device vnode.
1856 * @param pInterface Pointer to the interface.
1857 * @param IpMuxFd The IP multiplexor ID.
1858 * @param ArpMuxFd The ARP multiplexor ID.
1859 */
1860static int vboxNetFltSolarisRelinkIp4(vnode_t *pVNode, struct lifreq *pInterface, int IpMuxFd, int ArpMuxFd)
1861{
1862 LogFunc((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: pVNode=%p pInterface=%p IpMuxFd=%d ArpMuxFd=%d\n", pVNode,
1863 pInterface, IpMuxFd, ArpMuxFd));
1864
1865 int NewIpMuxId;
1866 int NewArpMuxId;
1867 int rc = strioctl(pVNode, I_PLINK, (intptr_t)IpMuxFd, 0, K_TO_K, kcred, &NewIpMuxId);
1868 int rc2 = strioctl(pVNode, I_PLINK, (intptr_t)ArpMuxFd, 0, K_TO_K, kcred, &NewArpMuxId);
1869 if ( !rc
1870 && !rc2)
1871 {
1872 pInterface->lifr_ip_muxid = NewIpMuxId;
1873 pInterface->lifr_arp_muxid = NewArpMuxId;
1874 rc = vboxNetFltSolarisSetMuxId(pVNode, pInterface);
1875 if (RT_SUCCESS(rc))
1876 return VINF_SUCCESS;
1877
1878 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: failed to set new Mux Id.\n"));
1879 }
1880 else
1881 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: failed to link.\n"));
1882
1883 return VERR_GENERAL_FAILURE;
1884}
1885
1886
1887/**
1888 * Relinks the lower and the upper IPv6 stream.
1889 *
1890 * @returns VBox status code.
1891 * @param pVNode Pointer to the device vnode.
1892 * @param pInterface Pointer to the interface.
1893 * @param Ip6MuxFd The IPv6 multiplexor ID.
1894 */
1895static int vboxNetFltSolarisRelinkIp6(vnode_t *pVNode, struct lifreq *pInterface, int Ip6MuxFd)
1896{
1897 LogFunc((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: pVNode=%p pInterface=%p Ip6MuxFd=%d\n", pVNode, pInterface, Ip6MuxFd));
1898
1899 int NewIp6MuxId;
1900 int rc = strioctl(pVNode, I_PLINK, (intptr_t)Ip6MuxFd, 0, K_TO_K, kcred, &NewIp6MuxId);
1901 if (!rc)
1902 {
1903 pInterface->lifr_ip_muxid = NewIp6MuxId;
1904 rc = vboxNetFltSolarisSetMuxId(pVNode, pInterface);
1905 if (RT_SUCCESS(rc))
1906 return VINF_SUCCESS;
1907
1908 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: failed to set new Mux Id.\n"));
1909 }
1910 else
1911 LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: failed to link.\n"));
1912
1913 return VERR_GENERAL_FAILURE;
1914}
1915
1916
1917/**
1918 * Dynamically find the position on the host stack where to attach/detach ourselves.
1919 *
1920 * @returns VBox status code.
1921 * @param fAttach Is this an attach or detach.
1922 * @param pVNode Pointer to the lower stream vnode.
1923 * @param pModPos Where to store the module position.
1924 */
1925static int vboxNetFltSolarisDetermineModPos(bool fAttach, vnode_t *pVNode, int *pModPos)
1926{
1927 LogFunc((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: fAttach=%d pVNode=%p pModPos=%p\n", fAttach, pVNode, pModPos));
1928
1929 int cMod;
1930 int rc = strioctl(pVNode, I_LIST, (intptr_t)NULL, 0, K_TO_K, kcred, &cMod);
1931 if (!rc)
1932 {
1933 if (cMod < 1)
1934 {
1935 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: too few modules on host interface. cMod=%d\n"));
1936 return VERR_OUT_OF_RANGE;
1937 }
1938
1939 /*
1940 * While attaching we make sure we are at the bottom most of the stack, excepting
1941 * the host driver.
1942 */
1943 Log((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: cMod=%d\n", cMod));
1944 if (fAttach)
1945 {
1946 *pModPos = cMod - 1;
1947 return VINF_SUCCESS;
1948 }
1949
1950 /*
1951 * Detaching is a bit more complicated; since user could have altered the stack positions
1952 * we take the safe approach by finding our position.
1953 */
1954 struct str_list StrList;
1955 StrList.sl_nmods = cMod;
1956 StrList.sl_modlist = RTMemAllocZ(cMod * sizeof(struct str_list));
1957 if (RT_UNLIKELY(!StrList.sl_modlist))
1958 {
1959 Log((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to alloc memory for StrList.\n"));
1960 return VERR_NO_MEMORY;
1961 }
1962
1963 /*
1964 * Get the list of all modules on the stack.
1965 */
1966 int ret;
1967 rc = strioctl(pVNode, I_LIST, (intptr_t)&StrList, 0, K_TO_K, kcred, &ret);
1968 if (!rc)
1969 {
1970 /*
1971 * Find our filter.
1972 */
1973 for (int i = 0; i < StrList.sl_nmods; i++)
1974 {
1975 if (!strcmp(DEVICE_NAME, StrList.sl_modlist[i].l_name))
1976 {
1977 Log((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: Success! Found %s at %d.\n", DEVICE_NAME, i));
1978 *pModPos = i;
1979 RTMemFree(StrList.sl_modlist);
1980 return VINF_SUCCESS;
1981 }
1982 }
1983
1984 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to find %s in the host stack.\n", DEVICE_NAME));
1985 }
1986 else
1987 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get module information. rc=%d\n"));
1988
1989 RTMemFree(StrList.sl_modlist);
1990 }
1991 else
1992 LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get list of modules on host interface. rc=%d\n", rc));
1993 return VERR_GENERAL_FAILURE;
1994}
1995
1996
1997/**
1998 * Opens up the DLPI style 2 link that requires explicit PPA attach
1999 * phase.
2000 *
2001 * @returns VBox status code.
2002 * @param pThis The instance.
2003 * @param pDevId Where to store the opened LDI device id.
2004 */
2005static int vboxNetFltSolarisOpenStyle2(PVBOXNETFLTINS pThis, ldi_ident_t *pDevId)
2006{
2007 /*
2008 * Strip out PPA from the device name, eg: "ce3".
2009 */
2010 char *pszDev = RTStrDup(pThis->szName);
2011 if (!pszDev)
2012 return VERR_NO_MEMORY;
2013
2014 char *pszEnd = strchr(pszDev, '\0');
2015 while (--pszEnd > pszDev)
2016 if (!RT_C_IS_DIGIT(*pszEnd))
2017 break;
2018 pszEnd++;
2019
2020 int rc = VERR_GENERAL_FAILURE;
2021 long PPA = -1;
2022 if ( pszEnd
2023 && ddi_strtol(pszEnd, NULL, 10, &PPA) == 0)
2024 {
2025 *pszEnd = '\0';
2026 char szDev[128];
2027 RTStrPrintf(szDev, sizeof(szDev), "/dev/%s", pszDev);
2028
2029 /*
2030 * Try open the device as DPLI style 2.
2031 */
2032 rc = ldi_open_by_name(szDev, FREAD | FWRITE, kcred, &pThis->u.s.hIface, *pDevId);
2033 if (!rc)
2034 {
2035 /*
2036 * Attach the PPA explictly.
2037 */
2038 rc = vboxNetFltSolarisAttachReq(pThis->u.s.hIface, (int)PPA);
2039 if (RT_SUCCESS(rc))
2040 {
2041 RTStrFree(pszDev);
2042 return rc;
2043 }
2044
2045 ldi_close(pThis->u.s.hIface, FREAD | FWRITE, kcred);
2046 pThis->u.s.hIface = NULL;
2047 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStyle2 dl_attach failed. rc=%d szDev=%s PPA=%d rc=%d\n", rc, szDev, PPA));
2048 }
2049 else
2050 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStyle2 Failed to open. rc=%d szDev=%s PPA=%d\n", rc, szDev, PPA));
2051 }
2052 else
2053 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStyle2 Failed to construct PPA. pszDev=%s pszEnd=%s.\n", pszDev, pszEnd));
2054
2055 RTStrFree(pszDev);
2056 return VERR_INTNET_FLT_IF_FAILED;
2057}
2058
2059
2060/**
2061 * Opens up dedicated stream on top of the interface.
2062 * As a side-effect, the stream gets opened during
2063 * the I_PUSH phase.
2064 *
2065 * @param pThis The instance.
2066 */
2067static int vboxNetFltSolarisOpenStream(PVBOXNETFLTINS pThis)
2068{
2069 ldi_ident_t DevId;
2070 DevId = ldi_ident_from_anon();
2071 int ret;
2072
2073 /*
2074 * Figure out if this is a VLAN interface or not based on the interface name.
2075 * Only works for the VLAN PPA-hack based names. See @bugref{4854} for details.
2076 */
2077 char *pszEnd = strchr(pThis->szName, '\0');
2078 while (--pszEnd > pThis->szName)
2079 if (!RT_C_IS_DIGIT(*pszEnd))
2080 break;
2081 pszEnd++;
2082 uint32_t PPA = RTStrToUInt32(pszEnd);
2083 if (PPA > 1000)
2084 {
2085 pThis->u.s.fVLAN = true;
2086 LogRel((DEVICE_NAME ": %s detected as VLAN interface with VID=%u.\n", pThis->szName, PPA / 1000U));
2087 }
2088
2089 /*
2090 * Try style-1 open first.
2091 */
2092 char szDev[128];
2093 RTStrPrintf(szDev, sizeof(szDev), "/dev/net/%s", pThis->szName);
2094 int rc = ldi_open_by_name(szDev, FREAD | FWRITE, kcred, &pThis->u.s.hIface, DevId);
2095 if ( rc
2096 && rc == ENODEV) /* ENODEV is returned when resolvepath fails, not ENOENT */
2097 {
2098 /*
2099 * Fallback to non-ClearView style-1 open.
2100 */
2101 RTStrPrintf(szDev, sizeof(szDev), "/dev/%s", pThis->szName);
2102 rc = ldi_open_by_name(szDev, FREAD | FWRITE, kcred, &pThis->u.s.hIface, DevId);
2103 }
2104
2105 if (rc)
2106 {
2107 /*
2108 * Try DLPI style 2.
2109 */
2110 rc = vboxNetFltSolarisOpenStyle2(pThis, &DevId);
2111 if (RT_FAILURE(rc))
2112 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream vboxNetFltSolarisOpenStyle2 failed. rc=%d\n", rc));
2113 else
2114 rc = 0;
2115 }
2116
2117 ldi_ident_release(DevId);
2118 if (rc)
2119 {
2120 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to open '%s' rc=%d pszName='%s'\n", szDev, rc, pThis->szName));
2121 return VERR_INTNET_FLT_IF_FAILED;
2122 }
2123
2124 rc = ldi_ioctl(pThis->u.s.hIface, I_FIND, (intptr_t)DEVICE_NAME, FKIOCTL, kcred, &ret);
2125 if (!rc)
2126 {
2127 if (!ret)
2128 {
2129 if (RT_LIKELY(g_pVBoxNetFltSolarisCred)) /* Paranoia */
2130 {
2131 rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
2132 AssertRCReturn(rc, rc);
2133
2134 g_VBoxNetFltSolarisInstance = pThis;
2135 g_VBoxNetFltSolarisStreamType = kPromiscStream;
2136
2137 rc = ldi_ioctl(pThis->u.s.hIface, I_PUSH, (intptr_t)DEVICE_NAME, FKIOCTL, g_pVBoxNetFltSolarisCred, &ret);
2138
2139 g_VBoxNetFltSolarisInstance = NULL;
2140 g_VBoxNetFltSolarisStreamType = kUndefined;
2141
2142 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
2143 }
2144 else
2145 {
2146 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream huh!? Missing credentials.\n"));
2147 rc = VERR_INVALID_POINTER;
2148 }
2149
2150 if (!rc)
2151 return VINF_SUCCESS;
2152
2153 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to push filter onto host interface '%s'\n", pThis->szName));
2154 }
2155 else
2156 return VINF_SUCCESS;
2157 }
2158 else
2159 LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to search for filter in interface '%s'.\n", pThis->szName));
2160
2161 ldi_close(pThis->u.s.hIface, FREAD | FWRITE, kcred);
2162 pThis->u.s.hIface = NULL;
2163
2164 return VERR_INTNET_FLT_IF_FAILED;
2165}
2166
2167
2168/**
2169 * Closes the interface, thereby closing the dedicated stream.
2170 *
2171 * @param pThis The instance.
2172 */
2173static void vboxNetFltSolarisCloseStream(PVBOXNETFLTINS pThis)
2174{
2175 LogFunc((DEVICE_NAME ":vboxNetFltSolarisCloseStream pThis=%p\n"));
2176
2177 if (pThis->u.s.hIface)
2178 {
2179 ldi_close(pThis->u.s.hIface, FREAD | FWRITE, kcred);
2180 pThis->u.s.hIface = NULL;
2181 }
2182}
2183
2184
2185/**
2186 * Dynamically attach under IPv4 and ARP streams on the host stack.
2187 *
2188 * @returns VBox status code.
2189 * @param pThis The instance.
2190 * @param fAttach Is this an attach or detach.
2191 */
2192static int vboxNetFltSolarisAttachIp4(PVBOXNETFLTINS pThis, bool fAttach)
2193{
2194 LogFunc((DEVICE_NAME ":vboxNetFltSolarisAttachIp4 pThis=%p fAttach=%d\n", pThis, fAttach));
2195
2196 /*
2197 * Statutory Warning: Hackish code ahead.
2198 */
2199 char *pszModName = DEVICE_NAME;
2200
2201 struct lifreq Ip4Interface;
2202 bzero(&Ip4Interface, sizeof(Ip4Interface));
2203 Ip4Interface.lifr_addr.ss_family = AF_INET;
2204 strncpy(Ip4Interface.lifr_name, pThis->szName, sizeof(Ip4Interface.lifr_name));
2205
2206 struct strmodconf StrMod;
2207 StrMod.mod_name = pszModName;
2208 StrMod.pos = -1; /* this is filled in later. */
2209
2210 struct strmodconf ArpStrMod;
2211 bcopy(&StrMod, &ArpStrMod, sizeof(StrMod));
2212
2213 int rc;
2214 int rc2;
2215 int ret;
2216 ldi_ident_t DeviceIdent = ldi_ident_from_anon();
2217 ldi_handle_t Ip4DevHandle;
2218 ldi_handle_t ArpDevHandle;
2219
2220 /*
2221 * Open the IP and ARP streams as layered devices.
2222 */
2223 rc = ldi_open_by_name(IP_DEV_NAME, FREAD | FWRITE, kcred, &Ip4DevHandle, DeviceIdent);
2224 if (rc)
2225 {
2226 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open the IP stream on '%s'.\n", pThis->szName));
2227 ldi_ident_release(DeviceIdent);
2228 return VERR_INTNET_FLT_IF_FAILED;
2229 }
2230
2231 rc = ldi_open_by_name("/dev/arp", FREAD | FWRITE, kcred, &ArpDevHandle, DeviceIdent);
2232 if (rc)
2233 {
2234 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open the ARP stream on '%s'.\n", pThis->szName));
2235 ldi_ident_release(DeviceIdent);
2236 ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
2237 return VERR_INTNET_FLT_IF_FAILED;
2238 }
2239
2240 ldi_ident_release(DeviceIdent);
2241
2242 /*
2243 * Obtain the interface flags from IPv4.
2244 */
2245 rc = vboxNetFltSolarisGetIfFlags(Ip4DevHandle, &Ip4Interface);
2246 if (RT_SUCCESS(rc))
2247 {
2248 /*
2249 * Open the UDP stream. We sort of cheat here and obtain the vnode so that we can perform
2250 * things that are not possible from the layered interface.
2251 */
2252 vnode_t *pUdp4VNode = NULL;
2253 vnode_t *pUdp4VNodeHeld = NULL;
2254 TIUSER *pUdp4User = NULL;
2255 rc = vboxNetFltSolarisOpenDev(UDP_DEV_NAME, &pUdp4VNode, &pUdp4VNodeHeld, &pUdp4User);
2256 if (RT_SUCCESS(rc))
2257 {
2258 /*
2259 * Get the multiplexor IDs.
2260 */
2261 rc = ldi_ioctl(Ip4DevHandle, SIOCGLIFMUXID, (intptr_t)&Ip4Interface, FKIOCTL, kcred, &ret);
2262 if (!rc)
2263 {
2264 /*
2265 * Get the multiplex file descriptor to the lower streams. Generally this is lost
2266 * once a module is I_PLINK, we need to reobtain it for inserting/removing ourselves from the stack.
2267 */
2268 int Ip4MuxFd;
2269 int ArpMuxFd;
2270 rc = vboxNetFltSolarisMuxIdToFd(pUdp4VNode, Ip4Interface.lifr_ip_muxid, &Ip4MuxFd);
2271 rc2 = vboxNetFltSolarisMuxIdToFd(pUdp4VNode, Ip4Interface.lifr_arp_muxid, &ArpMuxFd);
2272 if ( RT_SUCCESS(rc)
2273 && RT_SUCCESS(rc2))
2274 {
2275 /*
2276 * We need to I_PUNLINK on these multiplexor IDs before we can start
2277 * operating on the lower stream as insertions are direct operations on the lower stream.
2278 */
2279 rc = strioctl(pUdp4VNode, I_PUNLINK, (intptr_t)Ip4Interface.lifr_ip_muxid, 0, K_TO_K, kcred, &ret);
2280 rc2 = strioctl(pUdp4VNode, I_PUNLINK, (intptr_t)Ip4Interface.lifr_arp_muxid, 0, K_TO_K, kcred, &ret);
2281 if ( !rc
2282 && !rc2)
2283 {
2284 /*
2285 * Obtain the vnode from the useless userland file descriptor.
2286 */
2287 file_t *pIpFile = getf(Ip4MuxFd);
2288 file_t *pArpFile = getf(ArpMuxFd);
2289 if ( pIpFile
2290 && pArpFile
2291 && VNODE_FOR_FILE_T(pArpFile)
2292 && VNODE_FOR_FILE_T(pIpFile))
2293 {
2294 vnode_t *pIp4VNode = VNODE_FOR_FILE_T(pIpFile);
2295 vnode_t *pArpVNode = VNODE_FOR_FILE_T(pArpFile);
2296
2297 /*
2298 * Find the position on the host stack for attaching/detaching ourselves.
2299 */
2300 rc = vboxNetFltSolarisDetermineModPos(fAttach, pIp4VNode, &StrMod.pos);
2301 rc2 = vboxNetFltSolarisDetermineModPos(fAttach, pArpVNode, &ArpStrMod.pos);
2302 if ( RT_SUCCESS(rc)
2303 && RT_SUCCESS(rc2))
2304 {
2305 /*
2306 * Inject/Eject from the host IP stack.
2307 */
2308
2309 /*
2310 * Set global data which will be grabbed by ModOpen.
2311 * There is a known (though very unlikely) race here because
2312 * of the inability to pass user data while inserting.
2313 */
2314 rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
2315 AssertRCReturn(rc, rc);
2316
2317 if (fAttach)
2318 {
2319 g_VBoxNetFltSolarisInstance = pThis;
2320 g_VBoxNetFltSolarisStreamType = kIp4Stream;
2321 }
2322
2323 rc = strioctl(pIp4VNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K,
2324 g_pVBoxNetFltSolarisCred, &ret);
2325
2326 if (fAttach)
2327 {
2328 g_VBoxNetFltSolarisInstance = NULL;
2329 g_VBoxNetFltSolarisStreamType = kUndefined;
2330 }
2331
2332 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
2333
2334 if (!rc)
2335 {
2336 /*
2337 * Inject/Eject from the host ARP stack.
2338 */
2339 rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
2340 AssertRCReturn(rc, rc);
2341
2342 if (fAttach)
2343 {
2344 g_VBoxNetFltSolarisInstance = pThis;
2345 g_VBoxNetFltSolarisStreamType = kArpStream;
2346 }
2347
2348 rc = strioctl(pArpVNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&ArpStrMod, 0, K_TO_K,
2349 g_pVBoxNetFltSolarisCred, &ret);
2350
2351 if (fAttach)
2352 {
2353 g_VBoxNetFltSolarisInstance = NULL;
2354 g_VBoxNetFltSolarisStreamType = kUndefined;
2355 }
2356
2357 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
2358
2359 if (!rc)
2360 {
2361 /*
2362 * Our job's not yet over; we need to relink the upper and lower streams
2363 * otherwise we've pretty much screwed up the host interface.
2364 */
2365 rc = vboxNetFltSolarisRelinkIp4(pUdp4VNode, &Ip4Interface, Ip4MuxFd, ArpMuxFd);
2366 if (RT_SUCCESS(rc))
2367 {
2368 /*
2369 * Close the devices ONLY during the return from function case; otherwise
2370 * we end up close twice which is an instant kernel panic.
2371 */
2372 vboxNetFltSolarisCloseDev(pUdp4VNodeHeld, pUdp4User);
2373 ldi_close(ArpDevHandle, FREAD | FWRITE, kcred);
2374 ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
2375 releasef(Ip4MuxFd);
2376 releasef(ArpMuxFd);
2377
2378 Log((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Success! %s %s@(IPv4:%d Arp:%d) "
2379 "%s interface %s\n", fAttach ? "Injected" : "Ejected", StrMod.mod_name,
2380 StrMod.pos, ArpStrMod.pos, fAttach ? "to" : "from", pThis->szName));
2381 return VINF_SUCCESS;
2382 }
2383 else
2384 {
2385 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Relinking failed. Mode=%s rc=%d.\n",
2386 fAttach ? "inject" : "eject", rc));
2387 }
2388
2389 /*
2390 * Try failing gracefully during attach.
2391 */
2392 if (fAttach)
2393 strioctl(pArpVNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
2394 }
2395 else
2396 {
2397 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to %s the ARP stack. rc=%d\n",
2398 fAttach ? "inject into" : "eject from", rc));
2399 }
2400
2401 if (fAttach)
2402 strioctl(pIp4VNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
2403
2404 vboxNetFltSolarisRelinkIp4(pUdp4VNode, &Ip4Interface, Ip4MuxFd, ArpMuxFd);
2405 }
2406 else
2407 {
2408 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to %s the IP stack. rc=%d\n",
2409 fAttach ? "inject into" : "eject from", rc));
2410 }
2411 }
2412 else
2413 {
2414 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to find position. rc=%d rc2=%d\n", rc,
2415 rc2));
2416 }
2417
2418 releasef(Ip4MuxFd);
2419 releasef(ArpMuxFd);
2420 }
2421 else
2422 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get vnode from MuxFd.\n"));
2423 }
2424 else
2425 {
2426 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to unlink upper stream rc=%d rc2=%d.\n", rc,
2427 rc2));
2428 }
2429 }
2430 else
2431 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get MuxFd from MuxId. rc=%d rc2=%d\n", rc, rc2));
2432 }
2433 else
2434 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get Mux Ids. rc=%d\n", rc));
2435 vboxNetFltSolarisCloseDev(pUdp4VNodeHeld, pUdp4User);
2436 }
2437 else
2438 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open UDP. rc=%d\n", rc));
2439
2440 rc = VERR_INTNET_FLT_IF_FAILED;
2441 }
2442 else
2443 {
2444 /*
2445 * This would happen for interfaces that are not plumbed.
2446 */
2447 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Warning: seems '%s' is unplumbed.\n", pThis->szName));
2448 rc = VINF_SUCCESS;
2449 }
2450
2451 ldi_close(ArpDevHandle, FREAD | FWRITE, kcred);
2452 ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
2453
2454 return rc;
2455}
2456
2457
2458/**
2459 * Dynamically attach under IPv6 on the host stack.
2460 *
2461 * @returns VBox status code.
2462 * @param pThis The instance.
2463 * @param fAttach Is this an attach or detach.
2464 */
2465static int vboxNetFltSolarisAttachIp6(PVBOXNETFLTINS pThis, bool fAttach)
2466{
2467 LogFunc((DEVICE_NAME ":vboxNetFltSolarisAttachIp6 pThis=%p fAttach=%d\n", pThis, fAttach));
2468
2469 /*
2470 * Statutory Warning: Hackish code ahead.
2471 */
2472 char *pszModName = DEVICE_NAME;
2473
2474 struct lifreq Ip6Interface;
2475 bzero(&Ip6Interface, sizeof(Ip6Interface));
2476 Ip6Interface.lifr_addr.ss_family = AF_INET6;
2477 strncpy(Ip6Interface.lifr_name, pThis->szName, sizeof(Ip6Interface.lifr_name));
2478
2479 struct strmodconf StrMod;
2480 StrMod.mod_name = pszModName;
2481 StrMod.pos = -1; /* this is filled in later. */
2482
2483 int rc;
2484 int ret;
2485 ldi_ident_t DeviceIdent = ldi_ident_from_anon();
2486 ldi_handle_t Ip6DevHandle;
2487
2488 /*
2489 * Open the IPv6 stream as a layered devices.
2490 */
2491 rc = ldi_open_by_name(IP6_DEV_NAME, FREAD | FWRITE, kcred, &Ip6DevHandle, DeviceIdent);
2492 ldi_ident_release(DeviceIdent);
2493 if (rc)
2494 {
2495 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to open the IPv6 stream on '%s'.\n", pThis->szName));
2496 return VERR_INTNET_FLT_IF_FAILED;
2497 }
2498
2499 /*
2500 * Obtain the interface flags from IPv6.
2501 */
2502 rc = vboxNetFltSolarisGetIfFlags(Ip6DevHandle, &Ip6Interface);
2503 if (RT_SUCCESS(rc))
2504 {
2505 /*
2506 * Open the UDP stream. We sort of cheat here and obtain the vnode so that we can perform
2507 * things that are not possible from the layered interface.
2508 */
2509 vnode_t *pUdp6VNode = NULL;
2510 vnode_t *pUdp6VNodeHeld = NULL;
2511 TIUSER *pUdp6User = NULL;
2512 rc = vboxNetFltSolarisOpenDev(UDP6_DEV_NAME, &pUdp6VNode, &pUdp6VNodeHeld, &pUdp6User);
2513 if (RT_SUCCESS(rc))
2514 {
2515 /*
2516 * Get the multiplexor IDs.
2517 */
2518 rc = ldi_ioctl(Ip6DevHandle, SIOCGLIFMUXID, (intptr_t)&Ip6Interface, FKIOCTL, kcred, &ret);
2519 if (!rc)
2520 {
2521 /*
2522 * Get the multiplex file descriptor to the lower streams. Generally this is lost
2523 * once a module is I_PLINK, we need to reobtain it for inserting/removing ourselves from the stack.
2524 */
2525 int Ip6MuxFd;
2526 rc = vboxNetFltSolarisMuxIdToFd(pUdp6VNode, Ip6Interface.lifr_ip_muxid, &Ip6MuxFd);
2527 if (RT_SUCCESS(rc))
2528 {
2529 /*
2530 * We need to I_PUNLINK on these multiplexor IDs before we can start
2531 * operating on the lower stream as insertions are direct operations on the lower stream.
2532 */
2533 rc = strioctl(pUdp6VNode, I_PUNLINK, (intptr_t)Ip6Interface.lifr_ip_muxid, 0, K_TO_K, kcred, &ret);
2534 if (!rc)
2535 {
2536 /*
2537 * Obtain the vnode from the useless userland file descriptor.
2538 */
2539 file_t *pIpFile = getf(Ip6MuxFd);
2540 if ( pIpFile
2541 && VNODE_FOR_FILE_T(pIpFile))
2542 {
2543 vnode_t *pIp6VNode = VNODE_FOR_FILE_T(pIpFile);
2544
2545 /*
2546 * Find the position on the host stack for attaching/detaching ourselves.
2547 */
2548 rc = vboxNetFltSolarisDetermineModPos(fAttach, pIp6VNode, &StrMod.pos);
2549 if (RT_SUCCESS(rc))
2550 {
2551 /*
2552 * Set global data which will be grabbed by ModOpen.
2553 * There is a known (though very unlikely) race here because
2554 * of the inability to pass user data while inserting.
2555 */
2556 rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
2557 AssertRCReturn(rc, rc);
2558
2559 if (fAttach)
2560 {
2561 g_VBoxNetFltSolarisInstance = pThis;
2562 g_VBoxNetFltSolarisStreamType = kIp6Stream;
2563 }
2564
2565 /*
2566 * Inject/Eject from the host IPv6 stack.
2567 */
2568 rc = strioctl(pIp6VNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K,
2569 g_pVBoxNetFltSolarisCred, &ret);
2570
2571 if (fAttach)
2572 {
2573 g_VBoxNetFltSolarisInstance = NULL;
2574 g_VBoxNetFltSolarisStreamType = kUndefined;
2575 }
2576
2577 RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
2578
2579 if (!rc)
2580 {
2581 /*
2582 * Our job's not yet over; we need to relink the upper and lower streams
2583 * otherwise we've pretty much screwed up the host interface.
2584 */
2585 rc = vboxNetFltSolarisRelinkIp6(pUdp6VNode, &Ip6Interface, Ip6MuxFd);
2586 if (RT_SUCCESS(rc))
2587 {
2588 /*
2589 * Close the devices ONLY during the return from function case; otherwise
2590 * we end up close twice which is an instant kernel panic.
2591 */
2592 vboxNetFltSolarisCloseDev(pUdp6VNodeHeld, pUdp6User);
2593 ldi_close(Ip6DevHandle, FREAD | FWRITE, kcred);
2594 releasef(Ip6MuxFd);
2595
2596 Log((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: Success! %s %s@(IPv6:%d) "
2597 "%s interface %s\n", fAttach ? "Injected" : "Ejected", StrMod.mod_name,
2598 StrMod.pos, fAttach ? "to" : "from", pThis->szName));
2599 return VINF_SUCCESS;
2600 }
2601 else
2602 {
2603 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: Relinking failed. Mode=%s rc=%d.\n",
2604 fAttach ? "inject" : "eject", rc));
2605 }
2606
2607 if (fAttach)
2608 strioctl(pIp6VNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
2609
2610 vboxNetFltSolarisRelinkIp6(pUdp6VNode, &Ip6Interface, Ip6MuxFd);
2611 }
2612 else
2613 {
2614 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to %s the IP stack. rc=%d\n",
2615 fAttach ? "inject into" : "eject from", rc));
2616 }
2617 }
2618 else
2619 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to find position. rc=%d\n", rc));
2620
2621 releasef(Ip6MuxFd);
2622 }
2623 else
2624 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get vnode from MuxFd.\n"));
2625 }
2626 else
2627 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to unlink upper stream rc=%d.\n", rc));
2628 }
2629 else
2630 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get MuxFd from MuxId. rc=%d\n", rc));
2631 }
2632 else
2633 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get Mux Ids. rc=%d\n", rc));
2634
2635 vboxNetFltSolarisCloseDev(pUdp6VNodeHeld, pUdp6User);
2636 }
2637 else
2638 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to open UDP. rc=%d\n", rc));
2639
2640 rc = VERR_INTNET_FLT_IF_FAILED;
2641 }
2642 else
2643 {
2644 Log((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get IPv6 flags.\n", pThis->szName));
2645 rc = VERR_INTNET_FLT_IF_NOT_FOUND;
2646 }
2647
2648 ldi_close(Ip6DevHandle, FREAD | FWRITE, kcred);
2649
2650 return rc;
2651}
2652
2653
2654#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
2655/**
2656 * Ipv6 dynamic attachment timer callback to attach to the Ipv6 stream if needed.
2657 *
2658 * @param pTimer Pointer to the timer.
2659 * @param pvData Opaque pointer to the instance.
2660 * @param iTick Timer tick (unused).
2661 */
2662static void vboxNetFltSolarispIp6Timer(PRTTIMER pTimer, void *pvData, uint64_t iTick)
2663{
2664 LogFunc((DEVICE_NAME ":vboxNetFltSolarispIp6Timer pTimer=%p pvData=%p\n", pTimer, pvData));
2665
2666 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvData;
2667 if ( RT_LIKELY(pThis)
2668 && RT_LIKELY(pTimer))
2669 {
2670 vboxnetflt_stream_t *pIp6Stream = ASMAtomicUoReadPtrT(&pThis->u.s.pIp6Stream, vboxnetflt_stream_t *);
2671 bool fIp6Attaching = ASMAtomicUoReadBool(&pThis->u.s.fAttaching);
2672 if ( !pIp6Stream
2673 && !fIp6Attaching)
2674 {
2675 int rc = RTSemFastMutexRequest(pThis->u.s.hPollMtx);
2676 if (RT_SUCCESS(rc))
2677 {
2678 ASMAtomicUoWriteBool(&pThis->u.s.fAttaching, true);
2679
2680 vboxNetFltSolarisAttachIp6(pThis, true /* fAttach */);
2681
2682 ASMAtomicUoWriteBool(&pThis->u.s.fAttaching, false);
2683 RTSemFastMutexRelease(pThis->u.s.hPollMtx);
2684 }
2685 else
2686 LogRel((DEVICE_NAME ":vboxNetFltSolarispIp6Timer failed to obtain mutex. rc=%Rrc\n", rc));
2687 }
2688 }
2689
2690 NOREF(iTick);
2691}
2692
2693
2694/**
2695 * Setups up a kernel timer based on the driver property for attaching to IPv6 stream
2696 * whenever the stream gets plumbed for the interface.
2697 *
2698 * @returns VBox status code.
2699 * @param pThis The instance.
2700 */
2701static int vboxNetFltSolarisSetupIp6Polling(PVBOXNETFLTINS pThis)
2702{
2703 LogFunc((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling pThis=%p\n", pThis));
2704
2705 int rc = VERR_GENERAL_FAILURE;
2706 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream, vboxnetflt_promisc_stream_t *);
2707 if (RT_LIKELY(pPromiscStream))
2708 {
2709 if (RT_LIKELY(pPromiscStream->pIp6Timer == NULL))
2710 {
2711 /*
2712 * Validate IPv6 polling interval.
2713 */
2714 int Interval = g_VBoxNetFltSolarisPollInterval;
2715 if (Interval < 1 || Interval > 120)
2716 {
2717 LogRel((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Invalid polling interval %d. Expected between"
2718 " 1 and 120 secs.\n", Interval));
2719 return VERR_INVALID_PARAMETER;
2720 }
2721
2722 /*
2723 * Setup kernel poll timer.
2724 */
2725 rc = RTTimerCreateEx(&pPromiscStream->pIp6Timer, Interval * (uint64_t)1000000000, RTTIMER_FLAGS_CPU_ANY,
2726 vboxNetFltSolarispIp6Timer, (void *)pThis);
2727 if (RT_SUCCESS(rc))
2728 {
2729 rc = RTTimerStart(pPromiscStream->pIp6Timer, 10 * (uint64_t)1000000000 /* 10 seconds to blastoff */);
2730 Log((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Ipv6 %d second timer begins firing in 10 seconds.\n",
2731 Interval));
2732 }
2733 else
2734 LogRel((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Failed to create timer. rc=%d\n", rc));
2735 }
2736 else
2737 {
2738 LogRel((DEVICE_NAME ":vboxNetFltSolarisSetupIp6Polling: Polling already started.\n"));
2739 rc = VINF_SUCCESS;
2740 }
2741 }
2742 return rc;
2743}
2744#endif
2745
2746/**
2747 * Wrapper for detaching ourselves from the interface.
2748 *
2749 * @returns VBox status code.
2750 * @param pThis The instance.
2751 * @remarks Owns the globals mutex, so re-requesting it anytime during this phase
2752 * would panic the system (e.g. in vboxNetFltSolarisFindInstance).
2753 */
2754static int vboxNetFltSolarisDetachFromInterface(PVBOXNETFLTINS pThis)
2755{
2756 LogFunc((DEVICE_NAME ":vboxNetFltSolarisDetachFromInterface pThis=%p\n", pThis));
2757
2758 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
2759 vboxNetFltSolarisCloseStream(pThis);
2760 int rc = VINF_SUCCESS;
2761 if (pThis->u.s.pIp4Stream)
2762 rc = vboxNetFltSolarisAttachIp4(pThis, false /* fAttach */);
2763 if (pThis->u.s.pIp6Stream)
2764 rc = vboxNetFltSolarisAttachIp6(pThis, false /* fAttach */);
2765
2766#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
2767 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream, vboxnetflt_promisc_stream_t *);
2768 if ( pPromiscStream
2769 && pPromiscStream->pIp6Timer == NULL)
2770 {
2771 RTTimerStop(pPromiscStream->pIp6Timer);
2772 RTTimerDestroy(pPromiscStream->pIp6Timer);
2773 ASMAtomicUoWriteNullPtr(&pPromiscStream->pIp6Timer);
2774 }
2775#endif
2776
2777 return rc;
2778}
2779
2780
2781/**
2782 * Wrapper for attaching ourselves to the interface.
2783 *
2784 * @returns VBox status code.
2785 * @param pThis The instance.
2786 */
2787static int vboxNetFltSolarisAttachToInterface(PVBOXNETFLTINS pThis)
2788{
2789 LogFunc((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface pThis=%p\n", pThis));
2790
2791 /*
2792 * Since this is asynchronous streams injection, let the attach succeed before we can start
2793 * processing the stream.
2794 */
2795 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
2796 int rc = vboxNetFltSolarisOpenStream(pThis);
2797 if (RT_SUCCESS(rc))
2798 {
2799 rc = vboxNetFltSolarisAttachIp4(pThis, true /* fAttach */);
2800 if (RT_SUCCESS(rc))
2801 {
2802 /*
2803 * Ipv6 attaching is optional and can fail. We don't bother to bring down the whole
2804 * attach process just if Ipv6 interface is unavailable.
2805 */
2806 int rc2 = vboxNetFltSolarisAttachIp6(pThis, true /* fAttach */);
2807
2808#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
2809 /*
2810 * If Ip6 interface is not plumbed and an Ip6 polling interval is specified, we need
2811 * to begin polling to attach on the Ip6 interface whenever it comes up.
2812 */
2813 if ( rc2 == VERR_INTNET_FLT_IF_NOT_FOUND
2814 && g_VBoxNetFltSolarisPollInterval != -1)
2815 {
2816 int rc3 = vboxNetFltSolarisSetupIp6Polling(pThis);
2817 if (RT_FAILURE(rc3))
2818 {
2819 /*
2820 * If we failed to setup Ip6 polling, warn in the release log and continue.
2821 */
2822 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface IPv6 polling inactive. rc=%Rrc\n", rc3));
2823 }
2824 }
2825#endif
2826
2827 /*
2828 * Report promiscuousness and capabilities.
2829 */
2830 if (vboxNetFltTryRetainBusyNotDisconnected(pThis))
2831 {
2832 Assert(pThis->pSwitchPort);
2833 /** @todo There is no easy way of obtaining the global host side promiscuous
2834 * counter. Currently we just return false. */
2835 pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, false);
2836 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
2837 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
2838 vboxNetFltRelease(pThis, true /*fBusy*/);
2839 }
2840
2841 /*
2842 * Ipv4 is successful, and maybe Ipv6, we're ready for transfers.
2843 */
2844 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, false);
2845
2846 return VINF_SUCCESS;
2847 }
2848
2849 vboxNetFltSolarisCloseStream(pThis);
2850 }
2851 else
2852 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface vboxNetFltSolarisOpenStream failed rc=%Rrc\n", rc));
2853
2854 return rc;
2855}
2856
2857
2858/**
2859 * Create a solaris message block from the SG list.
2860 *
2861 * @returns Solaris message block.
2862 * @param pThis The instance.
2863 * @param pSG Pointer to the scatter-gather list.
2864 * @param fDst The destination mask, INTNETTRUNKDIR_XXX. Ignored.
2865 */
2866static mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
2867{
2868 LogFunc((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG pThis=%p pSG=%p\n", pThis, pSG));
2869
2870 mblk_t *pMsg = allocb(pSG->cbTotal, BPRI_MED);
2871 if (RT_UNLIKELY(!pMsg))
2872 {
2873 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed to alloc %d bytes for mblk_t.\n", pSG->cbTotal));
2874 return NULL;
2875 }
2876
2877 /*
2878 * Single buffer copy. Maybe later explore the
2879 * need/possibility for using a mblk_t chain rather.
2880 */
2881 for (unsigned i = 0; i < pSG->cSegsUsed; i++)
2882 {
2883 if (pSG->aSegs[i].pv)
2884 {
2885 bcopy(pSG->aSegs[i].pv, pMsg->b_wptr, pSG->aSegs[i].cb);
2886 pMsg->b_wptr += pSG->aSegs[i].cb;
2887 }
2888 }
2889 DB_TYPE(pMsg) = M_DATA;
2890 return pMsg;
2891}
2892
2893
2894/**
2895 * Calculate the number of segments required for this message block.
2896 *
2897 * @returns Number of segments.
2898 * @param pThis The instance
2899 * @param pMsg Pointer to the data message.
2900 */
2901static unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg)
2902{
2903 unsigned cSegs = 0;
2904 for (mblk_t *pCur = pMsg; pCur; pCur = pCur->b_cont)
2905 if (MBLKL(pCur))
2906 cSegs++;
2907
2908#ifdef PADD_RUNT_FRAMES_FROM_HOST
2909 if (msgdsize(pMsg) < 60)
2910 cSegs++;
2911#endif
2912
2913 NOREF(pThis);
2914 return RT_MAX(cSegs, 1);
2915}
2916
2917
2918/**
2919 * Initializes an SG list from the given message block.
2920 *
2921 * @returns VBox status code.
2922 * @param pThis The instance.
2923 * @param pMsg Pointer to the data message.
2924 The caller must ensure it's not a control message block.
2925 * @param pSG Pointer to the SG.
2926 * @param cSegs Number of segments in the SG.
2927 * This should match the number in the message block exactly!
2928 * @param fSrc The source of the message.
2929 */
2930static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
2931{
2932 LogFunc((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
2933
2934 /*
2935 * Convert the message block to segments. Work INTNETSG::cbTotal.
2936 */
2937 IntNetSgInitTempSegs(pSG, 0 /*cbTotal*/, cSegs, 0 /*cSegsUsed*/);
2938 mblk_t *pCur = pMsg;
2939 unsigned iSeg = 0;
2940 while (pCur)
2941 {
2942 size_t cbSeg = MBLKL(pCur);
2943 if (cbSeg)
2944 {
2945 void *pvSeg = pCur->b_rptr;
2946 pSG->aSegs[iSeg].pv = pvSeg;
2947 pSG->aSegs[iSeg].cb = cbSeg;
2948 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
2949 pSG->cbTotal += cbSeg;
2950 iSeg++;
2951 }
2952 pCur = pCur->b_cont;
2953 }
2954 pSG->cSegsUsed = iSeg;
2955
2956#ifdef PADD_RUNT_FRAMES_FROM_HOST
2957 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
2958 {
2959 Log((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pulling up to length.\n"));
2960
2961 static uint8_t const s_abZero[128] = {0};
2962 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
2963 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
2964 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
2965 pSG->cbTotal = 60;
2966 pSG->cSegsUsed++;
2967 Assert(iSeg + 1 < cSegs);
2968 }
2969#endif
2970
2971 Log((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
2972 return VINF_SUCCESS;
2973}
2974
2975
2976/**
2977 * Converts raw mode M_DATA messages to M_PROTO DL_UNITDATA_IND format.
2978 *
2979 * @returns VBox status code.
2980 * @param pMsg Pointer to the raw message.
2981 * @param ppDlpiMsg Where to store the M_PROTO message.
2982 *
2983 * @remarks The original raw message would be no longer valid and will be
2984 * linked as part of the new DLPI message. Callers must take care
2985 * not to use the raw message if this routine is successful.
2986 */
2987static int vboxNetFltSolarisRawToUnitData(mblk_t *pMsg, mblk_t **ppDlpiMsg)
2988{
2989 LogFunc((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData pMsg=%p\n", pMsg));
2990
2991 if (DB_TYPE(pMsg) != M_DATA)
2992 return VERR_NO_MEMORY;
2993
2994 size_t cbMsg = sizeof(dl_unitdata_ind_t) + 2 * sizeof(vboxnetflt_dladdr_t);
2995 mblk_t *pDlpiMsg = allocb(cbMsg, BPRI_MED);
2996 if (RT_UNLIKELY(!pDlpiMsg))
2997 return VERR_NO_MEMORY;
2998
2999 DB_TYPE(pDlpiMsg) = M_PROTO;
3000 dl_unitdata_ind_t *pDlpiData = (dl_unitdata_ind_t *)pDlpiMsg->b_rptr;
3001 pDlpiData->dl_primitive = DL_UNITDATA_IND;
3002 pDlpiData->dl_dest_addr_length = VBOXNETFLT_DLADDRL;
3003 pDlpiData->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
3004 pDlpiData->dl_src_addr_length = VBOXNETFLT_DLADDRL;
3005 pDlpiData->dl_src_addr_offset = VBOXNETFLT_DLADDRL + sizeof(dl_unitdata_ind_t);
3006
3007 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
3008
3009 vboxnetflt_dladdr_t *pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_dest_addr_offset);
3010 pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
3011 bcopy(&pEthHdr->DstMac, &pDlAddr->Mac, sizeof(RTMAC));
3012
3013 pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_src_addr_offset);
3014 pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
3015 bcopy(&pEthHdr->SrcMac, &pDlAddr->Mac, sizeof(RTMAC));
3016
3017 pDlpiMsg->b_wptr = pDlpiMsg->b_rptr + cbMsg;
3018
3019 /* Make the message point to the protocol header */
3020 pMsg->b_rptr += sizeof(RTNETETHERHDR);
3021
3022 pDlpiMsg->b_cont = pMsg;
3023 *ppDlpiMsg = pDlpiMsg;
3024 return VINF_SUCCESS;
3025}
3026
3027#if 0
3028/**
3029 * Converts DLPI M_PROTO messages to the raw mode M_DATA format.
3030 *
3031 * @returns VBox status code.
3032 * @param pMsg Pointer to the M_PROTO message.
3033 * @param ppRawMsg Where to store the converted message.
3034 *
3035 * @remarks If successful, the original pMsg is no longer valid, it will be deleted.
3036 * Callers must take care not to continue to use pMsg after a successful
3037 * call to this conversion routine.
3038 */
3039static int vboxNetFltSolarisUnitDataToRaw(PVBOXNETFLTINS pThis, mblk_t *pMsg, mblk_t **ppRawMsg)
3040{
3041 LogFunc((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw pMsg=%p\n", pMsg));
3042
3043 if ( !pMsg->b_cont
3044 || DB_TYPE(pMsg) != M_PROTO)
3045 {
3046 LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw invalid input message.\n"));
3047 return VERR_NET_PROTOCOL_ERROR;
3048 }
3049
3050 /*
3051 * Upstream consumers send/receive packets in the fast path mode.
3052 * We of course need to convert them into raw ethernet frames.
3053 */
3054 RTNETETHERHDR EthHdr;
3055 union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
3056 switch (pPrim->dl_primitive)
3057 {
3058 case DL_UNITDATA_IND:
3059 {
3060 /*
3061 * Receive side.
3062 */
3063 dl_unitdata_ind_t *pDlpiMsg = (dl_unitdata_ind_t *)pMsg->b_rptr;
3064 bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
3065 bcopy(pMsg->b_rptr + pDlpiMsg->dl_src_addr_offset, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
3066
3067 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
3068 EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
3069
3070 break;
3071 }
3072
3073 case DL_UNITDATA_REQ:
3074 {
3075 /*
3076 * Send side.
3077 */
3078 dl_unitdata_req_t *pDlpiMsg = (dl_unitdata_req_t *)pMsg->b_rptr;
3079
3080 bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
3081 bcopy(&pThis->u.s.MacAddr, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
3082
3083 vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
3084 EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
3085
3086 break;
3087 }
3088
3089 default:
3090 {
3091 LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw Unknown M_PROTO. This shouldn't be happening!!"));
3092 return VERR_NET_PROTOCOL_ERROR;
3093 }
3094 }
3095
3096 /*
3097 * Let us just link it as a mblk_t chain rather than re-copy the entire message.
3098 * The vboxNetFltSolarisMBlkToSG function will handle chained mblk_t's.
3099 */
3100 size_t cbLen = sizeof(EthHdr);
3101 mblk_t *pEtherMsg = allocb(cbLen, BPRI_MED);
3102 if (RT_UNLIKELY(!pEtherMsg))
3103 return VERR_NO_MEMORY;
3104
3105 DB_TYPE(pEtherMsg) = M_DATA;
3106 bcopy(&EthHdr, pEtherMsg->b_wptr, sizeof(EthHdr));
3107 pEtherMsg->b_wptr += cbLen;
3108
3109 pEtherMsg->b_cont = pMsg->b_cont;
3110
3111 /*
3112 * Change the chained blocks to type M_DATA.
3113 */
3114 for (mblk_t *pTmp = pEtherMsg->b_cont; pTmp; pTmp = pTmp->b_cont)
3115 DB_TYPE(pTmp) = M_DATA;
3116
3117 pMsg->b_cont = NULL;
3118 freemsg(pMsg);
3119
3120 *ppRawMsg = pEtherMsg;
3121 return VINF_SUCCESS;
3122}
3123#endif
3124
3125/**
3126 * Initializes a packet identifier.
3127 *
3128 * @param pTag Pointer to the packed identifier.
3129 * @param pMsg Pointer to the message to be identified.
3130 *
3131 * @remarks Warning!!! This function assumes 'pMsg' is an unchained message.
3132 */
3133static inline void vboxNetFltSolarisInitPacketId(PVBOXNETFLTPACKETID pTag, mblk_t *pMsg)
3134{
3135 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
3136 size_t cbMsg = MBLKL(pMsg);
3137
3138 pTag->cbPacket = cbMsg;
3139 pTag->Checksum = RTCrc32(pMsg->b_rptr, cbMsg);
3140 bcopy(&pEthHdr->SrcMac, &pTag->SrcMac, sizeof(RTMAC));
3141 bcopy(&pEthHdr->DstMac, &pTag->DstMac, sizeof(RTMAC));
3142}
3143
3144
3145/**
3146 * Queues a packet for loopback elimination.
3147 *
3148 * @returns VBox status code.
3149 * @param pThis The instance.
3150 * @param pPromiscStream Pointer to the promiscuous stream.
3151 * @param pMsg Pointer to the message.
3152 */
3153static int vboxNetFltSolarisQueueLoopback(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg)
3154{
3155 Assert(pThis);
3156 Assert(pMsg);
3157 Assert(DB_TYPE(pMsg) == M_DATA);
3158 Assert(pPromiscStream);
3159
3160 LogFunc((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback pThis=%p pPromiscStream=%p pMsg=%p\n", pThis, pPromiscStream, pMsg));
3161
3162 if (RT_UNLIKELY(pMsg->b_cont))
3163 {
3164 /*
3165 * We don't currently make chained messages in on Xmit
3166 * so this only needs to be supported when we do that.
3167 */
3168 return VERR_NOT_SUPPORTED;
3169 }
3170
3171 size_t cbMsg = MBLKL(pMsg);
3172 if (RT_UNLIKELY(cbMsg < sizeof(RTNETETHERHDR)))
3173 return VERR_NET_MSG_SIZE;
3174
3175 int rc = VINF_SUCCESS;
3176 mutex_enter(&pThis->u.s.hMtx);
3177
3178 PVBOXNETFLTPACKETID pCur = NULL;
3179 if (pPromiscStream->cLoopback < VBOXNETFLT_LOOPBACK_SIZE
3180 || ( pPromiscStream->pHead
3181 && pPromiscStream->pHead->cbPacket == 0))
3182 {
3183 do
3184 {
3185 if (!pPromiscStream->pHead)
3186 {
3187 pCur = RTMemAlloc(sizeof(VBOXNETFLTPACKETID));
3188 if (RT_UNLIKELY(!pCur))
3189 {
3190 rc = VERR_NO_MEMORY;
3191 break;
3192 }
3193
3194 vboxNetFltSolarisInitPacketId(pCur, pMsg);
3195
3196 pCur->pNext = NULL;
3197 pPromiscStream->pHead = pCur;
3198 pPromiscStream->pTail = pCur;
3199 pPromiscStream->cLoopback++;
3200
3201 Log((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback initialized head. checksum=%u.\n",
3202 pPromiscStream->pHead->Checksum));
3203 break;
3204 }
3205 else if ( pPromiscStream->pHead
3206 && pPromiscStream->pHead->cbPacket == 0)
3207 {
3208 pCur = pPromiscStream->pHead;
3209 vboxNetFltSolarisInitPacketId(pCur, pMsg);
3210
3211 Log((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback re-used head checksum=%u cLoopback=%d.\n",
3212 pCur->Checksum, pPromiscStream->cLoopback));
3213 break;
3214 }
3215 else
3216 {
3217 pCur = RTMemAlloc(sizeof(VBOXNETFLTPACKETID));
3218 if (RT_UNLIKELY(!pCur))
3219 {
3220 rc = VERR_NO_MEMORY;
3221 break;
3222 }
3223
3224 vboxNetFltSolarisInitPacketId(pCur, pMsg);
3225
3226 pCur->pNext = pPromiscStream->pHead;
3227 pPromiscStream->pHead = pCur;
3228 pPromiscStream->cLoopback++;
3229
3230 Log((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback added head checksum=%u cLoopback=%d.\n", pCur->Checksum,
3231 pPromiscStream->cLoopback));
3232 break;
3233 }
3234 } while (0);
3235 }
3236 else
3237 {
3238 /*
3239 * Maximum loopback queue size reached. Re-use tail as head.
3240 */
3241 Assert(pPromiscStream->pHead);
3242 Assert(pPromiscStream->pTail);
3243
3244 /*
3245 * Find tail's previous item.
3246 */
3247 PVBOXNETFLTPACKETID pPrev = NULL;
3248 pCur = pPromiscStream->pHead;
3249
3250 /** @todo consider if this is worth switching to a double linked list... */
3251 while (pCur != pPromiscStream->pTail)
3252 {
3253 pPrev = pCur;
3254 pCur = pCur->pNext;
3255 }
3256
3257 pPromiscStream->pTail = pPrev;
3258 pPromiscStream->pTail->pNext = NULL;
3259 pCur->pNext = pPromiscStream->pHead;
3260 pPromiscStream->pHead = pCur;
3261
3262 vboxNetFltSolarisInitPacketId(pCur, pMsg);
3263 Log((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback recycled tail!! checksum=%u cLoopback=%d\n", pCur->Checksum,
3264 pPromiscStream->cLoopback));
3265 }
3266
3267 mutex_exit(&pThis->u.s.hMtx);
3268
3269 return rc;
3270}
3271
3272
3273/**
3274 * Checks if the packet is enqueued for loopback as our own packet.
3275 *
3276 * @returns If it's our packet, returns true after dequeuing it, otherwise false.
3277 * @param pThis The instance.
3278 * @param pPromiscStream Pointer to the promiscuous stream.
3279 * @param pMsg Pointer to the message.
3280 */
3281static bool vboxNetFltSolarisIsOurMBlk(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg)
3282{
3283 Assert(pThis);
3284 Assert(pPromiscStream);
3285 Assert(pMsg);
3286 Assert(DB_TYPE(pMsg) == M_DATA);
3287
3288 LogFunc((DEVICE_NAME ":vboxNetFltSolarisIsOurMBlk pThis=%p pMsg=%p\n", pThis, pMsg));
3289
3290 if (pMsg->b_cont)
3291 {
3292 /** Handle this when Xmit makes chained messages */
3293 return false;
3294 }
3295
3296 size_t cbMsg = MBLKL(pMsg);
3297 if (cbMsg < sizeof(RTNETETHERHDR))
3298 return false;
3299
3300 mutex_enter(&pThis->u.s.hMtx);
3301
3302 PVBOXNETFLTPACKETID pPrev = NULL;
3303 PVBOXNETFLTPACKETID pCur = pPromiscStream->pHead;
3304 bool fIsOurPacket = false;
3305 while (pCur)
3306 {
3307 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
3308 if ( pCur->cbPacket != cbMsg
3309 || pCur->SrcMac.au8[0] != pEthHdr->SrcMac.au8[0]
3310 || pCur->SrcMac.au8[1] != pEthHdr->SrcMac.au8[1]
3311 || pCur->SrcMac.au8[2] != pEthHdr->SrcMac.au8[2]
3312 || pCur->SrcMac.au8[3] != pEthHdr->SrcMac.au8[3]
3313 || pCur->SrcMac.au8[4] != pEthHdr->SrcMac.au8[4]
3314 || pCur->SrcMac.au8[5] != pEthHdr->SrcMac.au8[5]
3315 || pCur->DstMac.au8[0] != pEthHdr->DstMac.au8[0]
3316 || pCur->DstMac.au8[1] != pEthHdr->DstMac.au8[1]
3317 || pCur->DstMac.au8[2] != pEthHdr->DstMac.au8[2]
3318 || pCur->DstMac.au8[3] != pEthHdr->DstMac.au8[3]
3319 || pCur->DstMac.au8[4] != pEthHdr->DstMac.au8[4]
3320 || pCur->DstMac.au8[5] != pEthHdr->DstMac.au8[5])
3321 {
3322 pPrev = pCur;
3323 pCur = pCur->pNext;
3324 continue;
3325 }
3326
3327 uint16_t Checksum = RTCrc32(pMsg->b_rptr, cbMsg);
3328 if (pCur->Checksum != Checksum)
3329 {
3330 pPrev = pCur;
3331 pCur = pCur->pNext;
3332 continue;
3333 }
3334
3335 /*
3336 * Yes, it really is our own packet, mark it as handled
3337 * and move it as a "free slot" to the head and return success.
3338 */
3339 pCur->cbPacket = 0;
3340 if (pPrev)
3341 {
3342 if (!pCur->pNext)
3343 pPromiscStream->pTail = pPrev;
3344
3345 pPrev->pNext = pCur->pNext;
3346 pCur->pNext = pPromiscStream->pHead;
3347 pPromiscStream->pHead = pCur;
3348 }
3349 fIsOurPacket = true;
3350
3351 Log((DEVICE_NAME ":vboxNetFltSolarisIsOurMBlk found packet %p Checksum=%u cLoopback=%d\n", pMsg, Checksum,
3352 pPromiscStream->cLoopback));
3353 break;
3354 }
3355
3356 Log((DEVICE_NAME ":vboxNetFltSolarisIsOurMBlk returns %d.\n", fIsOurPacket));
3357 mutex_exit(&pThis->u.s.hMtx);
3358 return fIsOurPacket;
3359}
3360
3361
3362/**
3363 * Helper.
3364 */
3365DECLINLINE(bool) vboxNetFltPortSolarisIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
3366{
3367 /*
3368 * MAC address change acknowledgements are intercepted on the read side
3369 * hence theoretically we are always update to date with any changes.
3370 */
3371 return pThis->u.s.MacAddr.au16[0] == pMac->au16[0]
3372 && pThis->u.s.MacAddr.au16[1] == pMac->au16[1]
3373 && pThis->u.s.MacAddr.au16[2] == pMac->au16[2];
3374}
3375
3376
3377/**
3378 * Worker for routing messages from the wire or from the host.
3379 *
3380 * @returns VBox status code.
3381 * @param pThis The instance.
3382 * @param pStream Pointer to the stream.
3383 * @param pQueue Pointer to the read queue.
3384 * @param pMsg Pointer to the message.
3385 */
3386static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pMsg)
3387{
3388 LogFunc((DEVICE_NAME ":vboxNetFltSolarisRecv pThis=%p pMsg=%p\n", pThis, pMsg));
3389
3390 AssertCompile(sizeof(struct ether_header) == sizeof(RTNETETHERHDR));
3391 Assert(pStream->Type == kPromiscStream);
3392
3393 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream, vboxnetflt_promisc_stream_t *);
3394 if (RT_UNLIKELY(!pPromiscStream))
3395 {
3396 LogRel((DEVICE_NAME ":Promiscuous stream missing!! Failing to receive packet.\n"));
3397 return VERR_INVALID_POINTER;
3398 }
3399
3400 /*
3401 * Paranoia...
3402 */
3403 if (RT_UNLIKELY(MBLKL(pMsg) < sizeof(RTNETETHERHDR)))
3404 {
3405 size_t cbMsg = msgdsize(pMsg);
3406 if (cbMsg < sizeof(RTNETETHERHDR))
3407 {
3408 LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv %s: packet too small. Dropping packet.\n", pThis->szName));
3409 return VINF_SUCCESS;
3410 }
3411
3412 mblk_t *pFullMsg = msgpullup(pMsg, -1 /* all data blocks */);
3413 if (pFullMsg)
3414 {
3415 freemsg(pMsg);
3416 pMsg = pFullMsg;
3417 }
3418 else
3419 {
3420 LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv msgpullup failed.\n"));
3421 return VERR_NO_MEMORY;
3422 }
3423 }
3424
3425 /*
3426 * Don't loopback packets we transmit to the wire.
3427 */
3428 if (vboxNetFltSolarisIsOurMBlk(pThis, pPromiscStream, pMsg))
3429 {
3430 Log((DEVICE_NAME ":Avoiding packet loopback.\n"));
3431 return VINF_SUCCESS;
3432 }
3433
3434 /*
3435 * Figure out the source of the packet based on the source Mac address.
3436 */
3437 uint32_t fSrc = INTNETTRUNKDIR_WIRE;
3438 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
3439 if (vboxNetFltPortSolarisIsHostMac(pThis, &pEthHdr->SrcMac))
3440 fSrc = INTNETTRUNKDIR_HOST;
3441
3442 /*
3443 * Afaik; we no longer need to worry about incorrect checksums because we now use
3444 * a dedicated stream and don't intercept packets under IP/ARP which might be doing
3445 * checksum offloading.
3446 */
3447#if 0
3448 if (fSrc & INTNETTRUNKDIR_HOST)
3449 {
3450 mblk_t *pCorrectedMsg = vboxNetFltSolarisFixChecksums(pMsg);
3451 if (pCorrectedMsg)
3452 pMsg = pCorrectedMsg;
3453 }
3454 vboxNetFltSolarisAnalyzeMBlk(pMsg);
3455#endif
3456
3457 /*
3458 * Solaris raw mode streams for priority-tagged VLAN does not strip the VLAN tag.
3459 * It zero's the VLAN-Id but keeps the tag intact as part of the Ethernet header.
3460 * We need to manually strip these tags out or the guests might get confused.
3461 */
3462 bool fCopied = false;
3463 bool fTagged = false;
3464 if ( pThis->u.s.fVLAN
3465 && pPromiscStream->fRawMode)
3466 {
3467 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_VLAN))
3468 {
3469 if (msgdsize(pMsg) > sizeof(RTNETETHERHDR) + sizeof(VLANHEADER))
3470 {
3471 if (pMsg->b_cont)
3472 {
3473 mblk_t *pFullMsg = msgpullup(pMsg, -1 /* all data blocks */);
3474 if (pFullMsg)
3475 {
3476 /* Original pMsg will be freed by the caller */
3477 pMsg = pFullMsg;
3478 fCopied = true;
3479 }
3480 else
3481 {
3482 LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv msgpullup failed.\n"));
3483 return VERR_NO_MEMORY;
3484 }
3485 }
3486
3487 PVLANHEADER pVlanHdr = (PVLANHEADER)(pMsg->b_rptr + sizeof(RTNETETHERHDR) - sizeof(pEthHdr->EtherType));
3488 Log((DEVICE_NAME ":Recv VLAN Pcp=%u Cfi=%u Id=%u\n", VLAN_PRI(RT_BE2H_U16(pVlanHdr->Data)),
3489 VLAN_CFI(RT_BE2H_U16(pVlanHdr->Data)), VLAN_ID(RT_BE2H_U16(pVlanHdr->Data))));
3490 if ( VLAN_PRI(RT_BE2H_U16(pVlanHdr->Data)) > 0
3491 && VLAN_ID(RT_BE2H_U16(pVlanHdr->Data)) == 0)
3492 {
3493 /*
3494 * Create new Ethernet header with stripped VLAN tag.
3495 */
3496 size_t cbEthPrefix = sizeof(RTNETETHERHDR) - sizeof(pEthHdr->EtherType);
3497 mblk_t *pStrippedMsg = allocb(cbEthPrefix, BPRI_MED);
3498 if (RT_LIKELY(pStrippedMsg))
3499 {
3500 fTagged = true;
3501
3502 /*
3503 * Copy ethernet header excluding the ethertype.
3504 */
3505 bcopy(pMsg->b_rptr, pStrippedMsg->b_wptr, cbEthPrefix);
3506 pStrippedMsg->b_wptr += cbEthPrefix;
3507
3508 /*
3509 * Link the rest of the message (ethertype + data, skipping VLAN header).
3510 */
3511 pMsg->b_rptr += cbEthPrefix + sizeof(VLANHEADER);
3512 pStrippedMsg->b_cont = pMsg;
3513 pMsg = pStrippedMsg;
3514 Log((DEVICE_NAME ":Stripped VLAN tag.\n"));
3515 }
3516 else
3517 {
3518 LogRel((DEVICE_NAME ":vboxNetFltSolarisRecv insufficient memory for creating VLAN stripped packet"
3519 " cbMsg=%u.\n", cbEthPrefix));
3520 if (fCopied)
3521 freemsg(pMsg);
3522 return VERR_NO_MEMORY;
3523 }
3524 }
3525 }
3526 }
3527 }
3528
3529 /*
3530 * Route all received packets into the internal network.
3531 */
3532 unsigned cSegs = vboxNetFltSolarisMBlkCalcSGSegs(pThis, pMsg);
3533 PINTNETSG pSG = (PINTNETSG)alloca(RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]));
3534 int rc = vboxNetFltSolarisMBlkToSG(pThis, pMsg, pSG, cSegs, fSrc);
3535 if (RT_SUCCESS(rc))
3536 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc);
3537 else
3538 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG failed. rc=%d\n", rc));
3539
3540 /*
3541 * If we've allocated the prefix before the VLAN tag in a new message, free that.
3542 */
3543 if (fTagged)
3544 {
3545 mblk_t *pTagMsg = pMsg->b_cont;
3546 pMsg->b_cont = NULL; /* b_cont could be the message from the caller or a copy we made (fCopied) */
3547 freemsg(pMsg);
3548 pMsg = pTagMsg;
3549 }
3550
3551 /*
3552 * If we made an extra copy for VLAN stripping, we need to free that ourselves.
3553 */
3554 if (fCopied)
3555 freemsg(pMsg);
3556
3557 return VINF_SUCCESS;
3558}
3559
3560#if 0
3561/**
3562 * Finalize the message to be fed into the internal network.
3563 * Verifies and tries to fix checksums for TCP, UDP and IP.
3564 *
3565 * @returns Corrected message or NULL if no change was required.
3566 * @param pMsg Pointer to the message block.
3567 * This must not be DLPI linked messages, must be M_DATA.
3568 *
3569 * @remarks If this function returns a checksum adjusted message, the
3570 * passed in input message has been freed and should not be
3571 * referenced anymore by the caller.
3572 */
3573static mblk_t *vboxNetFltSolarisFixChecksums(mblk_t *pMsg)
3574{
3575 LogFunc((DEVICE_NAME ":vboxNetFltSolarisFixChecksums pMsg=%p\n"));
3576
3577 Assert(DB_TYPE(pMsg) == M_DATA);
3578
3579 if (MBLKL(pMsg) < sizeof(RTNETETHERHDR))
3580 {
3581 LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums Packet shorter than ethernet header size!\n"));
3582 return NULL;
3583 }
3584
3585 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
3586 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
3587 {
3588 /*
3589 * Check if we have a complete packet or being fed a chain.
3590 */
3591 size_t cbIpPacket = 0;
3592 mblk_t *pFullMsg = NULL;
3593 if (pMsg->b_cont)
3594 {
3595 Log((DEVICE_NAME ":Chained mblk_t.\n"));
3596
3597 /*
3598 * Handle chain by making a packet copy to verify if the IP checksum is correct.
3599 * Contributions to calculating IP checksums from a chained message block with
3600 * odd/non-pulled up sizes are welcome.
3601 */
3602 size_t cbFullMsg = msgdsize(pMsg);
3603 mblk_t *pFullMsg = allocb(cbFullMsg, BPRI_MED);
3604 Log((DEVICE_NAME ":msgdsize returns %d\n", cbFullMsg));
3605 if (RT_UNLIKELY(!pFullMsg))
3606 {
3607 LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums failed to alloc new message of %d bytes.\n", cbFullMsg));
3608 return NULL;
3609 }
3610
3611 for (mblk_t *pTmp = pMsg; pTmp; pTmp = pTmp->b_cont)
3612 {
3613 if (DB_TYPE(pTmp) == M_DATA)
3614 {
3615 bcopy(pTmp->b_rptr, pFullMsg->b_wptr, MBLKL(pTmp));
3616 pFullMsg->b_wptr += MBLKL(pTmp);
3617 }
3618 }
3619
3620 DB_TYPE(pFullMsg) = M_DATA;
3621 pEthHdr = (PRTNETETHERHDR)pFullMsg->b_rptr;
3622 cbIpPacket = MBLKL(pFullMsg) - sizeof(RTNETETHERHDR);
3623 }
3624 else
3625 cbIpPacket = MBLKL(pMsg) - sizeof(RTNETETHERHDR);
3626
3627 /*
3628 * Check if the IP checksum is valid.
3629 */
3630 uint8_t *pbProtocol = (uint8_t *)(pEthHdr + 1);
3631 PRTNETIPV4 pIpHdr = (PRTNETIPV4)pbProtocol;
3632 size_t cbPayload = cbIpPacket - (pIpHdr->ip_hl << 2);
3633 bool fChecksumAdjusted = false;
3634 if (RTNetIPv4IsHdrValid(pIpHdr, cbPayload, cbPayload))
3635 {
3636 pbProtocol += (pIpHdr->ip_hl << 2);
3637
3638 /*
3639 * Fix up TCP/UDP and IP checksums if they're incomplete/invalid.
3640 */
3641 if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
3642 {
3643 PRTNETTCP pTcpHdr = (PRTNETTCP)pbProtocol;
3644 uint16_t TcpChecksum = RTNetIPv4TCPChecksum(pIpHdr, pTcpHdr, NULL);
3645 if (pTcpHdr->th_sum != TcpChecksum)
3646 {
3647 pTcpHdr->th_sum = TcpChecksum;
3648 fChecksumAdjusted = true;
3649 Log((DEVICE_NAME ":fixed TCP checksum.\n"));
3650 }
3651 }
3652 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
3653 {
3654 PRTNETUDP pUdpHdr = (PRTNETUDP)pbProtocol;
3655 uint16_t UdpChecksum = RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1);
3656
3657 if (pUdpHdr->uh_sum != UdpChecksum)
3658 {
3659 pUdpHdr->uh_sum = UdpChecksum;
3660 fChecksumAdjusted = true;
3661 Log((DEVICE_NAME ":Fixed UDP checksum."));
3662 }
3663 }
3664 }
3665
3666 if (fChecksumAdjusted)
3667 {
3668 /*
3669 * If we made a copy and the checksum is corrected on the copy,
3670 * free the original, return the checksum fixed copy.
3671 */
3672 if (pFullMsg)
3673 {
3674 freemsg(pMsg);
3675 return pFullMsg;
3676 }
3677
3678 return pMsg;
3679 }
3680
3681 /*
3682 * If we made a copy and the checksum is NOT corrected, free the copy,
3683 * and return NULL.
3684 */
3685 if (pFullMsg)
3686 freemsg(pFullMsg);
3687
3688 return NULL;
3689 }
3690
3691 return NULL;
3692}
3693
3694
3695/**
3696 * Simple packet dump, used for internal debugging.
3697 *
3698 * @param pMsg Pointer to the message to analyze and dump.
3699 */
3700static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg)
3701{
3702 LogFunc((DEVICE_NAME ":vboxNetFltSolarisAnalyzeMBlk pMsg=%p\n", pMsg));
3703
3704 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
3705 uint8_t *pb = pMsg->b_rptr;
3706 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
3707 {
3708 PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
3709 size_t cbLen = MBLKL(pMsg) - sizeof(*pEthHdr);
3710 if (!pMsg->b_cont)
3711 {
3712 if (pIpHdr->ip_p == RTNETIPV4_PROT_ICMP)
3713 LogRel((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
3714 else if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
3715 LogRel((DEVICE_NAME ":TCP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
3716 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
3717 {
3718 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint32_t *)pIpHdr + pIpHdr->ip_hl);
3719 if ( RT_BE2H_U16(pUdpHdr->uh_sport) == 67
3720 && RT_BE2H_U16(pUdpHdr->uh_dport) == 68)
3721 {
3722 LogRel((DEVICE_NAME ":UDP bootp ack D=%.6Rhxs S=%.6Rhxs UDP_CheckSum=%04x Computex=%04x\n", pb, pb + 6,
3723 RT_BE2H_U16(pUdpHdr->uh_sum), RT_BE2H_U16(RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1))));
3724 }
3725 }
3726 }
3727 else
3728 {
3729 Log((DEVICE_NAME ":Chained IP packet. Skipping validity check.\n"));
3730 }
3731 }
3732 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_VLAN))
3733 {
3734 PVLANHEADER pVlanHdr = (PVLANHEADER)(pMsg->b_rptr + sizeof(RTNETETHERHDR) - sizeof(pEthHdr->EtherType));
3735 LogRel((DEVICE_NAME ":VLAN Pcp=%u Cfi=%u Id=%u\n", VLAN_PRI(RT_BE2H_U16(pVlanHdr->Data)),
3736 VLAN_CFI(RT_BE2H_U16(pVlanHdr->Data)), VLAN_ID(RT_BE2H_U16(pVlanHdr->Data))));
3737 LogRel((DEVICE_NAME "%.*Rhxd\n", sizeof(VLANHEADER), pVlanHdr));
3738 }
3739 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
3740 {
3741 PRTNETARPHDR pArpHdr = (PRTNETARPHDR)(pEthHdr + 1);
3742 LogRel((DEVICE_NAME ":ARP Op=%d\n", pArpHdr->ar_oper));
3743 }
3744 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
3745 {
3746 LogRel((DEVICE_NAME ":IPv6 D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
3747 }
3748 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_1)
3749 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_2)
3750 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_3))
3751 {
3752 LogRel((DEVICE_NAME ":IPX packet.\n"));
3753 }
3754 else
3755 {
3756 LogRel((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
3757 &pEthHdr->SrcMac));
3758 /* Log((DEVICE_NAME ":%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
3759 }
3760}
3761#endif
3762
3763
3764/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
3765
3766
3767
3768void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
3769{
3770 LogFunc((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d\n", pThis, fActive));
3771
3772 /*
3773 * Enable/disable promiscuous mode.
3774 */
3775 vboxnetflt_promisc_params_t *pData = RTMemAllocZ(sizeof(vboxnetflt_promisc_params_t));
3776 if (RT_LIKELY(pData))
3777 {
3778 /*
3779 * See @bugref{5262} as to why we need to do all this qtimeout/qwriter tricks.
3780 */
3781 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream,
3782 vboxnetflt_promisc_stream_t *);
3783 if ( pPromiscStream
3784 && pPromiscStream->Stream.pReadQueue)
3785 {
3786 pData->pThis = pThis;
3787 pData->fPromiscOn = fActive;
3788 if (ASMAtomicReadPtr(&pPromiscStream->TimeoutId))
3789 quntimeout(WR(pPromiscStream->Stream.pReadQueue), pPromiscStream->TimeoutId);
3790 timeout_id_t TimeoutId = qtimeout(WR(pPromiscStream->Stream.pReadQueue), vboxNetFltSolarisPromiscReqWrap,
3791 pData, 1 /* ticks */);
3792 ASMAtomicWritePtr(&pPromiscStream->TimeoutId, TimeoutId);
3793 return; /* pData will be freed by vboxNetFltSolarisPromiscReqWrap() */
3794 }
3795 else
3796 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d missing stream!\n", pThis, fActive));
3797 RTMemFree(pData);
3798 }
3799 else
3800 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive out of memory!\n"));
3801}
3802
3803
3804int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
3805{
3806 LogFunc((DEVICE_NAME ":vboxNetFltOsDisconnectIt pThis=%p\n", pThis));
3807
3808 vboxNetFltSolarisDetachFromInterface(pThis);
3809
3810 return VINF_SUCCESS;
3811}
3812
3813
3814int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
3815{
3816 /* Nothing to do here. */
3817 return VINF_SUCCESS;
3818}
3819
3820
3821void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
3822{
3823 LogFunc((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n", pThis));
3824
3825 mutex_destroy(&pThis->u.s.hMtx);
3826
3827#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
3828 if (pThis->u.s.hPollMtx != NIL_RTSEMFASTMUTEX)
3829 {
3830 RTSemFastMutexDestroy(pThis->u.s.hPollMtx);
3831 pThis->u.s.hPollMtx = NIL_RTSEMFASTMUTEX;
3832 }
3833#endif
3834
3835}
3836
3837
3838int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
3839{
3840 LogFunc((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p\n"));
3841
3842 /*
3843 * Mutex used for loopback lockouts.
3844 */
3845 int rc = VINF_SUCCESS;
3846 mutex_init(&pThis->u.s.hMtx, NULL /* name */, MUTEX_DRIVER, NULL /* cookie */);
3847#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
3848 rc = RTSemFastMutexCreate(&pThis->u.s.hPollMtx);
3849 if (RT_SUCCESS(rc))
3850 {
3851#endif
3852 rc = vboxNetFltSolarisAttachToInterface(pThis);
3853 if (RT_SUCCESS(rc))
3854 return rc;
3855
3856 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed. rc=%Rrc\n", rc));
3857
3858#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
3859 RTSemFastMutexDestroy(pThis->u.s.hPollMtx);
3860 pThis->u.s.hPollMtx = NIL_RTSEMFASTMUTEX;
3861 }
3862 else
3863 LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to create poll mutex. rc=%Rrc\n", rc));
3864#endif
3865
3866 mutex_destroy(&pThis->u.s.hMtx);
3867
3868 NOREF(pvContext);
3869 return rc;
3870}
3871
3872
3873int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
3874{
3875 /*
3876 * Init. the solaris specific data.
3877 */
3878 pThis->u.s.hIface = NULL;
3879 pThis->u.s.pIp4Stream = NULL;
3880 pThis->u.s.pIp6Stream = NULL;
3881 pThis->u.s.pArpStream = NULL;
3882 pThis->u.s.pPromiscStream = NULL;
3883 pThis->u.s.fAttaching = false;
3884 pThis->u.s.fVLAN = false;
3885#ifdef VBOXNETFLT_SOLARIS_IPV6_POLLING
3886 pThis->u.s.hPollMtx = NIL_RTSEMFASTMUTEX;
3887#endif
3888 bzero(&pThis->u.s.MacAddr, sizeof(pThis->u.s.MacAddr));
3889 return VINF_SUCCESS;
3890}
3891
3892
3893bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
3894{
3895 /*
3896 * We don't support interface rediscovery on Solaris hosts because the
3897 * filter is very tightly bound to the stream.
3898 */
3899 return false;
3900}
3901
3902
3903void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
3904{
3905 NOREF(pThis); NOREF(pvIfData); NOREF(pMac);
3906}
3907
3908
3909int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
3910{
3911 /* Nothing to do */
3912 NOREF(pThis); NOREF(pvIf); NOREF(ppvIfData);
3913 return VINF_SUCCESS;
3914}
3915
3916
3917int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
3918{
3919 /* Nothing to do */
3920 NOREF(pThis); NOREF(pvIfData);
3921 return VINF_SUCCESS;
3922}
3923
3924
3925int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
3926{
3927 NOREF(pvIfData);
3928 LogFunc((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p pSG=%p fDst=%d\n", pThis, pSG, fDst));
3929
3930 int rc = VINF_SUCCESS;
3931 if (fDst & INTNETTRUNKDIR_WIRE)
3932 {
3933 vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream,
3934 vboxnetflt_promisc_stream_t *);
3935 if (RT_LIKELY(pPromiscStream))
3936 {
3937 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
3938 if (RT_LIKELY(pMsg))
3939 {
3940 Log((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_WIRE\n"));
3941
3942 vboxNetFltSolarisQueueLoopback(pThis, pPromiscStream, pMsg);
3943 putnext(WR(pPromiscStream->Stream.pReadQueue), pMsg);
3944 }
3945 else
3946 {
3947 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
3948 return VERR_NO_MEMORY;
3949 }
3950 }
3951 }
3952
3953 if (fDst & INTNETTRUNKDIR_HOST)
3954 {
3955 /*
3956 * For unplumbed interfaces we would not be bound to IP or ARP.
3957 * We either bind to both or neither; so atomic reading one should be sufficient.
3958 */
3959 vboxnetflt_stream_t *pIp4Stream = ASMAtomicUoReadPtrT(&pThis->u.s.pIp4Stream, vboxnetflt_stream_t *);
3960 if (!pIp4Stream)
3961 return rc;
3962
3963 /*
3964 * Create a message block and send it up the host stack (upstream).
3965 */
3966 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
3967 if (RT_LIKELY(pMsg))
3968 {
3969 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
3970
3971 /*
3972 * Send message up ARP stream.
3973 */
3974 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
3975 {
3976 Log((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST ARP\n"));
3977
3978 vboxnetflt_stream_t *pArpStream = ASMAtomicUoReadPtrT(&pThis->u.s.pArpStream, vboxnetflt_stream_t *);
3979 if (pArpStream)
3980 {
3981 /*
3982 * Construct a DL_UNITDATA_IND style message for ARP as it doesn't understand fast path.
3983 */
3984 mblk_t *pDlpiMsg;
3985 rc = vboxNetFltSolarisRawToUnitData(pMsg, &pDlpiMsg);
3986 if (RT_SUCCESS(rc))
3987 {
3988 pMsg = pDlpiMsg;
3989
3990 queue_t *pArpReadQueue = pArpStream->pReadQueue;
3991 putnext(pArpReadQueue, pMsg);
3992 }
3993 else
3994 {
3995 LogRel((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData failed!\n"));
3996 freemsg(pMsg);
3997 rc = VERR_NO_MEMORY;
3998 }
3999 }
4000 else
4001 freemsg(pMsg); /* Should really never happen... */
4002 }
4003 else
4004 {
4005 vboxnetflt_stream_t *pIp6Stream = ASMAtomicUoReadPtrT(&pThis->u.s.pIp6Stream, vboxnetflt_stream_t *);
4006 if ( pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6)
4007 && pIp6Stream)
4008 {
4009 /*
4010 * Send messages up IPv6 stream.
4011 */
4012 Log((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST IPv6\n"));
4013
4014 pMsg->b_rptr += sizeof(RTNETETHERHDR);
4015 queue_t *pIp6ReadQueue = pIp6Stream->pReadQueue;
4016 putnext(pIp6ReadQueue, pMsg);
4017 }
4018 else
4019 {
4020 /*
4021 * Send messages up IPv4 stream.
4022 */
4023 Log((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST IPv4\n"));
4024
4025 pMsg->b_rptr += sizeof(RTNETETHERHDR);
4026 queue_t *pIp4ReadQueue = pIp4Stream->pReadQueue;
4027 putnext(pIp4ReadQueue, pMsg);
4028 }
4029 }
4030 }
4031 else
4032 {
4033 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed.\n"));
4034 rc = VERR_NO_MEMORY;
4035 }
4036 }
4037
4038 return rc;
4039}
4040
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