Exemplo n.º 1
0
/*
 * Do local shutdown processing..
 * All our links and the name have already been removed.
 * If we are a persistant device, we might refuse to go away.
 * In the case of a persistant node we signal the framework that we
 * are still in business by clearing the NGF_INVALID bit. However
 * If we find the NGF_REALLY_DIE bit set, this means that
 * we REALLY need to die (e.g. hardware removed).
 * This would have been set using the NG_NODE_REALLY_DIE(node)
 * macro in some device dependent function (not shown here) before
 * calling ng_rmnode_self().
 */
static int
ng_xxx_shutdown(node_p node)
{
	const xxx_p privdata = NG_NODE_PRIVATE(node);

#ifndef PERSISTANT_NODE
	NG_NODE_SET_PRIVATE(node, NULL);
	NG_NODE_UNREF(node);
	free(privdata, M_NETGRAPH);
#else
	if (node->nd_flags & NGF_REALLY_DIE) {
		/*
		 * WE came here because the widget card is being unloaded,
		 * so stop being persistant.
		 * Actually undo all the things we did on creation.
		 */
		NG_NODE_SET_PRIVATE(node, NULL);
		NG_NODE_UNREF(privdata->node);
		free(privdata, M_NETGRAPH);
		return (0);
	}
	NG_NODE_REVIVE(node);		/* tell ng_rmnode() we will persist */
#endif /* PERSISTANT_NODE */
	return (0);
}
Exemplo n.º 2
0
static int
ng_bt3c_shutdown(node_p node)
{
	bt3c_softc_p	sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);

	/* Let old node go */
	NG_NODE_SET_PRIVATE(node, NULL);
	NG_NODE_UNREF(node);

	/* Create new fresh one if we are not going down */
	if (sc == NULL)
		goto out;

	/* Create new Netgraph node */
	if (ng_make_node_common(&typestruct, &sc->node) != 0) {
		device_printf(sc->dev, "Could not create Netgraph node\n");
		sc->node = NULL;
		goto out;
	}

	/* Name new Netgraph node */
	if (ng_name_node(sc->node,  device_get_nameunit(sc->dev)) != 0) {
		device_printf(sc->dev, "Could not name Netgraph node\n");
		NG_NODE_UNREF(sc->node);
		sc->node = NULL;
		goto out;
	}

	NG_NODE_SET_PRIVATE(sc->node, sc);
out:
	return (0);
} /* ng_bt3c_shutdown */
static int
bt3c_pccard_detach(device_t dev)
{
	bt3c_softc_p	sc = (bt3c_softc_p) device_get_softc(dev);

	if (sc == NULL)
		return (0);

	unregister_swi(sc->ith, SWI_TTY, -1);
	sc->ith = NULL;

	bus_teardown_intr(dev, sc->irq, sc->irq_cookie);
	bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
	sc->irq_cookie = NULL;
	sc->irq = NULL;
	sc->irq_rid = 0;

	bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase);
	sc->iobase = NULL;
	sc->iobase_rid = 0;

	if (sc->node != NULL) {
		NG_NODE_SET_PRIVATE(sc->node, NULL);
		ng_rmnode_self(sc->node);
		sc->node = NULL;
	}

	NG_FREE_M(sc->m);
	IF_DRAIN(&sc->inq);
	IF_DRAIN(&sc->outq);

	return (0);
} /* bt3c_pccacd_detach */
Exemplo n.º 4
0
/*
 * Destroy node
 */
