VirtualBox

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

Last change on this file since 37808 was 37766, checked in by vboxsync, 14 years ago

Solaris/VBoxNetBow: don't create device nodes, some renaming.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.7 KB
Line 
1/* $Id: VBoxNetFltBow-solaris.c 37766 2011-07-04 14:15:25Z vboxsync $ */
2/** @file
3 * VBoxNetFlt - Network Filter Driver (Host), Solaris Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
22#include <VBox/log.h>
23#include <VBox/err.h>
24#include <VBox/intnetinline.h>
25#include <VBox/version.h>
26#include <iprt/initterm.h>
27#include <iprt/alloca.h>
28#include <iprt/assert.h>
29#include <iprt/err.h>
30#include <iprt/string.h>
31#include <iprt/rand.h>
32#include <iprt/net.h>
33#include <iprt/spinlock.h>
34#include <iprt/mem.h>
35
36#include <sys/types.h>
37#include <sys/modctl.h>
38#include <sys/conf.h>
39#include <sys/stat.h>
40#include <sys/ddi.h>
41#include <sys/gld.h>
42#include <sys/sunddi.h>
43#include <sys/strsubr.h>
44#include <sys/dlpi.h>
45#include <sys/dls_mgmt.h>
46#include <sys/mac.h>
47#include <sys/strsun.h>
48
49#include <sys/vnic_mgmt.h>
50#include <sys/mac_client.h>
51#include <sys/mac_provider.h>
52#include <sys/dls.h>
53#include <sys/dld.h>
54#include <sys/cred.h>
55
56
57#define VBOXNETFLT_OS_SPECFIC 1
58#include "../VBoxNetFltInternal.h"
59
60/*******************************************************************************
61* Defined Constants And Macros *
62*******************************************************************************/
63/** The module name. */
64#define DEVICE_NAME "vboxbow"
65/** The module descriptions as seen in 'modinfo'. */
66#define DEVICE_DESC_DRV "VirtualBox NetBow"
67/** The dynamically created VNIC name (hardcoded in NetIf-solaris.cpp).
68 * @todo move this define into a common header. */
69#define VBOXBOW_VNIC_NAME "vboxvnic"
70/** The VirtualBox VNIC template name (hardcoded in NetIf-solaris.cpp).
71 * * @todo move this define into a common header. */
72#define VBOXBOW_VNIC_TEMPLATE_NAME "vboxvnic_template"
73/** Debugging switch for using symbols in kmdb */
74# define LOCAL static
75/** VBOXNETFLTVNIC::u32Magic */
76# define VBOXNETFLTVNIC_MAGIC 0x0ddfaced
77
78#if defined(DEBUG_ramshankar)
79# undef Log
80# define Log LogRel
81# undef LogFlow
82# define LogFlow LogRel
83# undef LOCAL
84# define LOCAL
85#endif
86
87/** VLAN tag masking, should probably be in IPRT? */
88#define VLAN_ID(vlan) (((vlan) >> 0) & 0x0fffu)
89#define VLAN_CFI(vlan) (((vlan) >> 12) & 0x0001u)
90#define VLAN_PRI(vlan) (((vlan) >> 13) & 0x0007u)
91#define VLAN_TAG(pri,cfi,vid) (((pri) << 13) | ((cfi) << 12) | ((vid) << 0))
92
93typedef struct VLANHEADER
94{
95 uint16_t Type;
96 uint16_t Data;
97} VLANHEADER;
98typedef struct VLANHEADER *PVLANHEADER;
99
100/* Private: from sys/vlan.h */
101#ifndef VLAN_ID_NONE
102# define VLAN_ID_NONE 0
103#endif
104
105/* Private: from sys/param.h */
106#ifndef MAXLINKNAMESPECIFIER
107# define MAXLINKNAMESPECIFIER 96 /* MAXLINKNAMELEN + ZONENAME_MAX */
108#endif
109
110/* Private: from sys/mac_client_priv.h, mac client function prototypes. */
111extern uint16_t mac_client_vid(mac_client_handle_t hClient);
112extern void mac_client_get_resources(mac_client_handle_t hClient, mac_resource_props_t *pResources);
113extern int mac_client_set_resources(mac_client_handle_t hClient, mac_resource_props_t *pResources);
114
115
116/*******************************************************************************
117* Kernel Entry Hooks *
118*******************************************************************************/
119LOCAL int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
120LOCAL int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
121LOCAL int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
122
123
124/*******************************************************************************
125* Structures and Typedefs *
126*******************************************************************************/
127/**
128 * cb_ops: for drivers that support char/block entry points
129 */
130static struct cb_ops g_VBoxNetFltSolarisCbOps =
131{
132 nulldev, /* c open */
133 nulldev, /* c close */
134 nodev, /* b strategy */
135 nodev, /* b dump */
136 nodev, /* b print */
137 nodev, /* c read */
138 nodev, /* c write*/
139 nodev, /* c ioctl*/
140 nodev, /* c devmap */
141 nodev, /* c mmap */
142 nodev, /* c segmap */
143 nochpoll, /* c poll */
144 ddi_prop_op, /* property ops */
145 NULL, /* streamtab */
146 D_NEW | D_MP, /* compat. flag */
147 CB_REV, /* revision */
148 nodev, /* c aread */
149 nodev /* c awrite */
150};
151
152/**
153 * dev_ops: for driver device operations
154 */
155static struct dev_ops g_VBoxNetFltSolarisDevOps =
156{
157 DEVO_REV, /* driver build revision */
158 0, /* ref count */
159 VBoxNetFltSolarisGetInfo,
160 nulldev, /* identify */
161 nulldev, /* probe */
162 VBoxNetFltSolarisAttach,
163 VBoxNetFltSolarisDetach,
164 nodev, /* reset */
165 &g_VBoxNetFltSolarisCbOps,
166 NULL, /* bus ops */
167 nodev, /* power */
168 ddi_quiesce_not_needed
169};
170
171/**
172 * modldrv: export driver specifics to the kernel
173 */
174static struct modldrv g_VBoxNetFltSolarisModule =
175{
176 &mod_driverops, /* extern from kernel */
177 DEVICE_DESC_DRV " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV),
178 &g_VBoxNetFltSolarisDevOps
179};
180
181/**
182 * modlinkage: export install/remove/info to the kernel
183 */
184static struct modlinkage g_VBoxNetFltSolarisModLinkage =
185{
186 MODREV_1,
187 {
188 &g_VBoxNetFltSolarisModule,
189 NULL,
190 }
191};
192
193/*
194 * VBOXNETFLTVNICTEMPLATE: VNIC template information.
195 */
196typedef struct VBOXNETFLTVNICTEMPLATE
197{
198 /** The name of link on which the VNIC template is created on. */
199 char szLinkName[MAXNAMELEN];
200 /** The VLAN Id (can be VLAN_ID_NONE). */
201 uint16_t uVLANId;
202 /** Resources (bandwidth, CPU bindings, flow priority etc.) */
203 mac_resource_props_t Resources;
204} VBOXNETFLTVNICTEMPLATE;
205typedef struct VBOXNETFLTVNICTEMPLATE *PVBOXNETFLTVNICTEMPLATE;
206
207/**
208 * VBOXNETFLTVNIC: Per-VNIC instance data.
209 */
210typedef struct VBOXNETFLTVNIC
211{
212 /** Magic number (VBOXNETFLTVNIC_MAGIC). */
213 uint32_t u32Magic;
214 /** Whether we created the VNIC or not. */
215 bool fCreated;
216 /** Pointer to the VNIC template if any. */
217 PVBOXNETFLTVNICTEMPLATE pVNICTemplate;
218 /** Pointer to the VirtualBox interface instance. */
219 void *pvIf;
220 /** The MAC handle. */
221 mac_handle_t hInterface;
222 /** The VNIC link ID. */
223 datalink_id_t hLinkId;
224 /** The MAC client handle */
225 mac_client_handle_t hClient;
226 /** The unicast address handle. */
227 mac_unicast_handle_t hUnicast;
228 /* The VNIC name. */
229 char szName[MAXLINKNAMESPECIFIER];
230 /** Handle to the next VNIC in the list. */
231 list_node_t hNode;
232} VBOXNETFLTVNIC;
233typedef struct VBOXNETFLTVNIC *PVBOXNETFLTVNIC;
234
235/*******************************************************************************
236* Global Variables *
237*******************************************************************************/
238/** Global Device handle we only support one instance. */
239static dev_info_t *g_pVBoxNetFltSolarisDip = NULL;
240/** Global Mutex (actually an rw lock). */
241static RTSEMFASTMUTEX g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
242/** The (common) global data. */
243static VBOXNETFLTGLOBALS g_VBoxNetFltSolarisGlobals;
244
245
246/*******************************************************************************
247* Internal Functions *
248*******************************************************************************/
249LOCAL mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst);
250LOCAL unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg);
251LOCAL int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc);
252LOCAL void vboxNetFltSolarisRecv(void *pvData, mac_resource_handle_t hResource, mblk_t *pMsg, boolean_t fLoopback);
253LOCAL void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg);
254LOCAL int vboxNetFltSolarisReportInfo(PVBOXNETFLTINS pThis, mac_handle_t hInterface, bool fIsVNIC);
255LOCAL int vboxNetFltSolarisInitVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC pVNIC);
256LOCAL int vboxNetFltSolarisInitVNICTemplate(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC pVNIC, PVBOXNETFLTVNICTEMPLATE pVNICTemplate);
257LOCAL PVBOXNETFLTVNIC vboxNetFltSolarisAllocVNIC(void);
258LOCAL void vboxNetFltSolarisFreeVNIC(PVBOXNETFLTVNIC pVNIC);
259LOCAL void vboxNetFltSolarisDestroyVNIC(PVBOXNETFLTVNIC pVNIC);
260LOCAL int vboxNetFltSolarisCreateVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC *ppVNIC);
261LOCAL inline int vboxNetFltSolarisGetLinkId(const char *pszMacName, datalink_id_t *pLinkId);
262
263
264/**
265 * Kernel entry points
266 */
267int _init(void)
268{
269 LogFlow((DEVICE_NAME ":_init\n"));
270
271 /*
272 * Prevent module autounloading.
273 */
274 modctl_t *pModCtl = mod_getctl(&g_VBoxNetFltSolarisModLinkage);
275 if (pModCtl)
276 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
277 else
278 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
279
280 /*
281 * Initialize IPRT.
282 */
283 int rc = RTR0Init(0);
284 if (RT_SUCCESS(rc))
285 {
286 /*
287 * Initialize Solaris specific globals here.
288 */
289 rc = RTSemFastMutexCreate(&g_VBoxNetFltSolarisMtx);
290 if (RT_SUCCESS(rc))
291 {
292 /*
293 * Initialize the globals and connect to the support driver.
294 *
295 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
296 * for establishing the connect to the support driver.
297 */
298 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
299 rc = vboxNetFltInitGlobalsAndIdc(&g_VBoxNetFltSolarisGlobals);
300 if (RT_SUCCESS(rc))
301 {
302 rc = mod_install(&g_VBoxNetFltSolarisModLinkage);
303 if (!rc)
304 return rc;
305
306 LogRel((DEVICE_NAME ":mod_install failed. rc=%d\n", rc));
307 vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltSolarisGlobals);
308 }
309 else
310 LogRel((DEVICE_NAME ":failed to initialize globals.\n"));
311
312 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
313 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
314 }
315
316 RTR0Term();
317 }
318 else
319 LogRel((DEVICE_NAME ":failed to initialize IPRT (rc=%d)\n", rc));
320
321 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
322 return RTErrConvertToErrno(rc);
323}
324
325
326int _fini(void)
327{
328 int rc;
329 LogFlow((DEVICE_NAME ":_fini\n"));
330
331 /*
332 * Undo the work done during start (in reverse order).
333 */
334 rc = vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltSolarisGlobals);
335 if (RT_FAILURE(rc))
336 {
337 LogRel((DEVICE_NAME ":_fini - busy!\n"));
338 return EBUSY;
339 }
340
341 rc = mod_remove(&g_VBoxNetFltSolarisModLinkage);
342 if (!rc)
343 {
344 if (g_VBoxNetFltSolarisMtx != NIL_RTSEMFASTMUTEX)
345 {
346 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
347 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
348 }
349
350 RTR0Term();
351 }
352
353 return rc;
354}
355
356
357int _info(struct modinfo *pModInfo)
358{
359 LogFlow((DEVICE_NAME ":_info\n"));
360
361 int rc = mod_info(&g_VBoxNetFltSolarisModLinkage, pModInfo);
362
363 LogFlow((DEVICE_NAME ":_info returns %d\n", rc));
364 return rc;
365}
366
367
368/**
369 * Attach entry point, to attach a device to the system or resume it.
370 *
371 * @param pDip The module structure instance.
372 * @param enmCmd Operation type (attach/resume).
373 *
374 * @returns corresponding solaris error code.
375 */
376LOCAL int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
377{
378 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
379
380 switch (enmCmd)
381 {
382 case DDI_ATTACH:
383 {
384 g_pVBoxNetFltSolarisDip = pDip;
385 return DDI_SUCCESS;
386 }
387
388 case DDI_RESUME:
389 {
390 /* Nothing to do here... */
391 return DDI_SUCCESS;
392 }
393
394 /* case DDI_PM_RESUME: */
395 default:
396 return DDI_FAILURE;
397 }
398}
399
400
401/**
402 * Detach entry point, to detach a device to the system or suspend it.
403 *
404 * @param pDip The module structure instance.
405 * @param enmCmd Operation type (detach/suspend).
406 *
407 * @returns corresponding solaris error code.
408 */
409LOCAL int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
410{
411 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
412
413 switch (enmCmd)
414 {
415 case DDI_DETACH:
416 {
417 return DDI_SUCCESS;
418 }
419
420 case DDI_RESUME:
421 {
422 /* Nothing to do here... */
423 return DDI_SUCCESS;
424 }
425
426 /* case DDI_PM_SUSPEND: */
427 /* case DDI_HOT_PLUG_DETACH: */
428 default:
429 return DDI_FAILURE;
430 }
431}
432
433
434/**
435 * Info entry point, called by solaris kernel for obtaining driver info.
436 *
437 * @param pDip The module structure instance (do not use).
438 * @param enmCmd Information request type.
439 * @param pvArg Type specific argument.
440 * @param ppvResult Where to store the requested info.
441 *
442 * @returns corresponding solaris error code.
443 */
444LOCAL int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppResult)
445{
446 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd, getminor((dev_t)pvArg)));
447
448 switch (enmCmd)
449 {
450 case DDI_INFO_DEVT2DEVINFO:
451 {
452 *ppResult = g_pVBoxNetFltSolarisDip;
453 return DDI_SUCCESS;
454 }
455
456 case DDI_INFO_DEVT2INSTANCE:
457 {
458 int instance = getminor((dev_t)pvArg);
459 *ppResult = (void *)(uintptr_t)instance;
460 return DDI_SUCCESS;
461 }
462 }
463
464 return DDI_FAILURE;
465}
466
467
468/**
469 * Create a solaris message block from the SG list.
470 *
471 * @param pThis The instance.
472 * @param pSG Pointer to the scatter-gather list.
473 *
474 * @returns Solaris message block.
475 */
476LOCAL inline mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
477{
478 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG pThis=%p pSG=%p\n", pThis, pSG));
479
480 mblk_t *pMsg = allocb(pSG->cbTotal, BPRI_HI);
481 if (RT_UNLIKELY(!pMsg))
482 {
483 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed to alloc %d bytes for mblk_t.\n", pSG->cbTotal));
484 return NULL;
485 }
486
487 /*
488 * Single buffer copy. Maybe later explore the
489 * need/possibility for using a mblk_t chain rather.
490 */
491 for (unsigned i = 0; i < pSG->cSegsUsed; i++)
492 {
493 if (pSG->aSegs[i].pv)
494 {
495 bcopy(pSG->aSegs[i].pv, pMsg->b_wptr, pSG->aSegs[i].cb);
496 pMsg->b_wptr += pSG->aSegs[i].cb;
497 }
498 }
499 return pMsg;
500}
501
502
503/**
504 * Calculate the number of segments required for this message block.
505 *
506 * @param pThis The instance
507 * @param pMsg Pointer to the data message.
508 *
509 * @returns Number of segments.
510 */
511LOCAL unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg)
512{
513 unsigned cSegs = 0;
514 for (mblk_t *pCur = pMsg; pCur; pCur = pCur->b_cont)
515 if (MBLKL(pCur))
516 cSegs++;
517
518#ifdef PADD_RUNT_FRAMES_FROM_HOST
519 if (msgdsize(pMsg) < 60)
520 cSegs++;
521#endif
522
523 NOREF(pThis);
524 return RT_MAX(cSegs, 1);
525}
526
527
528/**
529 * Initializes an SG list from the given message block.
530 *
531 * @param pThis The instance.
532 * @param pMsg Pointer to the data message.
533 The caller must ensure it's not a control message block.
534 * @param pSG Pointer to the SG.
535 * @param cSegs Number of segments in the SG.
536 * This should match the number in the message block exactly!
537 * @param fSrc The source of the message.
538 *
539 * @returns VBox status code.
540 */
541LOCAL int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
542{
543 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
544
545 /*
546 * Convert the message block to segments. Works cbTotal and sets cSegsUsed.
547 */
548 IntNetSgInitTempSegs(pSG, 0 /*cbTotal*/, cSegs, 0 /*cSegsUsed*/);
549 mblk_t *pCur = pMsg;
550 unsigned iSeg = 0;
551 while (pCur)
552 {
553 size_t cbSeg = MBLKL(pCur);
554 if (cbSeg)
555 {
556 void *pvSeg = pCur->b_rptr;
557 pSG->aSegs[iSeg].pv = pvSeg;
558 pSG->aSegs[iSeg].cb = cbSeg;
559 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
560 pSG->cbTotal += cbSeg;
561 iSeg++;
562 }
563 pCur = pCur->b_cont;
564 }
565 pSG->cSegsUsed = iSeg;
566
567#ifdef PADD_RUNT_FRAMES_FROM_HOST
568 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
569 {
570 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pulling up to length.\n"));
571
572 static uint8_t const s_abZero[128] = {0};
573 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
574 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
575 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
576 pSG->cbTotal = 60;
577 pSG->cSegsUsed++;
578 Assert(iSeg + 1 < cSegs);
579 }
580#endif
581
582 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
583 return VINF_SUCCESS;
584}
585
586
587/**
588 * Simple packet dump, used for internal debugging.
589 *
590 * @param pMsg Pointer to the message to analyze and dump.
591 */
592LOCAL void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg)
593{
594 LogFlowFunc((DEVICE_NAME ":vboxNetFltSolarisAnalyzeMBlk pMsg=%p\n", pMsg));
595
596 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
597 uint8_t *pb = pMsg->b_rptr;
598 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
599 {
600 PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
601 if (!pMsg->b_cont)
602 {
603 if (pIpHdr->ip_p == RTNETIPV4_PROT_ICMP)
604 LogRel((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
605 else if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
606 LogRel((DEVICE_NAME ":TCP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
607 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
608 {
609 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint32_t *)pIpHdr + pIpHdr->ip_hl);
610 if ( RT_BE2H_U16(pUdpHdr->uh_sport) == 67
611 && RT_BE2H_U16(pUdpHdr->uh_dport) == 68)
612 {
613 LogRel((DEVICE_NAME ":UDP bootp ack D=%.6Rhxs S=%.6Rhxs UDP_CheckSum=%04x Computex=%04x\n", pb, pb + 6,
614 RT_BE2H_U16(pUdpHdr->uh_sum), RT_BE2H_U16(RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1))));
615 }
616 }
617 }
618 else
619 {
620 LogFlow((DEVICE_NAME ":Chained IP packet. Skipping validity check.\n"));
621 }
622 }
623 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_VLAN))
624 {
625 PVLANHEADER pVlanHdr = (PVLANHEADER)(pMsg->b_rptr + sizeof(RTNETETHERHDR) - sizeof(pEthHdr->EtherType));
626 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))));
627 LogRel((DEVICE_NAME "%.*Rhxd\n", sizeof(VLANHEADER), pVlanHdr));
628 }
629 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
630 {
631 PRTNETARPHDR pArpHdr = (PRTNETARPHDR)(pEthHdr + 1);
632 LogRel((DEVICE_NAME ":ARP Op=%d\n", pArpHdr->ar_oper));
633 }
634 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
635 {
636 LogRel((DEVICE_NAME ":IPv6 D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
637 }
638 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_1)
639 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_2)
640 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_3))
641 {
642 LogRel((DEVICE_NAME ":IPX packet.\n"));
643 }
644 else
645 {
646 LogRel((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
647 &pEthHdr->SrcMac));
648 /* LogFlow((DEVICE_NAME ":%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
649 }
650}
651
652
653/**
654 * Helper.
655 */
656DECLINLINE(bool) vboxNetFltPortSolarisIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
657{
658 return pThis->u.s.MacAddr.au16[0] == pMac->au16[0]
659 && pThis->u.s.MacAddr.au16[1] == pMac->au16[1]
660 && pThis->u.s.MacAddr.au16[2] == pMac->au16[2];
661}
662
663
664/**
665 * Receive (rx) entry point.
666 *
667 * @param pvData Private data.
668 * @param hResource The resource handle.
669 * @param pMsg The packet.
670 * @param fLoopback Whether this is a loopback packet or not.
671 */
672LOCAL void vboxNetFltSolarisRecv(void *pvData, mac_resource_handle_t hResource, mblk_t *pMsg, boolean_t fLoopback)
673{
674 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRecv pvData=%p pMsg=%p fLoopback=%d cbData=%d\n", pvData, pMsg, fLoopback, pMsg ? MBLKL(pMsg) : 0));
675
676 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvData;
677 AssertPtrReturnVoid(pThis);
678 AssertPtrReturnVoid(pMsg);
679
680 /*
681 * Active? Retain the instance and increment the busy counter.
682 */
683 if (!vboxNetFltTryRetainBusyActive(pThis))
684 {
685 freemsgchain(pMsg);
686 return;
687 }
688
689 uint32_t fSrc = INTNETTRUNKDIR_WIRE;
690 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
691 if ( MBLKL(pMsg) >= sizeof(RTNETETHERHDR)
692 && vboxNetFltPortSolarisIsHostMac(pThis, &pEthHdr->SrcMac))
693 fSrc = INTNETTRUNKDIR_HOST;
694
695 /*
696 * Route all received packets into the internal network.
697 */
698 uint16_t cFailed = 0;
699 for (mblk_t *pCurMsg = pMsg; pCurMsg != NULL; pCurMsg = pCurMsg->b_next)
700 {
701 unsigned cSegs = vboxNetFltSolarisMBlkCalcSGSegs(pThis, pCurMsg);
702 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
703 int rc = vboxNetFltSolarisMBlkToSG(pThis, pMsg, pSG, cSegs, fSrc);
704 if (RT_SUCCESS(rc))
705 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL, pSG, fSrc);
706 else
707 cFailed++;
708 }
709 vboxNetFltRelease(pThis, true /* fBusy */);
710
711 if (RT_UNLIKELY(cFailed))
712 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG failed for %u packets.\n", cFailed));
713
714 freemsgchain(pMsg);
715
716 NOREF(hResource);
717}
718
719
720#if 0
721/**
722 * MAC layer link notification hook.
723 *
724 * @param pvArg Opaque pointer to the instance.
725 * @param Type Notification Type.
726 *
727 * @remarks This hook will be invoked for various changes to the underlying
728 * interface even when VMs aren't running so don't do any funky stuff
729 * here.
730 */
731LOCAL void vboxNetFltSolarisLinkNotify(void *pvArg, mac_notify_type_t Type)
732{
733 LogRel((DEVICE_NAME ":vboxNetFltSolarisLinkNotify pvArg=%p Type=%d\n", pvArg, Type));
734
735 PVBOXNETFLTINS pThis = pvArg;
736 AssertReturnVoid(VALID_PTR(pThis));
737 AssertReturnVoid(pThis->u.s.hInterface);
738
739 switch (Type)
740 {
741 case MAC_NOTE_LINK:
742 {
743 LogRel((DEVICE_NAME ":vboxNetFltSolarisLinkNotify link state change\n"));
744 link_state_t hLinkState = mac_stat_get(pThis->u.s.hInterface, MAC_STAT_LINK_STATE);
745 bool fDisconnectedFromHost = hLinkState == LINK_STATE_UP ? false : true;
746 if (fDisconnectedFromHost != ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost))
747 {
748 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, fDisconnectedFromHost);
749 LogRel((DEVICE_NAME ":vboxNetFltSolarisLinkNotify link state change: new state=%s\n", fDisconnectedFromHost ? "DOWN" : "UP"));
750 }
751 break;
752 }
753
754 default:
755 return;
756 }
757}
758#endif
759
760
761/**
762 * Report capabilities and MAC address to IntNet after obtaining the MAC address
763 * of the underlying interface for a VNIC or the current interface if it's a
764 * physical/ether-stub interface.
765 *
766 * @param pThis The instance.
767 * @param hInterface The Interface handle.
768 * @param fIsVNIC Whether this interface handle corresponds to a VNIC
769 * or not.
770 *
771 * @remarks Retains the instance while doing it's job.
772 * @returns VBox status code.
773 */
774LOCAL int vboxNetFltSolarisReportInfo(PVBOXNETFLTINS pThis, mac_handle_t hInterface, bool fIsVNIC)
775{
776 mac_handle_t hLowerMac = NULL;
777 if (!fIsVNIC)
778 hLowerMac = hInterface;
779 else
780 {
781 hLowerMac = mac_get_lower_mac_handle(hInterface);
782 if (RT_UNLIKELY(!hLowerMac))
783 {
784 LogRel((DEVICE_NAME ":vboxNetFltSolarisReportInfo failed to get lower MAC handle for '%s'\n", pThis->szName));
785 return VERR_INVALID_HANDLE;
786 }
787 }
788
789 pThis->u.s.hInterface = hLowerMac;
790
791#if 0
792 /*
793 * Try setup link notification hooks, this might fail if mac_no_notification()
794 * doesn't support it. We won't bother using the private function since link notification
795 * isn't critical for us and ignore failures.
796 */
797 pThis->u.s.hNotify = mac_notify_add(hLowerMac, vboxNetFltSolarisLinkNotify, pThis);
798 if (!pThis->u.s.hNotify)
799 LogRel((DEVICE_NAME ":vboxNetFltSolarisReportInfo Warning! Failed to setup link notification hook.\n"));
800#endif
801
802 mac_unicast_primary_get(hLowerMac, (uint8_t *)pThis->u.s.MacAddr.au8);
803 if (vboxNetFltTryRetainBusyNotDisconnected(pThis))
804 {
805 Assert(pThis->pSwitchPort);
806 LogFlow((DEVICE_NAME ":vboxNetFltSolarisReportInfo phys mac %.6Rhxs\n", &pThis->u.s.MacAddr));
807 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
808 pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, false); /** @todo Promisc */
809 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
810 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
811 vboxNetFltRelease(pThis, true /*fBusy*/);
812 return VINF_SUCCESS;
813 }
814 else
815 LogRel((DEVICE_NAME ":vboxNetFltSolarisReportInfo failed to retain interface. pThis=%p\n", pThis));
816
817 return VERR_INTNET_FLT_IF_BUSY;
818}
819
820
821/**
822 * Initialize a VNIC, optionally from a template.
823 *
824 * @param pThis The instance.
825 * @param pVNIC Pointer to the VNIC.
826 * @param pVNICTemplate Pointer to the VNIC template initialize from, can be
827 * NULL.
828 *
829 * @returns VBox status code.
830 */
831LOCAL int vboxNetFltSolarisInitVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC pVNIC)
832{
833 /*
834 * Some paranoia.
835 */
836 AssertReturn(pThis, VERR_INVALID_PARAMETER);
837 AssertReturn(pVNIC, VERR_INVALID_PARAMETER);
838 AssertReturn(pVNIC->hInterface, VERR_INVALID_POINTER);
839 AssertReturn(pVNIC->hLinkId != DATALINK_INVALID_LINKID, VERR_INVALID_HANDLE);
840 AssertReturn(!pVNIC->hClient, VERR_INVALID_POINTER);
841
842 int rc = mac_client_open(pVNIC->hInterface, &pVNIC->hClient,
843 NULL, /* name of this client */
844 MAC_OPEN_FLAGS_USE_DATALINK_NAME | /* client name same as underlying NIC */
845 MAC_OPEN_FLAGS_MULTI_PRIMARY /* allow multiple primary unicasts */
846 );
847 if (RT_LIKELY(!rc))
848 {
849 if (pVNIC->pVNICTemplate)
850 rc = mac_client_set_resources(pVNIC->hClient, &pVNIC->pVNICTemplate->Resources);
851
852 if (RT_LIKELY(!rc))
853 {
854 LogFlow((DEVICE_NAME ":vboxNetFltSolarisInitVNIC succesfully initialized VNIC.\n"));
855 return VINF_SUCCESS;
856 }
857 else
858 {
859 LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNIC mac_client_set_resources failed. rc=%d\n", rc));
860 rc = VERR_INTNET_FLT_VNIC_CREATE_FAILED;
861 }
862
863 mac_client_close(pVNIC->hClient, 0 /* flags */);
864 pVNIC->hClient = NULL;
865 }
866 else
867 LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNIC failed to open mac client for '%s' rc=%d\n", pThis->szName, rc));
868
869 return rc;
870}
871
872
873/**
874 * Initializes the VNIC template. This involves opening the template VNIC to
875 * retreive info. like the VLAN Id, underlying MAC address etc.
876 *
877 * @param pThis The VM connection instance.
878 * @param pVNIC Pointer to the VNIC.
879 * @param pVNICTemplate Pointer to a VNIC template to initialize.
880 *
881 * @returns VBox status code.
882 */
883LOCAL int vboxNetFltSolarisInitVNICTemplate(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC pVNIC, PVBOXNETFLTVNICTEMPLATE pVNICTemplate)
884{
885 LogFlow((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate pThis=%p pVNIC=%p pVNICTemplate=%p\n", pThis, pVNIC, pVNICTemplate));
886
887 AssertReturn(pVNICTemplate, VERR_INVALID_PARAMETER);
888 AssertReturn(pThis->u.s.fIsVNICTemplate == true, VERR_INVALID_STATE);
889
890 /*
891 * Get the VNIC template's datalink ID.
892 */
893 datalink_id_t VNICLinkId;
894 int rc = vboxNetFltSolarisGetLinkId(pThis->szName, &VNICLinkId);
895 if (RT_SUCCESS(rc))
896 {
897 /*
898 * Open the VNIC to obtain a MAC handle so as to retreive the VLAN ID.
899 */
900 mac_handle_t hInterface;
901 rc = mac_open_by_linkid(VNICLinkId, &hInterface);
902 if (!rc)
903 {
904 /*
905 * Get the underlying linkname.
906 */
907 mac_handle_t hPhysLinkHandle = mac_get_lower_mac_handle(hInterface);
908 if (RT_LIKELY(hPhysLinkHandle))
909 {
910 const char *pszLinkName = mac_name(hPhysLinkHandle);
911 rc = RTStrCopy(pVNICTemplate->szLinkName, sizeof(pVNICTemplate->szLinkName), pszLinkName);
912 if (RT_SUCCESS(rc))
913 {
914 /*
915 * Now open the VNIC template to retrieve the VLAN Id & resources.
916 */
917 mac_client_handle_t hClient;
918 rc = mac_client_open(hInterface, &hClient,
919 NULL, /* name of this client */
920 MAC_OPEN_FLAGS_USE_DATALINK_NAME | /* client name same as underlying NIC */
921 MAC_OPEN_FLAGS_MULTI_PRIMARY /* allow multiple primary unicasts */
922 );
923 if (RT_LIKELY(!rc))
924 {
925 pVNICTemplate->uVLANId = mac_client_vid(hClient);
926 mac_client_get_resources(hClient, &pVNICTemplate->Resources);
927 mac_client_close(hClient, 0 /* fFlags */);
928 mac_close(hInterface);
929
930 LogFlow((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate successfully init. VNIC template. szLinkName=%s\n",
931 pVNICTemplate->szLinkName));
932 return VINF_SUCCESS;
933 }
934 else
935 {
936 LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to open VNIC template. rc=%d\n", rc));
937 rc = VERR_INTNET_FLT_IF_FAILED;
938 }
939 }
940 else
941 LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to copy link name of underlying interface. rc=%d\n", rc));
942 }
943 else
944 {
945 LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to get lower handle for VNIC template '%s'.\n", pThis->szName));
946 rc = VERR_INTNET_FLT_IF_FAILED;
947 }
948
949 mac_close(hInterface);
950 }
951 else
952 {
953 LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to open by link ID. rc=%d\n", rc));
954 rc = VERR_INTNET_FLT_IF_FAILED;
955 }
956 }
957 else
958 LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to get VNIC template link Id. rc=%d\n", rc));
959
960 return rc;
961}
962
963
964/**
965 * Allocate a VNIC structure.
966 *
967 * @returns An allocated VNIC structure or NULL in case of errors.
968 */
969LOCAL PVBOXNETFLTVNIC vboxNetFltSolarisAllocVNIC(void)
970{
971 PVBOXNETFLTVNIC pVNIC = RTMemAllocZ(sizeof(VBOXNETFLTVNIC));
972 if (RT_UNLIKELY(!pVNIC))
973 return NULL;
974
975 pVNIC->u32Magic = VBOXNETFLTVNIC_MAGIC;
976 pVNIC->fCreated = false;
977 pVNIC->pVNICTemplate = NULL;
978 pVNIC->pvIf = NULL;
979 pVNIC->hInterface = NULL;
980 pVNIC->hLinkId = DATALINK_INVALID_LINKID;
981 pVNIC->hClient = NULL;
982 pVNIC->hUnicast = NULL;
983 RT_ZERO(pVNIC->szName);
984 list_link_init(&pVNIC->hNode);
985 return pVNIC;
986}
987
988
989/**
990 * Frees an allocated VNIC.
991 *
992 * @param pVNIC Pointer to the VNIC.
993 */
994LOCAL inline void vboxNetFltSolarisFreeVNIC(PVBOXNETFLTVNIC pVNIC)
995{
996 RTMemFree(pVNIC);
997}
998
999
1000/**
1001 * Destroy a created VNIC if it was created by us, or just
1002 * de-initializes the VNIC freeing up resources handles.
1003 *
1004 * @param pVNIC Pointer to the VNIC.
1005 */
1006LOCAL void vboxNetFltSolarisDestroyVNIC(PVBOXNETFLTVNIC pVNIC)
1007{
1008 AssertPtrReturnVoid(pVNIC);
1009 AssertMsgReturnVoid(pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC, ("pVNIC=%p u32Magic=%#x\n", pVNIC, pVNIC->u32Magic));
1010 if (pVNIC)
1011 {
1012 if (pVNIC->hClient)
1013 {
1014 if (pVNIC->hUnicast)
1015 {
1016 mac_unicast_remove(pVNIC->hClient, pVNIC->hUnicast);
1017 pVNIC->hUnicast = NULL;
1018 }
1019
1020 mac_rx_clear(pVNIC->hClient);
1021
1022 mac_client_close(pVNIC->hClient, 0 /* fFlags */);
1023 pVNIC->hClient = NULL;
1024 }
1025
1026 if (pVNIC->hInterface)
1027 {
1028 mac_close(pVNIC->hInterface);
1029 pVNIC->hInterface = NULL;
1030 }
1031
1032 if (pVNIC->fCreated)
1033 {
1034 vnic_delete(pVNIC->hLinkId, 0 /* Flags */);
1035 pVNIC->hLinkId = DATALINK_INVALID_LINKID;
1036 pVNIC->fCreated = false;
1037 }
1038
1039 if (pVNIC->pVNICTemplate)
1040 {
1041 RTMemFree(pVNIC->pVNICTemplate);
1042 pVNIC->pVNICTemplate = NULL;
1043 }
1044 }
1045}
1046
1047
1048/**
1049 * Create a non-persistent VNIC over the given interface.
1050 *
1051 * @param pThis The VM connection instance.
1052 * @param ppVNIC Where to store the created VNIC.
1053 *
1054 * @returns VBox status code.
1055 */
1056LOCAL int vboxNetFltSolarisCreateVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC *ppVNIC)
1057{
1058 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC pThis=%p\n", pThis));
1059
1060 AssertReturn(pThis, VERR_INVALID_POINTER);
1061 AssertReturn(ppVNIC, VERR_INVALID_POINTER);
1062
1063 PVBOXNETFLTVNIC pVNIC = vboxNetFltSolarisAllocVNIC();
1064 if (RT_UNLIKELY(!pVNIC))
1065 return VERR_NO_MEMORY;
1066
1067 RTStrPrintf(pVNIC->szName, sizeof(pVNIC->szName), "%s%RU64", VBOXBOW_VNIC_NAME, pThis->u.s.uInstance);
1068
1069 /*
1070 * Set a random MAC address for now. It will be changed to the VM interface's
1071 * MAC address later, see vboxNetFltPortOsNotifyMacAddress().
1072 */
1073 RTMAC GuestMac;
1074 GuestMac.au8[0] = 0x08;
1075 GuestMac.au8[1] = 0x00;
1076 GuestMac.au8[2] = 0x27;
1077 RTRandBytes(&GuestMac.au8[3], 3);
1078
1079 AssertCompile(sizeof(RTMAC) <= MAXMACADDRLEN);
1080
1081 const char *pszLinkName = pThis->szName;
1082 uint16_t uVLANId = VLAN_ID_NONE;
1083 vnic_mac_addr_type_t AddrType = VNIC_MAC_ADDR_TYPE_FIXED;
1084 vnic_ioc_diag_t Diag = VNIC_IOC_DIAG_NONE;
1085 int MacSlot = 0;
1086 int MacLen = sizeof(GuestMac);
1087 uint32_t fFlags = 0;
1088 int rc = VERR_INVALID_STATE;
1089
1090 if (pThis->u.s.fIsVNICTemplate)
1091 {
1092 pVNIC->pVNICTemplate = RTMemAllocZ(sizeof(VBOXNETFLTVNICTEMPLATE));
1093 if (RT_UNLIKELY(!pVNIC->pVNICTemplate))
1094 {
1095 vboxNetFltSolarisFreeVNIC(pVNIC);
1096 return VERR_NO_MEMORY;
1097 }
1098
1099 /*
1100 * Initialize the VNIC template.
1101 */
1102 rc = vboxNetFltSolarisInitVNICTemplate(pThis, pVNIC, pVNIC->pVNICTemplate);
1103 if (RT_FAILURE(rc))
1104 {
1105 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to initialize VNIC from VNIC template. rc=%Rrc\n", rc));
1106 vboxNetFltSolarisFreeVNIC(pVNIC);
1107 return rc;
1108 }
1109
1110 pszLinkName = pVNIC->pVNICTemplate->szLinkName;
1111 uVLANId = pVNIC->pVNICTemplate->uVLANId;
1112#if 0
1113 /*
1114 * Required only if we're creating a VLAN interface & not a VNIC with a VLAN Id.
1115 */
1116 if (uVLANId != VLAN_ID_NONE)
1117 fFlags |= MAC_VLAN;
1118#endif
1119 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC pThis=%p VLAN Id=%u\n", pThis, uVLANId));
1120 }
1121
1122 /*
1123 * Create the VNIC under 'pszLinkName', which can be the one from the VNIC template or can
1124 * be a physical interface.
1125 */
1126 rc = vnic_create(pVNIC->szName, pszLinkName, &AddrType, &MacLen, GuestMac.au8, &MacSlot, 0 /* Mac-Prefix Length */, uVLANId,
1127 fFlags, &pVNIC->hLinkId, &Diag, NULL /* Reserved */);
1128 if (!rc)
1129 {
1130 pVNIC->fCreated = true;
1131
1132 /*
1133 * Now try opening the created VNIC.
1134 */
1135 rc = mac_open_by_linkid(pVNIC->hLinkId, &pVNIC->hInterface);
1136 if (!rc)
1137 {
1138 /*
1139 * Initialize the VNIC from the physical interface or the VNIC template.
1140 */
1141 rc = vboxNetFltSolarisInitVNIC(pThis, pVNIC);
1142 if (RT_SUCCESS(rc))
1143 {
1144 pThis->u.s.uInstance++;
1145 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC successfully created VNIC '%s' over '%s' with random mac %.6Rhxs\n",
1146 pVNIC->szName, pszLinkName, &GuestMac));
1147 *ppVNIC = pVNIC;
1148 return VINF_SUCCESS;
1149 }
1150 else
1151 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC vboxNetFltSolarisInitVNIC failed. rc=%d\n", rc));
1152
1153 mac_close(pVNIC->hInterface);
1154 pVNIC->hInterface = NULL;
1155 }
1156 else
1157 {
1158 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to open VNIC '%s' over '%s'. rc=%d\n", pVNIC->szName,
1159 pThis->szName, rc));
1160 }
1161
1162 vboxNetFltSolarisDestroyVNIC(pVNIC);
1163 rc = VERR_INTNET_FLT_VNIC_CREATE_FAILED;
1164 }
1165 else
1166 {
1167 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to create VNIC '%s' over '%s' rc=%d Diag=%d\n", pVNIC->szName,
1168 pszLinkName, rc, Diag));
1169 rc = VERR_INTNET_FLT_VNIC_CREATE_FAILED;
1170 }
1171
1172 vboxNetFltSolarisFreeVNIC(pVNIC);
1173
1174 return rc;
1175}
1176
1177
1178/**
1179 * Wrapper for getting the datalink ID given the MAC name.
1180 *
1181 * @param pszMacName The MAC name.
1182 * @param pLinkId Where to store the datalink ID.
1183 *
1184 * @returns VBox status code.
1185 */
1186LOCAL inline int vboxNetFltSolarisGetLinkId(const char *pszMacName, datalink_id_t *pLinkId)
1187{
1188 /*
1189 * dls_mgmt_get_linkid() requires to be in a state to answer upcalls. We should always use this
1190 * first before resorting to other means to retrieve the MAC name.
1191 */
1192 int rc = dls_mgmt_get_linkid(pszMacName, pLinkId);
1193 if (rc)
1194 rc = dls_devnet_macname2linkid(pszMacName, pLinkId);
1195
1196 if (RT_LIKELY(!rc))
1197 return VINF_SUCCESS;
1198
1199 LogRel((DEVICE_NAME ":vboxNetFltSolarisGetLinkId failed for '%s'. rc=%d\n", pszMacName, rc));
1200 return RTErrConvertFromErrno(rc);
1201}
1202
1203
1204/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
1205
1206
1207void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
1208{
1209 LogFlow((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d\n", pThis, fActive));
1210
1211 /*
1212 * Reactivate/quiesce the interface.
1213 */
1214 PVBOXNETFLTVNIC pVNIC = list_head(&pThis->u.s.hVNICs);
1215 if (fActive)
1216 {
1217 for (; pVNIC != NULL; pVNIC = list_next(&pThis->u.s.hVNICs, pVNIC))
1218 if (pVNIC->hClient)
1219 mac_rx_set(pVNIC->hClient, vboxNetFltSolarisRecv, pThis);
1220 }
1221 else
1222 {
1223 for (; pVNIC != NULL; pVNIC = list_next(&pThis->u.s.hVNICs, pVNIC))
1224 if (pVNIC->hClient)
1225 mac_rx_clear(pVNIC->hClient);
1226 }
1227}
1228
1229
1230int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
1231{
1232 LogFlow((DEVICE_NAME ":vboxNetFltOsDisconnectIt pThis=%p\n", pThis));
1233 return VINF_SUCCESS;
1234}
1235
1236
1237int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
1238{
1239 LogFlow((DEVICE_NAME ":vboxNetFltOsConnectIt pThis=%p\n", pThis));
1240 return VINF_SUCCESS;
1241}
1242
1243
1244void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
1245{
1246 LogFlow((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n", pThis));
1247
1248 if (pThis->u.s.hNotify)
1249 mac_notify_remove(pThis->u.s.hNotify, B_TRUE /* Wait */);
1250
1251 /*
1252 * Destroy all managed VNICs. If a VNIC was passed to us, there
1253 * will be only 1 item in the list, otherwise as many interfaces
1254 * that were somehow not destroyed using DisconnectInterface() will be
1255 * present.
1256 */
1257 PVBOXNETFLTVNIC pVNIC = NULL;
1258 while ((pVNIC = list_remove_head(&pThis->u.s.hVNICs)) != NULL)
1259 {
1260 vboxNetFltSolarisDestroyVNIC(pVNIC);
1261 vboxNetFltSolarisFreeVNIC(pVNIC);
1262 }
1263
1264 list_destroy(&pThis->u.s.hVNICs);
1265}
1266
1267
1268int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
1269{
1270 LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p pvContext=%p\n", pThis, pvContext));
1271
1272 /*
1273 * Figure out if the interface is a VNIC or a physical/etherstub/whatever NIC, then
1274 * do the actual VNIC creation if necessary in vboxNetFltPortOsConnectInterface().
1275 */
1276 mac_handle_t hInterface;
1277 int rc = mac_open_by_linkname(pThis->szName, &hInterface);
1278 if (RT_LIKELY(!rc))
1279 {
1280 rc = mac_is_vnic(hInterface);
1281 if (!rc)
1282 {
1283 LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p physical interface '%s' detected.\n", pThis, pThis->szName));
1284 pThis->u.s.fIsVNIC = false;
1285 }
1286 else
1287 {
1288 pThis->u.s.fIsVNIC = true;
1289 if (RTStrNCmp(pThis->szName, VBOXBOW_VNIC_TEMPLATE_NAME, sizeof(VBOXBOW_VNIC_TEMPLATE_NAME) - 1) == 0)
1290 {
1291 LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p VNIC template '%s' detected.\n", pThis, pThis->szName));
1292 pThis->u.s.fIsVNICTemplate = true;
1293 }
1294 }
1295
1296 if ( pThis->u.s.fIsVNIC
1297 && !pThis->u.s.fIsVNICTemplate)
1298 LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p VNIC '%s' detected.\n", pThis, pThis->szName));
1299
1300 /*
1301 * Report info. (host MAC address, promiscuous, GSO capabilities etc.) to IntNet.
1302 */
1303 rc = vboxNetFltSolarisReportInfo(pThis, hInterface, pThis->u.s.fIsVNIC);
1304 if (RT_FAILURE(rc))
1305 LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to report info. rc=%d\n", rc));
1306
1307 mac_close(hInterface);
1308 }
1309 else
1310 {
1311 LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to open link '%s'! rc=%d\n", pThis->szName, rc));
1312 rc = VERR_INTNET_FLT_IF_FAILED;
1313 }
1314
1315 return rc;
1316}
1317
1318
1319int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
1320{
1321 /*
1322 * Init. the solaris specific data.
1323 */
1324 pThis->u.s.fIsVNIC = false;
1325 pThis->u.s.fIsVNICTemplate = false;
1326 list_create(&pThis->u.s.hVNICs, sizeof(VBOXNETFLTVNIC), offsetof(VBOXNETFLTVNIC, hNode));
1327 pThis->u.s.uInstance = 0;
1328 pThis->u.s.hNotify = NULL;
1329 RT_ZERO(pThis->u.s.MacAddr);
1330 return VINF_SUCCESS;
1331}
1332
1333
1334bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
1335{
1336 /*
1337 * @todo Think about this.
1338 */
1339 return false;
1340}
1341
1342
1343int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
1344{
1345 /*
1346 * Validate parameters.
1347 */
1348 PVBOXNETFLTVNIC pVNIC = pvIfData;
1349 AssertReturn(VALID_PTR(pVNIC), VERR_INVALID_POINTER);
1350 AssertMsgReturn(pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC,
1351 ("Invalid magic=%#x (expected %#x)\n", pVNIC->u32Magic, VBOXNETFLTVNIC_MAGIC),
1352 VERR_INVALID_MAGIC);
1353
1354 /*
1355 * Xmit the packet down the appropriate VNIC interface.
1356 */
1357 int rc = VINF_SUCCESS;
1358 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
1359 if (RT_LIKELY(pMsg))
1360 {
1361 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p cbData=%d\n", pThis, MBLKL(pMsg)));
1362
1363 mac_tx_cookie_t pXmitCookie = mac_tx(pVNIC->hClient, pMsg, 0 /* Hint */, MAC_DROP_ON_NO_DESC, NULL /* return message */);
1364 if (RT_LIKELY(!pXmitCookie))
1365 return VINF_SUCCESS;
1366
1367 pMsg = NULL;
1368 rc = VERR_NET_IO_ERROR;
1369 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit Xmit failed pVNIC=%p.\n", pVNIC));
1370 }
1371 else
1372 {
1373 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit no memory for allocating Xmit packet.\n"));
1374 rc = VERR_NO_MEMORY;
1375 }
1376
1377 return rc;
1378}
1379
1380
1381void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
1382{
1383 LogFlow((DEVICE_NAME ":vboxNetFltPortOSNotifyMacAddress pszIf=%s pszVNIC=%s MAC=%.6Rhxs\n", pThis->szName,
1384 ((PVBOXNETFLTVNIC)pvIfData)->szName, pMac));
1385
1386 /*
1387 * Validate parameters.
1388 */
1389 PVBOXNETFLTVNIC pVNIC = pvIfData;
1390 AssertMsgReturnVoid(VALID_PTR(pVNIC) && pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC,
1391 ("Invalid pVNIC=%p magic=%#x (expected %#x)\n", pvIfData, VALID_PTR(pVNIC) ? pVNIC->u32Magic : 0, VBOXNETFLTVNIC_MAGIC));
1392 AssertMsgReturnVoid(pVNIC->hLinkId != DATALINK_INVALID_LINKID,
1393 ("Invalid hLinkId pVNIC=%p magic=%#x\n", pVNIC, pVNIC->u32Magic));
1394
1395 /*
1396 * Set the MAC address of the VNIC to the one used by the VM interface.
1397 */
1398 uchar_t au8GuestMac[MAXMACADDRLEN];
1399 bcopy(pMac->au8, au8GuestMac, sizeof(RTMAC));
1400
1401 vnic_mac_addr_type_t AddrType = VNIC_MAC_ADDR_TYPE_FIXED;
1402 vnic_ioc_diag_t Diag = VNIC_IOC_DIAG_NONE;
1403 int MacSlot = 0;
1404 int MacLen = sizeof(RTMAC);
1405
1406 int rc = vnic_modify_addr(pVNIC->hLinkId, &AddrType, &MacLen, au8GuestMac, &MacSlot, 0 /* Mac-Prefix Length */, &Diag);
1407 if (RT_LIKELY(!rc))
1408 {
1409 /*
1410 * Remove existing unicast address and the RX hook.
1411 */
1412 if (pVNIC->hUnicast)
1413 {
1414 mac_rx_clear(pVNIC->hClient);
1415 mac_unicast_remove(pVNIC->hClient, pVNIC->hUnicast);
1416 pVNIC->hUnicast = NULL;
1417 }
1418
1419 /*
1420 * Add the primary unicast address and set the RX hook.
1421 */
1422 mac_diag_t MacDiag = MAC_DIAG_NONE;
1423 /* uint16_t uVLANId = pVNIC->pVNICTemplate ? pVNIC->pVNICTemplate->uVLANId : 0; */
1424 rc = mac_unicast_add(pVNIC->hClient, NULL, MAC_UNICAST_PRIMARY, &pVNIC->hUnicast, 0 /* VLAN Id */, &MacDiag);
1425 if (RT_LIKELY(!rc))
1426 {
1427 /*
1428 * Set the RX receive function.
1429 * This shouldn't be necessary as vboxNetFltPortOsSetActive() will be invoked after this, but in the future,
1430 * if the guest NIC changes MAC address this may not be followed by a vboxNetFltPortOsSetActive() call, so set it here anyway.
1431 */
1432 mac_rx_set(pVNIC->hClient, vboxNetFltSolarisRecv, pThis);
1433 LogFlow((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress successfully added unicast address %.6Rhxs\n", pMac));
1434 }
1435 else
1436 LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress failed to add primary unicast address. rc=%d Diag=%d\n", rc, MacDiag));
1437 }
1438 else
1439 {
1440 /*
1441 * They really ought to use EEXIST, but I'm afraid this error comes from the VNIC device driver directly.
1442 * Sequence: vnic_modify_addr()->mac_unicast_primary_set()->mac_update_macaddr() which uses a function pointer
1443 * to the MAC driver (calls mac_vnic_unicast_set() in our case). Documented here if the error code should change we know
1444 * where to look.
1445 */
1446 if (rc == ENOTSUP)
1447 {
1448 LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress: failed! a VNIC with mac %.6Rhxs probably already exists.",
1449 pMac, rc));
1450 LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress: This NIC cannot establish connection. szName=%s szVNIC=%s\n",
1451 pThis->szName, pVNIC->szName));
1452 }
1453 else
1454 LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress failed! mac %.6Rhxs rc=%d Diag=%d\n", pMac, rc, Diag));
1455 }
1456}
1457
1458
1459int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
1460{
1461 LogFlow((DEVICE_NAME ":vboxNetFltPortOsConnectInterface pThis=%p pvIf=%p\n", pThis, pvIf));
1462
1463 int rc = VINF_SUCCESS;
1464
1465 /*
1466 * If the underlying interface is a physical interface or a VNIC template, we need to create
1467 * a VNIC per guest NIC.
1468 */
1469 if ( !pThis->u.s.fIsVNIC
1470 || pThis->u.s.fIsVNICTemplate)
1471 {
1472 PVBOXNETFLTVNIC pVNIC = NULL;
1473 rc = vboxNetFltSolarisCreateVNIC(pThis, &pVNIC);
1474 if (RT_SUCCESS(rc))
1475 {
1476 /*
1477 * VM Interface<->VNIC association so that we can Xmit/Recv on the right ones.
1478 */
1479 pVNIC->pvIf = pvIf;
1480 *ppvIfData = pVNIC;
1481
1482 /*
1483 * Add the created VNIC to the list of VNICs we manage.
1484 */
1485 list_insert_tail(&pThis->u.s.hVNICs, pVNIC);
1486 return VINF_SUCCESS;
1487 }
1488 else
1489 LogRel((DEVICE_NAME ":vboxNetFltPortOsConnectInterface failed to create VNIC rc=%d\n", rc));
1490 }
1491 else
1492 {
1493 /*
1494 * This is a VNIC passed to us, use it directly.
1495 */
1496 PVBOXNETFLTVNIC pVNIC = vboxNetFltSolarisAllocVNIC();
1497 if (RT_LIKELY(pVNIC))
1498 {
1499 pVNIC->fCreated = false;
1500
1501 rc = mac_open_by_linkname(pThis->szName, &pVNIC->hInterface);
1502 if (!rc)
1503 {
1504 /*
1505 * Obtain the data link ID for this VNIC, it's needed for modifying the MAC address among other things.
1506 */
1507 rc = vboxNetFltSolarisGetLinkId(pThis->szName, &pVNIC->hLinkId);
1508 if (RT_SUCCESS(rc))
1509 {
1510 /*
1511 * Initialize the VNIC and add it to the list of managed VNICs.
1512 */
1513 RTStrPrintf(pVNIC->szName, sizeof(pVNIC->szName), "%s", pThis->szName);
1514 rc = vboxNetFltSolarisInitVNIC(pThis, pVNIC);
1515 if (!rc)
1516 {
1517 pVNIC->pvIf = pvIf;
1518 *ppvIfData = pVNIC;
1519 list_insert_head(&pThis->u.s.hVNICs, pVNIC);
1520 return VINF_SUCCESS;
1521 }
1522 else
1523 LogRel((DEVICE_NAME ":vboxNetFltPortOsConnectInterface failed to initialize VNIC. rc=%d\n", rc));
1524 }
1525 else
1526 LogRel((DEVICE_NAME ":vboxNetFltPortOsConnectInterface failed to get link id for '%s'. rc=%d\n", pThis->szName, rc));
1527 }
1528 else
1529 {
1530 LogRel((DEVICE_NAME ":vboxNetFltPortOsConnectInterface failed to open VNIC '%s'. rc=%d\n", pThis->szName, rc));
1531 rc = VERR_OPEN_FAILED;
1532 }
1533
1534 vboxNetFltSolarisFreeVNIC(pVNIC);
1535 }
1536 else
1537 {
1538 LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to allocate VNIC private data.\n"));
1539 rc = VERR_NO_MEMORY;
1540 }
1541 }
1542
1543 return rc;
1544}
1545
1546
1547int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
1548{
1549 LogFlow((DEVICE_NAME ":vboxNetFltPortOsDisconnectInterface pThis=%p\n", pThis));
1550
1551 PVBOXNETFLTVNIC pVNIC = pvIfData;
1552 AssertMsgReturn(VALID_PTR(pVNIC) && pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC,
1553 ("Invalid pvIfData=%p magic=%#x (expected %#x)\n", pvIfData, pVNIC ? pVNIC->u32Magic : 0, VBOXNETFLTVNIC_MAGIC),
1554 VERR_INVALID_POINTER);
1555
1556 /*
1557 * If the underlying interface is not a VNIC, we need to delete the created VNIC.
1558 */
1559 if (!pThis->u.s.fIsVNIC)
1560 {
1561 /*
1562 * Remove the VNIC from the list, destroy and free it.
1563 */
1564 list_remove(&pThis->u.s.hVNICs, pVNIC);
1565 LogFlow((DEVICE_NAME ":vboxNetFltPortOsDisconnectInterface destroying pVNIC=%p\n", pVNIC));
1566 vboxNetFltSolarisDestroyVNIC(pVNIC);
1567 vboxNetFltSolarisFreeVNIC(pVNIC);
1568 }
1569
1570 return VINF_SUCCESS;
1571}
1572
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