VirtualBox

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

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

HostDrivers/solaris: LogFlow->Log for debug purposes.

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