VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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