Esempio n. 1
0
/*
 * Bind a PF_PACKET socket to a network interface.
 *
 * The default operation of this bind() is to place the socket (and thus the
 * network interface) into promiscuous mode. It is then up to the application
 * to turn that down by issuing the relevant ioctls, if desired.
 */
static int
sdpfp_bind(sock_lower_handle_t handle, struct sockaddr *addr,
    socklen_t addrlen, struct cred *cred)
{
	struct sockaddr_ll *addr_ll, *sol;
	mac_client_handle_t mch;
	struct pfpsock *ps;
	mac_handle_t mh;
	int error;

	ps = (struct pfpsock *)handle;
	if (ps->ps_bound)
		return (EINVAL);

	if (addrlen < sizeof (struct sockaddr_ll) || addr == NULL)
		return (EINVAL);

	addr_ll = (struct sockaddr_ll *)addr;

	error = pfp_open_index(addr_ll->sll_ifindex, &mh, &mch, cred);
	if (error != 0)
		return (error);
	/*
	 * Ensure that each socket is only bound once.
	 */
	mutex_enter(&ps->ps_lock);
	if (ps->ps_mh != 0) {
		mutex_exit(&ps->ps_lock);
		pfp_close(mh, mch);
		return (EADDRINUSE);
	}
	ps->ps_mh = mh;
	ps->ps_mch = mch;
	mutex_exit(&ps->ps_lock);

	/*
	 * Cache all of the information from bind so that it's in an easy
	 * place to get at when packets are received.
	 */
	sol = &ps->ps_sock;
	sol->sll_family = AF_PACKET;
	sol->sll_ifindex = addr_ll->sll_ifindex;
	sol->sll_protocol = addr_ll->sll_protocol;
	sol->sll_halen = mac_addr_len(ps->ps_mh);
	mac_unicast_primary_get(ps->ps_mh, sol->sll_addr);
	mac_sdu_get(ps->ps_mh, NULL, &ps->ps_max_sdu);
	ps->ps_linkid = addr_ll->sll_ifindex;

	error = mac_promisc_add(ps->ps_mch, MAC_CLIENT_PROMISC_ALL,
	    pfp_packet, ps, &ps->ps_phd, MAC_PROMISC_FLAGS_VLAN_TAG_STRIP);
	if (error == 0) {
		ps->ps_promisc = MAC_CLIENT_PROMISC_ALL;
		ps->ps_bound = B_TRUE;
	}

	return (error);
}
Esempio n. 2
0
/*
 * DL_PHYS_ADDR_REQ
 */
static void
proto_physaddr_req(dld_str_t *dsp, mblk_t *mp)
{
	dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)mp->b_rptr;
	queue_t		*q = dsp->ds_wq;
	t_uscalar_t	dl_err = 0;
	char		*addr = NULL;
	uint_t		addr_length;

	if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) {
		dl_err = DL_BADPRIM;
		goto done;
	}

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

	addr_length = dsp->ds_mip->mi_addr_length;
	if (addr_length > 0) {
		addr = kmem_alloc(addr_length, KM_SLEEP);
		switch (dlp->dl_addr_type) {
		case DL_CURR_PHYS_ADDR:
			mac_unicast_primary_get(dsp->ds_mh, (uint8_t *)addr);
			break;
		case DL_FACT_PHYS_ADDR:
			bcopy(dsp->ds_mip->mi_unicst_addr, addr, addr_length);
			break;
		case DL_CURR_DEST_ADDR:
			if (!mac_dst_get(dsp->ds_mh, (uint8_t *)addr))
				dl_err = DL_NOTSUPPORTED;
			break;
		default:
			dl_err = DL_UNSUPPORTED;
		}
	}
