VirtualBox

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

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

Solaris/vbi Solaris/NetFlt: close ctf file opens.

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