17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*f4b3ec61Sdh155122 * Common Development and Distribution License (the "License"). 6*f4b3ec61Sdh155122 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*f4b3ec61Sdh155122 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/systm.h> 317c478bd9Sstevel@tonic-gate #include <inet/common.h> 327c478bd9Sstevel@tonic-gate #include <sys/stream.h> 337c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 347c478bd9Sstevel@tonic-gate #include <inet/mi.h> 357c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 377c478bd9Sstevel@tonic-gate #include <sys/policy.h> 387c478bd9Sstevel@tonic-gate #include <inet/nd.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate /* Free the table pointed to by 'ndp' */ 417c478bd9Sstevel@tonic-gate void 427c478bd9Sstevel@tonic-gate nd_free(caddr_t *nd_pparam) 437c478bd9Sstevel@tonic-gate { 447c478bd9Sstevel@tonic-gate ND *nd; 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate if ((nd = (ND *)(*nd_pparam)) != NULL) { 477c478bd9Sstevel@tonic-gate if (nd->nd_tbl) 487c478bd9Sstevel@tonic-gate mi_free((char *)nd->nd_tbl); 497c478bd9Sstevel@tonic-gate mi_free((char *)nd); 507c478bd9Sstevel@tonic-gate *nd_pparam = NULL; 517c478bd9Sstevel@tonic-gate } 527c478bd9Sstevel@tonic-gate } 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate int 557c478bd9Sstevel@tonic-gate nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp) 567c478bd9Sstevel@tonic-gate { 577c478bd9Sstevel@tonic-gate int err; 587c478bd9Sstevel@tonic-gate IOCP iocp; 597c478bd9Sstevel@tonic-gate MBLKP mp1; 607c478bd9Sstevel@tonic-gate ND *nd; 617c478bd9Sstevel@tonic-gate NDE *nde; 627c478bd9Sstevel@tonic-gate char *valp; 637c478bd9Sstevel@tonic-gate long avail; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate if (!nd_param) 667c478bd9Sstevel@tonic-gate return (B_FALSE); 677c478bd9Sstevel@tonic-gate nd = (ND *)nd_param; 687c478bd9Sstevel@tonic-gate iocp = (IOCP)mp->b_rptr; 697c478bd9Sstevel@tonic-gate if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) { 707c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 717c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 727c478bd9Sstevel@tonic-gate iocp->ioc_error = EINVAL; 737c478bd9Sstevel@tonic-gate return (B_TRUE); 747c478bd9Sstevel@tonic-gate } 757c478bd9Sstevel@tonic-gate /* 767c478bd9Sstevel@tonic-gate * NOTE - logic throughout nd_xxx assumes single data block for ioctl. 777c478bd9Sstevel@tonic-gate * However, existing code sends in some big buffers. 787c478bd9Sstevel@tonic-gate */ 797c478bd9Sstevel@tonic-gate avail = iocp->ioc_count; 807c478bd9Sstevel@tonic-gate if (mp1->b_cont) { 817c478bd9Sstevel@tonic-gate freemsg(mp1->b_cont); 827c478bd9Sstevel@tonic-gate mp1->b_cont = NULL; 837c478bd9Sstevel@tonic-gate } 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate mp1->b_datap->db_lim[-1] = '\0'; /* Force null termination */ 867c478bd9Sstevel@tonic-gate valp = (char *)mp1->b_rptr; 877c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; ; nde++) { 887c478bd9Sstevel@tonic-gate if (!nde->nde_name) 897c478bd9Sstevel@tonic-gate return (B_FALSE); 907c478bd9Sstevel@tonic-gate if (mi_strcmp(nde->nde_name, valp) == 0) 917c478bd9Sstevel@tonic-gate break; 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate err = EINVAL; 947c478bd9Sstevel@tonic-gate while (*valp++) 957c478bd9Sstevel@tonic-gate noop; 967c478bd9Sstevel@tonic-gate if (!*valp || valp >= (char *)mp1->b_wptr) 977c478bd9Sstevel@tonic-gate valp = NULL; 987c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 997c478bd9Sstevel@tonic-gate case ND_GET: 1007c478bd9Sstevel@tonic-gate /* 1017c478bd9Sstevel@tonic-gate * (temporary) hack: "*valp" is size of user buffer for 1027c478bd9Sstevel@tonic-gate * copyout. If result of action routine is too big, free 1037c478bd9Sstevel@tonic-gate * excess and return ioc_rval as buffer size needed. Return 1047c478bd9Sstevel@tonic-gate * as many mblocks as will fit, free the rest. For backward 1057c478bd9Sstevel@tonic-gate * compatibility, assume size of original ioctl buffer if 1067c478bd9Sstevel@tonic-gate * "*valp" bad or not given. 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate if (valp) 1097c478bd9Sstevel@tonic-gate (void) ddi_strtol(valp, NULL, 10, &avail); 1107c478bd9Sstevel@tonic-gate /* We overwrite the name/value with the reply data */ 1117c478bd9Sstevel@tonic-gate { 1127c478bd9Sstevel@tonic-gate mblk_t *mp2 = mp1; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate while (mp2) { 1157c478bd9Sstevel@tonic-gate mp2->b_wptr = mp2->b_rptr; 1167c478bd9Sstevel@tonic-gate mp2 = mp2->b_cont; 1177c478bd9Sstevel@tonic-gate } 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate err = (*nde->nde_get_pfi)(q, mp1, nde->nde_data, iocp->ioc_cr); 1207c478bd9Sstevel@tonic-gate if (!err) { 1217c478bd9Sstevel@tonic-gate int size_out; 1227c478bd9Sstevel@tonic-gate int excess; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate iocp->ioc_rval = 0; 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /* Tack on the null */ 1277c478bd9Sstevel@tonic-gate (void) mi_mpprintf_putc((char *)mp1, '\0'); 1287c478bd9Sstevel@tonic-gate size_out = msgdsize(mp1); 1297c478bd9Sstevel@tonic-gate excess = size_out - avail; 1307c478bd9Sstevel@tonic-gate if (excess > 0) { 1317c478bd9Sstevel@tonic-gate iocp->ioc_rval = size_out; 1327c478bd9Sstevel@tonic-gate size_out -= excess; 1337c478bd9Sstevel@tonic-gate (void) adjmsg(mp1, -(excess + 1)); 1347c478bd9Sstevel@tonic-gate (void) mi_mpprintf_putc((char *)mp1, '\0'); 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate iocp->ioc_count = size_out; 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate break; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate case ND_SET: 1417c478bd9Sstevel@tonic-gate if (valp) { 1427c478bd9Sstevel@tonic-gate if ((iocp->ioc_cr != NULL) && 143*f4b3ec61Sdh155122 ((err = secpolicy_ip_config(iocp->ioc_cr, B_FALSE)) 1447c478bd9Sstevel@tonic-gate == 0)) { 1457c478bd9Sstevel@tonic-gate err = (*nde->nde_set_pfi)(q, mp1, valp, 1467c478bd9Sstevel@tonic-gate nde->nde_data, iocp->ioc_cr); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 1497c478bd9Sstevel@tonic-gate freemsg(mp1); 1507c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate break; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate default: 1557c478bd9Sstevel@tonic-gate break; 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate iocp->ioc_error = err; 1587c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 1597c478bd9Sstevel@tonic-gate return (B_TRUE); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1637c478bd9Sstevel@tonic-gate int 1647c478bd9Sstevel@tonic-gate nd_get_default(queue_t *q, MBLKP mp, caddr_t data, cred_t *ioc_cr) 1657c478bd9Sstevel@tonic-gate { 1667c478bd9Sstevel@tonic-gate return (EACCES); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * This routine may be used as the get dispatch routine in nd tables 1717c478bd9Sstevel@tonic-gate * for long variables. To use this routine instead of a module 1727c478bd9Sstevel@tonic-gate * specific routine, call nd_load as 1737c478bd9Sstevel@tonic-gate * nd_load(&nd_ptr, "name", nd_get_long, set_pfi, &long_variable) 1747c478bd9Sstevel@tonic-gate * The name of the variable followed by a space and the value of the 1757c478bd9Sstevel@tonic-gate * variable will be printed in response to a get_status call. 1767c478bd9Sstevel@tonic-gate */ 1777c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1787c478bd9Sstevel@tonic-gate int 1797c478bd9Sstevel@tonic-gate nd_get_long(queue_t *q, MBLKP mp, caddr_t data, cred_t *ioc_cr) 1807c478bd9Sstevel@tonic-gate { 1817c478bd9Sstevel@tonic-gate ulong_t *lp; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate lp = (ulong_t *)data; 1847c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, "%ld", *lp); 1857c478bd9Sstevel@tonic-gate return (0); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1897c478bd9Sstevel@tonic-gate int 1907c478bd9Sstevel@tonic-gate nd_get_names(queue_t *q, MBLKP mp, caddr_t nd_param, cred_t *ioc_cr) 1917c478bd9Sstevel@tonic-gate { 1927c478bd9Sstevel@tonic-gate ND *nd; 1937c478bd9Sstevel@tonic-gate NDE *nde; 1947c478bd9Sstevel@tonic-gate char *rwtag; 1957c478bd9Sstevel@tonic-gate boolean_t get_ok, set_ok; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate nd = (ND *)nd_param; 1987c478bd9Sstevel@tonic-gate if (!nd) 1997c478bd9Sstevel@tonic-gate return (ENOENT); 2007c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name; nde++) { 2017c478bd9Sstevel@tonic-gate get_ok = nde->nde_get_pfi != nd_get_default; 2027c478bd9Sstevel@tonic-gate set_ok = nde->nde_set_pfi != nd_set_default; 2037c478bd9Sstevel@tonic-gate if (get_ok) { 2047c478bd9Sstevel@tonic-gate if (set_ok) 2057c478bd9Sstevel@tonic-gate rwtag = "read and write"; 2067c478bd9Sstevel@tonic-gate else 2077c478bd9Sstevel@tonic-gate rwtag = "read only"; 2087c478bd9Sstevel@tonic-gate } else if (set_ok) 2097c478bd9Sstevel@tonic-gate rwtag = "write only"; 2107c478bd9Sstevel@tonic-gate else 2117c478bd9Sstevel@tonic-gate rwtag = "no read or write"; 2127c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, "%s (%s)", nde->nde_name, rwtag); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate return (0); 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate /* 2187c478bd9Sstevel@tonic-gate * Load 'name' into the named dispatch table pointed to by 'ndp'. 2197c478bd9Sstevel@tonic-gate * 'ndp' should be the address of a char pointer cell. If the table 2207c478bd9Sstevel@tonic-gate * does not exist (*ndp == 0), a new table is allocated and 'ndp' 2217c478bd9Sstevel@tonic-gate * is stuffed. If there is not enough space in the table for a new 2227c478bd9Sstevel@tonic-gate * entry, more space is allocated. 223*f4b3ec61Sdh155122 * Never fails due to memory allocation failures. 2247c478bd9Sstevel@tonic-gate */ 2257c478bd9Sstevel@tonic-gate boolean_t 2267c478bd9Sstevel@tonic-gate nd_load(caddr_t *nd_pparam, char *name, ndgetf_t get_pfi, ndsetf_t set_pfi, 2277c478bd9Sstevel@tonic-gate caddr_t data) 2287c478bd9Sstevel@tonic-gate { 2297c478bd9Sstevel@tonic-gate ND *nd; 2307c478bd9Sstevel@tonic-gate NDE *nde; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate if (!nd_pparam) 2337c478bd9Sstevel@tonic-gate return (B_FALSE); 2347c478bd9Sstevel@tonic-gate if ((nd = (ND *)(*nd_pparam)) == NULL) { 235*f4b3ec61Sdh155122 nd = (ND *)mi_alloc_sleep(sizeof (ND), BPRI_MED); 2367c478bd9Sstevel@tonic-gate bzero((caddr_t)nd, sizeof (ND)); 2377c478bd9Sstevel@tonic-gate *nd_pparam = (caddr_t)nd; 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate if (nd->nd_tbl) { 2407c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name; nde++) { 2417c478bd9Sstevel@tonic-gate if (mi_strcmp(name, nde->nde_name) == 0) 2427c478bd9Sstevel@tonic-gate goto fill_it; 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate if (nd->nd_free_count <= 1) { 246*f4b3ec61Sdh155122 nde = (NDE *)mi_alloc_sleep(nd->nd_size + 247*f4b3ec61Sdh155122 NDE_ALLOC_SIZE, BPRI_MED); 2487c478bd9Sstevel@tonic-gate bzero((char *)nde, nd->nd_size + NDE_ALLOC_SIZE); 2497c478bd9Sstevel@tonic-gate nd->nd_free_count += NDE_ALLOC_COUNT; 2507c478bd9Sstevel@tonic-gate if (nd->nd_tbl) { 2517c478bd9Sstevel@tonic-gate bcopy((char *)nd->nd_tbl, (char *)nde, nd->nd_size); 2527c478bd9Sstevel@tonic-gate mi_free((char *)nd->nd_tbl); 2537c478bd9Sstevel@tonic-gate } else { 2547c478bd9Sstevel@tonic-gate nd->nd_free_count--; 2557c478bd9Sstevel@tonic-gate nde->nde_name = "?"; 2567c478bd9Sstevel@tonic-gate nde->nde_get_pfi = nd_get_names; 2577c478bd9Sstevel@tonic-gate nde->nde_set_pfi = nd_set_default; 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate nde->nde_data = (caddr_t)nd; 2607c478bd9Sstevel@tonic-gate nd->nd_tbl = nde; 2617c478bd9Sstevel@tonic-gate nd->nd_size += NDE_ALLOC_SIZE; 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name; nde++) 2647c478bd9Sstevel@tonic-gate noop; 2657c478bd9Sstevel@tonic-gate nd->nd_free_count--; 2667c478bd9Sstevel@tonic-gate fill_it: 2677c478bd9Sstevel@tonic-gate nde->nde_name = name; 2687c478bd9Sstevel@tonic-gate nde->nde_get_pfi = get_pfi ? get_pfi : nd_get_default; 2697c478bd9Sstevel@tonic-gate nde->nde_set_pfi = set_pfi ? set_pfi : nd_set_default; 2707c478bd9Sstevel@tonic-gate nde->nde_data = data; 2717c478bd9Sstevel@tonic-gate return (B_TRUE); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * Unload 'name' from the named dispatch table. If the table does not 2767c478bd9Sstevel@tonic-gate * exist, I return. I do not free up space, but I do raise the 2777c478bd9Sstevel@tonic-gate * free count so future nd_load()s don't take as much memory. 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate void 2817c478bd9Sstevel@tonic-gate nd_unload(caddr_t *nd_pparam, char *name) 2827c478bd9Sstevel@tonic-gate { 2837c478bd9Sstevel@tonic-gate ND *nd; 2847c478bd9Sstevel@tonic-gate NDE *nde; 2857c478bd9Sstevel@tonic-gate boolean_t foundit = B_FALSE; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* My apologies for the in-boolean assignment. */ 2887c478bd9Sstevel@tonic-gate if (nd_pparam == NULL || (nd = (ND *)(*nd_pparam)) == NULL || 2897c478bd9Sstevel@tonic-gate nd->nd_tbl == NULL) 2907c478bd9Sstevel@tonic-gate return; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name != NULL; nde++) { 2937c478bd9Sstevel@tonic-gate if (foundit) 2947c478bd9Sstevel@tonic-gate *(nde - 1) = *nde; 2957c478bd9Sstevel@tonic-gate if (mi_strcmp(name, nde->nde_name) == 0) 2967c478bd9Sstevel@tonic-gate foundit = B_TRUE; 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate if (foundit) 2997c478bd9Sstevel@tonic-gate bzero(nde - 1, sizeof (NDE)); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3037c478bd9Sstevel@tonic-gate int 3047c478bd9Sstevel@tonic-gate nd_set_default(queue_t *q, MBLKP mp, char *value, caddr_t data, cred_t *ioc_cr) 3057c478bd9Sstevel@tonic-gate { 3067c478bd9Sstevel@tonic-gate return (EACCES); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3107c478bd9Sstevel@tonic-gate int 3117c478bd9Sstevel@tonic-gate nd_set_long(queue_t *q, MBLKP mp, char *value, caddr_t data, cred_t *ioc_cr) 3127c478bd9Sstevel@tonic-gate { 3137c478bd9Sstevel@tonic-gate ulong_t *lp; 3147c478bd9Sstevel@tonic-gate long new_value; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate if (ddi_strtol(value, NULL, 10, &new_value) != 0) 3177c478bd9Sstevel@tonic-gate return (EINVAL); 3187c478bd9Sstevel@tonic-gate lp = (ulong_t *)data; 3197c478bd9Sstevel@tonic-gate *lp = new_value; 3207c478bd9Sstevel@tonic-gate return (0); 3217c478bd9Sstevel@tonic-gate } 322