done:
	if (dl_err == 0)
		dlphysaddrack(q, mp, addr, (t_uscalar_t)addr_length);
	else
		dlerrorack(q, mp, DL_PHYS_ADDR_REQ, dl_err, 0);
	if (addr != NULL)
		kmem_free(addr, addr_length);
}
Esempio n. 3
0
static void
vnic_notify_cb(void *arg, mac_notify_type_t type)
{
	vnic_t *vnic = arg;

	/*
	 * Do not deliver notifications if the vnic is not fully initialized
	 * or is in process of being torn down.
	 */
	if (!vnic->vn_enabled)
		return;

	switch (type) {
	case MAC_NOTE_UNICST:
		/*
		 * Only the VLAN VNIC needs to be notified with primary MAC
		 * address change.
		 */
		if (vnic->vn_addr_type != VNIC_MAC_ADDR_TYPE_PRIMARY)
			return;

		/*  the unicast MAC address value */
		mac_unicast_primary_get(vnic->vn_lower_mh, vnic->vn_addr);

		/* notify its upper layer MAC about MAC address change */
		mac_unicst_update(vnic->vn_mh, (const uint8_t *)vnic->vn_addr);
		break;

	case MAC_NOTE_LINK:
		mac_link_update(vnic->vn_mh,
		    mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE));
		break;

	default:
		break;
	}
}
/* ARGSUSED */
static int
sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod,
    int32_t *rval, struct cred *cr)
{
#if defined(_SYSCALL32)
	struct timeval32 tival;
#else
	struct timeval tival;
#endif
	mac_client_promisc_type_t mtype;
	datalink_id_t linkid;
	struct lifreq lifreq;
	struct ifreq ifreq;
	struct pfpsock *ps;
	mac_handle_t mh;
	timespec_t tv;
	int error;

	switch (cmd) {
	/*
	 * ioctls that work on "struct lifreq"
	 */
	case SIOCSLIFFLAGS :
	case SIOCGLIFINDEX :
	case SIOCGLIFFLAGS :
	case SIOCGLIFMTU :
		error = pfp_lifreq_getlinkid(arg, &lifreq, &linkid);
		if (error != 0)
			return (error);
		break;

	/*
	 * ioctls that work on "struct ifreq".
	 * Not all of these have a "struct lifreq" partner, for example
	 * SIOCGIFHWADDR, for the simple reason that the logical interface
	 * does not have a hardware address.
	 */
	case SIOCSIFFLAGS :
	case SIOCGIFINDEX :
	case SIOCGIFFLAGS :
	case SIOCGIFMTU :
	case SIOCGIFHWADDR :
		error = pfp_ifreq_getlinkid(arg, &ifreq, &linkid);
		if (error != 0)
			return (error);
		break;
	}

	error =  mac_open_by_linkid(linkid, &mh);
	if (error != 0)
		return (error);

	ps = (struct pfpsock *)handle;

	switch (cmd) {
	case SIOCGLIFINDEX :
		lifreq.lifr_index = linkid;
		break;

	case SIOCGIFINDEX :
		ifreq.ifr_index = linkid;
		break;

	case SIOCGIFFLAGS :
		ifreq.ifr_flags = IFF_RUNNING;
		if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL)
			ifreq.ifr_flags |= IFF_PROMISC;
		break;

	case SIOCGLIFFLAGS :
		lifreq.lifr_flags = IFF_RUNNING;
		if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL)
			lifreq.lifr_flags |= IFF_PROMISC;
		break;

	case SIOCSIFFLAGS :
		if (linkid != ps->ps_linkid) {
			error = EINVAL;
		} else {
			if ((ifreq.ifr_flags & IFF_PROMISC) != 0)
				mtype = MAC_CLIENT_PROMISC_ALL;
			else
				mtype = MAC_CLIENT_PROMISC_FILTERED;
			error = pfp_set_promisc(ps, mtype);
		}
		break;

	case SIOCSLIFFLAGS :
		if (linkid != ps->ps_linkid) {
			error = EINVAL;
		} else {
			if ((lifreq.lifr_flags & IFF_PROMISC) != 0)
				mtype = MAC_CLIENT_PROMISC_ALL;
			else
				mtype = MAC_CLIENT_PROMISC_FILTERED;
			error = pfp_set_promisc(ps, mtype);
		}
		break;

	case SIOCGIFMTU :
		mac_sdu_get(mh, NULL, &ifreq.ifr_mtu);
		break;

	case SIOCGLIFMTU :
		mac_sdu_get(mh, NULL, &lifreq.lifr_mtu);
		break;

	case SIOCGIFHWADDR :
		mac_unicast_primary_get(mh, (uint8_t *)ifreq.ifr_addr.sa_data);
		ifreq.ifr_addr.sa_family = pfp_dl_to_arphrd(mac_type(mh));
		break;

	case SIOCGSTAMP :
		(void) gethrestime(&tv);
		tival.tv_sec = (time_t)tv.tv_sec;
		tival.tv_usec = tv.tv_nsec / 1000;
		error = ddi_copyout(&tival, (void *)arg, sizeof (tival), 0);
		break;

	default :
		break;
	}

	mac_close(mh);

	if (error == 0) {
		/*
		 * Only the "GET" ioctls need to copy data back to userace.
		 */
		switch (cmd) {
		case SIOCGLIFINDEX :
		case SIOCGLIFFLAGS :
		case SIOCGLIFMTU :
			error = ddi_copyout(&lifreq, (void *)arg,
			    sizeof (lifreq), 0);
			break;

		case SIOCGIFINDEX :
		case SIOCGIFFLAGS :
		case SIOCGIFMTU :
		case SIOCGIFHWADDR :
			error = ddi_copyout(&ifreq, (void *)arg,
			    sizeof (ifreq), 0);
			break;
		default :
			break;
		}
	}

	return (error);
}
Esempio n. 5
0
/*
 * Program the macaddress and vlans of a port.
 *
 * Returns 0 on sucess, 1 on failure.
 */
