Пример #1
0
/*
 * DL_UNBIND_REQ
 */
static void
proto_unbind_req(dld_str_t *dsp, mblk_t *mp)
{
	queue_t		*q = dsp->ds_wq;
	t_uscalar_t	dl_err;
	mac_perim_handle_t	mph;

	if (MBLKL(mp) < sizeof (dl_unbind_req_t)) {
		dl_err = DL_BADPRIM;
		goto failed;
	}

	if (dsp->ds_dlstate != DL_IDLE) {
		dl_err = DL_OUTSTATE;
		goto failed;
	}

	mutex_enter(&dsp->ds_lock);
	while (dsp->ds_datathr_cnt != 0)
		cv_wait(&dsp->ds_datathr_cv, &dsp->ds_lock);

	dsp->ds_dlstate = DL_UNBIND_PENDING;
	mutex_exit(&dsp->ds_lock);

	mac_perim_enter_by_mh(dsp->ds_mh, &mph);
	/*
	 * Unbind the channel to stop packets being received.
	 */
	dls_unbind(dsp);

	/*
	 * Disable polling mode, if it is enabled.
	 */
	(void) dld_capab_poll_disable(dsp, NULL);

	/*
	 * Clear LSO flags.
	 */
	dsp->ds_lso = B_FALSE;
	dsp->ds_lso_max = 0;

	/*
	 * Clear the receive callback.
	 */
	dls_rx_set(dsp, NULL, NULL);
	dsp->ds_direct = B_FALSE;

	/*
	 * Set the mode back to the default (unitdata).
	 */
	dsp->ds_mode = DLD_UNITDATA;
	dsp->ds_dlstate = DL_UNBOUND;

	dls_active_clear(dsp, B_FALSE);
	mac_perim_exit(mph);
	dlokack(dsp->ds_wq, mp, DL_UNBIND_REQ);
	return;
failed:
	dlerrorack(q, mp, DL_UNBIND_REQ, dl_err, 0);
}
Пример #2
0
/*
 * DL_ENABMULTI_REQ
 */
static void
proto_enabmulti_req(dld_str_t *dsp, mblk_t *mp)
{
	dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)mp->b_rptr;
	int		err = 0;
	t_uscalar_t	dl_err;
	queue_t		*q = dsp->ds_wq;
	mac_perim_handle_t	mph;

	if (dsp->ds_dlstate == DL_UNATTACHED ||
	    DL_ACK_PENDING(dsp->ds_dlstate)) {
		dl_err = DL_OUTSTATE;
		goto failed;
	}

	if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) ||
	    !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
	    dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
		dl_err = DL_BADPRIM;
		goto failed;
	}

	mac_perim_enter_by_mh(dsp->ds_mh, &mph);

	if ((dsp->ds_dmap == NULL) && (err = dls_active_set(dsp)) != 0) {
		dl_err = DL_SYSERR;
		goto failed2;
	}

	err = dls_multicst_add(dsp, mp->b_rptr + dlp->dl_addr_offset);
	if (err != 0) {
		switch (err) {
		case EINVAL:
			dl_err = DL_BADADDR;
			err = 0;
			break;
		case ENOSPC:
			dl_err = DL_TOOMANY;
			err = 0;
			break;
		default:
			dl_err = DL_SYSERR;
			break;
		}
		if (dsp->ds_dmap == NULL)
			dls_active_clear(dsp, B_FALSE);
		goto failed2;
	}

	mac_perim_exit(mph);

	dlokack(q, mp, DL_ENABMULTI_REQ);
	return;

failed2:
	mac_perim_exit(mph);
failed:
	dlerrorack(q, mp, DL_ENABMULTI_REQ, dl_err, (t_uscalar_t)err);
}
Пример #3
0
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);
}
Пример #4
0
/*
 * DL_SET_PHYS_ADDR_REQ
 */
