예제 #1
0
/*
 * DL_UDQOS_REQ
 */
static void
proto_udqos_req(dld_str_t *dsp, mblk_t *mp)
{
	dl_udqos_req_t *dlp = (dl_udqos_req_t *)mp->b_rptr;
	dl_qos_cl_sel1_t *selp;
	int		off, len;
	t_uscalar_t	dl_err;
	queue_t		*q = dsp->ds_wq;

	off = dlp->dl_qos_offset;
	len = dlp->dl_qos_length;

	if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) {
		dl_err = DL_BADPRIM;
		goto failed;
	}

	selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off);
	if (selp->dl_qos_type != DL_QOS_CL_SEL1) {
		dl_err = DL_BADQOSTYPE;
		goto failed;
	}

	if (selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 ||
	    selp->dl_priority < 0) {
		dl_err = DL_BADQOSPARAM;
		goto failed;
	}

	dsp->ds_pri = selp->dl_priority;
	dlokack(q, mp, DL_UDQOS_REQ);
	return;
failed:
	dlerrorack(q, mp, DL_UDQOS_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
/*
 * Bounds check payload area(s).
 */
static boolean_t
pbuf_ref_valid(multidata_t *mmd, pdescinfo_t *pdi)
{
	int i = 0, idx;
	boolean_t valid = B_TRUE;
	struct pld_ary_s *pa;

	mutex_enter(&mmd->mmd_pd_slab_lock);
	if (pdi->pld_cnt == 0 || pdi->pld_cnt > mmd->mmd_pbuf_cnt) {
		mutex_exit(&mmd->mmd_pd_slab_lock);
		return (B_FALSE);
	}

	pa = &pdi->pld_ary[0];
	while (valid && i < pdi->pld_cnt) {
		valid = (((idx = pa->pld_pbuf_idx) < mmd->mmd_pbuf_cnt) &&
		    pa->pld_rptr != NULL && pa->pld_wptr != NULL &&
		    pa->pld_wptr >= pa->pld_rptr &&
		    pa->pld_rptr >= mmd->mmd_pbuf[idx]->b_rptr &&
		    MBLKIN(mmd->mmd_pbuf[idx], (pa->pld_rptr -
			mmd->mmd_pbuf[idx]->b_rptr),
			PDESC_PLD_SPAN_SIZE(pdi, i)));

		if (!valid) {
			MMD_DEBUG((CE_WARN,
			    "pbuf_ref_valid: pdi 0x%p pld out of bound; "
			    "index %d has pld_cnt %d pbuf_idx %d "
			    "(mmd_pbuf_cnt %d), "
			    "pld_rptr 0x%p pld_wptr 0x%p len %d "
			    "(valid 0x%p-0x%p len %d)\n", (void *)pdi,
			    i, pdi->pld_cnt, idx, mmd->mmd_pbuf_cnt,
			    (void *)pa->pld_rptr,
			    (void *)pa->pld_wptr,
			    (int)PDESC_PLD_SPAN_SIZE(pdi, i),
			    (void *)mmd->mmd_pbuf[idx]->b_rptr,
			    (void *)mmd->mmd_pbuf[idx]->b_wptr,
			    (int)MBLKL(mmd->mmd_pbuf[idx])));
		}

		/* advance to next entry */
		i++;
		pa++;
	}

	mutex_exit(&mmd->mmd_pd_slab_lock);
	return (valid);
}
예제 #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_UINTDATA_REQ
 */
void
proto_unitdata_req(dld_str_t *dsp, mblk_t *mp)
{
	queue_t			*q = dsp->ds_wq;
	dl_unitdata_req_t	*dlp = (dl_unitdata_req_t *)mp->b_rptr;
	off_t			off;
	size_t			len, size;
	const uint8_t		*addr;
	uint16_t		sap;
	uint_t			addr_length;
	mblk_t			*bp, *payload;
	uint32_t		start, stuff, end, value, flags;
	t_uscalar_t		dl_err;
	uint_t			max_sdu;

	if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) {
		dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0);
		return;
	}

	mutex_enter(&dsp->ds_lock);
	if (dsp->ds_dlstate != DL_IDLE) {
		mutex_exit(&dsp->ds_lock);
		dlerrorack(q, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
		return;
	}
	DLD_DATATHR_INC(dsp);
	mutex_exit(&dsp->ds_lock);

	addr_length = dsp->ds_mip->mi_addr_length;

	off = dlp->dl_dest_addr_offset;
	len = dlp->dl_dest_addr_length;

	if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) {
		dl_err = DL_BADPRIM;
		goto failed;
	}

	if (len != addr_length + sizeof (uint16_t)) {
		dl_err = DL_BADADDR;
		goto failed;
	}

	addr = mp->b_rptr + off;
	sap = *(uint16_t *)(mp->b_rptr + off + addr_length);

	/*
	 * Check the length of the packet and the block types.
	 */
	size = 0;
	payload = mp->b_cont;
	for (bp = payload; bp != NULL; bp = bp->b_cont) {
		if (DB_TYPE(bp) != M_DATA)
			goto baddata;

		size += MBLKL(bp);
	}

	mac_sdu_get(dsp->ds_mh, NULL, &max_sdu);
	if (size > max_sdu)
		goto baddata;

	/*
	 * Build a packet header.
	 */
	if ((bp = dls_header(dsp, addr, sap, dlp->dl_priority.dl_max,
	    &payload)) == NULL) {
		dl_err = DL_BADADDR;
		goto failed;
	}

	/*
	 * We no longer need the M_PROTO header, so free it.
	 */
	freeb(mp);

	/*
	 * Transfer the checksum offload information if it is present.
	 */
	hcksum_retrieve(payload, NULL, NULL, &start, &stuff, &end, &value,
	    &flags);
	(void) hcksum_assoc(bp, NULL, NULL, start, stuff, end, value, flags, 0);

	/*
	 * Link the payload onto the new header.
	 */
	ASSERT(bp->b_cont == NULL);
	bp->b_cont = payload;

	/*
	 * No lock can be held across modules and putnext()'s,
	 * which can happen here with the call from DLD_TX().
	 */
	if (DLD_TX(dsp, bp, 0, 0) != NULL) {
		/* flow-controlled */
		DLD_SETQFULL(dsp);
	}
	DLD_DATATHR_DCR(dsp);
	return;