static int
vsw_set_if_hw_addr(vsw_t *vswp)
{
	mac_diag_t		diag;
	uint8_t			*macaddr;
	uint8_t			primary_addr[ETHERADDRL];
	uint16_t		vid = VLAN_ID_NONE;
	int			rv;
	uint16_t		mac_flags = MAC_UNICAST_TAG_DISABLE |
	    MAC_UNICAST_STRIP_DISABLE;

	D1(vswp, "%s: enter", __func__);

	ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
	if (vswp->mch == NULL)
		return (0);

	macaddr = (uint8_t *)vswp->if_addr.ether_addr_octet;

	/* check if it is the primary macaddr of the card. */
	mac_unicast_primary_get(vswp->mh, primary_addr);
	if (ether_cmp((void *)primary_addr, (void*)macaddr) == 0) {
		mac_flags |= MAC_UNICAST_PRIMARY;
	}

	/*
	 * If the interface has a specific 'pvid', then
	 * register with that vlan-id, otherwise register
	 * with VLAN_ID_NONE.
	 */
	if (vswp->pvid != vswp->default_vlan_id) {
		vid = vswp->pvid;
	}

	if (!(vswp->smode & VSW_LAYER2_PROMISC)) {
		mac_flags |= MAC_UNICAST_HW;
	}

	if (vswp->addr_set == B_FALSE) {
		vswp->muh = NULL;
		rv = mac_unicast_add(vswp->mch, macaddr, mac_flags,
		    &vswp->muh, vid, &diag);

		if (rv != 0) {
			cmn_err(CE_WARN, "vsw%d: Failed to program"
			    "macaddr,vid(%s, %d) err=%d",
			    vswp->instance, ether_sprintf((void *)macaddr),
			    vid, rv);
			return (rv);
		}
		vswp->addr_set = B_TRUE;

		D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s",
		    __func__, ether_sprintf((void *)macaddr), vid,
		    vswp->physname);
	}

	vsw_mac_add_vlans(vswp, vswp->mch, macaddr, mac_flags,
	    vswp->vids, vswp->nvids);

	vsw_maccl_set_bandwidth(vswp, NULL, VSW_LOCALDEV, vswp->bandwidth);

	mac_rx_set(vswp->mch, vsw_if_rx_cb, (void *)vswp);

	D1(vswp, "%s: exit", __func__);
	return (rv);
}
Esempio n. 6
0
static int
vnic_unicast_add(vnic_t *vnic, vnic_mac_addr_type_t vnic_addr_type,
    int *addr_slot, uint_t prefix_len, int *addr_len_ptr_arg,
    uint8_t *mac_addr_arg, uint16_t flags, vnic_ioc_diag_t *diag,
    uint16_t vid, boolean_t req_hwgrp_flag)
{
	mac_diag_t mac_diag;
	uint16_t mac_flags = 0;
	int err;
	uint_t addr_len;

	if (flags & VNIC_IOC_CREATE_NODUPCHECK)
		mac_flags |= MAC_UNICAST_NODUPCHECK;

	switch (vnic_addr_type) {
	case VNIC_MAC_ADDR_TYPE_FIXED:
	case VNIC_MAC_ADDR_TYPE_VRID:
		/*
		 * The MAC address value to assign to the VNIC
		 * is already provided in mac_addr_arg. addr_len_ptr_arg
		 * already contains the MAC address length.
		 */
		break;

	case VNIC_MAC_ADDR_TYPE_RANDOM:
		/*
		 * Random MAC address. There are two sub-cases:
		 *
		 * 1 - If mac_len == 0, a new MAC address is generated.
		 *	The length of the MAC address to generated depends
		 *	on the type of MAC used. The prefix to use for the MAC
		 *	address is stored in the most significant bytes
		 *	of the mac_addr argument, and its length is specified
		 *	by the mac_prefix_len argument. This prefix can
		 *	correspond to a IEEE OUI in the case of Ethernet,
		 *	for example.
		 *
		 * 2 - If mac_len > 0, the address was already picked
		 *	randomly, and is now passed back during VNIC
		 *	re-creation. The mac_addr argument contains the MAC
		 *	address that was generated. We distinguish this
		 *	case from the fixed MAC address case, since we
		 *	want the user consumers to know, when they query
		 *	the list of VNICs, that a VNIC was assigned a
		 *	random MAC address vs assigned a fixed address
		 *	specified by the user.
		 */

		/*
		 * If it's a pre-generated address, we're done. mac_addr_arg
		 * and addr_len_ptr_arg already contain the MAC address
		 * value and length.
		 */
		if (*addr_len_ptr_arg > 0)
			break;

		/* generate a new random MAC address */
		if ((err = mac_addr_random(vnic->vn_mch,
		    prefix_len, mac_addr_arg, &mac_diag)) != 0) {
			*diag = vnic_mac2vnic_diag(mac_diag);
			return (err);
		}
		*addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
		break;

	case VNIC_MAC_ADDR_TYPE_FACTORY:
		err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot);
		if (err != 0) {
			if (err == EINVAL)
				*diag = VNIC_IOC_DIAG_MACFACTORYSLOTINVALID;
			if (err == EBUSY)
				*diag = VNIC_IOC_DIAG_MACFACTORYSLOTUSED;
			if (err == ENOSPC)
				*diag = VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED;
			return (err);
		}

		mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot,
		    mac_addr_arg, &addr_len, NULL, NULL);
		*addr_len_ptr_arg = addr_len;
		break;

	case VNIC_MAC_ADDR_TYPE_AUTO:
		/* first try to allocate a factory MAC address */
		err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot);
		if (err == 0) {
			mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot,
			    mac_addr_arg, &addr_len, NULL, NULL);
			vnic_addr_type = VNIC_MAC_ADDR_TYPE_FACTORY;
			*addr_len_ptr_arg = addr_len;
			break;
		}

		/*
		 * Allocating a factory MAC address failed, generate a
		 * random MAC address instead.
		 */
		if ((err = mac_addr_random(vnic->vn_mch,
		    prefix_len, mac_addr_arg, &mac_diag)) != 0) {
			*diag = vnic_mac2vnic_diag(mac_diag);
			return (err);
		}
		*addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
		vnic_addr_type = VNIC_MAC_ADDR_TYPE_RANDOM;
		break;
	case VNIC_MAC_ADDR_TYPE_PRIMARY:
		/*
		 * We get the address here since we copy it in the
		 * vnic's vn_addr.
		 * We can't ask for hardware resources since we
		 * don't currently support hardware classification
		 * for these MAC clients.
		 */
		if (req_hwgrp_flag) {
			*diag = VNIC_IOC_DIAG_NO_HWRINGS;
			return (ENOTSUP);
		}
		mac_unicast_primary_get(vnic->vn_lower_mh, mac_addr_arg);
		*addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
		mac_flags |= MAC_UNICAST_VNIC_PRIMARY;
		break;
	}

	vnic->vn_addr_type = vnic_addr_type;

	err = mac_unicast_add(vnic->vn_mch, mac_addr_arg, mac_flags,
	    &vnic->vn_muh, vid, &mac_diag);
	if (err != 0) {
		if (vnic_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) {
			/* release factory MAC address */
			mac_addr_factory_release(vnic->vn_mch, *addr_slot);
		}
		*diag = vnic_mac2vnic_diag(mac_diag);
	}

	return (err);
}
Esempio n. 7
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);
}
Esempio n. 8
0
/*
 * DL_INFO_REQ
 */