static int
ng_ksocket_shutdown(node_p node)
{
	const priv_p priv = NG_NODE_PRIVATE(node);
	priv_p embryo;

	/* Close our socket (if any) */
	if (priv->so != NULL) {
		atomic_clear_int(&priv->so->so_rcv.ssb_flags, SSB_UPCALL);
		atomic_clear_int(&priv->so->so_snd.ssb_flags, SSB_UPCALL);
		priv->so->so_upcall = NULL;
		soclose(priv->so, FNONBLOCK);
		priv->so = NULL;
	}

	/* If we are an embryo, take ourselves out of the parent's list */
	if (priv->flags & KSF_EMBRYONIC) {
		LIST_REMOVE(priv, siblings);
		priv->flags &= ~KSF_EMBRYONIC;
	}

	/* Remove any embryonic children we have */
	while (!LIST_EMPTY(&priv->embryos)) {
		embryo = LIST_FIRST(&priv->embryos);
		ng_rmnode_self(embryo->node);
	}

	/* Take down netgraph node */
	bzero(priv, sizeof(*priv));
	kfree(priv, M_NETGRAPH);
	NG_NODE_SET_PRIVATE(node, NULL);
	NG_NODE_UNREF(node);		/* let the node escape */
	return (0);
}
Exemplo n.º 5
0
int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
{
    char nam[NG_NODESIZ];
    struct ifnet *ifp;
    node_p node;
    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;

    VBOXCURVNET_SET_FROM_UCRED();
    NOREF(pvContext);
    ifp = ifunit(pThis->szName);
    if (ifp == NULL)
        return VERR_INTNET_FLT_IF_NOT_FOUND;

    /* Create a new netgraph node for this instance */
    if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0)
        return VERR_INTERNAL_ERROR;

    RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);

    ASMAtomicUoWritePtr(&pThis->u.s.ifp, ifp);
    pThis->u.s.node = node;
    bcopy(IF_LLADDR(ifp), &pThis->u.s.MacAddr, ETHER_ADDR_LEN);
    ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);

    /* Initialize deferred input queue */
    bzero(&pThis->u.s.inq, sizeof(struct ifqueue));
    mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN);
    TASK_INIT(&pThis->u.s.tskin, 0, vboxNetFltFreeBSDinput, pThis);

    /* Initialize deferred output queue */
    bzero(&pThis->u.s.outq, sizeof(struct ifqueue));
    mtx_init(&pThis->u.s.outq.ifq_mtx, "vboxnetflt outq", NULL, MTX_SPIN);
    TASK_INIT(&pThis->u.s.tskout, 0, vboxNetFltFreeBSDoutput, pThis);

    RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);

    NG_NODE_SET_PRIVATE(node, pThis);

    /* Attempt to name it vboxnetflt_<ifname> */
    snprintf(nam, NG_NODESIZ, "vboxnetflt_%s", pThis->szName);
    ng_name_node(node, nam);

    /* Report MAC address, promiscuous mode and GSO capabilities. */
    /** @todo keep these reports up to date, either by polling for changes or
     *        intercept some control flow if possible. */
    if (vboxNetFltTryRetainBusyNotDisconnected(pThis))
    {
        Assert(pThis->pSwitchPort);
        pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
        pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, vboxNetFltFreeBsdIsPromiscuous(pThis));
        pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
        pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
        vboxNetFltRelease(pThis, true /*fBusy*/);
    }
    VBOXCURVNET_RESTORE();

    return VINF_SUCCESS;
}
Exemplo n.º 6
0
/*
 * Shutdown node
 */
static int
ngfrm_shutdown(node_p node)
{
	const sc_p sc = NG_NODE_PRIVATE(node);

	NG_NODE_SET_PRIVATE(node, NULL);
	FREE(sc, M_NETGRAPH);
	NG_NODE_UNREF(node);
	return (0);
}
Exemplo n.º 7
0
/*
 * Do local shutdown processing..
 * Cut any remaining links and free our local resources.
 */
static int
nglmi_shutdown(node_p node)
{
	const sc_p sc = NG_NODE_PRIVATE(node);

	NG_NODE_SET_PRIVATE(node, NULL);
	NG_NODE_UNREF(sc->node);
	free(sc, M_NETGRAPH);
	return (0);
}
Exemplo n.º 8
0
static int
ng_split_shutdown(node_p node)
{
	const priv_p	priv = NG_NODE_PRIVATE(node);

	NG_NODE_SET_PRIVATE(node, NULL);
	NG_NODE_UNREF(node);
	free(priv, M_NETGRAPH);

	return (0);
}
Exemplo n.º 9
0
static int
ng_vlan_constructor(node_p node)
{
	priv_p priv;

	priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
	priv->decap_enable = 0;
	priv->encap_enable = VLAN_ENCAP_FROM_FILTER;
	priv->encap_proto = htons(ETHERTYPE_VLAN);
	NG_NODE_SET_PRIVATE(node, priv);
	return (0);
}
Exemplo n.º 10
0
/*
 * Node constructor
 */
