VirtualBox

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

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

*: Please don NOT redefine logger macros.

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