static void
proto_info_req(dld_str_t *dsp, mblk_t *mp)
{
	dl_info_ack_wrapper_t	*dlwp;
	dl_info_ack_t		*dlp;
	dl_qos_cl_sel1_t	*selp;
	dl_qos_cl_range1_t	*rangep;
	uint8_t			*addr;
	uint8_t			*brdcst_addr;
	uint_t			addr_length;
	uint_t			sap_length;
	mac_info_t		minfo;
	mac_info_t		*minfop;
	queue_t			*q = dsp->ds_wq;

	/*
	 * Swap the request message for one large enough to contain the
	 * wrapper structure defined above.
	 */
	if ((mp = mexchange(q, mp, sizeof (dl_info_ack_wrapper_t),
	    M_PCPROTO, 0)) == NULL)
		return;

	bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t));
	dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr;

	dlp = &(dlwp->dl_info);
	ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr);

	dlp->dl_primitive = DL_INFO_ACK;

	/*
	 * Set up the sub-structure pointers.
	 */
	addr = dlwp->dl_addr;
	brdcst_addr = dlwp->dl_brdcst_addr;
	rangep = &(dlwp->dl_qos_range1);
	selp = &(dlwp->dl_qos_sel1);

	/*
	 * This driver supports only version 2 connectionless DLPI provider
	 * nodes.
	 */
	dlp->dl_service_mode = DL_CLDLS;
	dlp->dl_version = DL_VERSION_2;

	/*
	 * Set the style of the provider
	 */
	dlp->dl_provider_style = dsp->ds_style;
	ASSERT(dlp->dl_provider_style == DL_STYLE1 ||
	    dlp->dl_provider_style == DL_STYLE2);

	/*
	 * Set the current DLPI state.
	 */
	dlp->dl_current_state = dsp->ds_dlstate;

	/*
	 * Gratuitously set the media type. This is to deal with modules
	 * that assume the media type is known prior to DL_ATTACH_REQ
	 * being completed.
	 */
	dlp->dl_mac_type = DL_ETHER;

	/*
	 * If the stream is not at least attached we try to retrieve the
	 * mac_info using mac_info_get()
	 */
	if (dsp->ds_dlstate == DL_UNATTACHED ||
	    dsp->ds_dlstate == DL_ATTACH_PENDING ||
	    dsp->ds_dlstate == DL_DETACH_PENDING) {
		if (!mac_info_get(ddi_major_to_name(dsp->ds_major), &minfo)) {
			/*
			 * Cannot find mac_info. giving up.
			 */
			goto done;
		}
		minfop = &minfo;
	} else {
		minfop = (mac_info_t *)dsp->ds_mip;
		/* We can only get the sdu if we're attached. */
		mac_sdu_get(dsp->ds_mh, &dlp->dl_min_sdu, &dlp->dl_max_sdu);
	}

	/*
	 * Set the media type (properly this time).
	 */
	if (dsp->ds_native)
		dlp->dl_mac_type = minfop->mi_nativemedia;
	else
		dlp->dl_mac_type = minfop->mi_media;

	/*
	 * Set the DLSAP length. We only support 16 bit values and they
	 * appear after the MAC address portion of DLSAP addresses.
	 */
	sap_length = sizeof (uint16_t);
	dlp->dl_sap_length = NEG(sap_length);

	addr_length = minfop->mi_addr_length;

	/*
	 * Copy in the media broadcast address.
	 */
	if (minfop->mi_brdcst_addr != NULL) {
		dlp->dl_brdcst_addr_offset =
		    (uintptr_t)brdcst_addr - (uintptr_t)dlp;
		bcopy(minfop->mi_brdcst_addr, brdcst_addr, addr_length);
		dlp->dl_brdcst_addr_length = addr_length;
	}

	/* Only VLAN links and links that have a normal tag mode support QOS. */
	if ((dsp->ds_mch != NULL &&
	    mac_client_vid(dsp->ds_mch) != VLAN_ID_NONE) ||
	    (dsp->ds_dlp != NULL &&
	    dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_NORMAL)) {
		dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp;
		dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);

		rangep->dl_qos_type = DL_QOS_CL_RANGE1;
		rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN;
		rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN;
		rangep->dl_protection.dl_min = DL_UNKNOWN;
		rangep->dl_protection.dl_max = DL_UNKNOWN;
		rangep->dl_residual_error = DL_UNKNOWN;

		/*
		 * Specify the supported range of priorities.
		 */
		rangep->dl_priority.dl_min = 0;
		rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1;

		dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp;
		dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);

		selp->dl_qos_type = DL_QOS_CL_SEL1;
		selp->dl_trans_delay = DL_UNKNOWN;
		selp->dl_protection = DL_UNKNOWN;
		selp->dl_residual_error = DL_UNKNOWN;

		/*
		 * Specify the current priority (which can be changed by
		 * the DL_UDQOS_REQ primitive).
		 */
		selp->dl_priority = dsp->ds_pri;
	}

	dlp->dl_addr_length = addr_length + sizeof (uint16_t);
	if (dsp->ds_dlstate == DL_IDLE) {
		/*
		 * The stream is bound. Therefore we can formulate a valid
		 * DLSAP address.
		 */
		dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp;
		if (addr_length > 0)
			mac_unicast_primary_get(dsp->ds_mh, addr);

		*(uint16_t *)(addr + addr_length) = dsp->ds_sap;
	}