static int
ngt_constructor(node_p node)
{
	sc_p privdata;

	MALLOC(privdata, sc_p, sizeof(*privdata), M_NETGRAPH, M_NOWAIT|M_ZERO);
	if (privdata == NULL)
		return (ENOMEM);

	NG_NODE_SET_PRIVATE(node, privdata);
	privdata->node = node;
	return (0);
}
Exemplo n.º 11
0
static int
ng_sscop_shutdown(node_p node)
{
	struct priv *priv = NG_NODE_PRIVATE(node);

	sscop_destroy(priv->sscop);

	free(priv, M_NG_SSCOP);
	NG_NODE_SET_PRIVATE(node, NULL);

	NG_NODE_UNREF(node);

	return (0);
}
Exemplo n.º 12
0
/*
 * Shutdown processing
 *
 * This is tricky. If we have both a left and right hook, then we
 * probably want to extricate ourselves and leave the two peers
 * still linked to each other. Otherwise we should just shut down as
 * a normal node would.
 *
 * To keep the scope of info correct the routine to "extract" a node
 * from two links is in ng_base.c.
 */
static int
ngt_shutdown(node_p node)
{
	const sc_p privdata = NG_NODE_PRIVATE(node);

#if 0 /* can never happen as cutlinks is already called */
	if (privdata->left.hook && privdata->right.hook)
		ng_bypass(privdata->left.hook, privdata->right.hook);
#endif
	NG_NODE_SET_PRIVATE(node, NULL);
	NG_NODE_UNREF(privdata->node);
	FREE(privdata, M_NETGRAPH);
	return (0);
}
Exemplo n.º 13
0
/*
 * Node constructor
 */
static int
ngfrm_constructor(node_p node)
{
	sc_p sc;

	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_NOWAIT | M_ZERO);
	if (!sc)
		return (ENOMEM);
	sc->addrlen = 2;	/* default */

	/* Link the node and our private info */
	NG_NODE_SET_PRIVATE(node, sc);
	sc->node = node;
	return (0);
}
Exemplo n.º 14
0
/*
 * Create a new node
 */
static int
ng_vjc_constructor(node_p node)
{
	priv_p priv;

	/* Allocate private structure */
	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
	if (priv == NULL)
		return (ENOMEM);

	NG_NODE_SET_PRIVATE(node, priv);

	/* Done */
	return (0);
}
Exemplo n.º 15
0
/*
 * Constructor for a node
 */
static int
ng_split_constructor(node_p node)
{
	priv_p		priv;

	/* Allocate node */
	priv = malloc(sizeof(*priv), M_NETGRAPH, M_ZERO | M_WAITOK);

	/* Link together node and private info */
	NG_NODE_SET_PRIVATE(node, priv);
	priv->node = node;

	/* Done */
	return (0);
}
Exemplo n.º 16
0
static int
ng_ubt_shutdown(node_p node)
{
	if (node->nd_flags & NGF_REALLY_DIE) {
		/*
                 * We came here because the USB device is being
		 * detached, so stop being persistent.
                 */
		NG_NODE_SET_PRIVATE(node, NULL);
		NG_NODE_UNREF(node);
	} else
		NG_NODE_REVIVE(node); /* tell ng_rmnode we are persisant */

	return (0);
} /* ng_ubt_shutdown */
Exemplo n.º 17
0
/*
 * Node constructor
 */
static int
nglmi_constructor(node_p node)
{
	sc_p sc;

	sc = malloc(sizeof(*sc), M_NETGRAPH, M_WAITOK | M_ZERO);

	NG_NODE_SET_PRIVATE(node, sc);
	sc->node = node;

	ng_callout_init(&sc->handle);
	sc->protoname = NAME_NONE;
	sc->liv_per_full = NG_LMI_SEQ_PER_FULL;	/* make this dynamic */
	sc->liv_rate = NG_LMI_KEEPALIVE_RATE;
	return (0);
}
Exemplo n.º 18
0
/*
 * NODE MANAGEMENT
 */
