VirtualBox

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

Last change on this file since 28666 was 28666, checked in by vboxsync, 15 years ago

SrvIntNet,VBoxNetFlt: Changing from getting to reporting (VBoxNetFlt reports stuff to SrvIntNet).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.9 KB
Line 
1/* $Id: VBoxNetFltBow-solaris.c 28666 2010-04-23 17:25:58Z vboxsync $ */
2/** @file
3 * VBoxNetFlt - Network Filter Driver (Host), Solaris Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
26#include <VBox/log.h>
27#include <VBox/err.h>
28#include <VBox/intnetinline.h>
29#include <VBox/version.h>
30#include <iprt/initterm.h>
31#include <iprt/alloca.h>
32#include <iprt/assert.h>
33#include <iprt/err.h>
34#include <iprt/string.h>
35#include <iprt/net.h>
36#include <iprt/spinlock.h>
37
38#include <sys/types.h>
39#include <sys/modctl.h>
40#include <sys/conf.h>
41#include <sys/stat.h>
42#include <sys/ddi.h>
43#include <sys/gld.h>
44#include <sys/sunddi.h>
45#include <sys/strsubr.h>
46#include <sys/dlpi.h>
47#include <sys/dls_mgmt.h>
48#include <sys/mac.h>
49#include <sys/strsun.h>
50#include <sys/sunddi.h>
51
52#include "include/mac_provider.h" /* dependency for other headers */
53#include "include/mac_client.h" /* for mac_* */
54#include "include/mac_client_priv.h" /* for mac_info, mac_capab_get etc. */
55#if 0
56#include "include/dls.h" /* for dls_mgmt_* */
57#include "include/dld_ioc.h" /* required by vnic.h */
58#include "include/vnic.h" /* for vnic_ioc_diag_t */
59#include "include/vnic_impl.h" /* for vnic_dev_create */
60#endif
61
62#define VBOXNETFLT_OS_SPECFIC 1
63#include "../VBoxNetFltInternal.h"
64
65/*******************************************************************************
66* Defined Constants And Macros *
67*******************************************************************************/
68/** The module name. */
69#define DEVICE_NAME "vboxflt"
70/** The module descriptions as seen in 'modinfo'. */
71#define DEVICE_DESC_DRV "VirtualBox NetBow"
72/** The dynamically created VNIC name */
73#define VBOXFLT_VNIC_NAME "vboxvnic"
74/** Debugging switch for using symbols in kmdb */
75# define LOCAL static
76
77#if defined(DEBUG_ramshankar)
78# undef Log
79# define Log LogRel
80# undef LogFlow
81# define LogFlow LogRel
82# undef LOCAL
83# define LOCAL
84#endif
85
86
87/*******************************************************************************
88* Kernel Entry Hooks *
89*******************************************************************************/
90LOCAL int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
91LOCAL int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
92LOCAL int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
93
94
95/*******************************************************************************
96* Structures and Typedefs *
97*******************************************************************************/
98/**
99 * cb_ops: for drivers that support char/block entry points
100 */
101static struct cb_ops g_VBoxNetFltSolarisCbOps =
102{
103 nulldev, /* c open */
104 nulldev, /* c close */
105 nodev, /* b strategy */
106 nodev, /* b dump */
107 nodev, /* b print */
108 nodev, /* c read */
109 nodev, /* c write*/
110 nodev, /* c ioctl*/
111 nodev, /* c devmap */
112 nodev, /* c mmap */
113 nodev, /* c segmap */
114 nochpoll, /* c poll */
115 ddi_prop_op, /* property ops */
116 NULL, /* streamtab */
117 D_NEW | D_MP, /* compat. flag */
118 CB_REV, /* revision */
119 nodev, /* c aread */
120 nodev /* c awrite */
121};
122
123/**
124 * dev_ops: for driver device operations
125 */
126static struct dev_ops g_VBoxNetFltSolarisDevOps =
127{
128 DEVO_REV, /* driver build revision */
129 0, /* ref count */
130 VBoxNetFltSolarisGetInfo,
131 nulldev, /* identify */
132 nulldev, /* probe */
133 VBoxNetFltSolarisAttach,
134 VBoxNetFltSolarisDetach,
135 nodev, /* reset */
136 &g_VBoxNetFltSolarisCbOps,
137 NULL, /* bus ops */
138 nodev, /* power */
139 ddi_quiesce_not_needed
140};
141
142/**
143 * modldrv: export driver specifics to the kernel
144 */
145static struct modldrv g_VBoxNetFltSolarisModule =
146{
147 &mod_driverops, /* extern from kernel */
148 DEVICE_DESC_DRV " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV),
149 &g_VBoxNetFltSolarisDevOps
150};
151
152/**
153 * modlinkage: export install/remove/info to the kernel
154 */
155static struct modlinkage g_VBoxNetFltSolarisModLinkage =
156{
157 MODREV_1,
158 {
159 &g_VBoxNetFltSolarisModule,
160 NULL,
161 }
162};
163
164
165/*******************************************************************************
166* Global Variables *
167*******************************************************************************/
168/** Global Device handle we only support one instance. */
169static dev_info_t *g_pVBoxNetFltSolarisDip = NULL;
170/** Global Mutex (actually an rw lock). */
171static RTSEMFASTMUTEX g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
172/** The (common) global data. */
173static VBOXNETFLTGLOBALS g_VBoxNetFltSolarisGlobals;
174
175
176/*******************************************************************************
177* Internal Function *
178*******************************************************************************/
179LOCAL mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst);
180LOCAL unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg);
181LOCAL int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc);
182
183LOCAL int vboxNetFltSolarisAttachToInterface(PVBOXNETFLTINS pThis, bool fRediscovery);
184LOCAL int vboxNetFltSolarisDetachFromInterface(PVBOXNETFLTINS pThis);
185LOCAL void vboxNetFltSolarisRecv(void *pvData, mac_resource_handle_t hResource, mblk_t *pMsg, boolean_t fLoopback);
186
187
188/**
189 * Kernel entry points
190 */
191int _init(void)
192{
193 LogFlow((DEVICE_NAME ":_init\n"));
194
195 /*
196 * Prevent module autounloading.
197 */
198 modctl_t *pModCtl = mod_getctl(&g_VBoxNetFltSolarisModLinkage);
199 if (pModCtl)
200 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
201 else
202 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
203
204 /*
205 * Initialize IPRT.
206 */
207 int rc = RTR0Init(0);
208 if (RT_SUCCESS(rc))
209 {
210 /*
211 * Initialize Solaris specific globals here.
212 */
213 rc = RTSemFastMutexCreate(&g_VBoxNetFltSolarisMtx);
214 if (RT_SUCCESS(rc))
215 {
216 /*
217 * Initialize the globals and connect to the support driver.
218 *
219 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
220 * for establishing the connect to the support driver.
221 */
222 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
223 rc = vboxNetFltInitGlobalsAndIdc(&g_VBoxNetFltSolarisGlobals);
224 if (RT_SUCCESS(rc))
225 {
226 rc = mod_install(&g_VBoxNetFltSolarisModLinkage);
227 if (!rc)
228 return rc;
229
230 LogRel((DEVICE_NAME ":mod_install failed. rc=%d\n", rc));
231 vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltSolarisGlobals);
232 }
233 else
234 LogRel((DEVICE_NAME ":failed to initialize globals.\n"));
235
236 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
237 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
238 }
239
240 RTR0Term();
241 }
242 else
243 LogRel((DEVICE_NAME ":failed to initialize IPRT (rc=%d)\n", rc));
244
245 memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
246 return RTErrConvertToErrno(rc);
247}
248
249
250int _fini(void)
251{
252 int rc;
253 LogFlow((DEVICE_NAME ":_fini\n"));
254
255 /*
256 * Undo the work done during start (in reverse order).
257 */
258 rc = vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltSolarisGlobals);
259 if (RT_FAILURE(rc))
260 {
261 LogRel((DEVICE_NAME ":_fini - busy!\n"));
262 return EBUSY;
263 }
264
265 rc = mod_remove(&g_VBoxNetFltSolarisModLinkage);
266 if (!rc)
267 {
268 if (g_VBoxNetFltSolarisMtx != NIL_RTSEMFASTMUTEX)
269 {
270 RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
271 g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
272 }
273
274 RTR0Term();
275 }
276
277 return rc;
278}
279
280
281int _info(struct modinfo *pModInfo)
282{
283 LogFlow((DEVICE_NAME ":_info\n"));
284
285 int rc = mod_info(&g_VBoxNetFltSolarisModLinkage, pModInfo);
286
287 LogFlow((DEVICE_NAME ":_info returns %d\n", rc));
288 return rc;
289}
290
291
292/**
293 * Attach entry point, to attach a device to the system or resume it.
294 *
295 * @param pDip The module structure instance.
296 * @param enmCmd Operation type (attach/resume).
297 *
298 * @returns corresponding solaris error code.
299 */
300LOCAL int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
301{
302 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
303
304 switch (enmCmd)
305 {
306 case DDI_ATTACH:
307 {
308 int instance = ddi_get_instance(pDip);
309 int rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, 0, "none", "none", 0666);
310 if (rc == DDI_SUCCESS)
311 {
312 g_pVBoxNetFltSolarisDip = pDip;
313 ddi_report_dev(pDip);
314 return DDI_SUCCESS;
315 }
316 else
317 LogRel((DEVICE_NAME ":VBoxNetFltSolarisAttach failed to create minor node. rc=%d\n", rc));
318 return DDI_FAILURE;
319 }
320
321 case DDI_RESUME:
322 {
323 /* Nothing to do here... */
324 return DDI_SUCCESS;
325 }
326
327 /* case DDI_PM_RESUME: */
328 default:
329 return DDI_FAILURE;
330 }
331}
332
333
334/**
335 * Detach entry point, to detach a device to the system or suspend it.
336 *
337 * @param pDip The module structure instance.
338 * @param enmCmd Operation type (detach/suspend).
339 *
340 * @returns corresponding solaris error code.
341 */
342LOCAL int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
343{
344 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
345
346 switch (enmCmd)
347 {
348 case DDI_DETACH:
349 {
350 ddi_remove_minor_node(pDip, NULL);
351 return DDI_SUCCESS;
352 }
353
354 case DDI_RESUME:
355 {
356 /* Nothing to do here... */
357 return DDI_SUCCESS;
358 }
359
360 /* case DDI_PM_SUSPEND: */
361 /* case DDI_HOT_PLUG_DETACH: */
362 default:
363 return DDI_FAILURE;
364 }
365}
366
367
368/**
369 * Info entry point, called by solaris kernel for obtaining driver info.
370 *
371 * @param pDip The module structure instance (do not use).
372 * @param enmCmd Information request type.
373 * @param pvArg Type specific argument.
374 * @param ppvResult Where to store the requested info.
375 *
376 * @returns corresponding solaris error code.
377 */
378LOCAL int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppResult)
379{
380 LogFlow((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd, getminor((dev_t)pvArg)));
381
382 switch (enmCmd)
383 {
384 case DDI_INFO_DEVT2DEVINFO:
385 {
386 *ppResult = g_pVBoxNetFltSolarisDip;
387 return DDI_SUCCESS;
388 }
389
390 case DDI_INFO_DEVT2INSTANCE:
391 {
392 int instance = getminor((dev_t)pvArg);
393 *ppResult = (void *)(uintptr_t)instance;
394 return DDI_SUCCESS;
395 }
396 }
397
398 return DDI_FAILURE;
399}
400
401
402/**
403 * Create a solaris message block from the SG list.
404 *
405 * @param pThis The instance.
406 * @param pSG Pointer to the scatter-gather list.
407 *
408 * @returns Solaris message block.
409 */
410LOCAL mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
411{
412 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG pThis=%p pSG=%p\n", pThis, pSG));
413
414 mblk_t *pMsg = allocb(pSG->cbTotal, BPRI_HI);
415 if (RT_UNLIKELY(!pMsg))
416 {
417 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed to alloc %d bytes for mblk_t.\n", pSG->cbTotal));
418 return NULL;
419 }
420
421 /*
422 * Single buffer copy. Maybe later explore the
423 * need/possibility for using a mblk_t chain rather.
424 */
425 for (unsigned i = 0; i < pSG->cSegsUsed; i++)
426 {
427 if (pSG->aSegs[i].pv)
428 {
429 bcopy(pSG->aSegs[i].pv, pMsg->b_wptr, pSG->aSegs[i].cb);
430 pMsg->b_wptr += pSG->aSegs[i].cb;
431 }
432 }
433 DB_TYPE(pMsg) = M_DATA;
434 return pMsg;
435}
436
437
438/**
439 * Calculate the number of segments required for this message block.
440 *
441 * @param pThis The instance
442 * @param pMsg Pointer to the data message.
443 *
444 * @returns Number of segments.
445 */
446LOCAL unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg)
447{
448 unsigned cSegs = 0;
449 for (mblk_t *pCur = pMsg; pCur; pCur = pCur->b_cont)
450 if (MBLKL(pCur))
451 cSegs++;
452
453#ifdef PADD_RUNT_FRAMES_FROM_HOST
454 if (msgdsize(pMsg) < 60)
455 cSegs++;
456#endif
457
458 NOREF(pThis);
459 return RT_MAX(cSegs, 1);
460}
461
462
463/**
464 * Initializes an SG list from the given message block.
465 *
466 * @param pThis The instance.
467 * @param pMsg Pointer to the data message.
468 The caller must ensure it's not a control message block.
469 * @param pSG Pointer to the SG.
470 * @param cSegs Number of segments in the SG.
471 * This should match the number in the message block exactly!
472 * @param fSrc The source of the message.
473 *
474 * @returns VBox status code.
475 */
476LOCAL int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
477{
478 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
479
480 /*
481 * Convert the message block to segments. Works cbTotal and sets cSegsUsed.
482 */
483 INTNETSgInitTempSegs(pSG, 0 /*cbTotal*/, cSegs, 0 /*cSegsUsed*/);
484 mblk_t *pCur = pMsg;
485 unsigned iSeg = 0;
486 while (pCur)
487 {
488 size_t cbSeg = MBLKL(pCur);
489 if (cbSeg)
490 {
491 void *pvSeg = pCur->b_rptr;
492 pSG->aSegs[iSeg].pv = pvSeg;
493 pSG->aSegs[iSeg].cb = cbSeg;
494 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
495 pSG->cbTotal += cbSeg;
496 iSeg++;
497 }
498 pCur = pCur->b_cont;
499 }
500 pSG->cSegsUsed = iSeg;
501
502#ifdef PADD_RUNT_FRAMES_FROM_HOST
503 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
504 {
505 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pulling up to length.\n"));
506
507 static uint8_t const s_abZero[128] = {0};
508 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
509 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
510 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
511 pSG->cbTotal = 60;
512 pSG->cSegsUsed++;
513 Assert(iSeg + 1 < cSegs);
514 }
515#endif
516
517 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
518 return VINF_SUCCESS;
519}
520
521
522/**
523 * Simple packet dump, used for internal debugging.
524 *
525 * @param pMsg Pointer to the message to analyze and dump.
526 */
527static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg)
528{
529 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAnalyzeMBlk pMsg=%p\n", pMsg));
530
531 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
532 uint8_t *pb = pMsg->b_rptr;
533 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
534 {
535 PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
536 if (!pMsg->b_cont)
537 {
538 if (pIpHdr->ip_p == RTNETIPV4_PROT_ICMP)
539 LogFlow((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
540 else if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
541 LogFlow((DEVICE_NAME ":TCP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
542 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
543 {
544 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint32_t *)pIpHdr + pIpHdr->ip_hl);
545 if ( RT_BE2H_U16(pUdpHdr->uh_sport) == 67
546 && RT_BE2H_U16(pUdpHdr->uh_dport) == 68)
547 {
548 LogRel((DEVICE_NAME ":UDP bootp ack D=%.6Rhxs S=%.6Rhxs UDP_CheckSum=%04x Computex=%04x\n", pb, pb + 6,
549 RT_BE2H_U16(pUdpHdr->uh_sum), RT_BE2H_U16(RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1))));
550 }
551 }
552 }
553 else
554 {
555 LogFlow((DEVICE_NAME ":Chained IP packet. Skipping validity check.\n"));
556 }
557 }
558 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_VLAN))
559 {
560 typedef struct VLANHEADER
561 {
562 int Pcp:3;
563 int Cfi:1;
564 int Vid:12;
565 } VLANHEADER;
566
567 VLANHEADER *pVlanHdr = (VLANHEADER *)(pMsg->b_rptr + sizeof(RTNETETHERHDR));
568 LogFlow((DEVICE_NAME ":VLAN Pcp=%d Cfi=%d Id=%d\n", pVlanHdr->Pcp, pVlanHdr->Cfi, pVlanHdr->Vid >> 4));
569 LogFlow((DEVICE_NAME "%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr));
570 }
571 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
572 {
573 PRTNETARPHDR pArpHdr = (PRTNETARPHDR)(pEthHdr + 1);
574 LogFlow((DEVICE_NAME ":ARP Op=%d\n", pArpHdr->ar_oper));
575 }
576 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
577 {
578 LogFlow((DEVICE_NAME ":IPv6 D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
579 }
580 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_1)
581 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_2)
582 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_3))
583 {
584 LogFlow((DEVICE_NAME ":IPX packet.\n"));
585 }
586 else
587 {
588 LogFlow((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
589 &pEthHdr->SrcMac));
590 /* LogFlow((DEVICE_NAME ":%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
591 }
592}
593
594
595/**
596 * Helper.
597 */
598DECLINLINE(bool) vboxNetFltPortSolarisIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
599{
600 return pThis->u.s.MacAddr.au16[0] == pMac->au16[0]
601 && pThis->u.s.MacAddr.au16[1] == pMac->au16[1]
602 && pThis->u.s.MacAddr.au16[2] == pMac->au16[2];
603}
604
605
606/**
607 * Receive (rx) entry point.
608 *
609 * @param pvData Private data.
610 * @param hResource The resource handle.
611 * @param pMsg The packet.
612 * @param fLoopback Whether this is a loopback packet or not.
613 */
614LOCAL void vboxNetFltSolarisRecv(void *pvData, mac_resource_handle_t hResource, mblk_t *pMsg, boolean_t fLoopback)
615{
616 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRecv pvData=%p pMsg=%p fLoopback=%d cbData=%d\n", pvData, pMsg, fLoopback, pMsg ? MBLKL(pMsg) : 0));
617
618 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvData;
619 AssertPtrReturnVoid(pThis);
620 AssertPtrReturnVoid(pMsg);
621
622 /*
623 * Active? Retain the instance and increment the busy counter.
624 */
625 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
626 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
627 const bool fActive = ASMAtomicUoReadBool(&pThis->fActive);
628 if (fActive)
629 vboxNetFltRetain(pThis, true /* fBusy */);
630 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
631 if (!fActive)
632 return;
633
634 uint32_t fSrc = INTNETTRUNKDIR_WIRE;
635 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
636 if ( MBLKL(pMsg) >= sizeof(RTNETETHERHDR)
637 && vboxNetFltPortSolarisIsHostMac(pThis, &pEthHdr->SrcMac))
638 fSrc = INTNETTRUNKDIR_HOST;
639
640 /*
641 * Route all received packets into the internal network.
642 */
643 unsigned cSegs = vboxNetFltSolarisMBlkCalcSGSegs(pThis, pMsg);
644 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
645 int rc = vboxNetFltSolarisMBlkToSG(pThis, pMsg, pSG, cSegs, fSrc);
646 if (RT_SUCCESS(rc))
647 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc);
648 else
649 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG failed. rc=%d\n", rc));
650
651 vboxNetFltRelease(pThis, true /* fBusy */);
652 freemsgchain(pMsg);
653
654 NOREF(hResource);
655}
656
657
658/**
659 * Create a VNIC dynamically over the given interface.
660 *
661 * @param pThis The VM connection instance.
662 *
663 * @returns corresponding VBox error code.
664 */
665LOCAL int vboxNetFltSolarisCreateVNIC(PVBOXNETFLTINS pThis)
666{
667#if 0
668 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC pThis=%p\n", pThis));
669
670 datalink_id_t InterfaceLinkId;
671 int rc = dls_mgmt_get_linkid(pThis->szName, &InterfaceLinkId);
672 if (!rc)
673 {
674 dev_t DeviceNum = makedevice(ddi_driver_major(g_pVBoxNetFltSolarisDip), pThis->u.s.uInstance);
675 char szVNICName[sizeof(VBOXFLT_VNIC_NAME) + 16];
676 RTStrPrintf(szVNICName, sizeof(szVNICName), "%s%d", VBOXFLT_VNIC_NAME, pThis->u.s.uInstance);
677 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC Creating VNIC '%s' over '%s'\n", szVNICName, pThis->szName));
678 rc = dls_mgmt_create(szVNICName, DeviceNum, DATALINK_CLASS_VNIC, DL_ETHER, B_FALSE /* Persist */, &pThis->u.s.VNICLinkId);
679 if (!rc)
680 {
681 /* -XXX- @todo remove hardcoded Guest MAC address, should be sent from guest later. */
682 RTMAC GuestMac;
683 GuestMac.au8[0] = 0x08;
684 GuestMac.au8[1] = 0x00;
685 GuestMac.au8[2] = 0x27;
686 GuestMac.au8[3] = 0xFE;
687 GuestMac.au8[4] = 0x21;
688 GuestMac.au8[5] = 0x03;
689
690 AssertCompile(sizeof(RTMAC) <= MAXMACADDRLEN);
691 uchar_t MacAddr[MAXMACADDRLEN];
692 bzero(MacAddr, sizeof(MacAddr));
693 bcopy(GuestMac.au8, MacAddr, RT_MIN(sizeof(GuestMac), sizeof(MacAddr)));
694
695 int MacSlot = 0;
696 vnic_ioc_diag_t Diag = VNIC_IOC_DIAG_NONE;
697 vnic_mac_addr_type_t MacAddrType = VNIC_MAC_ADDR_TYPE_FIXED;
698 int cbMac = sizeof(RTMAC);
699 int fFlags = VNIC_IOC_CREATE_NODUPCHECK | VNIC_IOC_CREATE_REQ_HWRINGS;
700 rc = vnic_dev_create(pThis->u.s.VNICLinkId, InterfaceLinkId, &MacAddrType, &cbMac, MacAddr,
701 &MacSlot, 0 /* Mac Prefix */, 0 /* VLAN Id */, NULL /* Resources Caps */,
702 fFlags, &Diag, kcred);
703 if (rc)
704 {
705 if (Diag == VNIC_IOC_DIAG_NO_HWRINGS)
706 {
707 /*
708 * No hardware rings available, retry without requesting hardware ring.
709 */
710 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC No hardware rings available for VNIC over '%s'. Recreating VNIC '%s'\n", pThis->szName,
711 szVNICName));
712
713 fFlags = VNIC_IOC_CREATE_NODUPCHECK;
714 rc = vnic_dev_create(pThis->u.s.VNICLinkId, InterfaceLinkId, &MacAddrType, &cbMac, MacAddr,
715 &MacSlot, 0 /* Mac Prefix */, 0 /* VLAN Id */, NULL /* Resources Caps */,
716 fFlags, &Diag, kcred);
717 }
718 }
719
720 if (!rc)
721 {
722 pThis->u.s.fCreatedVNIC = true;
723 pThis->u.s.uInstance++;
724 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC successfully created VNIC '%s' over '%s'\n", "vboxvnic", pThis->szName));
725 return VINF_SUCCESS;
726 }
727 else
728 {
729 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to create VNIC over '%s'. rc=%d Diagnosis=%d\n", pThis->szName,
730 rc, Diag));
731 rc = VERR_INTNET_FLT_VNIC_CREATE_FAILED;
732 }
733
734 dls_mgmt_destroy(pThis->u.s.VNICLinkId, B_FALSE /* Persist */);
735 }
736 else
737 {
738 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to create a link id for a VNIC over '%s' rc=%d\n", pThis->szName, rc));
739 rc = VERR_INTNET_FLT_VNIC_CREATE_FAILED;
740 }
741 }
742 else
743 {
744 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to find interface '%s' rc=%d\n", pThis->szName, rc));
745 rc = VERR_INTNET_FLT_IF_NOT_FOUND;
746 }
747
748 return rc;
749#endif
750}
751
752
753/**
754 * Attach to the network interface.
755 *
756 * @param pThis The VM connection instance.
757 * @param fRediscovery Whether this is a rediscovery attempt after disconnect.
758 *
759 * @returns corresponding VBox error code.
760 */
761LOCAL int vboxNetFltSolarisAttachToInterface(PVBOXNETFLTINS pThis, bool fRediscovery)
762{
763 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface pThis=%p fRediscovery=%d\n", pThis, fRediscovery));
764
765 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
766
767 /*
768 * Open the underlying interface (lower MAC) and get it's handle.
769 */
770 int rc = mac_open_by_linkname(pThis->szName, &pThis->u.s.hInterface);
771 if (RT_LIKELY(!rc))
772 {
773 /*
774 * If this is not a VNIC, create a VNIC and open it instead.
775 */
776 rc = mac_is_vnic(pThis->u.s.hInterface);
777 if (!rc)
778 {
779 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface '%s' is not a VNIC. Creating one.\n", pThis->szName));
780
781 mac_close(pThis->u.s.hInterface);
782 pThis->u.s.hInterface = NULL;
783 rc = vboxNetFltSolarisCreateVNIC(pThis);
784 if (RT_SUCCESS(rc))
785 rc = mac_open_by_linkid(pThis->u.s.VNICLinkId, &pThis->u.s.hInterface);
786 else
787 {
788 pThis->u.s.hInterface = NULL;
789 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed to create VNIC. rc=%Rrc\n", rc));
790 }
791 }
792 else
793 rc = VINF_SUCCESS;
794
795 /*
796 * At this point "hInterface" should be a handle to a VNIC, we no longer would deal with physical interface
797 * if it has been passed by the user.
798 */
799 if (RT_SUCCESS(rc))
800 {
801 const mac_info_t *pMacInfo = mac_info(pThis->u.s.hInterface);
802 if (RT_LIKELY(pMacInfo))
803 {
804 if ( pMacInfo->mi_media == DL_ETHER
805 && pMacInfo->mi_nativemedia == DL_ETHER)
806 {
807 /*
808 * Obtain the MAC address of the interface.
809 */
810 AssertCompile(sizeof(RTMAC) == ETHERADDRL);
811 mac_unicast_primary_get(pThis->u.s.hInterface, (uint8_t *)&pThis->u.s.MacAddr.au8);
812
813 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface MAC address of %s is %.*Rhxs\n", pThis->szName,
814 sizeof(pThis->u.s.MacAddr), &pThis->u.s.MacAddr));
815
816 /** @todo Obtain the MTU size using mac_sdu_get() */
817 /** @todo Obtain capabilities (hardware checksum etc.) using mac_capab_get() */
818
819 /*
820 * Open a client connection to the lower MAC interface.
821 */
822 rc = mac_client_open(pThis->u.s.hInterface, &pThis->u.s.hClient,
823 NULL /* name of this client */,
824 MAC_OPEN_FLAGS_USE_DATALINK_NAME | /* client name same as underlying NIC */
825 MAC_OPEN_FLAGS_MULTI_PRIMARY /* allow multiple primary unicasts */
826 );
827 if (RT_LIKELY(!rc))
828 {
829 /** @todo -XXX- if possible we must move unicast_add and rx_set to when the Guest advertises it's MAC to us. */
830
831 /*
832 * Set a unicast address for this client and the packet receive callback.
833 * We want to use the primary unicast address of the underlying interface (VNIC) hence we pass NULL.
834 * Also we don't really set the RX function here, this is done when we activate promiscuous mode.
835 */
836 mac_diag_t MacDiag;
837 rc = mac_unicast_add(pThis->u.s.hClient, NULL /* MAC Address */,
838 MAC_UNICAST_PRIMARY | MAC_UNICAST_STRIP_DISABLE |
839 MAC_UNICAST_DISABLE_TX_VID_CHECK | MAC_UNICAST_NODUPCHECK | MAC_UNICAST_HW,
840 &pThis->u.s.hUnicast, 0 /* VLAN id */, &MacDiag);
841 if (!rc)
842 {
843 /*
844 * Report MAC address, promiscuous mode and capabilities.
845 */
846 Assert(pThis->pSwitchPort);
847 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
848 pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, false); /** @todo Promisc */
849 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
850
851
852 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface successfully attached over '%s'\n", pThis->szName));
853 return VINF_SUCCESS;
854 }
855
856 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed to set client MAC address over link '%s' rc=%d\n",
857 pThis->szName, rc));
858
859 mac_client_close(pThis->u.s.hClient, 0 /* fFlags */);
860 pThis->u.s.hClient = NULL;
861 }
862 else
863 {
864 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed to create client over link '%s' rc=%d\n",
865 pThis->szName, rc));
866 }
867 }
868 else
869 {
870 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface media type incompatible: %d %d\n", pMacInfo->mi_media,
871 pMacInfo->mi_nativemedia));
872 rc = EPROTO;
873 }
874 }
875 else
876 {
877 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed to obtain info for link '%s'\n", pThis->szName));
878 rc = ENXIO;
879 }
880 }
881 else
882 {
883 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface VNIC creation failed over '%s'\n", pThis->szName));
884 rc = ENXIO;
885 }
886
887 if (pThis->u.s.hInterface)
888 {
889 mac_close(pThis->u.s.hInterface);
890 pThis->u.s.hInterface = NULL;
891 }
892 }
893 else
894 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed to open link '%s' rc=%d\n", pThis->szName, rc));
895
896 return RTErrConvertFromErrno(rc);
897}
898
899
900
901/**
902 * Detach from the network interface.
903 *
904 * @param pThis The VM connection instance.
905 * @returns corresponding VBox error code.
906 */
907LOCAL int vboxNetFltSolarisDetachFromInterface(PVBOXNETFLTINS pThis)
908{
909 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
910
911 if (pThis->u.s.hPromiscuous)
912 {
913 mac_promisc_remove(pThis->u.s.hPromiscuous);
914 pThis->u.s.hPromiscuous = NULL;
915 }
916
917 if (pThis->u.s.hClient)
918 {
919 if (pThis->u.s.hUnicast)
920 {
921 mac_unicast_remove(pThis->u.s.hClient, pThis->u.s.hUnicast);
922 pThis->u.s.hUnicast = NULL;
923 }
924
925 mac_rx_clear(pThis->u.s.hClient);
926
927 mac_client_close(pThis->u.s.hClient, 0 /* fFlags */);
928 pThis->u.s.hClient = NULL;
929 }
930
931 if (pThis->u.s.hInterface)
932 {
933 mac_close(pThis->u.s.hInterface);
934 pThis->u.s.hInterface = NULL;
935 }
936
937 if (pThis->u.s.fCreatedVNIC)
938 {
939#if 0
940 vnic_dev_delete(pThis->u.s.VNICLinkId, 0 /* Flags -- ununsed in snv_127 */, kcred);
941 dls_mgmt_destroy(pThis->u.s.VNICLinkId, B_FALSE /* Persist */);
942 pThis->u.s.VNICLinkId = DATALINK_INVALID_LINKID;
943 pThis->u.s.fCreatedVNIC = false;
944#endif
945 }
946}
947
948
949/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
950
951
952void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
953{
954 LogFlow((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d\n", pThis, fActive));
955
956 if (fActive)
957 {
958 /*
959 * Activate promiscuous mode.
960 */
961 if (!pThis->u.s.hPromiscuous)
962 {
963 int rc = mac_promisc_add(pThis->u.s.hClient, MAC_CLIENT_PROMISC_ALL, vboxNetFltSolarisRecv, pThis, &pThis->u.s.hPromiscuous,
964 MAC_PROMISC_FLAGS_NO_TX_LOOP);
965 if (rc)
966 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive cannot enable promiscuous mode for '%s' rc=%d\n", pThis->szName, rc));
967 }
968 }
969 else
970 {
971 /*
972 * Deactivate promiscuous mode.
973 */
974 if (pThis->u.s.hPromiscuous)
975 {
976 mac_promisc_remove(pThis->u.s.hPromiscuous);
977 pThis->u.s.hPromiscuous = NULL;
978 }
979 }
980}
981
982
983int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
984{
985 LogFlow((DEVICE_NAME ":vboxNetFltOsDisconnectIt pThis=%p\n", pThis));
986 return vboxNetFltSolarisDetachFromInterface(pThis);
987}
988
989
990int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
991{
992 LogFlow((DEVICE_NAME ":vboxNetFltOsConnectIt pThis=%p\n", pThis));
993 return vboxNetFltSolarisAttachToInterface(pThis, false /* fRediscovery */);
994}
995
996
997void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
998{
999 LogFlow((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n", pThis));
1000}
1001
1002
1003int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
1004{
1005 LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p pvContext=%p\n", pThis, pvContext));
1006
1007 return VINF_SUCCESS;
1008}
1009
1010
1011int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
1012{
1013 /*
1014 * Init. the solaris specific data.
1015 */
1016 pThis->u.s.VNICLinkId = DATALINK_INVALID_LINKID;
1017 pThis->u.s.uInstance = 0;
1018 pThis->u.s.fCreatedVNIC = false;
1019 pThis->u.s.hInterface = NULL;
1020 pThis->u.s.hClient = NULL;
1021 pThis->u.s.hUnicast = NULL;
1022 pThis->u.s.hPromiscuous = NULL;
1023 bzero(&pThis->u.s.MacAddr, sizeof(pThis->u.s.MacAddr));
1024 return VINF_SUCCESS;
1025}
1026
1027
1028bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
1029{
1030 /*
1031 * @todo Think about this.
1032 */
1033 return false;
1034}
1035
1036
1037int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
1038{
1039 /*
1040 * Xmit the packet down the interface (tx)
1041 */
1042 int rc = VERR_INVALID_HANDLE;
1043 if (RT_LIKELY(pThis->u.s.hClient))
1044 {
1045 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
1046 if (RT_LIKELY(pMsg))
1047 {
1048 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p cbData=%d\n", pThis, MBLKL(pMsg)));
1049
1050 mac_tx_cookie_t pXmitCookie = mac_tx(pThis->u.s.hClient, pMsg, 0 /* Hint */, MAC_DROP_ON_NO_DESC, NULL /* return message */);
1051 if (RT_LIKELY(!pXmitCookie))
1052 return VINF_SUCCESS;
1053
1054 pMsg = NULL;
1055 rc = VERR_NET_IO_ERROR;
1056 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit Xmit failed.\n"));
1057 }
1058 else
1059 {
1060 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit no memory for allocating Xmit packet.\n"));
1061 rc = VERR_NO_MEMORY;
1062 }
1063 }
1064 else
1065 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit missing client.\n"));
1066
1067 return rc;
1068}
1069
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