VirtualBox

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

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

Runtime/r0drv/solaris, HostDrivers/VBoxNetFlt/Solaris: Hold mod_lock across ctf_modopen calls.

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