static int
ng_sscfu_constructor(node_p node)
{
	struct priv *priv;

	if ((priv = malloc(sizeof(*priv), M_NG_SSCFU, M_NOWAIT|M_ZERO)) == NULL)
		return (ENOMEM);

	if ((priv->sscf = sscfu_create(node, &sscfu_funcs)) == NULL) {
		free(priv, M_NG_SSCFU);
		return (ENOMEM);
	}

	NG_NODE_SET_PRIVATE(node, priv);

	return (0);
}
Exemplo n.º 19
0
/*
 * Allocate the private data structure. The generic node has already
 * been created. Link them together. We arrive with a reference to the node
 * i.e. the reference count is incremented for us already.
 *
 * If this were a device node than this work would be done in the attach()
 * routine and the constructor would return EINVAL as you should not be able
 * to creatednodes that depend on hardware (unless you can add the hardware :)
 */
static int
ng_xxx_constructor(node_p node)
{
	xxx_p privdata;
	int i;

	/* Initialize private descriptor */
	privdata = malloc(sizeof(*privdata), M_NETGRAPH, M_WAITOK | M_ZERO);
	for (i = 0; i < XXX_NUM_DLCIS; i++) {
		privdata->channel[i].dlci = -2;
		privdata->channel[i].channel = i;
	}

	/* Link structs together; this counts as our one reference to *nodep */
	NG_NODE_SET_PRIVATE(node, privdata);
	privdata->node = node;
	return (0);
}
Exemplo n.º 20
0
/*
 * Node type constructor
 * The NODE part is assumed to be all set up.
 * There is already a reference to the node for us.
 */
static int
ng_ksocket_constructor(node_p node)
{
	priv_p priv;

	/* Allocate private structure */
	priv = malloc(sizeof(*priv), M_NETGRAPH_KSOCKET, M_NOWAIT | M_ZERO);
	if (priv == NULL)
		return (ENOMEM);

	LIST_INIT(&priv->embryos);
	/* cross link them */
	priv->node = node;
	NG_NODE_SET_PRIVATE(node, priv);

	/* Done */
	return (0);
}
Exemplo n.º 21
0
/*
 * NODE MANAGEMENT
 */
static int
ng_sscop_constructor(node_p node)
{
	struct priv *p;

	if ((p = malloc(sizeof(*p), M_NG_SSCOP, M_NOWAIT | M_ZERO)) == NULL)
		return (ENOMEM);

	if ((p->sscop = sscop_create(node, &sscop_funcs)) == NULL) {
		free(p, M_NG_SSCOP);
		return (ENOMEM);
	}
	NG_NODE_SET_PRIVATE(node, p);

	/* All data message received by the node are expected to change the
	 * node's state. Therefor we must ensure, that we have a writer lock. */
	NG_NODE_FORCE_WRITER(node);

	return (0);
}
Exemplo n.º 22
0
/*
 * Do local shutdown processing.
 * In this case, that involves making sure the socket
 * knows we should be shutting down.
 */
