VirtualBox

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

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

lots under src/VBox: whitespace cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.8 KB
Line 
1/* $Id: VBoxNetFltBow-solaris.c 26498 2010-02-14 08:18:26Z 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/cdefs.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 pSG->pvOwnerData = NULL;
481 pSG->pvUserData = NULL;
482 pSG->pvUserData2 = NULL;
483 pSG->cUsers = 1;
484 pSG->cbTotal = 0;
485 pSG->fFlags = INTNETSG_FLAGS_TEMP;
486 pSG->cSegsAlloc = cSegs;
487
488 /*
489 * Convert the message block to segments.
490 */
491 mblk_t *pCur = pMsg;
492 unsigned iSeg = 0;
493 while (pCur)
494 {
495 size_t cbSeg = MBLKL(pCur);
496 if (cbSeg)
497 {
498 void *pvSeg = pCur->b_rptr;
499 pSG->aSegs[iSeg].pv = pvSeg;
500 pSG->aSegs[iSeg].cb = cbSeg;
501 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
502 pSG->cbTotal += cbSeg;
503 iSeg++;
504 }
505 pCur = pCur->b_cont;
506 }
507 pSG->cSegsUsed = iSeg;
508
509#ifdef PADD_RUNT_FRAMES_FROM_HOST
510 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
511 {
512 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pulling up to length.\n"));
513
514 static uint8_t const s_abZero[128] = {0};
515 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
516 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
517 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
518 pSG->cbTotal = 60;
519 pSG->cSegsUsed++;
520 }
521#endif
522
523 LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
524 return VINF_SUCCESS;
525}
526
527
528/**
529 * Simple packet dump, used for internal debugging.
530 *
531 * @param pMsg Pointer to the message to analyze and dump.
532 */
533static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg)
534{
535 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAnalyzeMBlk pMsg=%p\n", pMsg));
536
537 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
538 uint8_t *pb = pMsg->b_rptr;
539 if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
540 {
541 PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
542 if (!pMsg->b_cont)
543 {
544 if (pIpHdr->ip_p == RTNETIPV4_PROT_ICMP)
545 LogFlow((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
546 else if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
547 LogFlow((DEVICE_NAME ":TCP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
548 else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
549 {
550 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint32_t *)pIpHdr + pIpHdr->ip_hl);
551 if ( RT_BE2H_U16(pUdpHdr->uh_sport) == 67
552 && RT_BE2H_U16(pUdpHdr->uh_dport) == 68)
553 {
554 LogRel((DEVICE_NAME ":UDP bootp ack D=%.6Rhxs S=%.6Rhxs UDP_CheckSum=%04x Computex=%04x\n", pb, pb + 6,
555 RT_BE2H_U16(pUdpHdr->uh_sum), RT_BE2H_U16(RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1))));
556 }
557 }
558 }
559 else
560 {
561 LogFlow((DEVICE_NAME ":Chained IP packet. Skipping validity check.\n"));
562 }
563 }
564 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_VLAN))
565 {
566 typedef struct VLANHEADER
567 {
568 int Pcp:3;
569 int Cfi:1;
570 int Vid:12;
571 } VLANHEADER;
572
573 VLANHEADER *pVlanHdr = (VLANHEADER *)(pMsg->b_rptr + sizeof(RTNETETHERHDR));
574 LogFlow((DEVICE_NAME ":VLAN Pcp=%d Cfi=%d Id=%d\n", pVlanHdr->Pcp, pVlanHdr->Cfi, pVlanHdr->Vid >> 4));
575 LogFlow((DEVICE_NAME "%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr));
576 }
577 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
578 {
579 PRTNETARPHDR pArpHdr = (PRTNETARPHDR)(pEthHdr + 1);
580 LogFlow((DEVICE_NAME ":ARP Op=%d\n", pArpHdr->ar_oper));
581 }
582 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
583 {
584 LogFlow((DEVICE_NAME ":IPv6 D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
585 }
586 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_1)
587 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_2)
588 || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_3))
589 {
590 LogFlow((DEVICE_NAME ":IPX packet.\n"));
591 }
592 else
593 {
594 LogFlow((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
595 &pEthHdr->SrcMac));
596 /* LogFlow((DEVICE_NAME ":%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
597 }
598}
599
600
601/**
602 * Receive (rx) entry point.
603 *
604 * @param pvData Private data.
605 * @param hResource The resource handle.
606 * @param pMsg The packet.
607 * @param fLoopback Whether this is a loopback packet or not.
608 */
609LOCAL void vboxNetFltSolarisRecv(void *pvData, mac_resource_handle_t hResource, mblk_t *pMsg, boolean_t fLoopback)
610{
611 LogFlow((DEVICE_NAME ":vboxNetFltSolarisRecv pvData=%p pMsg=%p fLoopback=%d cbData=%d\n", pvData, pMsg, fLoopback, pMsg ? MBLKL(pMsg) : 0));
612
613 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvData;
614 AssertPtrReturnVoid(pThis);
615 AssertPtrReturnVoid(pMsg);
616
617 /*
618 * Active? Retain the instance and increment the busy counter.
619 */
620 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
621 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
622 const bool fActive = ASMAtomicUoReadBool(&pThis->fActive);
623 if (fActive)
624 vboxNetFltRetain(pThis, true /* fBusy */);
625 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
626 if (!fActive)
627 return;
628
629 uint32_t fSrc = INTNETTRUNKDIR_WIRE;
630 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
631 if ( MBLKL(pMsg) >= sizeof(RTNETETHERHDR)
632 && vboxNetFltPortOsIsHostMac(pThis, &pEthHdr->SrcMac))
633 fSrc = INTNETTRUNKDIR_HOST;
634
635 /*
636 * Route all received packets into the internal network.
637 */
638 unsigned cSegs = vboxNetFltSolarisMBlkCalcSGSegs(pThis, pMsg);
639 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
640 int rc = vboxNetFltSolarisMBlkToSG(pThis, pMsg, pSG, cSegs, fSrc);
641 if (RT_SUCCESS(rc))
642 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc);
643 else
644 LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG failed. rc=%d\n", rc));
645
646 vboxNetFltRelease(pThis, true /* fBusy */);
647 freemsgchain(pMsg);
648
649 NOREF(hResource);
650}
651
652
653/**
654 * Create a VNIC dynamically over the given interface.
655 *
656 * @param pThis The VM connection instance.
657 *
658 * @returns corresponding VBox error code.
659 */
660LOCAL int vboxNetFltSolarisCreateVNIC(PVBOXNETFLTINS pThis)
661{
662#if 0
663 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC pThis=%p\n", pThis));
664
665 datalink_id_t InterfaceLinkId;
666 int rc = dls_mgmt_get_linkid(pThis->szName, &InterfaceLinkId);
667 if (!rc)
668 {
669 dev_t DeviceNum = makedevice(ddi_driver_major(g_pVBoxNetFltSolarisDip), pThis->u.s.uInstance);
670 char szVNICName[sizeof(VBOXFLT_VNIC_NAME) + 16];
671 RTStrPrintf(szVNICName, sizeof(szVNICName), "%s%d", VBOXFLT_VNIC_NAME, pThis->u.s.uInstance);
672 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC Creating VNIC '%s' over '%s'\n", szVNICName, pThis->szName));
673 rc = dls_mgmt_create(szVNICName, DeviceNum, DATALINK_CLASS_VNIC, DL_ETHER, B_FALSE /* Persist */, &pThis->u.s.VNICLinkId);
674 if (!rc)
675 {
676 /* -XXX- @todo remove hardcoded Guest MAC address, should be sent from guest later. */
677 RTMAC GuestMac;
678 GuestMac.au8[0] = 0x08;
679 GuestMac.au8[1] = 0x00;
680 GuestMac.au8[2] = 0x27;
681 GuestMac.au8[3] = 0xFE;
682 GuestMac.au8[4] = 0x21;
683 GuestMac.au8[5] = 0x03;
684
685 AssertCompile(sizeof(RTMAC) <= MAXMACADDRLEN);
686 uchar_t MacAddr[MAXMACADDRLEN];
687 bzero(MacAddr, sizeof(MacAddr));
688 bcopy(GuestMac.au8, MacAddr, RT_MIN(sizeof(GuestMac), sizeof(MacAddr)));
689
690 int MacSlot = 0;
691 vnic_ioc_diag_t Diag = VNIC_IOC_DIAG_NONE;
692 vnic_mac_addr_type_t MacAddrType = VNIC_MAC_ADDR_TYPE_FIXED;
693 int cbMac = sizeof(RTMAC);
694 int fFlags = VNIC_IOC_CREATE_NODUPCHECK | VNIC_IOC_CREATE_REQ_HWRINGS;
695 rc = vnic_dev_create(pThis->u.s.VNICLinkId, InterfaceLinkId, &MacAddrType, &cbMac, MacAddr,
696 &MacSlot, 0 /* Mac Prefix */, 0 /* VLAN Id */, NULL /* Resources Caps */,
697 fFlags, &Diag, kcred);
698 if (rc)
699 {
700 if (Diag == VNIC_IOC_DIAG_NO_HWRINGS)
701 {
702 /*
703 * No hardware rings available, retry without requesting hardware ring.
704 */
705 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC No hardware rings available for VNIC over '%s'. Recreating VNIC '%s'\n", pThis->szName,
706 szVNICName));
707
708 fFlags = VNIC_IOC_CREATE_NODUPCHECK;
709 rc = vnic_dev_create(pThis->u.s.VNICLinkId, InterfaceLinkId, &MacAddrType, &cbMac, MacAddr,
710 &MacSlot, 0 /* Mac Prefix */, 0 /* VLAN Id */, NULL /* Resources Caps */,
711 fFlags, &Diag, kcred);
712 }
713 }
714
715 if (!rc)
716 {
717 pThis->u.s.fCreatedVNIC = true;
718 pThis->u.s.uInstance++;
719 LogFlow((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC successfully created VNIC '%s' over '%s'\n", "vboxvnic", pThis->szName));
720 return VINF_SUCCESS;
721 }
722 else
723 {
724 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to create VNIC over '%s'. rc=%d Diagnosis=%d\n", pThis->szName,
725 rc, Diag));
726 rc = VERR_INTNET_FLT_VNIC_CREATE_FAILED;
727 }
728
729 dls_mgmt_destroy(pThis->u.s.VNICLinkId, B_FALSE /* Persist */);
730 }
731 else
732 {
733 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to create a link id for a VNIC over '%s' rc=%d\n", pThis->szName, rc));
734 rc = VERR_INTNET_FLT_VNIC_CREATE_FAILED;
735 }
736 }
737 else
738 {
739 LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to find interface '%s' rc=%d\n", pThis->szName, rc));
740 rc = VERR_INTNET_FLT_IF_NOT_FOUND;
741 }
742
743 return rc;
744#endif
745}
746
747
748/**
749 * Attach to the network interface.
750 *
751 * @param pThis The VM connection instance.
752 * @param fRediscovery Whether this is a rediscovery attempt after disconnect.
753 *
754 * @returns corresponding VBox error code.
755 */
756LOCAL int vboxNetFltSolarisAttachToInterface(PVBOXNETFLTINS pThis, bool fRediscovery)
757{
758 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface pThis=%p fRediscovery=%d\n", pThis, fRediscovery));
759
760 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
761
762 /*
763 * Open the underlying interface (lower MAC) and get it's handle.
764 */
765 int rc = mac_open_by_linkname(pThis->szName, &pThis->u.s.hInterface);
766 if (RT_LIKELY(!rc))
767 {
768 /*
769 * If this is not a VNIC, create a VNIC and open it instead.
770 */
771 rc = mac_is_vnic(pThis->u.s.hInterface);
772 if (!rc)
773 {
774 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface '%s' is not a VNIC. Creating one.\n", pThis->szName));
775
776 mac_close(pThis->u.s.hInterface);
777 pThis->u.s.hInterface = NULL;
778 rc = vboxNetFltSolarisCreateVNIC(pThis);
779 if (RT_SUCCESS(rc))
780 rc = mac_open_by_linkid(pThis->u.s.VNICLinkId, &pThis->u.s.hInterface);
781 else
782 {
783 pThis->u.s.hInterface = NULL;
784 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed to create VNIC. rc=%Rrc\n", rc));
785 }
786 }
787 else
788 rc = VINF_SUCCESS;
789
790 /*
791 * At this point "hInterface" should be a handle to a VNIC, we no longer would deal with physical interface
792 * if it has been passed by the user.
793 */
794 if (RT_SUCCESS(rc))
795 {
796 const mac_info_t *pMacInfo = mac_info(pThis->u.s.hInterface);
797 if (RT_LIKELY(pMacInfo))
798 {
799 if ( pMacInfo->mi_media == DL_ETHER
800 && pMacInfo->mi_nativemedia == DL_ETHER)
801 {
802 /*
803 * Obtain the MAC address of the interface.
804 */
805 AssertCompile(sizeof(RTMAC) == ETHERADDRL);
806 mac_unicast_primary_get(pThis->u.s.hInterface, (uint8_t *)&pThis->u.s.Mac.au8);
807
808 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface MAC address of %s is %.*Rhxs\n", pThis->szName,
809 sizeof(pThis->u.s.Mac), &pThis->u.s.Mac));
810
811 /** @todo Obtain the MTU size using mac_sdu_get() */
812 /** @todo Obtain capabilities (hardware checksum etc.) using mac_capab_get() */
813
814 /*
815 * Open a client connection to the lower MAC interface.
816 */
817 rc = mac_client_open(pThis->u.s.hInterface, &pThis->u.s.hClient,
818 NULL /* name of this client */,
819 MAC_OPEN_FLAGS_USE_DATALINK_NAME | /* client name same as underlying NIC */
820 MAC_OPEN_FLAGS_MULTI_PRIMARY /* allow multiple primary unicasts */
821 );
822 if (RT_LIKELY(!rc))
823 {
824 /** @todo -XXX- if possible we must move unicast_add and rx_set to when the Guest advertises it's MAC to us. */
825
826 /*
827 * Set a unicast address for this client and the packet receive callback.
828 * We want to use the primary unicast address of the underlying interface (VNIC) hence we pass NULL.
829 * Also we don't really set the RX function here, this is done when we activate promiscuous mode.
830 */
831 mac_diag_t MacDiag;
832 rc = mac_unicast_add(pThis->u.s.hClient, NULL /* MAC Address */,
833 MAC_UNICAST_PRIMARY | MAC_UNICAST_STRIP_DISABLE |
834 MAC_UNICAST_DISABLE_TX_VID_CHECK | MAC_UNICAST_NODUPCHECK | MAC_UNICAST_HW,
835 &pThis->u.s.hUnicast, 0 /* VLAN id */, &MacDiag);
836 if (!rc)
837 {
838 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface successfully attached over '%s'\n", pThis->szName));
839 return VINF_SUCCESS;
840 }
841 else
842 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed to set client MAC address over link '%s' rc=%d\n",
843 pThis->szName, rc));
844
845 mac_client_close(pThis->u.s.hClient, 0 /* fFlags */);
846 pThis->u.s.hClient = NULL;
847 }
848 else
849 {
850 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed to create client over link '%s' rc=%d\n",
851 pThis->szName, rc));
852 }
853 }
854 else
855 {
856 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface media type incompatible: %d %d\n", pMacInfo->mi_media,
857 pMacInfo->mi_nativemedia));
858 rc = EPROTO;
859 }
860 }
861 else
862 {
863 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed to obtain info for link '%s'\n", pThis->szName));
864 rc = ENXIO;
865 }
866 }
867 else
868 {
869 LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface VNIC creation failed over '%s'\n", pThis->szName));
870 rc = ENXIO;
871 }
872
873 if (pThis->u.s.hInterface)
874 {
875 mac_close(pThis->u.s.hInterface);
876 pThis->u.s.hInterface = NULL;
877 }
878 }
879 else
880 LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed to open link '%s' rc=%d\n", pThis->szName, rc));
881
882 return RTErrConvertFromErrno(rc);
883}
884
885
886
887/**
888 * Detach from the network interface.
889 *
890 * @param pThis The VM connection instance.
891 * @returns corresponding VBox error code.
892 */
893LOCAL int vboxNetFltSolarisDetachFromInterface(PVBOXNETFLTINS pThis)
894{
895 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
896
897 if (pThis->u.s.hPromiscuous)
898 {
899 mac_promisc_remove(pThis->u.s.hPromiscuous);
900 pThis->u.s.hPromiscuous = NULL;
901 }
902
903 if (pThis->u.s.hClient)
904 {
905 if (pThis->u.s.hUnicast)
906 {
907 mac_unicast_remove(pThis->u.s.hClient, pThis->u.s.hUnicast);
908 pThis->u.s.hUnicast = NULL;
909 }
910
911 mac_rx_clear(pThis->u.s.hClient);
912
913 mac_client_close(pThis->u.s.hClient, 0 /* fFlags */);
914 pThis->u.s.hClient = NULL;
915 }
916
917 if (pThis->u.s.hInterface)
918 {
919 mac_close(pThis->u.s.hInterface);
920 pThis->u.s.hInterface = NULL;
921 }
922
923 if (pThis->u.s.fCreatedVNIC)
924 {
925#if 0
926 vnic_dev_delete(pThis->u.s.VNICLinkId, 0 /* Flags -- ununsed in snv_127 */, kcred);
927 dls_mgmt_destroy(pThis->u.s.VNICLinkId, B_FALSE /* Persist */);
928 pThis->u.s.VNICLinkId = DATALINK_INVALID_LINKID;
929 pThis->u.s.fCreatedVNIC = false;
930#endif
931 }
932}
933
934
935/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
936bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
937{
938 LogFlow((DEVICE_NAME ":vboxNetFltPortOsIsPromiscuous pThis=%p\n", pThis));
939 return false;
940}
941
942
943void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
944{
945 LogFlow((DEVICE_NAME ":vboxNetFltPortOsGetMacAddress pThis=%p\n", pThis));
946 *pMac = pThis->u.s.Mac;
947 return;
948}
949
950
951bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
952{
953 /** @todo What happens when the MAC address of the underlying NIC changes?? */
954 return pThis->u.s.Mac.au16[0] == pMac->au16[0]
955 && pThis->u.s.Mac.au16[1] == pMac->au16[1]
956 && pThis->u.s.Mac.au16[2] == pMac->au16[2];
957}
958
959
960void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
961{
962 LogFlow((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d\n", pThis, fActive));
963
964 if (fActive)
965 {
966 /*
967 * Activate promiscuous mode.
968 */
969 if (!pThis->u.s.hPromiscuous)
970 {
971 int rc = mac_promisc_add(pThis->u.s.hClient, MAC_CLIENT_PROMISC_ALL, vboxNetFltSolarisRecv, pThis, &pThis->u.s.hPromiscuous,
972 MAC_PROMISC_FLAGS_NO_TX_LOOP);
973 if (rc)
974 LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive cannot enable promiscuous mode for '%s' rc=%d\n", pThis->szName, rc));
975 }
976 }
977 else
978 {
979 /*
980 * Deactivate promiscuous mode.
981 */
982 if (pThis->u.s.hPromiscuous)
983 {
984 mac_promisc_remove(pThis->u.s.hPromiscuous);
985 pThis->u.s.hPromiscuous = NULL;
986 }
987 }
988}
989
990
991int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
992{
993 LogFlow((DEVICE_NAME ":vboxNetFltOsDisconnectIt pThis=%p\n", pThis));
994 return vboxNetFltSolarisDetachFromInterface(pThis);
995}
996
997
998int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
999{
1000 LogFlow((DEVICE_NAME ":vboxNetFltOsConnectIt pThis=%p\n", pThis));
1001 return vboxNetFltSolarisAttachToInterface(pThis, false /* fRediscovery */);
1002}
1003
1004
1005void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
1006{
1007 LogFlow((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n", pThis));
1008}
1009
1010
1011int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
1012{
1013 LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p pvContext=%p\n", pThis, pvContext));
1014
1015 return VINF_SUCCESS;
1016}
1017
1018
1019int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
1020{
1021 /*
1022 * Init. the solaris specific data.
1023 */
1024 pThis->u.s.VNICLinkId = DATALINK_INVALID_LINKID;
1025 pThis->u.s.uInstance = 0;
1026 pThis->u.s.fCreatedVNIC = false;
1027 pThis->u.s.hInterface = NULL;
1028 pThis->u.s.hClient = NULL;
1029 pThis->u.s.hUnicast = NULL;
1030 pThis->u.s.hPromiscuous = NULL;
1031 bzero(&pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
1032 return VINF_SUCCESS;
1033}
1034
1035
1036bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
1037{
1038 /*
1039 * @todo Think about this.
1040 */
1041 return false;
1042}
1043
1044
1045int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
1046{
1047 /*
1048 * Xmit the packet down the interface (tx)
1049 */
1050 int rc = VERR_INVALID_HANDLE;
1051 if (RT_LIKELY(pThis->u.s.hClient))
1052 {
1053 mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
1054 if (RT_LIKELY(pMsg))
1055 {
1056 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p cbData=%d\n", pThis, MBLKL(pMsg)));
1057
1058 mac_tx_cookie_t pXmitCookie = mac_tx(pThis->u.s.hClient, pMsg, 0 /* Hint */, MAC_DROP_ON_NO_DESC, NULL /* return message */);
1059 if (RT_LIKELY(!pXmitCookie))
1060 return VINF_SUCCESS;
1061
1062 pMsg = NULL;
1063 rc = VERR_NET_IO_ERROR;
1064 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit Xmit failed.\n"));
1065 }
1066 else
1067 {
1068 LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit no memory for allocating Xmit packet.\n"));
1069 rc = VERR_NO_MEMORY;
1070 }
1071 }
1072 else
1073 LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit missing client.\n"));
1074
1075 return rc;
1076}
1077
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