16512Ssowmini /*
26512Ssowmini * CDDL HEADER START
36512Ssowmini *
46512Ssowmini * The contents of this file are subject to the terms of the
56512Ssowmini * Common Development and Distribution License (the "License").
66512Ssowmini * You may not use this file except in compliance with the License.
76512Ssowmini *
86512Ssowmini * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96512Ssowmini * or http://www.opensolaris.org/os/licensing.
106512Ssowmini * See the License for the specific language governing permissions
116512Ssowmini * and limitations under the License.
126512Ssowmini *
136512Ssowmini * When distributing Covered Code, include this CDDL HEADER in each
146512Ssowmini * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156512Ssowmini * If applicable, add the following below this CDDL HEADER, with the
166512Ssowmini * fields enclosed by brackets "[]" replaced with your own identifying
176512Ssowmini * information: Portions Copyright [yyyy] [name of copyright owner]
186512Ssowmini *
196512Ssowmini * CDDL HEADER END
206512Ssowmini */
216512Ssowmini /*
22*12169SPrakash.Jalan@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
236512Ssowmini */
246512Ssowmini
256512Ssowmini /*
266512Ssowmini * functions to handle legacy ndd ioctls
276512Ssowmini */
286512Ssowmini #include <sys/types.h>
296512Ssowmini #include <sys/mac.h>
306512Ssowmini #include <sys/mac_impl.h>
3111878SVenu.Iyer@Sun.COM #include <sys/mac_client_priv.h>
326512Ssowmini #include <inet/nd.h>
336512Ssowmini #include <sys/mac_ether.h>
346512Ssowmini #include <sys/policy.h>
356512Ssowmini #include <sys/strsun.h>
366512Ssowmini
376512Ssowmini static int mac_ndd_set_ioctl(mac_impl_t *, mblk_t *, int, int *);
386512Ssowmini static int mac_ndd_get_ioctl(mac_impl_t *, mblk_t *, int, int *);
396512Ssowmini static int mac_ndd_get_names(mac_impl_t *, mblk_t *);
406512Ssowmini static boolean_t mac_add_name(mblk_t *, char *, int);
416512Ssowmini
426512Ssowmini /*
436512Ssowmini * add "<name> (<rwtag>) " into the mblk, allocating more memory if needed.
446512Ssowmini */
456512Ssowmini static boolean_t
mac_add_name(mblk_t * mp,char * name,int ndd_flags)466512Ssowmini mac_add_name(mblk_t *mp, char *name, int ndd_flags)
476512Ssowmini {
486512Ssowmini char *cp, *rwtag;
496512Ssowmini int len, flags;
506512Ssowmini
516512Ssowmini flags = (ndd_flags & (MAC_PROP_PERM_WRITE|MAC_PROP_PERM_READ));
526512Ssowmini switch (flags) {
536512Ssowmini case 0:
546512Ssowmini rwtag = "no read or write";
556512Ssowmini break;
566512Ssowmini case MAC_PROP_PERM_WRITE:
576512Ssowmini rwtag = "write only";
586512Ssowmini break;
596512Ssowmini case MAC_PROP_PERM_READ:
606512Ssowmini rwtag = "read only";
616512Ssowmini break;
626512Ssowmini default:
636512Ssowmini rwtag = "read and write";
646512Ssowmini break;
656512Ssowmini }
666512Ssowmini
676512Ssowmini while (mp->b_cont != NULL)
686512Ssowmini mp = mp->b_cont;
696512Ssowmini /*
706512Ssowmini * allocate space for name, <space>, '(', rwtag, ')', and
716512Ssowmini * two terminating null chars.
726512Ssowmini */
736512Ssowmini len = strlen(name) + strlen(rwtag) + 6;
746512Ssowmini if (mp->b_wptr + len >= mp->b_datap->db_lim) {
756512Ssowmini mp->b_cont = allocb(len, BPRI_HI);
766512Ssowmini mp = mp->b_cont;
77*12169SPrakash.Jalan@Sun.COM if (mp == NULL)
786512Ssowmini return (B_FALSE);
796512Ssowmini }
806512Ssowmini cp = (char *)mp->b_wptr;
816512Ssowmini (void) snprintf(cp, len, "%s (%s)", name, rwtag);
826512Ssowmini mp->b_wptr += strnlen(cp, len);
836512Ssowmini mp->b_wptr++; /* skip past the terminating \0 */
846512Ssowmini return (B_TRUE);
856512Ssowmini }
866512Ssowmini
876512Ssowmini
886512Ssowmini /*
896512Ssowmini * handle a query for "ndd -get \?". The result is put into mp, and
906512Ssowmini * more memory is allocated if needed. The resulting size of the data
916512Ssowmini * is returned.
926512Ssowmini */
936512Ssowmini static int
mac_ndd_get_names(mac_impl_t * mip,mblk_t * mp)946512Ssowmini mac_ndd_get_names(mac_impl_t *mip, mblk_t *mp)
956512Ssowmini {
966512Ssowmini int size_out, i;
976512Ssowmini mblk_t *tmp;
988118SVasumathi.Sundaram@Sun.COM uint_t permflags;
998118SVasumathi.Sundaram@Sun.COM int status;
1008118SVasumathi.Sundaram@Sun.COM uint64_t value;
10111878SVenu.Iyer@Sun.COM char *prop_name;
1026512Ssowmini
1036512Ssowmini if (!mac_add_name(mp, "?", MAC_PROP_PERM_READ))
1046512Ssowmini return (-1);
1056512Ssowmini
1066512Ssowmini /* first the known ndd mappings */
1076512Ssowmini for (i = 0; i < mip->mi_type->mt_mappingcount; i++) {
1088118SVasumathi.Sundaram@Sun.COM if ((mip->mi_type->mt_mapping[i].mp_flags & MAC_PROP_MAP_KSTAT)
1098118SVasumathi.Sundaram@Sun.COM != 0)
1108118SVasumathi.Sundaram@Sun.COM permflags = MAC_PROP_PERM_READ;
1118118SVasumathi.Sundaram@Sun.COM else {
1128118SVasumathi.Sundaram@Sun.COM status = mip->mi_callbacks->mc_getprop(mip->mi_driver,
1138118SVasumathi.Sundaram@Sun.COM mip->mi_type->mt_mapping[i].mp_name,
1148118SVasumathi.Sundaram@Sun.COM mip->mi_type->mt_mapping[i].mp_prop_id,
11511878SVenu.Iyer@Sun.COM mip->mi_type->mt_mapping[i].mp_valsize, &value);
11611878SVenu.Iyer@Sun.COM if (status != 0)
11711878SVenu.Iyer@Sun.COM continue;
11811878SVenu.Iyer@Sun.COM status = mac_prop_info((mac_handle_t)mip,
11911878SVenu.Iyer@Sun.COM mip->mi_type->mt_mapping[i].mp_prop_id,
12011878SVenu.Iyer@Sun.COM mip->mi_type->mt_mapping[i].mp_name, NULL, 0,
12111878SVenu.Iyer@Sun.COM NULL, &permflags);
1228118SVasumathi.Sundaram@Sun.COM if (status != 0)
1239623SVasumathi.Sundaram@Sun.COM continue;
1248118SVasumathi.Sundaram@Sun.COM }
1256512Ssowmini if (!mac_add_name(mp, mip->mi_type->mt_mapping[i].mp_name,
1268118SVasumathi.Sundaram@Sun.COM permflags))
1276512Ssowmini return (-1);
1286512Ssowmini }
1296512Ssowmini
1306512Ssowmini /* now the driver's ndd variables */
1316512Ssowmini for (i = 0; i < mip->mi_priv_prop_count; i++) {
1326512Ssowmini
13311878SVenu.Iyer@Sun.COM prop_name = mip->mi_priv_prop[i];
13411878SVenu.Iyer@Sun.COM
13511878SVenu.Iyer@Sun.COM if (mac_prop_info((mac_handle_t)mip, MAC_PROP_PRIVATE,
13611878SVenu.Iyer@Sun.COM prop_name, NULL, 0, NULL, &permflags) != 0)
13711878SVenu.Iyer@Sun.COM return (-1);
1386512Ssowmini
1396512Ssowmini /* skip over the "_" */
14011878SVenu.Iyer@Sun.COM if (!mac_add_name(mp, &prop_name[1], permflags))
1416512Ssowmini return (-1);
1426512Ssowmini }
1436512Ssowmini
1446512Ssowmini tmp = mp;
1456512Ssowmini while (tmp->b_cont != NULL)
1466512Ssowmini tmp = tmp->b_cont;
1476512Ssowmini *tmp->b_wptr++ = '\0';
1486512Ssowmini size_out = msgdsize(mp);
1496512Ssowmini return (size_out);
1506512Ssowmini }
1516512Ssowmini
1526512Ssowmini
1536512Ssowmini /*
1546512Ssowmini * Handle legacy ndd ioctls for ND_GET and ND_SET.
1556512Ssowmini */
1566512Ssowmini void
mac_ndd_ioctl(mac_impl_t * mip,queue_t * wq,mblk_t * mp)1576512Ssowmini mac_ndd_ioctl(mac_impl_t *mip, queue_t *wq, mblk_t *mp)
1586512Ssowmini {
1596512Ssowmini IOCP iocp;
1606512Ssowmini int cmd, err, rval;
1616512Ssowmini
1626512Ssowmini iocp = (IOCP)mp->b_rptr;
1636512Ssowmini if (iocp->ioc_count == 0 || mp->b_cont == NULL) {
1646512Ssowmini err = EINVAL;
1656512Ssowmini goto done;
1666512Ssowmini }
1676512Ssowmini
1686512Ssowmini cmd = iocp->ioc_cmd;
1696512Ssowmini
1706512Ssowmini if (cmd == ND_SET) {
1716512Ssowmini err = mac_ndd_set_ioctl(mip, mp, iocp->ioc_count, &rval);
1726512Ssowmini } else if (cmd == ND_GET) {
1736512Ssowmini err = mac_ndd_get_ioctl(mip, mp, iocp->ioc_count, &rval);
1746512Ssowmini }
1756512Ssowmini done:
1766512Ssowmini if (err == 0)
1776512Ssowmini miocack(wq, mp, msgdsize(mp->b_cont), rval);
1786512Ssowmini else
1796512Ssowmini miocnak(wq, mp, 0, err);
1806512Ssowmini }
1816512Ssowmini
1826512Ssowmini static int
mac_ndd_get_ioctl(mac_impl_t * mip,mblk_t * mp,int avail,int * rval)1836512Ssowmini mac_ndd_get_ioctl(mac_impl_t *mip, mblk_t *mp, int avail, int *rval)
1846512Ssowmini {
1856512Ssowmini mblk_t *mp1;
1866512Ssowmini char *valp;
1876512Ssowmini uchar_t *value;
1886512Ssowmini uint32_t new_value;
189*12169SPrakash.Jalan@Sun.COM int size_out = 0, i;
1906512Ssowmini int status = EINVAL;
1916512Ssowmini char *name, priv_name[MAXLINKPROPNAME];
1926512Ssowmini uint8_t u8;
1936512Ssowmini uint16_t u16;
1946512Ssowmini uint32_t u32;
1956512Ssowmini uint64_t u64;
1966512Ssowmini
1976512Ssowmini if (mp->b_cont == NULL || avail < 2)
1986512Ssowmini return (EINVAL);
1996512Ssowmini valp = (char *)mp->b_cont->b_rptr;
2006512Ssowmini mp1 = allocb(avail, BPRI_HI); /* the returned buffer */
2016512Ssowmini if (mp1 == NULL)
2026512Ssowmini return (ENOMEM);
2036512Ssowmini
2046512Ssowmini if (strcmp(valp, "?") == 0) {
2056512Ssowmini /*
2066512Ssowmini * handle "ndd -get <..> \?" queries.
2076512Ssowmini */
2086512Ssowmini size_out = mac_ndd_get_names(mip, mp1);
2096512Ssowmini if (size_out < 0) {
2106512Ssowmini status = ENOMEM;
2116512Ssowmini goto get_done;
2126512Ssowmini }
2136512Ssowmini if (size_out > avail) {
2146512Ssowmini int excess;
2156512Ssowmini char *cp;
2166512Ssowmini /*
2176512Ssowmini * need more user buffer space. Return as many
2186512Ssowmini * mblks as will fit and return the needed
2196512Ssowmini * buffer size in ioc_rval.
2206512Ssowmini */
2216512Ssowmini excess = size_out - avail;
2226512Ssowmini *rval = size_out; /* what's needed */
2236512Ssowmini size_out -= excess;
2246512Ssowmini (void) adjmsg(mp1, -(excess + 1));
2256512Ssowmini cp = (char *)mp1->b_wptr;
2266512Ssowmini *cp = '\0';
2276512Ssowmini }
2286512Ssowmini status = 0;
2296512Ssowmini goto get_done;
2306512Ssowmini }
2316512Ssowmini
2326512Ssowmini ASSERT(mip->mi_callbacks->mc_callbacks & MC_GETPROP);
2336512Ssowmini name = valp;
2346512Ssowmini valp = (char *)mp1->b_rptr;
2356512Ssowmini mp1->b_wptr = mp1->b_rptr;
2366512Ssowmini
2376512Ssowmini /* first lookup ndd <-> public property mapping */
2386512Ssowmini for (i = 0; i < mip->mi_type->mt_mappingcount; i++) {
2396512Ssowmini if (strcmp(name, mip->mi_type->mt_mapping[i].mp_name) != 0)
2406512Ssowmini continue;
2416512Ssowmini
2426512Ssowmini switch (mip->mi_type->mt_mapping[i].mp_valsize) {
2436512Ssowmini case 1:
2446512Ssowmini value = (uchar_t *)&u8;
2456512Ssowmini break;
2466512Ssowmini case 2:
2476512Ssowmini value = (uchar_t *)&u16;
2486512Ssowmini break;
2496512Ssowmini case 4:
2506512Ssowmini value = (uchar_t *)&u32;
2516512Ssowmini break;
2526512Ssowmini default:
2536512Ssowmini value = (uchar_t *)&u64;
2546512Ssowmini break;
2556512Ssowmini }
2566512Ssowmini
2576512Ssowmini if ((mip->mi_type->mt_mapping[i].mp_flags & MAC_PROP_MAP_KSTAT)
2586512Ssowmini != 0) {
2596512Ssowmini u64 = mac_stat_get((mac_handle_t)mip,
2606512Ssowmini mip->mi_type->mt_mapping[i].mp_kstat);
2616512Ssowmini status = 0;
2626512Ssowmini /*
2636512Ssowmini * ether_stats are all always KSTAT_DATA_UINT32
2646512Ssowmini */
2656512Ssowmini new_value = u32 = (long)u64;
2666512Ssowmini } else {
2676512Ssowmini status = mip->mi_callbacks->mc_getprop(mip->mi_driver,
26811878SVenu.Iyer@Sun.COM name, mip->mi_type->mt_mapping[i].mp_prop_id,
26911878SVenu.Iyer@Sun.COM mip->mi_type->mt_mapping[i].mp_valsize, value);
2706512Ssowmini switch (mip->mi_type->mt_mapping[i].mp_valsize) {
2716512Ssowmini case 1:
2726512Ssowmini new_value = u8;
2736512Ssowmini break;
2746512Ssowmini case 2:
2756512Ssowmini new_value = u16;
2766512Ssowmini break;
2776512Ssowmini case 4:
2786512Ssowmini new_value = u32;
2796512Ssowmini break;
2806512Ssowmini case 8:
2816512Ssowmini /*
2826512Ssowmini * The only uint64_t is for speed, which is
2836512Ssowmini * converted to Mbps in ndd reports.
2846512Ssowmini */
2856512Ssowmini new_value = (u64/1000000);
2866512Ssowmini break;
2876512Ssowmini }
2886512Ssowmini }
2896512Ssowmini
2906512Ssowmini if (status != 0)
2916512Ssowmini goto get_done;
2926512Ssowmini
2936512Ssowmini (void) snprintf(valp, avail, "%d", new_value);
2946512Ssowmini goto update_reply;
2956512Ssowmini }
2966512Ssowmini
2976512Ssowmini /*
2986512Ssowmini * could not find a public property. try the private prop route
2996512Ssowmini * where all string processing will be done by the driver.
3006512Ssowmini */
3016512Ssowmini (void) snprintf(priv_name, sizeof (priv_name), "_%s", name);
3026512Ssowmini status = mip->mi_callbacks->mc_getprop(mip->mi_driver, priv_name,
30311878SVenu.Iyer@Sun.COM MAC_PROP_PRIVATE, avail - 2, mp1->b_rptr);
3046512Ssowmini if (status != 0)
3056512Ssowmini goto get_done;
3066512Ssowmini
3076512Ssowmini update_reply:
3086512Ssowmini size_out += strnlen((const char *)mp1->b_rptr, avail);
3096512Ssowmini valp += size_out;
3106512Ssowmini *valp++ = '\0'; /* need \0\0 */
3116512Ssowmini *valp++ = '\0';
3126512Ssowmini mp1->b_wptr = (uchar_t *)valp;
3136512Ssowmini *rval = 0;
3146512Ssowmini
3156512Ssowmini get_done:
3166512Ssowmini freemsg(mp->b_cont);
3176512Ssowmini if (status == 0)
3186512Ssowmini mp->b_cont = mp1;
3196512Ssowmini else {
3206512Ssowmini freemsg(mp1);
3216512Ssowmini mp->b_cont = NULL;
3226512Ssowmini }
3236512Ssowmini return (status);
3246512Ssowmini }
3256512Ssowmini
3266512Ssowmini static int
mac_ndd_set_ioctl(mac_impl_t * mip,mblk_t * mp,int avail,int * rval)3276512Ssowmini mac_ndd_set_ioctl(mac_impl_t *mip, mblk_t *mp, int avail, int *rval)
3286512Ssowmini {
3296512Ssowmini mblk_t *mp1;
3306512Ssowmini char *valp, *name, *new_valuep;
3316512Ssowmini uchar_t *vp;
3326512Ssowmini long new_value;
3336512Ssowmini int status, i;
3346512Ssowmini uint8_t u8;
3356512Ssowmini uint16_t u16;
3366512Ssowmini uint32_t u32;
3376512Ssowmini IOCP iocp;
3386512Ssowmini char priv_name[MAXLINKPROPNAME];
3396512Ssowmini
3406512Ssowmini if (avail == 0 || !(mp1 = mp->b_cont))
3416512Ssowmini return (EINVAL);
3426512Ssowmini
3436512Ssowmini if (mp1->b_cont) {
3446512Ssowmini freemsg(mp1->b_cont);
3456512Ssowmini mp1->b_cont = NULL;
3466512Ssowmini }
3476512Ssowmini mp1->b_datap->db_lim[-1] = '\0';
3486512Ssowmini valp = (char *)mp1->b_rptr;
3496512Ssowmini name = valp;
3506512Ssowmini *rval = 0;
3516512Ssowmini while (*valp++)
3526512Ssowmini ;
3536512Ssowmini if (valp >= (char *)mp1->b_wptr)
3546512Ssowmini valp = NULL;
3556512Ssowmini
3566512Ssowmini new_valuep = valp;
3576512Ssowmini if (ddi_strtol(valp, NULL, 0, &new_value) != 0)
3586512Ssowmini goto priv_prop;
3596512Ssowmini
3606512Ssowmini iocp = (IOCP)mp->b_rptr;
3616512Ssowmini if (valp != NULL &&
3626512Ssowmini ((iocp->ioc_cr == NULL) ||
3636512Ssowmini ((status = secpolicy_net_config(iocp->ioc_cr, B_FALSE)) != 0)))
3646512Ssowmini return (status);
3656512Ssowmini
3666512Ssowmini status = EINVAL;
3676512Ssowmini
3686512Ssowmini /* first lookup ndd <-> public property mapping */
3696512Ssowmini for (i = 0; i < mip->mi_type->mt_mappingcount; i++) {
3706512Ssowmini if (strcmp(name, mip->mi_type->mt_mapping[i].mp_name) != 0)
3716512Ssowmini continue;
3726512Ssowmini
3736512Ssowmini if (mip->mi_type->mt_mapping[i].mp_flags & MAC_PROP_MAP_KSTAT)
3746512Ssowmini return (EINVAL);
3756512Ssowmini
3766512Ssowmini if (new_value > mip->mi_type->mt_mapping[i].mp_maxval ||
3776512Ssowmini new_value < mip->mi_type->mt_mapping[i].mp_minval ||
3786512Ssowmini (mip->mi_type->mt_mapping[i].mp_flags & MAC_PROP_PERM_WRITE)
3796512Ssowmini == 0)
3806512Ssowmini return (EINVAL);
3816512Ssowmini switch (mip->mi_type->mt_mapping[i].mp_valsize) {
3826512Ssowmini case 1:
3836512Ssowmini u8 = (uint8_t)new_value;
3846512Ssowmini vp = (uchar_t *)&u8;
3856512Ssowmini break;
3866512Ssowmini case 2:
3876512Ssowmini u16 = (uint16_t)new_value;
3886512Ssowmini vp = (uchar_t *)&u16;
3896512Ssowmini break;
3906512Ssowmini case 4:
3916512Ssowmini u32 = (uint32_t)new_value;
3926512Ssowmini vp = (uchar_t *)&u32;
3936512Ssowmini break;
3946512Ssowmini case 8:
3956512Ssowmini vp = (uchar_t *)&new_value;
3966512Ssowmini break;
3976512Ssowmini default:
3986512Ssowmini return (ENOTSUP);
3996512Ssowmini }
4006512Ssowmini
4016512Ssowmini status = mip->mi_callbacks->mc_setprop(mip->mi_driver,
4026512Ssowmini name, mip->mi_type->mt_mapping[i].mp_prop_id,
4036512Ssowmini mip->mi_type->mt_mapping[i].mp_valsize, (const void *)vp);
4046512Ssowmini goto done;
4056512Ssowmini }
4066512Ssowmini
4076512Ssowmini priv_prop:
4086512Ssowmini (void) snprintf(priv_name, sizeof (priv_name), "_%s", name);
4096512Ssowmini status = mip->mi_callbacks->mc_setprop(mip->mi_driver, priv_name,
4106789Sam223141 MAC_PROP_PRIVATE, strlen(new_valuep), new_valuep);
4116512Ssowmini done:
4126512Ssowmini freemsg(mp1);
4136512Ssowmini mp->b_cont = NULL;
4146512Ssowmini return (status);
4156512Ssowmini }
416