static int
ngs_shutdown(node_p node)
{
	struct ngsock *const priv = NG_NODE_PRIVATE(node);
	struct ngpcb *const dpcbp = priv->datasock;
	struct ngpcb *const pcbp = priv->ctlsock;

	if (dpcbp != NULL)
		soisdisconnected(dpcbp->ng_socket);

	if (pcbp != NULL)
		soisdisconnected(pcbp->ng_socket);

	mtx_lock(&priv->mtx);
	priv->node = NULL;
	NG_NODE_SET_PRIVATE(node, NULL);
	ng_socket_free_priv(priv);

	NG_NODE_UNREF(node);
	return (0);
}
Exemplo n.º 23
0
static int
ng_attach_cntl(struct socket *so)
{
	struct ngsock *priv;
	struct ngpcb *pcbp;
	int error;

	/* Allocate node private info */
	priv = kmalloc(sizeof(*priv), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO);

	/* Setup protocol control block */
	if ((error = ng_attach_common(so, NG_CONTROL)) != 0) {
		kfree(priv, M_NETGRAPH_SOCK);
		return (error);
	}
	pcbp = sotongpcb(so);

	/* Link the pcb the private data. */
	priv->ctlsock = pcbp;
	pcbp->sockdata = priv;
	priv->refs++;

	/* Initialize mutex. */
	mtx_init(&priv->mtx, "ng_socket");

	/* Make the generic node components */
	if ((error = ng_make_node_common(&typestruct, &priv->node)) != 0) {
		kfree(priv, M_NETGRAPH_SOCK);
		ng_detach_common(pcbp, NG_CONTROL);
		return (error);
	}

	/* Link the node and the private data. */
	NG_NODE_SET_PRIVATE(priv->node, priv);
	NG_NODE_REF(priv->node);
	priv->refs++;

	return (0);
}
Exemplo n.º 24
0
Arquivo: udbp.c Projeto: MarginC/kame
/*
 * Do local shutdown processing..
 * We are a persistant device, we refuse to go away, and
 * only remove our links and reset ourself.
 */
Static int
ng_udbp_rmnode(node_p node)
{
	const udbp_p sc = NG_NODE_PRIVATE(node);
	int err;

	if (sc->flags & DISCONNECTED) {
		/* 
		 * WE are really going away.. hardware must have gone.
		 * Assume that the hardware drive part will clear up the 
		 * sc, in fact it may already have done so..
		 * In which case we may have just segfaulted..XXX
		 */
		return (0);
	}

	/* stolen from attach routine */
	/* Drain the queues */
	IF_DRAIN(&sc->xmitq_hipri);
	IF_DRAIN(&sc->xmitq);

	sc->packets_in = 0;		/* reset stats */
	sc->packets_out = 0;
	NG_NODE_UNREF(node);			/* forget it ever existed */

	if ((err = ng_make_node_common(&ng_udbp_typestruct, &sc->node)) == 0) {
		char	nodename[128];
		sprintf(nodename, "%s", USBDEVNAME(sc->sc_dev));
		if ((err = ng_name_node(sc->node, nodename))) {
			NG_NODE_UNREF(sc->node); /* out damned spot! */
			sc->flags &= ~NETGRAPH_INITIALISED;
			sc->node = NULL;
		} else {
			NG_NODE_SET_PRIVATE(sc->node, sc);
		}
	}
	return (err);
}
Exemplo n.º 25
0
/*
 * Destroy node
 */
