14045d941Ssowmini /* 24045d941Ssowmini * CDDL HEADER START 34045d941Ssowmini * 44045d941Ssowmini * The contents of this file are subject to the terms of the 54045d941Ssowmini * Common Development and Distribution License (the "License"). 64045d941Ssowmini * You may not use this file except in compliance with the License. 74045d941Ssowmini * 84045d941Ssowmini * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94045d941Ssowmini * or http://www.opensolaris.org/os/licensing. 104045d941Ssowmini * See the License for the specific language governing permissions 114045d941Ssowmini * and limitations under the License. 124045d941Ssowmini * 134045d941Ssowmini * When distributing Covered Code, include this CDDL HEADER in each 144045d941Ssowmini * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154045d941Ssowmini * If applicable, add the following below this CDDL HEADER, with the 164045d941Ssowmini * fields enclosed by brackets "[]" replaced with your own identifying 174045d941Ssowmini * information: Portions Copyright [yyyy] [name of copyright owner] 184045d941Ssowmini * 194045d941Ssowmini * CDDL HEADER END 204045d941Ssowmini */ 214045d941Ssowmini /* 22*aa71ed93SPrakash Jalan * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 234045d941Ssowmini */ 244045d941Ssowmini 254045d941Ssowmini /* 264045d941Ssowmini * functions to handle legacy ndd ioctls 274045d941Ssowmini */ 284045d941Ssowmini #include <sys/types.h> 294045d941Ssowmini #include <sys/mac.h> 304045d941Ssowmini #include <sys/mac_impl.h> 310dc2366fSVenugopal Iyer #include <sys/mac_client_priv.h> 324045d941Ssowmini #include <inet/nd.h> 334045d941Ssowmini #include <sys/mac_ether.h> 344045d941Ssowmini #include <sys/policy.h> 354045d941Ssowmini #include <sys/strsun.h> 364045d941Ssowmini 374045d941Ssowmini static int mac_ndd_set_ioctl(mac_impl_t *, mblk_t *, int, int *); 384045d941Ssowmini static int mac_ndd_get_ioctl(mac_impl_t *, mblk_t *, int, int *); 394045d941Ssowmini static int mac_ndd_get_names(mac_impl_t *, mblk_t *); 404045d941Ssowmini static boolean_t mac_add_name(mblk_t *, char *, int); 414045d941Ssowmini 424045d941Ssowmini /* 434045d941Ssowmini * add "<name> (<rwtag>) " into the mblk, allocating more memory if needed. 444045d941Ssowmini */ 454045d941Ssowmini static boolean_t 464045d941Ssowmini mac_add_name(mblk_t *mp, char *name, int ndd_flags) 474045d941Ssowmini { 484045d941Ssowmini char *cp, *rwtag; 494045d941Ssowmini int len, flags; 504045d941Ssowmini 514045d941Ssowmini flags = (ndd_flags & (MAC_PROP_PERM_WRITE|MAC_PROP_PERM_READ)); 524045d941Ssowmini switch (flags) { 534045d941Ssowmini case 0: 544045d941Ssowmini rwtag = "no read or write"; 554045d941Ssowmini break; 564045d941Ssowmini case MAC_PROP_PERM_WRITE: 574045d941Ssowmini rwtag = "write only"; 584045d941Ssowmini break; 594045d941Ssowmini case MAC_PROP_PERM_READ: 604045d941Ssowmini rwtag = "read only"; 614045d941Ssowmini break; 624045d941Ssowmini default: 634045d941Ssowmini rwtag = "read and write"; 644045d941Ssowmini break; 654045d941Ssowmini } 664045d941Ssowmini 674045d941Ssowmini while (mp->b_cont != NULL) 684045d941Ssowmini mp = mp->b_cont; 694045d941Ssowmini /* 704045d941Ssowmini * allocate space for name, <space>, '(', rwtag, ')', and 714045d941Ssowmini * two terminating null chars. 724045d941Ssowmini */ 734045d941Ssowmini len = strlen(name) + strlen(rwtag) + 6; 744045d941Ssowmini if (mp->b_wptr + len >= mp->b_datap->db_lim) { 754045d941Ssowmini mp->b_cont = allocb(len, BPRI_HI); 764045d941Ssowmini mp = mp->b_cont; 77*aa71ed93SPrakash Jalan if (mp == NULL) 784045d941Ssowmini return (B_FALSE); 794045d941Ssowmini } 804045d941Ssowmini cp = (char *)mp->b_wptr; 814045d941Ssowmini (void) snprintf(cp, len, "%s (%s)", name, rwtag); 824045d941Ssowmini mp->b_wptr += strnlen(cp, len); 834045d941Ssowmini mp->b_wptr++; /* skip past the terminating \0 */ 844045d941Ssowmini return (B_TRUE); 854045d941Ssowmini } 864045d941Ssowmini 874045d941Ssowmini 884045d941Ssowmini /* 894045d941Ssowmini * handle a query for "ndd -get \?". The result is put into mp, and 904045d941Ssowmini * more memory is allocated if needed. The resulting size of the data 914045d941Ssowmini * is returned. 924045d941Ssowmini */ 934045d941Ssowmini static int 944045d941Ssowmini mac_ndd_get_names(mac_impl_t *mip, mblk_t *mp) 954045d941Ssowmini { 964045d941Ssowmini int size_out, i; 974045d941Ssowmini mblk_t *tmp; 98afdda45fSVasumathi Sundaram - Sun Microsystems uint_t permflags; 99afdda45fSVasumathi Sundaram - Sun Microsystems int status; 100afdda45fSVasumathi Sundaram - Sun Microsystems uint64_t value; 1010dc2366fSVenugopal Iyer char *prop_name; 1024045d941Ssowmini 1034045d941Ssowmini if (!mac_add_name(mp, "?", MAC_PROP_PERM_READ)) 1044045d941Ssowmini return (-1); 1054045d941Ssowmini 1064045d941Ssowmini /* first the known ndd mappings */ 1074045d941Ssowmini for (i = 0; i < mip->mi_type->mt_mappingcount; i++) { 108afdda45fSVasumathi Sundaram - Sun Microsystems if ((mip->mi_type->mt_mapping[i].mp_flags & MAC_PROP_MAP_KSTAT) 109afdda45fSVasumathi Sundaram - Sun Microsystems != 0) 110afdda45fSVasumathi Sundaram - Sun Microsystems permflags = MAC_PROP_PERM_READ; 111afdda45fSVasumathi Sundaram - Sun Microsystems else { 112afdda45fSVasumathi Sundaram - Sun Microsystems status = mip->mi_callbacks->mc_getprop(mip->mi_driver, 113afdda45fSVasumathi Sundaram - Sun Microsystems mip->mi_type->mt_mapping[i].mp_name, 114afdda45fSVasumathi Sundaram - Sun Microsystems mip->mi_type->mt_mapping[i].mp_prop_id, 1150dc2366fSVenugopal Iyer mip->mi_type->mt_mapping[i].mp_valsize, &value); 1160dc2366fSVenugopal Iyer if (status != 0) 1170dc2366fSVenugopal Iyer continue; 1180dc2366fSVenugopal Iyer status = mac_prop_info((mac_handle_t)mip, 1190dc2366fSVenugopal Iyer mip->mi_type->mt_mapping[i].mp_prop_id, 1200dc2366fSVenugopal Iyer mip->mi_type->mt_mapping[i].mp_name, NULL, 0, 1210dc2366fSVenugopal Iyer NULL, &permflags); 122afdda45fSVasumathi Sundaram - Sun Microsystems if (status != 0) 123646b4e2aSVasumathi Sundaram - Sun Microsystems continue; 124afdda45fSVasumathi Sundaram - Sun Microsystems } 1254045d941Ssowmini if (!mac_add_name(mp, mip->mi_type->mt_mapping[i].mp_name, 126afdda45fSVasumathi Sundaram - Sun Microsystems permflags)) 1274045d941Ssowmini return (-1); 1284045d941Ssowmini } 1294045d941Ssowmini 1304045d941Ssowmini /* now the driver's ndd variables */ 1314045d941Ssowmini for (i = 0; i < mip->mi_priv_prop_count; i++) { 1324045d941Ssowmini 1330dc2366fSVenugopal Iyer prop_name = mip->mi_priv_prop[i]; 1340dc2366fSVenugopal Iyer 1350dc2366fSVenugopal Iyer if (mac_prop_info((mac_handle_t)mip, MAC_PROP_PRIVATE, 1360dc2366fSVenugopal Iyer prop_name, NULL, 0, NULL, &permflags) != 0) 1370dc2366fSVenugopal Iyer return (-1); 1384045d941Ssowmini 1394045d941Ssowmini /* skip over the "_" */ 1400dc2366fSVenugopal Iyer if (!mac_add_name(mp, &prop_name[1], permflags)) 1414045d941Ssowmini return (-1); 1424045d941Ssowmini } 1434045d941Ssowmini 1444045d941Ssowmini tmp = mp; 1454045d941Ssowmini while (tmp->b_cont != NULL) 1464045d941Ssowmini tmp = tmp->b_cont; 1474045d941Ssowmini *tmp->b_wptr++ = '\0'; 1484045d941Ssowmini size_out = msgdsize(mp); 1494045d941Ssowmini return (size_out); 1504045d941Ssowmini } 1514045d941Ssowmini 1524045d941Ssowmini 1534045d941Ssowmini /* 1544045d941Ssowmini * Handle legacy ndd ioctls for ND_GET and ND_SET. 1554045d941Ssowmini */ 1564045d941Ssowmini void 1574045d941Ssowmini mac_ndd_ioctl(mac_impl_t *mip, queue_t *wq, mblk_t *mp) 1584045d941Ssowmini { 1594045d941Ssowmini IOCP iocp; 1604045d941Ssowmini int cmd, err, rval; 1614045d941Ssowmini 1624045d941Ssowmini iocp = (IOCP)mp->b_rptr; 1634045d941Ssowmini if (iocp->ioc_count == 0 || mp->b_cont == NULL) { 1644045d941Ssowmini err = EINVAL; 1654045d941Ssowmini goto done; 1664045d941Ssowmini } 1674045d941Ssowmini 1684045d941Ssowmini cmd = iocp->ioc_cmd; 1694045d941Ssowmini 1704045d941Ssowmini if (cmd == ND_SET) { 1714045d941Ssowmini err = mac_ndd_set_ioctl(mip, mp, iocp->ioc_count, &rval); 1724045d941Ssowmini } else if (cmd == ND_GET) { 1734045d941Ssowmini err = mac_ndd_get_ioctl(mip, mp, iocp->ioc_count, &rval); 1744045d941Ssowmini } 1754045d941Ssowmini done: 1764045d941Ssowmini if (err == 0) 1774045d941Ssowmini miocack(wq, mp, msgdsize(mp->b_cont), rval); 1784045d941Ssowmini else 1794045d941Ssowmini miocnak(wq, mp, 0, err); 1804045d941Ssowmini } 1814045d941Ssowmini 1824045d941Ssowmini static int 1834045d941Ssowmini mac_ndd_get_ioctl(mac_impl_t *mip, mblk_t *mp, int avail, int *rval) 1844045d941Ssowmini { 1854045d941Ssowmini mblk_t *mp1; 1864045d941Ssowmini char *valp; 1874045d941Ssowmini uchar_t *value; 1884045d941Ssowmini uint32_t new_value; 189*aa71ed93SPrakash Jalan int size_out = 0, i; 1904045d941Ssowmini int status = EINVAL; 1914045d941Ssowmini char *name, priv_name[MAXLINKPROPNAME]; 1924045d941Ssowmini uint8_t u8; 1934045d941Ssowmini uint16_t u16; 1944045d941Ssowmini uint32_t u32; 1954045d941Ssowmini uint64_t u64; 1964045d941Ssowmini 1974045d941Ssowmini if (mp->b_cont == NULL || avail < 2) 1984045d941Ssowmini return (EINVAL); 1994045d941Ssowmini valp = (char *)mp->b_cont->b_rptr; 2004045d941Ssowmini mp1 = allocb(avail, BPRI_HI); /* the returned buffer */ 2014045d941Ssowmini if (mp1 == NULL) 2024045d941Ssowmini return (ENOMEM); 2034045d941Ssowmini 2044045d941Ssowmini if (strcmp(valp, "?") == 0) { 2054045d941Ssowmini /* 2064045d941Ssowmini * handle "ndd -get <..> \?" queries. 2074045d941Ssowmini */ 2084045d941Ssowmini size_out = mac_ndd_get_names(mip, mp1); 2094045d941Ssowmini if (size_out < 0) { 2104045d941Ssowmini status = ENOMEM; 2114045d941Ssowmini goto get_done; 2124045d941Ssowmini } 2134045d941Ssowmini if (size_out > avail) { 2144045d941Ssowmini int excess; 2154045d941Ssowmini char *cp; 2164045d941Ssowmini /* 2174045d941Ssowmini * need more user buffer space. Return as many 2184045d941Ssowmini * mblks as will fit and return the needed 2194045d941Ssowmini * buffer size in ioc_rval. 2204045d941Ssowmini */ 2214045d941Ssowmini excess = size_out - avail; 2224045d941Ssowmini *rval = size_out; /* what's needed */ 2234045d941Ssowmini size_out -= excess; 2244045d941Ssowmini (void) adjmsg(mp1, -(excess + 1)); 2254045d941Ssowmini cp = (char *)mp1->b_wptr; 2264045d941Ssowmini *cp = '\0'; 2274045d941Ssowmini } 2284045d941Ssowmini status = 0; 2294045d941Ssowmini goto get_done; 2304045d941Ssowmini } 2314045d941Ssowmini 2324045d941Ssowmini ASSERT(mip->mi_callbacks->mc_callbacks & MC_GETPROP); 2334045d941Ssowmini name = valp; 2344045d941Ssowmini valp = (char *)mp1->b_rptr; 2354045d941Ssowmini mp1->b_wptr = mp1->b_rptr; 2364045d941Ssowmini 2374045d941Ssowmini /* first lookup ndd <-> public property mapping */ 2384045d941Ssowmini for (i = 0; i < mip->mi_type->mt_mappingcount; i++) { 2394045d941Ssowmini if (strcmp(name, mip->mi_type->mt_mapping[i].mp_name) != 0) 2404045d941Ssowmini continue; 2414045d941Ssowmini 2424045d941Ssowmini switch (mip->mi_type->mt_mapping[i].mp_valsize) { 2434045d941Ssowmini case 1: 2444045d941Ssowmini value = (uchar_t *)&u8; 2454045d941Ssowmini break; 2464045d941Ssowmini case 2: 2474045d941Ssowmini value = (uchar_t *)&u16; 2484045d941Ssowmini break; 2494045d941Ssowmini case 4: 2504045d941Ssowmini value = (uchar_t *)&u32; 2514045d941Ssowmini break; 2524045d941Ssowmini default: 2534045d941Ssowmini value = (uchar_t *)&u64; 2544045d941Ssowmini break; 2554045d941Ssowmini } 2564045d941Ssowmini 2574045d941Ssowmini if ((mip->mi_type->mt_mapping[i].mp_flags & MAC_PROP_MAP_KSTAT) 2584045d941Ssowmini != 0) { 2594045d941Ssowmini u64 = mac_stat_get((mac_handle_t)mip, 2604045d941Ssowmini mip->mi_type->mt_mapping[i].mp_kstat); 2614045d941Ssowmini status = 0; 2624045d941Ssowmini /* 2634045d941Ssowmini * ether_stats are all always KSTAT_DATA_UINT32 2644045d941Ssowmini */ 2654045d941Ssowmini new_value = u32 = (long)u64; 2664045d941Ssowmini } else { 2674045d941Ssowmini status = mip->mi_callbacks->mc_getprop(mip->mi_driver, 2680dc2366fSVenugopal Iyer name, mip->mi_type->mt_mapping[i].mp_prop_id, 2690dc2366fSVenugopal Iyer mip->mi_type->mt_mapping[i].mp_valsize, value); 2704045d941Ssowmini switch (mip->mi_type->mt_mapping[i].mp_valsize) { 2714045d941Ssowmini case 1: 2724045d941Ssowmini new_value = u8; 2734045d941Ssowmini break; 2744045d941Ssowmini case 2: 2754045d941Ssowmini new_value = u16; 2764045d941Ssowmini break; 2774045d941Ssowmini case 4: 2784045d941Ssowmini new_value = u32; 2794045d941Ssowmini break; 2804045d941Ssowmini case 8: 2814045d941Ssowmini /* 2824045d941Ssowmini * The only uint64_t is for speed, which is 2834045d941Ssowmini * converted to Mbps in ndd reports. 2844045d941Ssowmini */ 2854045d941Ssowmini new_value = (u64/1000000); 2864045d941Ssowmini break; 2874045d941Ssowmini } 2884045d941Ssowmini } 2894045d941Ssowmini 2904045d941Ssowmini if (status != 0) 2914045d941Ssowmini goto get_done; 2924045d941Ssowmini 2934045d941Ssowmini (void) snprintf(valp, avail, "%d", new_value); 2944045d941Ssowmini goto update_reply; 2954045d941Ssowmini } 2964045d941Ssowmini 2974045d941Ssowmini /* 2984045d941Ssowmini * could not find a public property. try the private prop route 2994045d941Ssowmini * where all string processing will be done by the driver. 3004045d941Ssowmini */ 3014045d941Ssowmini (void) snprintf(priv_name, sizeof (priv_name), "_%s", name); 3024045d941Ssowmini status = mip->mi_callbacks->mc_getprop(mip->mi_driver, priv_name, 3030dc2366fSVenugopal Iyer MAC_PROP_PRIVATE, avail - 2, mp1->b_rptr); 3044045d941Ssowmini if (status != 0) 3054045d941Ssowmini goto get_done; 3064045d941Ssowmini 3074045d941Ssowmini update_reply: 3084045d941Ssowmini size_out += strnlen((const char *)mp1->b_rptr, avail); 3094045d941Ssowmini valp += size_out; 3104045d941Ssowmini *valp++ = '\0'; /* need \0\0 */ 3114045d941Ssowmini *valp++ = '\0'; 3124045d941Ssowmini mp1->b_wptr = (uchar_t *)valp; 3134045d941Ssowmini *rval = 0; 3144045d941Ssowmini 3154045d941Ssowmini get_done: 3164045d941Ssowmini freemsg(mp->b_cont); 3174045d941Ssowmini if (status == 0) 3184045d941Ssowmini mp->b_cont = mp1; 3194045d941Ssowmini else { 3204045d941Ssowmini freemsg(mp1); 3214045d941Ssowmini mp->b_cont = NULL; 3224045d941Ssowmini } 3234045d941Ssowmini return (status); 3244045d941Ssowmini } 3254045d941Ssowmini 3264045d941Ssowmini static int 3274045d941Ssowmini mac_ndd_set_ioctl(mac_impl_t *mip, mblk_t *mp, int avail, int *rval) 3284045d941Ssowmini { 3294045d941Ssowmini mblk_t *mp1; 3304045d941Ssowmini char *valp, *name, *new_valuep; 3314045d941Ssowmini uchar_t *vp; 3324045d941Ssowmini long new_value; 3334045d941Ssowmini int status, i; 3344045d941Ssowmini uint8_t u8; 3354045d941Ssowmini uint16_t u16; 3364045d941Ssowmini uint32_t u32; 3374045d941Ssowmini IOCP iocp; 3384045d941Ssowmini char priv_name[MAXLINKPROPNAME]; 3394045d941Ssowmini 3404045d941Ssowmini if (avail == 0 || !(mp1 = mp->b_cont)) 3414045d941Ssowmini return (EINVAL); 3424045d941Ssowmini 3434045d941Ssowmini if (mp1->b_cont) { 3444045d941Ssowmini freemsg(mp1->b_cont); 3454045d941Ssowmini mp1->b_cont = NULL; 3464045d941Ssowmini } 3474045d941Ssowmini mp1->b_datap->db_lim[-1] = '\0'; 3484045d941Ssowmini valp = (char *)mp1->b_rptr; 3494045d941Ssowmini name = valp; 3504045d941Ssowmini *rval = 0; 3514045d941Ssowmini while (*valp++) 3524045d941Ssowmini ; 3534045d941Ssowmini if (valp >= (char *)mp1->b_wptr) 3544045d941Ssowmini valp = NULL; 3554045d941Ssowmini 3564045d941Ssowmini new_valuep = valp; 3574045d941Ssowmini if (ddi_strtol(valp, NULL, 0, &new_value) != 0) 3584045d941Ssowmini goto priv_prop; 3594045d941Ssowmini 3604045d941Ssowmini iocp = (IOCP)mp->b_rptr; 3614045d941Ssowmini if (valp != NULL && 3624045d941Ssowmini ((iocp->ioc_cr == NULL) || 3634045d941Ssowmini ((status = secpolicy_net_config(iocp->ioc_cr, B_FALSE)) != 0))) 3644045d941Ssowmini return (status); 3654045d941Ssowmini 3664045d941Ssowmini status = EINVAL; 3674045d941Ssowmini 3684045d941Ssowmini /* first lookup ndd <-> public property mapping */ 3694045d941Ssowmini for (i = 0; i < mip->mi_type->mt_mappingcount; i++) { 3704045d941Ssowmini if (strcmp(name, mip->mi_type->mt_mapping[i].mp_name) != 0) 3714045d941Ssowmini continue; 3724045d941Ssowmini 3734045d941Ssowmini if (mip->mi_type->mt_mapping[i].mp_flags & MAC_PROP_MAP_KSTAT) 3744045d941Ssowmini return (EINVAL); 3754045d941Ssowmini 3764045d941Ssowmini if (new_value > mip->mi_type->mt_mapping[i].mp_maxval || 3774045d941Ssowmini new_value < mip->mi_type->mt_mapping[i].mp_minval || 3784045d941Ssowmini (mip->mi_type->mt_mapping[i].mp_flags & MAC_PROP_PERM_WRITE) 3794045d941Ssowmini == 0) 3804045d941Ssowmini return (EINVAL); 3814045d941Ssowmini switch (mip->mi_type->mt_mapping[i].mp_valsize) { 3824045d941Ssowmini case 1: 3834045d941Ssowmini u8 = (uint8_t)new_value; 3844045d941Ssowmini vp = (uchar_t *)&u8; 3854045d941Ssowmini break; 3864045d941Ssowmini case 2: 3874045d941Ssowmini u16 = (uint16_t)new_value; 3884045d941Ssowmini vp = (uchar_t *)&u16; 3894045d941Ssowmini break; 3904045d941Ssowmini case 4: 3914045d941Ssowmini u32 = (uint32_t)new_value; 3924045d941Ssowmini vp = (uchar_t *)&u32; 3934045d941Ssowmini break; 3944045d941Ssowmini case 8: 3954045d941Ssowmini vp = (uchar_t *)&new_value; 3964045d941Ssowmini break; 3974045d941Ssowmini default: 3984045d941Ssowmini return (ENOTSUP); 3994045d941Ssowmini } 4004045d941Ssowmini 4014045d941Ssowmini status = mip->mi_callbacks->mc_setprop(mip->mi_driver, 4024045d941Ssowmini name, mip->mi_type->mt_mapping[i].mp_prop_id, 4034045d941Ssowmini mip->mi_type->mt_mapping[i].mp_valsize, (const void *)vp); 4044045d941Ssowmini goto done; 4054045d941Ssowmini } 4064045d941Ssowmini 4074045d941Ssowmini priv_prop: 4084045d941Ssowmini (void) snprintf(priv_name, sizeof (priv_name), "_%s", name); 4094045d941Ssowmini status = mip->mi_callbacks->mc_setprop(mip->mi_driver, priv_name, 4103fd94f8cSam223141 MAC_PROP_PRIVATE, strlen(new_valuep), new_valuep); 4114045d941Ssowmini done: 4124045d941Ssowmini freemsg(mp1); 4134045d941Ssowmini mp->b_cont = NULL; 4144045d941Ssowmini return (status); 4154045d941Ssowmini } 416