VirtualBox

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

Last change on this file since 32740 was 30336, checked in by vboxsync, 14 years ago

logging.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.6 KB
Line 
1/* $Id: VBoxNetFltBow-solaris.c 30336 2010-06-21 14:38:52Z 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#include <sys/sunddi.h>
49
50#include <sys/vnic_mgmt.h>
51#include <sys/mac_client.h>
52#include <sys/mac_provider.h>
53#include <sys/dls.h>
54
55#if 0
56#include "include/mac_provider.h" /* dependency for other headers */
57#include "include/mac_client.h" /* for mac_* */
58#include "include/mac_client_priv.h" /* for mac_info, mac_capab_get etc. */
59#if 1
60#include "include/dls.h" /* for dls_mgmt_* */
61#include "include/dld_ioc.h" /* required by vnic.h */
62#include "include/vnic.h" /* for vnic_ioc_diag_t */
63#include "include/vnic_impl.h" /* for vnic_dev_create */
64#endif
65#endif
66
67#define VBOXNETFLT_OS_SPECFIC 1
68#include "../VBoxNetFltInternal.h"
69
70/*******************************************************************************
71* Defined Constants And Macros *
72*******************************************************************************/
73/** The module name. */
74#define DEVICE_NAME "vboxflt"
75/** The module descriptions as seen in 'modinfo'. */
76#define DEVICE_DESC_DRV "VirtualBox NetBow"
77/** The dynamically created VNIC name */
78#define VBOXFLT_VNIC_NAME "vboxvnic"
79/** Debugging switch for using symbols in kmdb */
80# define LOCAL static
81/** VBOXNETFLTVNIC::u32Magic */
82# define VBOXNETFLTVNIC_MAGIC 0x0ddfaced
83
84#if defined(DEBUG_ramshankar)
85# undef Log
86# define Log LogRel
87# undef LogFlow
88# define LogFlow LogRel
89# undef LOCAL
90# define LOCAL
91#endif
92
93/** VLAN tag masking, should probably be in IPRT? */
94#define VLAN_ID(vlan) (((vlan) >> 0) & 0x0fffu)
95#define VLAN_CFI(vlan) (((vlan) >> 12) & 0x0001u)
96#define VLAN_PRI(vlan) (((vlan) >> 13) & 0x0007u)
97#define VLAN_TAG(pri,cfi,vid) (((pri) << 13) | ((cfi) << 12) | ((vid) << 0))
98
99typedef struct VLANHEADER
100{
101 uint16_t Type;
102 uint16_t Data;
103} VLANHEADER;
104typedef struct VLANHEADER *PVLANHEADER;
105
106
107/*******************************************************************************
108* Kernel Entry Hooks *
109*******************************************************************************/
110LOCAL int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
111LOCAL int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
112LOCAL int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
113
114
115/*******************************************************************************
116* Structures and Typedefs *
117*******************************************************************************/
118/**
119 * cb_ops: for drivers that support char/block entry points
120 */
121static struct cb_ops g_VBoxNetFltSolarisCbOps =
122{
123 nulldev, /* c open */
124 nulldev, /* c close */
125 nodev, /* b strategy */
126 nodev, /* b dump */
127 nodev, /* b print */
128 nodev, /* c read */
129 nodev, /* c write*/
130 nodev, /* c ioctl*/
131 nodev, /* c devmap */
132 nodev, /* c mmap */
133 nodev, /* c segmap */
134 nochpoll, /* c poll */
135 ddi_prop_op, /* property ops */
136 NULL, /* streamtab */
137 D_NEW | D_MP, /* compat. flag */
138 CB_REV, /* revision */
139 nodev, /* c aread */
140 nodev /* c awrite */
141};
142
143/**
144 * dev_ops: for driver device operations
145 */
146static struct dev_ops g_VBoxNetFltSolarisDevOps =
147{
148 DEVO_REV, /* driver build revision */
149 0, /* ref count */
150 VBoxNetFltSolarisGetInfo,
151 nulldev, /* identify */
152 nulldev, /* probe */
153 VBoxNetFltSolarisAttach,
154 VBoxNetFltSolarisDetach,
155 nodev, /* reset */
156 &g_VBoxNetFltSolarisCbOps,
157 NULL, /* bus ops */
158 nodev, /* power */
159 ddi_quiesce_not_needed
160};
161
162/**
163 * modldrv: export driver specifics to the kernel
164 */
165static struct modldrv g_VBoxNetFltSolarisModule =
166{
167 &mod_driverops, /* extern from kernel */
168 DEVICE_DESC_DRV " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV),
169 &g_VBoxNetFltSolarisDevOps
170};
171
172/**
173 * modlinkage: export install/remove/info to the kernel
174 */
175static struct modlinkage g_VBoxNetFltSolarisModLinkage =
176{
177 MODREV_1,
178 {
179 &g_VBoxNetFltSolarisModule,
180 NULL,
181 }
182};
183
184/**
185 * VBOXNETFLTVNIC: Per-VNIC instance data.
186 */
187typedef struct VBOXNETFLTVNIC
188{
189 uint32_t u32Magic; /* Magic number (VBOXNETFLTVNIC_MAGIC) */
190 bool fCreated; /* Whether we created the VNIC or not */
191 void *pvIf; /* The VirtualBox interface */
192 mac_handle_t hInterface; /* The lower MAC handle */
193 datalink_id_t hLinkId; /* The link ID */
194 mac_client_handle_t hClient; /* Client handle */
195 mac_unicast_handle_t hUnicast; /* Unicast address handle */
196 mac_promisc_handle_t hPromiscuous; /* Promiscuous handle */
197 char szName[128]; /* The VNIC name */
198 list_node_t hNode; /* Handle to the next VNIC in the list */
199} VBOXNETFLTVNIC;
200typedef struct VBOXNETFLTVNIC *PVBOXNETFLTVNIC;
201
202
203/*******************************************************************************
204* Global Variables *
205*******************************************************************************/
206/** Global Device handle we only support one instance. */
207static dev_info_t *g_pVBoxNetFltSolarisDip = NULL;
208/** Global Mutex (actually an rw lock). */
209static RTSEMFASTMUTEX g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
210/** The (common) global data. */
211static VBOXNETFLTGLOBALS g_VBoxNetFltSolarisGlobals;
212
213
214/*******************************************************************************
215* Internal Functions *
216*******************************************************************************/
217LOCAL mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst);
218LOCAL unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg);
219LOCAL int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc);
220LOCAL void vboxNetFltSolarisRecv(void *pvData, mac_resource_handle_t hResource, mblk_t *pMsg, boolean_t fLoopback);
221LOCAL void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg);
222LOCAL void vboxNetFltSolarisReportInfo(PVBOXNETFLTINS pThis);
223LOCAL int vboxNetFltSolarisInitVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC pVNIC);
224LOCAL PVBOXNETFLTVNIC vboxNetFltSolarisAllocVNIC(void);
225LOCAL void vboxNetFltSolarisFreeVNIC(PVBOXNETFLTVNIC pVNIC);
226LOCAL void vboxNetFltSolarisDestroyVNIC(PVBOXNETFLTVNIC pVNIC);
227LOCAL int vboxNetFltSolarisCreateVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC *ppVNIC);
228
229
230/**
231 * Kernel entry points
232 */
233int _init(void)
234{
235 LogFlow((DEVICE_NAME ":_init\n"));
236
237 /*
238 * Prevent module autounloading.
239 */
240 modctl_t *pModCtl = mod_getctl(&g_VBoxNetFltSolarisModLinkage);
241 if (pModCtl)
242 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
243 else
244 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
245
246 /*
247 * Initialize IPRT.
248 */
249 int rc = RTR0Init(0);
250 if (RT_SUCCESS(rc))
251 {
252 /*
253 * Initialize Solaris specific globals here.
254 */
255 rc = RTSemFastMutexCreate(&g_VBoxNetFltSolarisMtx);
256 if (RT_SUCCESS(rc))
257 {
258 /*
259 * Initialize the globals and connect to the support driver.
260 *
261 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
262 * for establishing the connect to the support driver.
263 */
264 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
265 rc = vboxNetFltInitGlobalsAndIdc(&g_VBoxNetFltSolarisGlobals);
266 if (RT_SUCCESS(rc))
267 {
268 rc = mod_install(&g_VBoxNetFltSolarisModLinkage);
269 if (!rc)
270 return rc;
271
272 LogRel((DEVICE_NAME ":mod_install failed. rc=%d\n", rc));
273 vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltSolarisGlobals);
274 }
275 else
276 LogRel((DEVICE_NAME ":failed to initialize globals.\n"));
277
278 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
279 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
280 }
281
282 RTR0Term();
283 }
284 else
285 LogRel((DEVICE_NAME ":failed to initialize IPRT (rc=%d)\n", rc));
286
287 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
288 return RTErrConvertToErrno(rc);
289}
290
291
292int _fini(void)
293{
294 int rc;
295 LogFlow((DEVICE_NAME ":_fini\n"));
296
297 /*
298 * Undo the work done during start (in reverse order).
299 */
300 rc = vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltSolarisGlobals);
301 if (RT_FAILURE(rc))
302 {
303 LogRel((DEVICE_NAME ":_fini - busy!\n"));
304 return EBUSY;
305 }
306
307 rc = mod_remove(&g_VBoxNetFltSolarisModLinkage);
308 if (!rc)
309 {
310 if (g_VBoxNetFltSolarisMtx != NIL_RTSEMFASTMUTEX)
311 {
312 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
313 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
314 }
315
316 RTR0Term();
317 }
318
319 return rc;
320}
321
322
323int _info(struct modinfo *pModInfo)
324{
325 LogFlow((DEVICE_NAME ":_info\n"));
326
327 int rc = mod_info(&g_VBoxNetFltSolarisModLinkage, pModInfo);
328
329 LogFlow((DEVICE_NAME ":_info returns %d\n", rc));
330 return rc;
331}
332
333
334/**
335 * Attach entry point, to attach a device to the system or resume it.
336 *
337 * @param pDip The module structure instance.
338 * @param enmCmd Operation type (attach/resume).
339 *
340 * @returns corresponding solaris error code.
341 */
342LOCAL int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
343{
344 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
345
346 switch (enmCmd)
347 {
348 case DDI_ATTACH:
349 {
350 int instance = ddi_get_instance(pDip);
351 int rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, 0, "none", "none", 0666);
352 if (rc == DDI_SUCCESS)
353 {
354 g_pVBoxNetFltSolarisDip = pDip;
355 ddi_report_dev(pDip);
356 return DDI_SUCCESS;
357 }
358 else
359 LogRel((DEVICE_NAME ":VBoxNetFltSolarisAttach failed to create minor node. rc=%d\n", rc));
360 return DDI_FAILURE;
361 }
362
363 case DDI_RESUME:
364 {
365 /* Nothing to do here... */
366 return DDI_SUCCESS;
367 }
368
369 /* case DDI_PM_RESUME: */
370 default:
371 return DDI_FAILURE;
372 }
373}
374
375
376/**
377 * Detach entry point, to detach a device to the system or suspend it.
378 *
379 * @param pDip The module structure instance.
380 * @param enmCmd Operation type (detach/suspend).
381 *
382 * @returns corresponding solaris error code.
383 */
384LOCAL int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
385{
386 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
387
388 switch (enmCmd)
389 {
390 case DDI_DETACH:
391 {
392 ddi_remove_minor_node(pDip, NULL);
393 return DDI_SUCCESS;
394 }
395
396 case DDI_RESUME:
397 {
398 /* Nothing to do here... */
399 return DDI_SUCCESS;
400 }
401
402 /* case DDI_PM_SUSPEND: */
403 /* case DDI_HOT_PLUG_DETACH: */
404 default:
405 return DDI_FAILURE;
406 }
407}
408
409
410/**
411 * Info entry point, called by solaris kernel for obtaining driver info.
412 *
413 * @param pDip The module structure instance (do not use).
414 * @param enmCmd Information request type.
415 * @param pvArg Type specific argument.
416 * @param ppvResult Where to store the requested info.
417 *
418 * @returns corresponding solaris error code.
419 */
420LOCAL int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppResult)
421{
422 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd, getminor((dev_t)pvArg)));
423
424 switch (enmCmd)
425 {
426 case DDI_INFO_DEVT2DEVINFO:
427 {
428 *ppResult = g_pVBoxNetFltSolarisDip;
429 return DDI_SUCCESS;
430 }
431
432 case DDI_INFO_DEVT2INSTANCE:
433 {
434 int instance = getminor((dev_t)pvArg);
435 *ppResult = (void *)(uintptr_t)instance;
436 return DDI_SUCCESS;
437 }
438 }
439
440 return DDI_FAILURE;
441}
442
443
444/**
445 * Create a solaris message block from the SG list.
446 *
447 * @param pThis The instance.
448 * @param pSG Pointer to the scatter-gather list.
449 *
450 * @returns Solaris message block.
451 */
452LOCAL mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
453{
454 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG pThis=%p pSG=%p\n", pThis, pSG));
455
456 mblk_t *pMsg = allocb(pSG->cbTotal, BPRI_HI);
457 if (RT_UNLIKELY(!pMsg))
458 {
459 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed to alloc %d bytes for mblk_t.\n", pSG->cbTotal));
460 return NULL;
461 }
462
463 /*
464 * Single buffer copy. Maybe later explore the
465 * need/possibility for using a mblk_t chain rather.
466 */
467 for (unsigned i = 0; i < pSG->cSegsUsed; i++)
468 {
469 if (pSG->aSegs[i].pv)
470 {
471 bcopy(pSG->aSegs[i].pv, pMsg->b_wptr, pSG->aSegs[i].cb);
472 pMsg->b_wptr += pSG->aSegs[i].cb;
473 }
474 }
475 DB_TYPE(pMsg) = M_DATA;
476 return pMsg;
477}
478
479
480/**
481 * Calculate the number of segments required for this message block.
482 *
483 * @param pThis The instance
484 * @param pMsg Pointer to the data message.
485 *
486 * @returns Number of segments.
487 */
488LOCAL unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg)
489{
490 unsigned cSegs = 0;
491 for (mblk_t *pCur = pMsg; pCur; pCur = pCur->b_cont)
492 if (MBLKL(pCur))
493 cSegs++;
494
495#ifdef PADD_RUNT_FRAMES_FROM_HOST
496 if (msgdsize(pMsg) < 60)
497 cSegs++;
498#endif
499
500 NOREF(pThis);
501 return RT_MAX(cSegs, 1);
502}
503
504
505/**
506 * Initializes an SG list from the given message block.
507 *
508 * @param pThis The instance.
509 * @param pMsg Pointer to the data message.
510 The caller must ensure it's not a control message block.
511 * @param pSG Pointer to the SG.
512 * @param cSegs Number of segments in the SG.
513 * This should match the number in the message block exactly!
514 * @param fSrc The source of the message.
515 *
516 * @returns VBox status code.
517 */
518LOCAL int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
519{
520 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
521
522 /*
523 * Convert the message block to segments. Works cbTotal and sets cSegsUsed.
524 */
525 IntNetSgInitTempSegs(pSG, 0 /*cbTotal*/, cSegs, 0 /*cSegsUsed*/);
526 mblk_t *pCur = pMsg;
527 unsigned iSeg = 0;
528 while (pCur)
529 {
530 size_t cbSeg = MBLKL(pCur);
531 if (cbSeg)
532 {
533 void *pvSeg = pCur->b_rptr;
534 pSG->aSegs[iSeg].pv = pvSeg;
535 pSG->aSegs[iSeg].cb = cbSeg;
536 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
537 pSG->cbTotal += cbSeg;
538 iSeg++;
539 }
540 pCur = pCur->b_cont;
541 }
542 pSG->cSegsUsed = iSeg;
543
544#ifdef PADD_RUNT_FRAMES_FROM_HOST
545 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
546 {
547 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pulling up to length.\n"));
548
549 static uint8_t const s_abZero[128] = {0};
550 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
551 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
552 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
553 pSG->cbTotal = 60;
554 pSG->cSegsUsed++;
555 Assert(iSeg + 1 < cSegs);
556 }
557#endif
558
559 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
560 return VINF_SUCCESS;
561}
562
563
564/**
565 * Simple packet dump, used for internal debugging.
566 *
567 * @param pMsg Pointer to the message to analyze and dump.
568 */
569LOCAL void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg)
570{
571 LogFlowFunc((DEVICE_NAME ":vboxNetFltSolarisAnalyzeMBlk pMsg=%p\n", pMsg));
572
573 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
574 uint8_t *pb = pMsg->b_rptr;
575 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
576 {
577 PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
578 if (!pMsg->b_cont)
579 {
580 if (pIpHdr->ip_p == RTNETIPV4_PROT_ICMP)
581 LogRel((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
582 else if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
583 LogRel((DEVICE_NAME ":TCP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
584 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
585 {
586 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint32_t *)pIpHdr + pIpHdr->ip_hl);
587 if ( RT_BE2H_U16(pUdpHdr->uh_sport) == 67
588 && RT_BE2H_U16(pUdpHdr->uh_dport) == 68)
589 {
590 LogRel((DEVICE_NAME ":UDP bootp ack D=%.6Rhxs S=%.6Rhxs UDP_CheckSum=%04x Computex=%04x\n", pb, pb + 6,
591 RT_BE2H_U16(pUdpHdr->uh_sum), RT_BE2H_U16(RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1))));
592 }
593 }
594 }
595 else
596 {
597 LogFlow((DEVICE_NAME ":Chained IP packet. Skipping validity check.\n"));
598 }
599 }
600 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_VLAN))
601 {
602 PVLANHEADER pVlanHdr = (PVLANHEADER)(pMsg->b_rptr + sizeof(RTNETETHERHDR) - sizeof(pEthHdr->EtherType));
603 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))));
604 LogRel((DEVICE_NAME "%.*Rhxd\n", sizeof(VLANHEADER), pVlanHdr));
605 }
606 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
607 {
608 PRTNETARPHDR pArpHdr = (PRTNETARPHDR)(pEthHdr + 1);
609 LogRel((DEVICE_NAME ":ARP Op=%d\n", pArpHdr->ar_oper));
610 }
611 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
612 {
613 LogRel((DEVICE_NAME ":IPv6 D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
614 }
615 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_1)
616 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_2)
617 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_3))
618 {
619 LogRel((DEVICE_NAME ":IPX packet.\n"));
620 }
621 else
622 {
623 LogRel((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
624 &pEthHdr->SrcMac));
625 /* LogFlow((DEVICE_NAME ":%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
626 }
627}
628
629
630/**
631 * Helper.
632 */
633DECLINLINE(bool) vboxNetFltPortSolarisIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
634{
635 return pThis->u.s.MacAddr.au16[0] == pMac->au16[0]
636 && pThis->u.s.MacAddr.au16[1] == pMac->au16[1]
637 && pThis->u.s.MacAddr.au16[2] == pMac->au16[2];
638}
639
640
641/**
642 * Receive (rx) entry point.
643 *
644 * @param pvData Private data.
645 * @param hResource The resource handle.
646 * @param pMsg The packet.
647 * @param fLoopback Whether this is a loopback packet or not.
648 */
649LOCAL void vboxNetFltSolarisRecv(void *pvData, mac_resource_handle_t hResource, mblk_t *pMsg, boolean_t fLoopback)
650{
651 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRecv pvData=%p pMsg=%p fLoopback=%d cbData=%d\n", pvData, pMsg, fLoopback, pMsg ? MBLKL(pMsg) : 0));
652
653 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvData;
654 AssertPtrReturnVoid(pThis);
655 AssertPtrReturnVoid(pMsg);
656
657 /*
658 * Active? Retain the instance and increment the busy counter.
659 */
660 if (!vboxNetFltTryRetainBusyActive(pThis))
661 return;
662
663 uint32_t fSrc = INTNETTRUNKDIR_WIRE;
664 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
665 if ( MBLKL(pMsg) >= sizeof(RTNETETHERHDR)
666 && vboxNetFltPortSolarisIsHostMac(pThis, &pEthHdr->SrcMac))
667 fSrc = INTNETTRUNKDIR_HOST;
668
669 /*
670 * Route all received packets into the internal network.
671 */
672 uint16_t cFailed = 0;
673 for (mblk_t *pCurMsg = pMsg; pCurMsg != NULL; pCurMsg = pCurMsg->b_next)
674 {
675 unsigned cSegs = vboxNetFltSolarisMBlkCalcSGSegs(pThis, pCurMsg);
676 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
677 int rc = vboxNetFltSolarisMBlkToSG(pThis, pMsg, pSG, cSegs, fSrc);
678 if (RT_SUCCESS(rc))
679 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL, pSG, fSrc);
680 else
681 cFailed++;
682 }
683 vboxNetFltRelease(pThis, true /* fBusy */);
684
685 if (RT_UNLIKELY(cFailed))
686 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG failed for %u packets.\n", cFailed));
687
688 freemsgchain(pMsg);
689
690 NOREF(hResource);
691}
692
693
694/**
695 * Report capabilities and MAC address to IntNet.
696 *
697 * @param pThis The instance.
698 * @remarks Retains the instance while doing it's job.
699 */
700LOCAL void vboxNetFltSolarisReportInfo(PVBOXNETFLTINS pThis)
701{
702 if (!pThis->u.s.fReportedInfo)
703 {
704 if (vboxNetFltTryRetainBusyNotDisconnected(pThis))
705 {
706 Assert(pThis->pSwitchPort);
707 LogFlow((DEVICE_NAME ":vboxNetFltSolarisInitVNIC phys mac %.6Rhxs\n", &pThis->u.s.MacAddr));
708 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
709 pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, false); /** @todo Promisc */
710 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
711 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
712 vboxNetFltRelease(pThis, true /*fBusy*/);
713 pThis->u.s.fReportedInfo = true;
714 }
715 }
716}
717
718
719/**
720 * Initialize a VNIC.
721 *
722 * @param pThis The instance.
723 * @param pVNIC Pointer to the VNIC.
724 *
725 * @returns Solaris error code (errno).
726 */
727LOCAL int vboxNetFltSolarisInitVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC pVNIC)
728{
729 /*
730 * Some paranoia.
731 */
732 AssertReturn(pThis, VERR_INVALID_PARAMETER);
733 AssertReturn(pVNIC, VERR_INVALID_PARAMETER);
734 AssertReturn(pVNIC->hInterface, VERR_INVALID_POINTER);
735 AssertReturn(pVNIC->hLinkId, VERR_INVALID_POINTER);
736 AssertReturn(!pVNIC->hClient, VERR_INVALID_HANDLE);
737
738 int rc = mac_client_open(pVNIC->hInterface, &pVNIC->hClient,
739 NULL, /* name of this client */
740 MAC_OPEN_FLAGS_USE_DATALINK_NAME | /* client name same as underlying NIC */
741 MAC_OPEN_FLAGS_MULTI_PRIMARY /* allow multiple primary unicasts */
742 );
743 if (RT_LIKELY(!rc))
744 {
745 /*
746 * Set the RX callback.
747 */
748 mac_diag_t Diag = MAC_DIAG_NONE;
749 rc = mac_unicast_add_set_rx(pVNIC->hClient,
750 NULL /* MAC address, use existing VNIC address */,
751 MAC_UNICAST_PRIMARY | /* Use Primary address of the VNIC */
752 MAC_UNICAST_NODUPCHECK, /* Don't fail for conflicting MAC/VLAN-id combinations */
753 &pVNIC->hUnicast,
754 0 /* VLAN-id */,
755 &Diag,
756 vboxNetFltSolarisRecv, /* RX callback */
757 pThis /* callback private data */
758 );
759 if (RT_LIKELY(!rc))
760 {
761 if (!pThis->u.s.fReportedInfo)
762 {
763 /*
764 * Obtain the MAC address of the underlying physical interface.
765 */
766 mac_handle_t hLowerMac = mac_get_lower_mac_handle(pVNIC->hInterface);
767 if (RT_LIKELY(hLowerMac))
768 {
769 mac_unicast_primary_get(hLowerMac, (uint8_t *)pThis->u.s.MacAddr.au8);
770 vboxNetFltSolarisReportInfo(pThis);
771 }
772 else
773 {
774 LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNIC failed to get lower MAC handle for '%s'\n", pThis->szName));
775 rc = ENODEV;
776 }
777 }
778
779 if (!rc)
780 {
781 Assert(pVNIC->hClient);
782 Assert(pVNIC->hInterface);
783 Assert(pVNIC->hLinkId);
784 LogFlow((DEVICE_NAME ":vboxNetFltSolarisInitVNIC successfully initialized VNIC '%s'\n", pVNIC->szName));
785 return 0;
786 }
787
788 mac_unicast_remove(pVNIC->hClient, pVNIC->hUnicast);
789 mac_rx_clear(pVNIC->hClient);
790 pVNIC->hUnicast = NULL;
791 }
792 else
793 LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNIC failed to set RX callback. rc=%d Diag=%d\n", rc, Diag));
794
795 mac_client_close(pVNIC->hClient, 0 /* flags */);
796 pVNIC->hClient = NULL;
797 }
798 else
799 LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNIC failed to open mac client for '%s' rc=%d\n", pThis->szName, rc));
800
801 return RTErrConvertFromErrno(rc);
802}
803
804
805/**
806 * Allocate a VNIC structure.
807 *
808 * @returns An allocated VNIC structure or NULL in case of errors.
809 */
810LOCAL PVBOXNETFLTVNIC vboxNetFltSolarisAllocVNIC(void)
811{
812 PVBOXNETFLTVNIC pVNIC = RTMemAlloc(sizeof(VBOXNETFLTVNIC));
813 if (RT_UNLIKELY(!pVNIC))
814 return NULL;
815
816 pVNIC->u32Magic = VBOXNETFLTVNIC_MAGIC;
817 pVNIC->fCreated = false;
818 pVNIC->pvIf = NULL;
819 pVNIC->hInterface = NULL;
820 pVNIC->hLinkId = DATALINK_INVALID_LINKID;
821 pVNIC->hClient = NULL;
822 pVNIC->hUnicast = NULL;
823 pVNIC->hPromiscuous = NULL;
824 RT_ZERO(pVNIC->szName);
825 list_link_init(&pVNIC->hNode);
826 return pVNIC;
827}
828
829
830/**
831 * Frees an allocated VNIC.
832 *
833 * @param pVNIC Pointer to the VNIC.
834 */
835LOCAL void vboxNetFltSolarisFreeVNIC(PVBOXNETFLTVNIC pVNIC)
836{
837 if (pVNIC)
838 RTMemFree(pVNIC);
839}
840
841
842/**
843 * Destroy a created VNIC if it was created by us, or just
844 * de-initializes the VNIC freeing up resources handles.
845 *
846 * @param pVNIC Pointer to the VNIC.
847 */
848LOCAL void vboxNetFltSolarisDestroyVNIC(PVBOXNETFLTVNIC pVNIC)
849{
850 if (pVNIC)
851 {
852 if (pVNIC->hPromiscuous)
853 {
854 mac_promisc_remove(pVNIC->hPromiscuous);
855 pVNIC->hPromiscuous = NULL;
856 }
857
858 if (pVNIC->hClient)
859 {
860 if (pVNIC->hUnicast)
861 {
862 mac_unicast_remove(pVNIC->hClient, pVNIC->hUnicast);
863 pVNIC->hUnicast = NULL;
864 }
865
866 mac_rx_clear(pVNIC->hClient);
867
868 mac_client_close(pVNIC->hClient, 0 /* fFlags */);
869 pVNIC->hClient = NULL;
870 }
871
872 if (pVNIC->hInterface)
873 {
874 mac_close(pVNIC->hInterface);
875 pVNIC->hInterface = NULL;
876 }
877
878 if (pVNIC->fCreated)
879 {
880 vnic_delete(pVNIC->hLinkId, 0 /* Flags */);
881 pVNIC->hLinkId = DATALINK_INVALID_LINKID;
882 pVNIC->fCreated = false;
883 }
884 }
885}
886
887
888/**
889 * Create a non-persistent VNIC over the given interface.
890 *
891 * @param pThis The VM connection instance.
892 * @param ppVNIC Where to store the created VNIC.
893 *
894 * @returns corresponding VBox error code.
895 */
896LOCAL int vboxNetFltSolarisCreateVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC *ppVNIC)
897{
898 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC pThis=%p\n", pThis));
899
900 AssertReturn(pThis, VERR_INVALID_POINTER);
901 AssertReturn(ppVNIC, VERR_INVALID_POINTER);
902
903 PVBOXNETFLTVNIC pVNIC = vboxNetFltSolarisAllocVNIC();
904 if (RT_UNLIKELY(!pVNIC))
905 return VERR_NO_MEMORY;
906
907 AssertCompile(sizeof(pVNIC->szName) > sizeof(VBOXFLT_VNIC_NAME) + 64);
908 RTStrPrintf(pVNIC->szName, sizeof(pVNIC->szName), "%s%RU64", VBOXFLT_VNIC_NAME, pThis->u.s.uInstance);
909
910 /*
911 * Set a random MAC address for now. It will be changed to the VM interface's
912 * MAC address later, see vboxNetFltPortOsNotifyMacAddress().
913 */
914 RTMAC GuestMac;
915 GuestMac.au8[0] = 0x08;
916 GuestMac.au8[1] = 0x00;
917 GuestMac.au8[2] = 0x27;
918 RTRandBytes(&GuestMac.au8[3], 3);
919
920 AssertCompile(sizeof(RTMAC) <= MAXMACADDRLEN);
921
922 vnic_mac_addr_type_t AddrType = VNIC_MAC_ADDR_TYPE_FIXED;
923 vnic_ioc_diag_t Diag = VNIC_IOC_DIAG_NONE;
924 int MacSlot = 0;
925 int MacLen = sizeof(GuestMac);
926 uint32_t fFlags = 0;
927
928 int rc = vnic_create(pVNIC->szName, pThis->szName, &AddrType, &MacLen, GuestMac.au8, &MacSlot, 0 /* Mac-Prefix Length */, 0 /* VLAN-ID */,
929 fFlags, &pVNIC->hLinkId, &Diag, NULL /* Reserved */);
930 if (!rc)
931 {
932 pVNIC->fCreated = true;
933
934 /*
935 * Now try opening the created VNIC.
936 */
937 rc = mac_open_by_linkid(pVNIC->hLinkId, &pVNIC->hInterface);
938 if (!rc)
939 {
940 rc = vboxNetFltSolarisInitVNIC(pThis, pVNIC);
941 if (RT_LIKELY(!rc))
942 {
943 pThis->u.s.uInstance++;
944 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC successfully created VNIC '%s' over '%s'\n", pVNIC->szName, pThis->szName));
945 *ppVNIC = pVNIC;
946 return VINF_SUCCESS;
947 }
948 else
949 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC vboxNetFltSolarisInitVNIC failed. rc=%d\n", rc));
950
951 mac_close(pVNIC->hInterface);
952 pVNIC->hInterface = NULL;
953 }
954 else
955 {
956 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to open VNIC '%s' over '%s'. rc=%d\n", pVNIC->szName,
957 pThis->szName, rc));
958 }
959
960 vboxNetFltSolarisDestroyVNIC(pVNIC);
961 rc = VERR_OPEN_FAILED;
962 }
963 else
964 {
965 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to create VNIC '%s' over '%s' rc=%d Diag=%d\n", pVNIC->szName,
966 pThis->szName, rc, Diag));
967 rc = VERR_INTNET_FLT_VNIC_CREATE_FAILED;
968 }
969
970 vboxNetFltSolarisFreeVNIC(pVNIC);
971
972 return rc;
973}
974
975
976/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
977
978
979void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
980{
981 LogFlow((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d\n", pThis, fActive));
982#if 0
983 if (fActive)
984 {
985 /*
986 * Activate promiscuous mode.
987 */
988 if (!pThis->u.s.hPromiscuous)
989 {
990 int rc = mac_promisc_add(pThis->u.s.hClient, MAC_CLIENT_PROMISC_ALL, vboxNetFltSolarisRecv, pThis, &pThis->u.s.hPromiscuous,
991 MAC_PROMISC_FLAGS_NO_TX_LOOP);
992 if (rc)
993 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive cannot enable promiscuous mode for '%s' rc=%d\n", pThis->szName, rc));
994 }
995 }
996 else
997 {
998 /*
999 * Deactivate promiscuous mode.
1000 */
1001 if (pThis->u.s.hPromiscuous)
1002 {
1003 mac_promisc_remove(pThis->u.s.hPromiscuous);
1004 pThis->u.s.hPromiscuous = NULL;
1005 }
1006 }
1007#endif
1008}
1009
1010
1011int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
1012{
1013 LogFlow((DEVICE_NAME ":vboxNetFltOsDisconnectIt pThis=%p\n", pThis));
1014 return VINF_SUCCESS;
1015}
1016
1017
1018int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
1019{
1020 LogFlow((DEVICE_NAME ":vboxNetFltOsConnectIt pThis=%p\n", pThis));
1021 return VINF_SUCCESS;
1022}
1023
1024
1025void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
1026{
1027 LogFlow((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n", pThis));
1028
1029 /*
1030 * Destroy all managed VNICs. If a VNIC was passed to us, there
1031 * will be only 1 item in the list, otherwise as many interfaces
1032 * that were somehow not destroyed using DisconnectInterface() will be
1033 * present.
1034 */
1035 PVBOXNETFLTVNIC pVNIC = NULL;
1036 while ((pVNIC = list_remove_head(&pThis->u.s.hVNICs)) != NULL)
1037 {
1038 vboxNetFltSolarisDestroyVNIC(pVNIC);
1039 vboxNetFltSolarisFreeVNIC(pVNIC);
1040 }
1041
1042 list_destroy(&pThis->u.s.hVNICs);
1043}
1044
1045
1046int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
1047{
1048 LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p pvContext=%p\n", pThis, pvContext));
1049
1050 /*
1051 * Figure out if the interface is a VNIC or a physical/etherstub/whatever NIC.
1052 */
1053 mac_handle_t hInterface;
1054 int rc = mac_open_by_linkname(pThis->szName, &hInterface);
1055 if (RT_LIKELY(!rc))
1056 {
1057 rc = mac_is_vnic(hInterface);
1058 if (!rc)
1059 {
1060 /*
1061 * This is NOT a VNIC. Just pretend success for now.
1062 * We will create a VNIC per VM interface later, see vboxNetFltPortOsConnectInterface().
1063 */
1064 pThis->u.s.fIsVNIC = false;
1065 mac_unicast_primary_get(hInterface, pThis->u.s.MacAddr.au8);
1066 vboxNetFltSolarisReportInfo(pThis);
1067 mac_close(hInterface);
1068 return VINF_SUCCESS;
1069 }
1070
1071 pThis->u.s.fIsVNIC = true;
1072
1073 PVBOXNETFLTVNIC pVNIC = vboxNetFltSolarisAllocVNIC();
1074 if (RT_LIKELY(pVNIC))
1075 {
1076 pVNIC->fCreated = false;
1077 pVNIC->hInterface = hInterface;
1078
1079 /*
1080 * Obtain the data link ID for this VNIC, it's needed for modifying the MAC address among other things.
1081 */
1082 rc = dls_mgmt_get_linkid(pThis->szName, &pVNIC->hLinkId);
1083 if (RT_LIKELY(!rc))
1084 {
1085 /*
1086 * Initialize the VNIC and add it to the list of managed VNICs.
1087 */
1088 RTStrPrintf(pVNIC->szName, sizeof(pVNIC->szName), "%s", pThis->szName);
1089 rc = vboxNetFltSolarisInitVNIC(pThis, pVNIC);
1090 if (!rc)
1091 {
1092 list_insert_head(&pThis->u.s.hVNICs, pVNIC);
1093 return VINF_SUCCESS;
1094 }
1095 else
1096 LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance vboxNetFltSolarisInitVNIC failed. rc=%d\n", rc));
1097 }
1098 else
1099 LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to get link id for '%s'. rc=%d\n", pThis->szName, rc));
1100
1101 vboxNetFltSolarisFreeVNIC(pVNIC);
1102 }
1103 else
1104 LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to allocate VNIC private data.\n"));
1105
1106 mac_close(hInterface);
1107 }
1108 else
1109 LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to open link '%s'! rc=%d\n", pThis->szName, rc));
1110
1111 return RTErrConvertFromErrno(rc);
1112}
1113
1114
1115int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
1116{
1117 /*
1118 * Init. the solaris specific data.
1119 */
1120 pThis->u.s.fIsVNIC = false;
1121 list_create(&pThis->u.s.hVNICs, sizeof(VBOXNETFLTVNIC), offsetof(VBOXNETFLTVNIC, hNode));
1122 pThis->u.s.uInstance = 0;
1123 pThis->u.s.pvVNIC = NULL;
1124 bzero(&pThis->u.s.MacAddr, sizeof(pThis->u.s.MacAddr));
1125 pThis->u.s.fReportedInfo = false;
1126 return VINF_SUCCESS;
1127}
1128
1129
1130bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
1131{
1132 /*
1133 * @todo Think about this.
1134 */
1135 return false;
1136}
1137
1138
1139int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
1140{
1141 /*
1142 * Validate parameters.
1143 */
1144 PVBOXNETFLTVNIC pVNIC = pvIfData;
1145 AssertMsgReturn(VALID_PTR(pVNIC) && pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC,
1146 ("Invalid pvIfData=%p magic=%#x (expected %#x)\n", pvIfData, pVNIC ? pVNIC->u32Magic : 0, VBOXNETFLTVNIC_MAGIC),
1147 VERR_INVALID_PARAMETER);
1148
1149 /*
1150 * Xmit the packet down the appropriate VNIC interface.
1151 */
1152 int rc = VINF_SUCCESS;
1153 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
1154 if (RT_LIKELY(pMsg))
1155 {
1156 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p cbData=%d\n", pThis, MBLKL(pMsg)));
1157
1158 mac_tx_cookie_t pXmitCookie = mac_tx(pVNIC->hClient, pMsg, 0 /* Hint */, MAC_DROP_ON_NO_DESC, NULL /* return message */);
1159 if (RT_LIKELY(!pXmitCookie))
1160 return VINF_SUCCESS;
1161
1162 pMsg = NULL;
1163 rc = VERR_NET_IO_ERROR;
1164 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit Xmit failed pVNIC=%p.\n", pVNIC));
1165 }
1166 else
1167 {
1168 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit no memory for allocating Xmit packet.\n"));
1169 rc = VERR_NO_MEMORY;
1170 }
1171
1172 return rc;
1173}
1174
1175
1176void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
1177{
1178 LogFlow((DEVICE_NAME ":vboxNetFltPortOSNotifyMacAddress %s %.6Rhxs\n", pThis->szName, pMac));
1179
1180 /*
1181 * Validate parameters.
1182 */
1183 PVBOXNETFLTVNIC pVNIC = pvIfData;
1184 AssertMsgReturnVoid(VALID_PTR(pVNIC) && pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC,
1185 ("Invalid pvIfData=%p magic=%#x (expected %#x)\n", pvIfData, pVNIC ? pVNIC->u32Magic : 0, VBOXNETFLTVNIC_MAGIC));
1186 AssertMsgReturnVoid(pVNIC->hLinkId != DATALINK_INVALID_LINKID,
1187 ("Invalid hLinkId pVNIC=%p magic=%#x\n", pVNIC, pVNIC->u32Magic));
1188
1189 /*
1190 * Set the MAC address of the VNIC to the one used by the VM interface.
1191 */
1192 uchar_t au8GuestMac[MAXMACADDRLEN];
1193 bcopy(pMac->au8, au8GuestMac, sizeof(RTMAC));
1194
1195 vnic_mac_addr_type_t AddrType = VNIC_MAC_ADDR_TYPE_FIXED;
1196 vnic_ioc_diag_t Diag = VNIC_IOC_DIAG_NONE;
1197 int MacSlot = 0;
1198 int MacLen = sizeof(RTMAC);
1199
1200 int rc = vnic_modify_addr(pVNIC->hLinkId, &AddrType, &MacLen, au8GuestMac, &MacSlot, 0 /* Mac-Prefix Length */, &Diag);
1201 if (RT_UNLIKELY(rc))
1202 LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress failed! rc=%d Diag=%d\n", rc, Diag));
1203}
1204
1205
1206int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
1207{
1208 LogFlow((DEVICE_NAME ":vboxNetFltPortOsConnectInterface pThis=%p pvIf=%p\n", pThis, pvIf));
1209
1210 int rc = VINF_SUCCESS;
1211
1212 /*
1213 * If the underlying interface is not a VNIC, we need to create
1214 * a VNIC per guest NIC.
1215 */
1216 if (!pThis->u.s.fIsVNIC)
1217 {
1218 PVBOXNETFLTVNIC pVNIC = NULL;
1219 rc = vboxNetFltSolarisCreateVNIC(pThis, &pVNIC);
1220 if (RT_SUCCESS(rc))
1221 {
1222 /*
1223 * VM Interface<->VNIC association so that we can Xmit/Recv on the right ones.
1224 */
1225 pVNIC->pvIf = pvIf;
1226 *ppvIfData = pVNIC;
1227
1228 /*
1229 * Add the created VNIC to the list of VNICs we manage.
1230 */
1231 list_insert_tail(&pThis->u.s.hVNICs, pVNIC);
1232 LogFlow((DEVICE_NAME ":vboxNetFltPortOsConnectInterface successfully created VNIC '%s'.\n", pVNIC->szName));
1233 return VINF_SUCCESS;
1234 }
1235 else
1236 LogRel((DEVICE_NAME ":vboxNetFltPortOsConnectInterface failed to create VNIC rc=%d\n", rc));
1237 }
1238 else
1239 {
1240 PVBOXNETFLTVNIC pVNIC = list_head(&pThis->u.s.hVNICs);
1241 if (RT_LIKELY(pVNIC))
1242 {
1243 *ppvIfData = pVNIC;
1244 LogFlow((DEVICE_NAME ":vboxNetFltPortOsConnectInterface set VNIC '%s' private data\n", pVNIC->szName));
1245 }
1246 else
1247 {
1248 LogRel((DEVICE_NAME ":vboxNetFltPortOsConnectInterface huh!? Missing VNIC!\n"));
1249 return VERR_GENERAL_FAILURE;
1250 }
1251 }
1252
1253 return rc;
1254}
1255
1256
1257int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
1258{
1259 LogFlow((DEVICE_NAME ":vboxNetFltPortOsDisconnectInterface pThis=%p\n", pThis));
1260
1261 PVBOXNETFLTVNIC pVNIC = pvIfData;
1262 AssertMsgReturn(VALID_PTR(pVNIC) && pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC,
1263 ("Invalid pvIfData=%p magic=%#x (expected %#x)\n", pvIfData, pVNIC ? pVNIC->u32Magic : 0, VBOXNETFLTVNIC_MAGIC),
1264 VERR_INVALID_POINTER);
1265
1266 /*
1267 * If the underlying interface is not a VNIC, we need to delete the created VNIC.
1268 */
1269 if (!pThis->u.s.fIsVNIC)
1270 {
1271 /*
1272 * Remove the VNIC from the list, destroy and free it.
1273 */
1274 list_remove(&pThis->u.s.hVNICs, pVNIC);
1275 LogRel((DEVICE_NAME ":vboxNetFltPortOsDisconnectInterface destroying pVNIC=%p\n", pVNIC));
1276 vboxNetFltSolarisDestroyVNIC(pVNIC);
1277 vboxNetFltSolarisFreeVNIC(pVNIC);
1278 }
1279
1280 return VINF_SUCCESS;
1281}
1282
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