static int
ng_ksocket_shutdown(node_p node)
{
	const priv_p priv = NG_NODE_PRIVATE(node);
	priv_p embryo;

	/* Close our socket (if any) */
	if (priv->so != NULL) {
		SOCKBUF_LOCK(&priv->so->so_rcv);
		soupcall_clear(priv->so, SO_RCV);
		SOCKBUF_UNLOCK(&priv->so->so_rcv);
		SOCKBUF_LOCK(&priv->so->so_snd);
		soupcall_clear(priv->so, SO_SND);
		SOCKBUF_UNLOCK(&priv->so->so_snd);
		soclose(priv->so);
		priv->so = NULL;
	}

	/* If we are an embryo, take ourselves out of the parent's list */
	if (priv->flags & KSF_EMBRYONIC) {
		LIST_REMOVE(priv, siblings);
		priv->flags &= ~KSF_EMBRYONIC;
	}

	/* Remove any embryonic children we have */
	while (!LIST_EMPTY(&priv->embryos)) {
		embryo = LIST_FIRST(&priv->embryos);
		ng_rmnode_self(embryo->node);
	}

	/* Take down netgraph node */
	bzero(priv, sizeof(*priv));
	free(priv, M_NETGRAPH_KSOCKET);
	NG_NODE_SET_PRIVATE(node, NULL);
	NG_NODE_UNREF(node);		/* let the node escape */
	return (0);
}
Exemplo n.º 26
0
static int
bt3c_pccard_attach(device_t dev)
{
	bt3c_softc_p	sc = (bt3c_softc_p) device_get_softc(dev);

	/* Allocate I/O ports */
	sc->iobase_rid = 0;
	sc->iobase = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT,
			&sc->iobase_rid, 8, RF_ACTIVE);
	if (sc->iobase == NULL) {
		device_printf(dev, "Could not allocate I/O ports\n");
		goto bad;
	}
	sc->iot = rman_get_bustag(sc->iobase);
	sc->ioh = rman_get_bushandle(sc->iobase);

	/* Allocate IRQ */
	sc->irq_rid = 0;
	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
			RF_ACTIVE);
	if (sc->irq == NULL) {
		device_printf(dev, "Could not allocate IRQ\n");
		goto bad;
	}

	sc->irq_cookie = NULL;
	if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, NULL, bt3c_intr, sc,
			&sc->irq_cookie) != 0) {
		device_printf(dev, "Could not setup ISR\n");
		goto bad;
	}

	/* Attach handler to TTY SWI thread */
	sc->ith = NULL;
	if (swi_add(&tty_intr_event, device_get_nameunit(dev),
			bt3c_swi_intr, sc, SWI_TTY, 0, &sc->ith) < 0) {
		device_printf(dev, "Could not setup SWI ISR\n");
		goto bad;
	}

	/* Create Netgraph node */
	if (ng_make_node_common(&typestruct, &sc->node) != 0) {
		device_printf(dev, "Could not create Netgraph node\n");
		sc->node = NULL;
		goto bad;
	}

	/* Name Netgraph node */
	if (ng_name_node(sc->node, device_get_nameunit(dev)) != 0) {
		device_printf(dev, "Could not name Netgraph node\n");
		NG_NODE_UNREF(sc->node);
		sc->node = NULL;
		goto bad;
	}

	sc->dev = dev;
	sc->debug = NG_BT3C_WARN_LEVEL;

	sc->inq.ifq_maxlen = sc->outq.ifq_maxlen = BT3C_DEFAULTQLEN;
	mtx_init(&sc->inq.ifq_mtx, "BT3C inq", NULL, MTX_DEF);
	mtx_init(&sc->outq.ifq_mtx, "BT3C outq", NULL, MTX_DEF);

	sc->state = NG_BT3C_W4_PKT_IND;
	sc->want = 1;

	NG_NODE_SET_PRIVATE(sc->node, sc);

	return (0);