failed:
	dlerrorack(q, mp, DL_UNITDATA_REQ, dl_err, 0);
	DLD_DATATHR_DCR(dsp);
	return;

baddata:
	dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0);
	DLD_DATATHR_DCR(dsp);
}
예제 #6
0
/*
 * DL_CAPABILITY_REQ
 */
static void
proto_capability_req(dld_str_t *dsp, mblk_t *mp)
{
	dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr;
	dl_capability_sub_t *sp;
	size_t		size, len;
	offset_t	off, end;
	t_uscalar_t	dl_err;
	queue_t		*q = dsp->ds_wq;

	if (MBLKL(mp) < sizeof (dl_capability_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;
	}

	/*
	 * This request is overloaded. If there are no requested capabilities
	 * then we just want to acknowledge with all the capabilities we
	 * support. Otherwise we enable the set of capabilities requested.
	 */
	if (dlp->dl_sub_length == 0) {
		proto_capability_advertise(dsp, mp);
		return;
	}

	if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) {
		dl_err = DL_BADPRIM;
		goto failed;
	}

	dlp->dl_primitive = DL_CAPABILITY_ACK;

	off = dlp->dl_sub_offset;
	len = dlp->dl_sub_length;

	/*
	 * Walk the list of capabilities to be enabled.
	 */
	for (end = off + len; off < end; ) {
		sp = (dl_capability_sub_t *)(mp->b_rptr + off);
		size = sizeof (dl_capability_sub_t) + sp->dl_length;

		if (off + size > end ||
		    !IS_P2ALIGNED(off, sizeof (uint32_t))) {
			dl_err = DL_BADPRIM;
			goto failed;
		}

		switch (sp->dl_cap) {
		/*
		 * TCP/IP checksum offload to hardware.
		 */
		case DL_CAPAB_HCKSUM: {
			dl_capab_hcksum_t *hcksump;
			dl_capab_hcksum_t hcksum;

			hcksump = (dl_capab_hcksum_t *)&sp[1];
			/*
			 * Copy for alignment.
			 */
			bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t));
			dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
			bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t));
			break;
		}

		case DL_CAPAB_DLD: {
			dl_capab_dld_t	*dldp;
			dl_capab_dld_t	dld;

			dldp = (dl_capab_dld_t *)&sp[1];
			/*
			 * Copy for alignment.
			 */
			bcopy(dldp, &dld, sizeof (dl_capab_dld_t));
			dlcapabsetqid(&(dld.dld_mid), dsp->ds_rq);
			bcopy(&dld, dldp, sizeof (dl_capab_dld_t));
			break;
		}
		default:
			break;
		}
		off += size;
	}
	qreply(q, mp);
	return;
