VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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

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