bad:
	if (sc->ith != NULL) {
		swi_remove(sc->ith);
		sc->ith = NULL;
	}

	if (sc->irq != NULL) {
		if (sc->irq_cookie != NULL)
			bus_teardown_intr(dev, sc->irq, sc->irq_cookie);

		bus_release_resource(dev, SYS_RES_IRQ,
			sc->irq_rid, sc->irq);

		sc->irq = NULL;
		sc->irq_rid = 0;
	}

	if (sc->iobase != NULL) {
		bus_release_resource(dev, SYS_RES_IOPORT,
			sc->iobase_rid, sc->iobase);

		sc->iobase = NULL;
		sc->iobase_rid = 0;
	}

	return (ENXIO);
} /* bt3c_pccacd_attach */
Exemplo n.º 27
0
static int
ubt_attach(device_t dev)
{
	struct usb_attach_arg		*uaa = device_get_ivars(dev);
	struct ubt_softc		*sc = device_get_softc(dev);
	struct usb_endpoint_descriptor	*ed;
	struct usb_interface_descriptor *id;
	struct usb_interface		*iface;
	uint16_t			wMaxPacketSize;
	uint8_t				alt_index, i, j;
	uint8_t				iface_index[2] = { 0, 1 };

	device_set_usb_desc(dev);

	sc->sc_dev = dev;
	sc->sc_debug = NG_UBT_WARN_LEVEL;

	/* 
	 * Create Netgraph node
	 */

	if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) {
		UBT_ALERT(sc, "could not create Netgraph node\n");
		return (ENXIO);
	}

	/* Name Netgraph node */
	if (ng_name_node(sc->sc_node, device_get_nameunit(dev)) != 0) {
		UBT_ALERT(sc, "could not name Netgraph node\n");
		NG_NODE_UNREF(sc->sc_node);
		return (ENXIO);
	}
	NG_NODE_SET_PRIVATE(sc->sc_node, sc);
	NG_NODE_FORCE_WRITER(sc->sc_node);

	/*
	 * Initialize device softc structure
	 */

	/* initialize locks */
	mtx_init(&sc->sc_ng_mtx, "ubt ng", NULL, MTX_DEF);
	mtx_init(&sc->sc_if_mtx, "ubt if", NULL, MTX_DEF | MTX_RECURSE);

	/* initialize packet queues */
	NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN);
	NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN);
	NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN);

	/* initialize glue task */
	TASK_INIT(&sc->sc_task, 0, ubt_task, sc);

	/*
	 * Configure Bluetooth USB device. Discover all required USB
	 * interfaces and endpoints.
	 *
	 * USB device must present two interfaces:
	 * 1) Interface 0 that has 3 endpoints
	 *	1) Interrupt endpoint to receive HCI events
	 *	2) Bulk IN endpoint to receive ACL data
	 *	3) Bulk OUT endpoint to send ACL data
	 *
	 * 2) Interface 1 then has 2 endpoints
	 *	1) Isochronous IN endpoint to receive SCO data
 	 *	2) Isochronous OUT endpoint to send SCO data
	 *
	 * Interface 1 (with isochronous endpoints) has several alternate
	 * configurations with different packet size.
	 */

	/*
	 * For interface #1 search alternate settings, and find
	 * the descriptor with the largest wMaxPacketSize
	 */

	wMaxPacketSize = 0;
	alt_index = 0;
	i = 0;
	j = 0;
	ed = NULL;

	/* 
	 * Search through all the descriptors looking for the largest
	 * packet size:
	 */
	while ((ed = (struct usb_endpoint_descriptor *)usb_desc_foreach(
	    usbd_get_config_descriptor(uaa->device), 
	    (struct usb_descriptor *)ed))) {

		if ((ed->bDescriptorType == UDESC_INTERFACE) &&
		    (ed->bLength >= sizeof(*id))) {
			id = (struct usb_interface_descriptor *)ed;
			i = id->bInterfaceNumber;
			j = id->bAlternateSetting;
		}

		if ((ed->bDescriptorType == UDESC_ENDPOINT) &&
		    (ed->bLength >= sizeof(*ed)) &&
		    (i == 1)) {
			uint16_t temp;

			temp = UGETW(ed->wMaxPacketSize);
			if (temp > wMaxPacketSize) {
				wMaxPacketSize = temp;
				alt_index = j;
			}
		}
	}

	/* Set alt configuration on interface #1 only if we found it */
	if (wMaxPacketSize > 0 &&
	    usbd_set_alt_interface_index(uaa->device, 1, alt_index)) {
		UBT_ALERT(sc, "could not set alternate setting %d " \
			"for interface 1!\n", alt_index);
		goto detach;
	}

	/* Setup transfers for both interfaces */
	if (usbd_transfer_setup(uaa->device, iface_index, sc->sc_xfer,
			ubt_config, UBT_N_TRANSFER, sc, &sc->sc_if_mtx)) {
		UBT_ALERT(sc, "could not allocate transfers\n");
		goto detach;
	}

	/* Claim all interfaces belonging to the Bluetooth part */
	for (i = 1;; i++) {
		iface = usbd_get_iface(uaa->device, i);
		if (iface == NULL)
			break;
		id = usbd_get_interface_descriptor(iface);

		if ((id != NULL) &&
		    (id->bInterfaceClass == UICLASS_WIRELESS) &&
		    (id->bInterfaceSubClass == UISUBCLASS_RF) &&
		    (id->bInterfaceProtocol == UIPROTO_BLUETOOTH)) {
			usbd_set_parent_iface(uaa->device, i,
			    uaa->info.bIfaceIndex);
		}
	}
	return (0); /* success */

detach:
	ubt_detach(dev);

	return (ENXIO);
} /* ubt_attach */