VirtualBox

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

Last change on this file since 43889 was 41774, checked in by vboxsync, 13 years ago

bugref..

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