done:
	IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0);
	IMPLY(dlp->dl_qos_range_offset != 0,
	    dlp->dl_qos_range_length != 0);
	IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0);
	IMPLY(dlp->dl_brdcst_addr_offset != 0,
	    dlp->dl_brdcst_addr_length != 0);

	qreply(q, mp);
}
Esempio n. 9
0
/* ARGSUSED */
static int
sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod,
    int32_t *rval, struct cred *cr)
{
	struct timeval tival;
	mac_client_promisc_type_t mtype;
	struct sockaddr_dl *sock;
	datalink_id_t linkid;
	struct lifreq lifreq;
	struct ifreq ifreq;
	struct pfpsock *ps;
	mac_handle_t mh;
	int error;

	ps = (struct pfpsock *)handle;

	switch (cmd) {
	/*
	 * ioctls that work on "struct lifreq"
	 */
	case SIOCSLIFFLAGS :
	case SIOCGLIFINDEX :
	case SIOCGLIFFLAGS :
	case SIOCGLIFMTU :
	case SIOCGLIFHWADDR :
		error = pfp_lifreq_getlinkid(arg, &lifreq, &linkid, mod);
		if (error != 0)
			return (error);
		break;

	/*
	 * ioctls that work on "struct ifreq".
	 * Not all of these have a "struct lifreq" partner, for example
	 * SIOCGIFHWADDR, for the simple reason that the logical interface
	 * does not have a hardware address.
	 */
	case SIOCSIFFLAGS :
	case SIOCGIFINDEX :
	case SIOCGIFFLAGS :
	case SIOCGIFMTU :
	case SIOCGIFHWADDR :
		error = pfp_ifreq_getlinkid(arg, &ifreq, &linkid, mod);
		if (error != 0)
			return (error);
		break;

	case SIOCGSTAMP :
		tival.tv_sec = (time_t)ps->ps_timestamp.tv_sec;
		tival.tv_usec = ps->ps_timestamp.tv_nsec / 1000;
		if (get_udatamodel() == DATAMODEL_NATIVE) {
			error = ddi_copyout(&tival, (void *)arg,
			    sizeof (tival), mod);
		}
#ifdef _SYSCALL32_IMPL
		else {
			struct timeval32 tv32;
			TIMEVAL_TO_TIMEVAL32(&tv32, &tival);
			error = ddi_copyout(&tv32, (void *)arg,
			    sizeof (tv32), mod);
		}
#endif
		return (error);
	}

	error =  mac_open_by_linkid(linkid, &mh);
	if (error != 0)
		return (error);

	switch (cmd) {
	case SIOCGLIFINDEX :
		lifreq.lifr_index = linkid;
		break;

	case SIOCGIFINDEX :
		ifreq.ifr_index = linkid;
		break;

	case SIOCGIFFLAGS :
		ifreq.ifr_flags = IFF_RUNNING;
		if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL)
			ifreq.ifr_flags |= IFF_PROMISC;
		break;

	case SIOCGLIFFLAGS :
		lifreq.lifr_flags = IFF_RUNNING;
		if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL)
			lifreq.lifr_flags |= IFF_PROMISC;
		break;

	case SIOCSIFFLAGS :
		if (linkid != ps->ps_linkid) {
			error = EINVAL;
		} else {
			if ((ifreq.ifr_flags & IFF_PROMISC) != 0)
				mtype = MAC_CLIENT_PROMISC_ALL;
			else
				mtype = MAC_CLIENT_PROMISC_FILTERED;
			error = pfp_set_promisc(ps, mtype);
		}
		break;

	case SIOCSLIFFLAGS :
		if (linkid != ps->ps_linkid) {
			error = EINVAL;
		} else {
			if ((lifreq.lifr_flags & IFF_PROMISC) != 0)
				mtype = MAC_CLIENT_PROMISC_ALL;
			else
				mtype = MAC_CLIENT_PROMISC_FILTERED;
			error = pfp_set_promisc(ps, mtype);
		}
		break;

	case SIOCGIFMTU :
		mac_sdu_get(mh, NULL, &ifreq.ifr_mtu);
		break;

	case SIOCGLIFMTU :
		mac_sdu_get(mh, NULL, &lifreq.lifr_mtu);
		break;

	case SIOCGIFHWADDR :
		if (mac_addr_len(mh) > sizeof (ifreq.ifr_addr.sa_data)) {
			error = EPFNOSUPPORT;
			break;
		}

		if (mac_addr_len(mh) == 0) {
			(void) memset(ifreq.ifr_addr.sa_data, 0,
			    sizeof (ifreq.ifr_addr.sa_data));
		} else {
			mac_unicast_primary_get(mh,
			    (uint8_t *)ifreq.ifr_addr.sa_data);
		}

		/*
		 * The behaviour here in setting sa_family is consistent
		 * with what applications such as tcpdump would expect
		 * for a Linux PF_PACKET socket.
		 */
		ifreq.ifr_addr.sa_family = pfp_dl_to_arphrd(mac_type(mh));
		break;

	case SIOCGLIFHWADDR :
		lifreq.lifr_type = 0;
		sock = (struct sockaddr_dl *)&lifreq.lifr_addr;

		if (mac_addr_len(mh) > sizeof (sock->sdl_data)) {
			error = EPFNOSUPPORT;
			break;
		}

		/*
		 * Fill in the sockaddr_dl with link layer details. Of note,
		 * the index is returned as 0 for a couple of reasons:
		 * (1) there is no public API that uses or requires it
		 * (2) the MAC index is currently 32bits and sdl_index is 16.
		 */
		sock->sdl_family = AF_LINK;
		sock->sdl_index = 0;
		sock->sdl_type = mac_type(mh);
		sock->sdl_nlen = 0;
		sock->sdl_alen = mac_addr_len(mh);
		sock->sdl_slen = 0;
		if (mac_addr_len(mh) == 0) {
			(void) memset(sock->sdl_data, 0,
			    sizeof (sock->sdl_data));
		} else {
			mac_unicast_primary_get(mh, (uint8_t *)sock->sdl_data);
		}
		break;

	default :
		break;
	}

	mac_close(mh);

	if (error == 0) {
		/*
		 * Only the "GET" ioctls need to copy data back to userace.
		 */
		switch (cmd) {
		case SIOCGLIFINDEX :
		case SIOCGLIFFLAGS :
		case SIOCGLIFMTU :
		case SIOCGLIFHWADDR :
			error = ddi_copyout(&lifreq, (void *)arg,
			    sizeof (lifreq), mod);
			break;

		case SIOCGIFINDEX :
		case SIOCGIFFLAGS :
		case SIOCGIFMTU :
		case SIOCGIFHWADDR :
			error = ddi_copyout(&ifreq, (void *)arg,
			    sizeof (ifreq), mod);
			break;
		default :
			break;
		}
	}

	return (error);
}