void dls_close(dls_channel_t dc) { dls_impl_t *dip = (dls_impl_t *)dc; dls_vlan_t *dvp; dls_link_t *dlp; dls_multicst_addr_t *p; dls_multicst_addr_t *nextp; dls_active_clear(dc); rw_enter(&(dip->di_lock), RW_WRITER); /* * Remove the notify function. */ mac_notify_remove(dip->di_mh, dip->di_mnh); dip->di_mnh = NULL; /* * If the dls_impl_t is bound then unbind it. */ dvp = dip->di_dvp; dlp = dvp->dv_dlp; if (dip->di_bound) { rw_exit(&(dip->di_lock)); dls_link_remove(dlp, dip); rw_enter(&(dip->di_lock), RW_WRITER); dip->di_bound = B_FALSE; } dip->di_rx = NULL; dip->di_rx_arg = NULL; /* * Walk the list of multicast addresses, disabling each at the MAC. */ for (p = dip->di_dmap; p != NULL; p = nextp) { (void) mac_multicst_remove(dip->di_mh, p->dma_addr); nextp = p->dma_nextp; kmem_free(p, sizeof (dls_multicst_addr_t)); } dip->di_dmap = NULL; rw_exit(&(dip->di_lock)); /* * If the MAC has been set in promiscuous mode then disable it. */ (void) dls_promisc(dc, 0); /* * Free the dls_impl_t back to the cache. */ dip->di_dvp = NULL; dip->di_txinfo = NULL; if (dip->di_soft_ring_list != NULL) { soft_ring_set_destroy(dip->di_soft_ring_list, dip->di_soft_ring_size); dip->di_soft_ring_list = NULL; } dip->di_soft_ring_size = 0; kmem_cache_free(i_dls_impl_cachep, dip); /* * Decrement the reference count to allow the cache to be destroyed * if there are no more dls_impl_t. */ atomic_add_32(&i_dls_impl_count, -1); /* * Release our reference to the dls_vlan_t allowing that to be * destroyed if there are no more dls_impl_t. An unreferenced tagged * vlan gets destroyed automatically. */ dls_vlan_rele(dvp); }
/* * DL_PROMISCOFF_REQ */ static void proto_promiscoff_req(dld_str_t *dsp, mblk_t *mp) { dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)mp->b_rptr; int err = 0; t_uscalar_t dl_err; uint32_t promisc_saved; queue_t *q = dsp->ds_wq; mac_perim_handle_t mph; if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) { dl_err = DL_BADPRIM; goto failed; } if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { dl_err = DL_OUTSTATE; goto failed; } promisc_saved = dsp->ds_promisc; switch (dlp->dl_level) { case DL_PROMISC_SAP: if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) { dl_err = DL_NOTENAB; goto failed; } dsp->ds_promisc &= ~DLS_PROMISC_SAP; break; case DL_PROMISC_MULTI: if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) { dl_err = DL_NOTENAB; goto failed; } dsp->ds_promisc &= ~DLS_PROMISC_MULTI; break; case DL_PROMISC_PHYS: if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) { dl_err = DL_NOTENAB; goto failed; } dsp->ds_promisc &= ~DLS_PROMISC_PHYS; break; default: dl_err = DL_NOTSUPPORTED; goto failed; } mac_perim_enter_by_mh(dsp->ds_mh, &mph); /* * Adjust channel promiscuity. */ err = dls_promisc(dsp, promisc_saved); if (err != 0) { mac_perim_exit(mph); dl_err = DL_SYSERR; goto failed; } if (dsp->ds_promisc == 0) dls_active_clear(dsp, B_FALSE); mac_perim_exit(mph); dlokack(q, mp, DL_PROMISCOFF_REQ); return; failed: dlerrorack(q, mp, DL_PROMISCOFF_REQ, dl_err, (t_uscalar_t)err); }