static void
proto_setphysaddr_req(dld_str_t *dsp, mblk_t *mp)
{
	dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)mp->b_rptr;
	int		err = 0;
	t_uscalar_t	dl_err;
	queue_t		*q = dsp->ds_wq;
	mac_perim_handle_t	mph;

	if (dsp->ds_dlstate == DL_UNATTACHED ||
	    DL_ACK_PENDING(dsp->ds_dlstate)) {
		dl_err = DL_OUTSTATE;
		goto failed;
	}

	if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) ||
	    !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
	    dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
		dl_err = DL_BADPRIM;
		goto failed;
	}

	mac_perim_enter_by_mh(dsp->ds_mh, &mph);

	if ((err = dls_active_set(dsp)) != 0) {
		dl_err = DL_SYSERR;
		goto failed2;
	}

	/*
	 * If mac-nospoof is enabled and the link is owned by a
	 * non-global zone, changing the mac address is not allowed.
	 */
	if (dsp->ds_dlp->dl_zid != GLOBAL_ZONEID &&
	    mac_protect_enabled(dsp->ds_mch, MPT_MACNOSPOOF)) {
		dls_active_clear(dsp, B_FALSE);
		err = EACCES;
		goto failed2;
	}

	err = mac_unicast_primary_set(dsp->ds_mh,
	    mp->b_rptr + dlp->dl_addr_offset);
	if (err != 0) {
		switch (err) {
		case EINVAL:
			dl_err = DL_BADADDR;
			err = 0;
			break;

		default:
			dl_err = DL_SYSERR;
			break;
		}
		dls_active_clear(dsp, B_FALSE);
		goto failed2;

	}

	mac_perim_exit(mph);

	dlokack(q, mp, DL_SET_PHYS_ADDR_REQ);
	return;

failed2:
	mac_perim_exit(mph);
failed:
	dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, dl_err, (t_uscalar_t)err);
}
Пример #5
0
/*
 * 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);
}
Пример #6
0
/*
 * DL_BIND_REQ
 */
static void
proto_bind_req(dld_str_t *dsp, mblk_t *mp)
{
	dl_bind_req_t	*dlp = (dl_bind_req_t *)mp->b_rptr;
	int		err = 0;
	uint8_t		dlsap_addr[MAXMACADDRLEN + sizeof (uint16_t)];
	uint_t		dlsap_addr_length;
	t_uscalar_t	dl_err;
	t_scalar_t	sap;
	queue_t		*q = dsp->ds_wq;
	mac_perim_handle_t	mph;
	void		*mdip;
	int32_t		intr_cpu;

	if (MBLKL(mp) < sizeof (dl_bind_req_t)) {
		dl_err = DL_BADPRIM;
		goto failed;
	}

	if (dlp->dl_xidtest_flg != 0) {
		dl_err = DL_NOAUTO;
		goto failed;
	}

	if (dlp->dl_service_mode != DL_CLDLS) {
		dl_err = DL_UNSUPPORTED;
		goto failed;
	}

	if (dsp->ds_dlstate != DL_UNBOUND) {
		dl_err = DL_OUTSTATE;
		goto failed;
	}

	mac_perim_enter_by_mh(dsp->ds_mh, &mph);

	if ((err = dls_active_set(dsp)) != 0) {
		dl_err = DL_SYSERR;
		goto failed2;
	}

	dsp->ds_dlstate = DL_BIND_PENDING;
	/*
	 * Set the receive callback.
	 */
	dls_rx_set(dsp, (dsp->ds_mode == DLD_RAW) ?
	    dld_str_rx_raw : dld_str_rx_unitdata, dsp);

	/*
	 * Bind the channel such that it can receive packets.
	 */
	sap = dlp->dl_sap;
	dsp->ds_nonip = !check_mod_above(dsp->ds_rq, "ip") &&
	    !check_mod_above(dsp->ds_rq, "arp");

	err = dls_bind(dsp, sap);
	if (err != 0) {
		switch (err) {
		case EINVAL:
			dl_err = DL_BADADDR;
			err = 0;
			break;
		default:
			dl_err = DL_SYSERR;
			break;
		}

		dsp->ds_dlstate = DL_UNBOUND;
		dls_active_clear(dsp, B_FALSE);
		goto failed2;
	}

	intr_cpu = mac_client_intr_cpu(dsp->ds_mch);
	mdip = mac_get_devinfo(dsp->ds_mh);
	mac_perim_exit(mph);

	/*
	 * We do this after we get out of the perim to avoid deadlocks
	 * etc. since part of mac_client_retarget_intr is to walk the
	 * device tree in order to find and retarget the interrupts.
	 */
	if (intr_cpu != -1)
		mac_client_set_intr_cpu(mdip, dsp->ds_mch, intr_cpu);

	/*
	 * Copy in MAC address.
	 */
	dlsap_addr_length = dsp->ds_mip->mi_addr_length;
	mac_unicast_primary_get(dsp->ds_mh, dlsap_addr);

	/*
	 * Copy in the SAP.
	 */
	*(uint16_t *)(dlsap_addr + dlsap_addr_length) = sap;
	dlsap_addr_length += sizeof (uint16_t);

	dsp->ds_dlstate = DL_IDLE;
	dlbindack(q, mp, sap, dlsap_addr, dlsap_addr_length, 0, 0);
	return;

failed2:
	mac_perim_exit(mph);
failed:
	dlerrorack(q, mp, DL_BIND_REQ, dl_err, (t_uscalar_t)err);
}