failed:
	dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0);
}
예제 #7
0
파일: mmd.c 프로젝트: mikess/illumos-gate
/* ARGSUSED */
int
pdesc_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
    multidata_t mmd;
    pdesc_t pd;
    pdescinfo_t *pdi = &pd.pd_pdi;
    pdesc_slab_t slab;
    mblk_t hbuf, pbuf[MULTIDATA_MAX_PBUFS];
    uint_t i, idx;
    boolean_t valid = B_TRUE;
    struct pld_ary_s *pa;

    if (!(flags & DCMD_ADDRSPEC) || argc != 0)
        return (DCMD_USAGE);

    if (mdb_vread(&pd, sizeof (pd), addr) == -1) {
        mdb_warn("couldn't read pdesc_t at %p", addr);
        return (DCMD_ERR);
    }

    if (pd.pd_magic != PDESC_MAGIC) {
        mdb_warn("Incorrect pdesc magic number at %p\n",
                 VA_OFF(addr, offsetof(pdesc_t, pd_magic)));
        return (DCMD_ERR);
    }

    if (mdb_vread(&slab, sizeof (slab), (uintptr_t)pd.pd_slab) == -1) {
        mdb_warn("couldn't read pdesc_slab_t at %p", pd.pd_slab);
        return (DCMD_ERR);
    }

    if (mdb_vread(&mmd, sizeof (mmd), (uintptr_t)slab.pds_mmd) == -1) {
        mdb_warn("couldn't read multidata_t at %p", slab.pds_mmd);
        return (DCMD_ERR);
    }

    if (mmd.mmd_magic != MULTIDATA_MAGIC)
        mdb_printf("Incorrect Multidata magic number at %p\n",
                   VA_OFF(slab.pds_mmd, offsetof(multidata_t, mmd_magic)));

    if (mmd.mmd_hbuf != 0 &&
            mdb_vread(&hbuf, sizeof (hbuf), (uintptr_t)mmd.mmd_hbuf) == -1) {
        mdb_warn("couldn't read mblk_t at %p", mmd.mmd_hbuf);
        return (DCMD_ERR);
    }

    if (mmd.mmd_pbuf_cnt > MULTIDATA_MAX_PBUFS) {
        mdb_warn("Multidata pbuf count exceeds %d\n",
                 MULTIDATA_MAX_PBUFS);
        return (DCMD_ERR);
    } else if (pdi->pld_cnt > mmd.mmd_pbuf_cnt) {
        mdb_warn("descriptor pbuf count exceeds Multidata "
                 "pbuf count %d\n", mmd.mmd_pbuf_cnt);
        return (DCMD_ERR);
    }

    if (mmd.mmd_pbuf_cnt > 0) {
        for (i = 0; i < mmd.mmd_pbuf_cnt; i++) {
            if (mdb_vread(&pbuf[i], sizeof (mblk_t),
                          (uintptr_t)mmd.mmd_pbuf[i]) == -1) {
                mdb_warn("couldn't read mblk_t at %p",
                         mmd.mmd_pbuf[i]);
                return (DCMD_ERR);
            }
        }
    }

    /* It should have at least one buffer reference */
    if (!(pdi->flags & PDESC_HAS_REF)) {
        mdb_warn("descriptor has no buffer reference indicator "
                 "in flags (0x%x)\n", pdi->flags);
        return (DCMD_ERR);
    } else if (!(pdi->flags & PDESC_PBUF_REF) && pdi->pld_cnt > 0) {
        mdb_warn("descriptor has no pbuf reference indicator in "
                 "flags (0x%x); but pld_cnt is %d\n", pdi->flags,
                 pdi->pld_cnt);
        return (DCMD_ERR);
    }

    /* Bounds check the header fragment, if any */
    if (!((pdi->flags & PDESC_HBUF_REF) && pdi->hdr_rptr != 0 &&
            pdi->hdr_wptr != 0 && pdi->hdr_base != 0 &&
            pdi->hdr_lim != 0 && pdi->hdr_lim >= pdi->hdr_base &&
            pdi->hdr_wptr >= pdi->hdr_rptr && pdi->hdr_base <= pdi->hdr_rptr &&
            pdi->hdr_lim >= pdi->hdr_wptr && pdi->hdr_base >= hbuf.b_rptr &&
            MBLKIN(&hbuf, (pdi->hdr_base - hbuf.b_rptr),
                   PDESC_HDRSIZE(pdi)))) {
        mdb_warn("descriptor has invalid header fragment\n");
        return (DCMD_ERR);
    }

    i = 0;
    pa = &pdi->pld_ary[0];
    /* Bounds check the payload fragment, if any */
    while (valid && i < pdi->pld_cnt) {
        valid = (((idx = pa->pld_pbuf_idx) < mmd.mmd_pbuf_cnt) &&
                 pa->pld_rptr != NULL && pa->pld_wptr != NULL &&
                 pa->pld_wptr >= pa->pld_rptr &&
                 pa->pld_rptr >= pbuf[idx].b_rptr &&
                 MBLKIN(&pbuf[idx], (pa->pld_rptr - pbuf[idx].b_rptr),
                        PDESC_PLD_SPAN_SIZE(pdi, i)));

        if (!valid) {
            mdb_warn("descriptor has invalid payload fragment\n");
            return (DCMD_ERR);
        }

        /* advance to next entry */
        i++;
        pa++;
    }

    return (DCMD_OK);
}