VirtualBox

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

Last change on this file since 41527 was 40806, checked in by vboxsync, 13 years ago

RTSpinlock: Redid the interface, eliminating NoInts and Tmp. Whether a spinlock is interrupt safe or not is now defined at creation time, preventing stupid bugs arrising from calling the wrong acquire and/or release methods somewhere. The saved flags are stored in the spinlock strucutre, eliminating the annoying Tmp variable. Needs testing on each platform before fixing the build burn.

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