VirtualBox

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

Last change on this file since 57358 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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