VBoxNetAdp-solaris.c revision 691aac57c6f10a29a7507143a789f3dca28ed1f3
0N/A/* $Id$ */
0N/A/** @file
0N/A * VBoxNetAdapter - Network Adapter Driver (Host), Solaris Specific Code.
0N/A */
0N/A
0N/A/*
0N/A * Copyright (C) 2008 Sun Microsystems, Inc.
0N/A *
0N/A * This file is part of VirtualBox Open Source Edition (OSE), as
0N/A * available from http://www.virtualbox.org. This file is free software;
0N/A * you can redistribute it and/or modify it under the terms of the GNU
0N/A * General Public License (GPL) as published by the Free Software
0N/A * Foundation, in version 2 as it comes in the "COPYING" file of the
0N/A * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
0N/A * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0N/A *
0N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0N/A * Clara, CA 95054 USA or visit http://www.sun.com if you need
0N/A * additional information or have any questions.
0N/A */
0N/A
0N/A/*******************************************************************************
0N/A* Header Files *
0N/A*******************************************************************************/
0N/A#if defined(DEBUG_ramshankar) && !defined(LOG_ENABLED)
0N/A# define LOG_ENABLED
0N/A#endif
0N/A
0N/A#define LOG_GROUP LOG_GROUP_NET_TAP_DRV
0N/A#include <VBox/log.h>
0N/A#include <VBox/err.h>
0N/A#include <VBox/version.h>
0N/A#include <iprt/assert.h>
0N/A#include <iprt/semaphore.h>
0N/A#include <iprt/initterm.h>
0N/A#include <iprt/assert.h>
0N/A#include <iprt/mem.h>
0N/A#include <iprt/rand.h>
0N/A
0N/A#include <sys/types.h>
0N/A#include <sys/dlpi.h>
0N/A#include <sys/types.h>
0N/A#include <sys/param.h>
0N/A#include <sys/stat.h>
0N/A#include <sys/stream.h>
0N/A#include <sys/stropts.h>
0N/A#include <sys/strsun.h>
0N/A#include <sys/modctl.h>
0N/A#include <sys/ddi.h>
0N/A#include <sys/sunddi.h>
0N/A#include <sys/sunldi.h>
0N/A#include <sys/gld.h>
0N/A
0N/A
0N/A/*******************************************************************************
0N/A* Defined Constants And Macros *
0N/A*******************************************************************************/
0N/A#define VBOXSOLQUOTE2(x) #x
0N/A#define VBOXSOLQUOTE(x) VBOXSOLQUOTE2(x)
0N/A#define DEVICE_NAME "vboxnet"
0N/A/** The module descriptions as seen in 'modinfo'. */
0N/A#define DEVICE_DESC_DRV "VirtualBox NetAdp"
0N/A#define DEVICE_DESC_MOD "VirtualBox AdpMod"
0N/A#define VBOXNETADP_MTU 1500
0N/A
0N/Astatic int VBoxNetAdpSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
0N/Astatic int VBoxNetAdpSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
0N/A
0N/Astatic int VBoxNetAdpSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fFile, int fStream, cred_t *pCred);
0N/Astatic int VBoxNetAdpSolarisModClose(queue_t *pQueue, int fFile, cred_t *pCred);
0N/Astatic int VBoxNetAdpSolarisModReadPut(queue_t *pQueue, mblk_t *pMsg);
0N/Astatic int VBoxNetAdpSolarisModWritePut(queue_t *pQueue, mblk_t *pMsg);
0N/Astatic int VBoxNetAdpSolarisModWriteService(queue_t *pQueue);
0N/A
0N/A/**
0N/A * Streams: module info.
0N/A */
0N/Astatic struct module_info g_VBoxNetAdpSolarisModInfo =
0N/A{
0N/A 0x0dd, /* module id */
0N/A DEVICE_NAME,
0N/A 0, /* min. packet size */
0N/A INFPSZ, /* max. packet size */
0N/A 0, /* hi-water mask */
0N/A 0 /* lo-water mask */
0N/A};
0N/A
0N/A/**
0N/A * Streams: read queue hooks.
0N/A */
0N/Astatic struct qinit g_VBoxNetAdpSolarisReadQ =
0N/A{
0N/A NULL, /* read */
0N/A gld_rsrv,
0N/A gld_open,
0N/A gld_close,
0N/A NULL, /* admin (reserved) */
0N/A &g_VBoxNetAdpSolarisModInfo,
0N/A NULL /* module stats */
0N/A};
0N/A
0N/A/**
0N/A * Streams: write queue hooks.
0N/A */
0N/Astatic struct qinit g_VBoxNetAdpSolarisWriteQ =
0N/A{
0N/A gld_wput,
0N/A gld_wsrv,
0N/A NULL, /* open */
0N/A NULL, /* close */
0N/A NULL, /* admin (reserved) */
0N/A &g_VBoxNetAdpSolarisModInfo,
0N/A NULL /* module stats */
0N/A};
0N/A
0N/A/**
0N/A * Streams: IO stream tab.
0N/A */
0N/Astatic struct streamtab g_VBoxNetAdpSolarisStreamTab =
0N/A{
0N/A &g_VBoxNetAdpSolarisReadQ,
0N/A &g_VBoxNetAdpSolarisWriteQ,
0N/A NULL, /* muxread init */
0N/A NULL /* muxwrite init */
0N/A};
0N/A
0N/A/**
0N/A * cb_ops: driver char/block entry points
0N/A */
0N/Astatic struct cb_ops g_VBoxNetAdpSolarisCbOps =
0N/A{
0N/A nulldev, /* cb open */
0N/A nulldev, /* cb close */
0N/A nodev, /* b strategy */
0N/A nodev, /* b dump */
0N/A nodev, /* b print */
0N/A nodev, /* cb read */
0N/A nodev, /* cb write */
0N/A nodev, /* cb ioctl */
0N/A nodev, /* c devmap */
0N/A nodev, /* c mmap */
0N/A nodev, /* c segmap */
0N/A nochpoll, /* c poll */
0N/A ddi_prop_op, /* property ops */
0N/A &g_VBoxNetAdpSolarisStreamTab,
0N/A D_MP, /* compat. flag */
0N/A CB_REV /* revision */
0N/A};
0N/A
0N/A/**
0N/A * dev_ops: driver entry/exit and other ops.
0N/A */
0N/Astatic struct dev_ops g_VBoxNetAdpSolarisDevOps =
0N/A{
0N/A DEVO_REV, /* driver build revision */
0N/A 0, /* ref count */
0N/A gld_getinfo,
0N/A nulldev, /* identify */
0N/A nulldev, /* probe */
0N/A VBoxNetAdpSolarisAttach,
0N/A VBoxNetAdpSolarisDetach,
0N/A nodev, /* reset */
0N/A &g_VBoxNetAdpSolarisCbOps,
0N/A (struct bus_ops *)0,
0N/A nodev, /* power */
0N/A ddi_quiesce_not_supported
0N/A};
0N/A
0N/A/**
0N/A * modldrv: export driver specifics to kernel
0N/A */
0N/Astatic struct modldrv g_VBoxNetAdpSolarisDriver =
0N/A{
0N/A &mod_driverops, /* extern from kernel */
0N/A DEVICE_DESC_DRV " " VBOX_VERSION_STRING "r" VBOXSOLQUOTE(VBOX_SVN_REV),
0N/A &g_VBoxNetAdpSolarisDevOps
0N/A};
0N/A
0N/A/**
0N/A * modlinkage: export install/remove/info to the kernel
0N/A */
0N/Astatic struct modlinkage g_VBoxNetAdpSolarisModLinkage =
0N/A{
0N/A MODREV_1, /* loadable module system revision */
0N/A &g_VBoxNetAdpSolarisDriver, /* adapter streams driver framework */
0N/A NULL /* terminate array of linkage structures */
0N/A};
0N/A
0N/A
0N/A/*******************************************************************************
0N/A* Global Variables *
0N/A*******************************************************************************/
0N/A/** Global device info handle. */
0N/Astatic dev_info_t *g_pVBoxNetAdpSolarisDip = NULL;
0N/A
0N/A/** The default ethernet broadcast address */
0N/Astatic uchar_t achBroadcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
0N/A
0N/A/** GCC C++ hack. */
0N/Aunsigned __gxx_personality_v0 = 0xbadb100d;
0N/A
0N/A
0N/A/**
0N/A * vboxnetadp_state_t: per-instance data
0N/A */
0N/Atypedef struct vboxnetadp_state_t
0N/A{
0N/A dev_info_t *pDip; /* device info. */
0N/A RTMAC FactoryMac; /* default 'factory' MAC address */
0N/A RTMAC CurrentMac; /* current MAC address */
0N/A} vboxnetadp_state_t;
0N/A
0N/A
0N/A/*******************************************************************************
0N/A* Internal Functions *
0N/A*******************************************************************************/
0N/Astatic int vboxNetAdpSolarisGenerateMac(PRTMAC pMac);
0N/Astatic int vboxNetAdpSolarisSetMacAddress(gld_mac_info_t *pMacInfo, unsigned char *pszMacAddr);
0N/Astatic int vboxNetAdpSolarisSend(gld_mac_info_t *pMacInfo, mblk_t *pMsg);
0N/A
0N/Astatic int vboxNetAdpSolarisStub(gld_mac_info_t *pMacInfo);
0N/Astatic int vboxNetAdpSolarisSetPromisc(gld_mac_info_t *pMacInfo, int fPromisc);
0N/Astatic int vboxNetAdpSolarisSetMulticast(gld_mac_info_t *pMacInfo, unsigned char *pMulticastAddr, int fMulticast);
0N/A
0N/A
0N/A/**
0N/A * Kernel entry points
0N/A */
0N/Aint _init(void)
0N/A{
0N/A LogFlow((DEVICE_NAME ":_init\n"));
0N/A
0N/A /*
0N/A * Prevent module autounloading.
0N/A */
0N/A modctl_t *pModCtl = mod_getctl(&g_VBoxNetAdpSolarisModLinkage);
0N/A if (pModCtl)
0N/A pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
0N/A else
0N/A LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
0N/A
0N/A /*
0N/A * Initialize IPRT.
0N/A */
0N/A int rc = RTR0Init(0);
0N/A if (RT_SUCCESS(rc))
0N/A {
0N/A rc = mod_install(&g_VBoxNetAdpSolarisModLinkage);
0N/A if (!rc)
0N/A return rc;
0N/A
0N/A LogRel((DEVICE_NAME ":mod_install failed. rc=%d\n", rc));
0N/A RTR0Term();
0N/A }
0N/A else
0N/A LogRel((DEVICE_NAME ":failed to initialize IPRT (rc=%d)\n", rc));
0N/A
0N/A return RTErrConvertToErrno(rc);
0N/A}
0N/A
0N/A
0N/Aint _fini(void)
0N/A{
0N/A int rc;
0N/A LogFlow((DEVICE_NAME ":_fini\n"));
0N/A
0N/A /*
0N/A * Undo the work done during start (in reverse order).
0N/A */
0N/A RTR0Term();
0N/A
0N/A return mod_remove(&g_VBoxNetAdpSolarisModLinkage);
0N/A}
0N/A
0N/A
0N/Aint _info(struct modinfo *pModInfo)
0N/A{
0N/A LogFlow((DEVICE_NAME ":_info\n"));
0N/A
0N/A int rc = mod_info(&g_VBoxNetAdpSolarisModLinkage, pModInfo);
0N/A
0N/A LogFlow((DEVICE_NAME ":_info returns %d\n", rc));
0N/A return rc;
0N/A}
0N/A
0N/A
0N/A/**
0N/A * Attach entry point, to attach a device to the system or resume it.
0N/A *
0N/A * @param pDip The module structure instance.
0N/A * @param enmCmd Operation type (attach/resume).
0N/A *
0N/A * @returns corresponding solaris error code.
0N/A */
0N/Astatic int VBoxNetAdpSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
0N/A{
0N/A LogFlow((DEVICE_NAME ":VBoxNetAdpSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
0N/A
0N/A int rc = -1;
0N/A switch (enmCmd)
0N/A {
0N/A case DDI_ATTACH:
0N/A {
0N/A gld_mac_info_t *pMacInfo = gld_mac_alloc(pDip);
0N/A if (pMacInfo)
0N/A {
0N/A vboxnetadp_state_t *pState = RTMemAllocZ(sizeof(vboxnetadp_state_t));
0N/A if (pState)
0N/A {
0N/A pState->pDip = pDip;
0N/A
0N/A /*
0N/A * Setup GLD MAC layer registeration info.
0N/A */
0N/A pMacInfo->gldm_reset = vboxNetAdpSolarisStub;
0N/A pMacInfo->gldm_start = vboxNetAdpSolarisStub;
0N/A pMacInfo->gldm_stop = vboxNetAdpSolarisStub;
0N/A pMacInfo->gldm_set_mac_addr = vboxNetAdpSolarisSetMacAddress;
0N/A pMacInfo->gldm_set_multicast = vboxNetAdpSolarisSetMulticast;
0N/A pMacInfo->gldm_set_promiscuous = vboxNetAdpSolarisSetPromisc;
0N/A pMacInfo->gldm_send = vboxNetAdpSolarisSend;
0N/A pMacInfo->gldm_intr = NULL;
0N/A pMacInfo->gldm_get_stats = NULL;
0N/A pMacInfo->gldm_ioctl = NULL;
0N/A pMacInfo->gldm_ident = DEVICE_NAME;
0N/A pMacInfo->gldm_type = DL_ETHER;
0N/A pMacInfo->gldm_minpkt = 0;
0N/A pMacInfo->gldm_maxpkt = VBOXNETADP_MTU;
0N/A
0N/A AssertCompile(sizeof(RTMAC) == ETHERADDRL);
0N/A
0N/A pMacInfo->gldm_addrlen = ETHERADDRL;
0N/A pMacInfo->gldm_saplen = -2;
0N/A pMacInfo->gldm_broadcast_addr = achBroadcastAddr;
0N/A pMacInfo->gldm_ppa = ddi_get_instance(pState->pDip);
0N/A pMacInfo->gldm_devinfo = pState->pDip;
0N/A pMacInfo->gldm_private = (caddr_t)pState;
0N/A
0N/A /*
0N/A * We use a semi-random MAC addresses similar to a guest NIC's MAC address
0N/A * as the default factory address of the interface.
0N/A */
0N/A rc = vboxNetAdpSolarisGenerateMac(&pState->FactoryMac);
0N/A if (RT_SUCCESS(rc))
0N/A {
0N/A bcopy(&pState->FactoryMac, &pState->CurrentMac, sizeof(RTMAC));
0N/A pMacInfo->gldm_vendor_addr = (unsigned char *)&pState->FactoryMac;
0N/A
0N/A /*
0N/A * Now try registering our GLD with the MAC layer.
0N/A * Registeration can fail on some S10 versions when the MTU size is more than 1500.
0N/A * When we implement jumbo frames we should probably retry with MTU 1500 for S10.
0N/A */
0N/A rc = gld_register(pDip, (char *)ddi_driver_name(pDip), pMacInfo);
0N/A if (rc == DDI_SUCCESS)
0N/A {
0N/A ddi_report_dev(pDip);
0N/A return DDI_SUCCESS;
0N/A }
0N/A else
0N/A LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to register GLD. rc=%d\n", rc));
0N/A }
0N/A else
0N/A LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to generate mac address.rc=%d\n"));
0N/A
0N/A RTMemFree(pState);
0N/A }
0N/A else
0N/A LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to alloc state.\n"));
0N/A
0N/A gld_mac_free(pMacInfo);
0N/A }
0N/A else
0N/A LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to alloc mac structure.\n"));
0N/A return DDI_FAILURE;
0N/A }
0N/A
0N/A case DDI_RESUME:
0N/A {
0N/A /* Nothing to do here... */
0N/A return DDI_SUCCESS;
0N/A }
0N/A }
0N/A return DDI_FAILURE;
0N/A}
0N/A
0N/A
0N/A/**
0N/A * Detach entry point, to detach a device to the system or suspend it.
0N/A *
0N/A * @param pDip The module structure instance.
0N/A * @param enmCmd Operation type (detach/suspend).
0N/A *
0N/A * @returns corresponding solaris error code.
0N/A */
0N/Astatic int VBoxNetAdpSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
0N/A{
0N/A LogFlow((DEVICE_NAME ":VBoxNetAdpSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
0N/A
0N/A switch (enmCmd)
0N/A {
0N/A case DDI_DETACH:
0N/A {
0N/A /*
0N/A * Unregister and clean up.
0N/A */
0N/A gld_mac_info_t *pMacInfo = ddi_get_driver_private(pDip);
0N/A if (pMacInfo)
0N/A {
0N/A vboxnetadp_state_t *pState = (vboxnetadp_state_t *)pMacInfo->gldm_private;
0N/A if (pState)
0N/A {
0N/A int rc = gld_unregister(pMacInfo);
0N/A if (rc == DDI_SUCCESS)
0N/A {
0N/A RTMemFree(pState);
0N/A gld_mac_free(pMacInfo);
0N/A return DDI_SUCCESS;
0N/A }
0N/A else
0N/A LogRel((DEVICE_NAME ":VBoxNetAdpSolarisDetach failed to unregister GLD from MAC layer.rc=%d\n", rc));
0N/A }
0N/A else
0N/A LogRel((DEVICE_NAME ":VBoxNetAdpSolarisDetach failed to get internal state.\n"));
0N/A }
0N/A else
0N/A LogRel((DEVICE_NAME ":VBoxNetAdpSolarisDetach failed to get driver private GLD data.\n"));
0N/A
0N/A return DDI_FAILURE;
0N/A }
0N/A
0N/A case DDI_RESUME:
0N/A {
0N/A /* Nothing to do here... */
0N/A return DDI_SUCCESS;
0N/A }
0N/A }
0N/A return DDI_FAILURE;
0N/A}
0N/A
0N/A
0N/Astatic int vboxNetAdpSolarisGenerateMac(PRTMAC pMac)
0N/A{
0N/A pMac->au8[0] = 0x00;
0N/A pMac->au8[1] = 0x08;
0N/A pMac->au8[2] = 0x27;
0N/A
0N/A unsigned char achRand[3];
0N/A RTRandBytes(&achRand, sizeof(achRand));
0N/A
0N/A pMac->au8[3] = achRand[0];
0N/A pMac->au8[4] = achRand[1];
0N/A pMac->au8[5] = achRand[2];
0N/A
0N/A LogFlow((DEVICE_NAME ":VBoxNetAdpSolarisGenerateMac Generated %.*Rhxs\n", sizeof(RTMAC), &pMac));
0N/A return VINF_SUCCESS;
0N/A}
0N/A
0N/A
0N/Astatic int vboxNetAdpSolarisSetMacAddress(gld_mac_info_t *pMacInfo, unsigned char *pszMacAddr)
0N/A{
0N/A vboxnetadp_state_t *pState = (vboxnetadp_state_t *)pMacInfo->gldm_private;
0N/A if (pState)
0N/A {
0N/A bcopy(pszMacAddr, &pState->CurrentMac, sizeof(RTMAC));
0N/A LogFlow((DEVICE_NAME ":vboxNetAdpSolarisSetMacAddress updated MAC %.*Rhxs\n", sizeof(RTMAC), &pState->CurrentMac));
0N/A return GLD_SUCCESS;
0N/A }
0N/A else
0N/A LogRel((DEVICE_NAME ":vboxNetAdpSolarisSetMacAddress failed to get internal state.\n"));
0N/A return GLD_FAILURE;
0N/A}
0N/A
0N/A
0N/Astatic int vboxNetAdpSolarisSend(gld_mac_info_t *pMacInfo, mblk_t *pMsg)
0N/A{
0N/A return GLD_SUCCESS;
0N/A}
0N/A
0N/A
0N/Astatic int vboxNetAdpSolarisStub(gld_mac_info_t *pMacInfo)
0N/A{
0N/A NOREF(pMacInfo);
0N/A return GLD_SUCCESS;
0N/A}
0N/A
0N/A
0N/Astatic int vboxNetAdpSolarisSetMulticast(gld_mac_info_t *pMacInfo, unsigned char *pMulticastAddr, int fMulticast)
0N/A{
0N/A NOREF(pMacInfo);
0N/A NOREF(pMulticastAddr);
0N/A NOREF(fMulticast);
0N/A return GLD_SUCCESS;
0N/A}
0N/A
0N/A
0N/Astatic int vboxNetAdpSolarisSetPromisc(gld_mac_info_t *pMacInfo, int fPromisc)
0N/A{
0N/A
0N/A}
0N/A
0N/A