VirtualBox

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

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

HostDrivers: Updated (C) year.

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