VirtualBox

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

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

Solaris/VBoxBow: crossbow netfilter initial commit, rx works, no tx.

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