VirtualBox

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

Last change on this file since 54558 was 52618, checked in by vboxsync, 10 years ago

HostDrivers, Runtime, Devices, Additions: TSC delta measurement and other changes resulting from bumping supdrv major version. TSC delta measurement currently disabled.

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