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 5f4b3ec61Sdh155122 * Common Development and Distribution License (the "License"). 6f4b3ec61Sdh155122 * 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*6e91bba0SGirish Moodalbail * Copyright 2010 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 #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/systm.h> 297c478bd9Sstevel@tonic-gate #include <inet/common.h> 307c478bd9Sstevel@tonic-gate #include <sys/stream.h> 317c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 327c478bd9Sstevel@tonic-gate #include <inet/mi.h> 337c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 357c478bd9Sstevel@tonic-gate #include <sys/policy.h> 367c478bd9Sstevel@tonic-gate #include <inet/nd.h> 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate /* Free the table pointed to by 'ndp' */ 397c478bd9Sstevel@tonic-gate void 407c478bd9Sstevel@tonic-gate nd_free(caddr_t *nd_pparam) 417c478bd9Sstevel@tonic-gate { 427c478bd9Sstevel@tonic-gate ND *nd; 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate if ((nd = (ND *)(*nd_pparam)) != NULL) { 457c478bd9Sstevel@tonic-gate if (nd->nd_tbl) 467c478bd9Sstevel@tonic-gate mi_free((char *)nd->nd_tbl); 477c478bd9Sstevel@tonic-gate mi_free((char *)nd); 487c478bd9Sstevel@tonic-gate *nd_pparam = NULL; 497c478bd9Sstevel@tonic-gate } 507c478bd9Sstevel@tonic-gate } 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate int 537c478bd9Sstevel@tonic-gate nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp) 547c478bd9Sstevel@tonic-gate { 557c478bd9Sstevel@tonic-gate int err; 567c478bd9Sstevel@tonic-gate IOCP iocp; 577c478bd9Sstevel@tonic-gate MBLKP mp1; 587c478bd9Sstevel@tonic-gate ND *nd; 597c478bd9Sstevel@tonic-gate NDE *nde; 607c478bd9Sstevel@tonic-gate char *valp; 617c478bd9Sstevel@tonic-gate long avail; 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate if (!nd_param) 647c478bd9Sstevel@tonic-gate return (B_FALSE); 657c478bd9Sstevel@tonic-gate nd = (ND *)nd_param; 667c478bd9Sstevel@tonic-gate iocp = (IOCP)mp->b_rptr; 677c478bd9Sstevel@tonic-gate if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) { 687c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 697c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 707c478bd9Sstevel@tonic-gate iocp->ioc_error = EINVAL; 717c478bd9Sstevel@tonic-gate return (B_TRUE); 727c478bd9Sstevel@tonic-gate } 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * NOTE - logic throughout nd_xxx assumes single data block for ioctl. 757c478bd9Sstevel@tonic-gate * However, existing code sends in some big buffers. 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate avail = iocp->ioc_count; 787c478bd9Sstevel@tonic-gate if (mp1->b_cont) { 797c478bd9Sstevel@tonic-gate freemsg(mp1->b_cont); 807c478bd9Sstevel@tonic-gate mp1->b_cont = NULL; 817c478bd9Sstevel@tonic-gate } 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate mp1->b_datap->db_lim[-1] = '\0'; /* Force null termination */ 847c478bd9Sstevel@tonic-gate valp = (char *)mp1->b_rptr; 857c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; ; nde++) { 867c478bd9Sstevel@tonic-gate if (!nde->nde_name) 877c478bd9Sstevel@tonic-gate return (B_FALSE); 887c478bd9Sstevel@tonic-gate if (mi_strcmp(nde->nde_name, valp) == 0) 897c478bd9Sstevel@tonic-gate break; 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate err = EINVAL; 927c478bd9Sstevel@tonic-gate while (*valp++) 937c478bd9Sstevel@tonic-gate noop; 947c478bd9Sstevel@tonic-gate if (!*valp || valp >= (char *)mp1->b_wptr) 957c478bd9Sstevel@tonic-gate valp = NULL; 967c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 977c478bd9Sstevel@tonic-gate case ND_GET: 987c478bd9Sstevel@tonic-gate /* We overwrite the name/value with the reply data */ 99*6e91bba0SGirish Moodalbail mp1->b_wptr = mp1->b_rptr; 1007c478bd9Sstevel@tonic-gate err = (*nde->nde_get_pfi)(q, mp1, nde->nde_data, iocp->ioc_cr); 1017c478bd9Sstevel@tonic-gate if (!err) { 1027c478bd9Sstevel@tonic-gate int size_out; 1037c478bd9Sstevel@tonic-gate int excess; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate iocp->ioc_rval = 0; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* Tack on the null */ 1087c478bd9Sstevel@tonic-gate (void) mi_mpprintf_putc((char *)mp1, '\0'); 1097c478bd9Sstevel@tonic-gate size_out = msgdsize(mp1); 1107c478bd9Sstevel@tonic-gate excess = size_out - avail; 1117c478bd9Sstevel@tonic-gate if (excess > 0) { 1127c478bd9Sstevel@tonic-gate iocp->ioc_rval = size_out; 1137c478bd9Sstevel@tonic-gate size_out -= excess; 1147c478bd9Sstevel@tonic-gate (void) adjmsg(mp1, -(excess + 1)); 1157c478bd9Sstevel@tonic-gate (void) mi_mpprintf_putc((char *)mp1, '\0'); 1167c478bd9Sstevel@tonic-gate } 1177c478bd9Sstevel@tonic-gate iocp->ioc_count = size_out; 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate break; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate case ND_SET: 1227c478bd9Sstevel@tonic-gate if (valp) { 1237c478bd9Sstevel@tonic-gate if ((iocp->ioc_cr != NULL) && 124f4b3ec61Sdh155122 ((err = secpolicy_ip_config(iocp->ioc_cr, B_FALSE)) 1257c478bd9Sstevel@tonic-gate == 0)) { 1267c478bd9Sstevel@tonic-gate err = (*nde->nde_set_pfi)(q, mp1, valp, 1277c478bd9Sstevel@tonic-gate nde->nde_data, iocp->ioc_cr); 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 1307c478bd9Sstevel@tonic-gate freemsg(mp1); 1317c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate break; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate default: 1367c478bd9Sstevel@tonic-gate break; 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate iocp->ioc_error = err; 1397c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 1407c478bd9Sstevel@tonic-gate return (B_TRUE); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1447c478bd9Sstevel@tonic-gate int 1457c478bd9Sstevel@tonic-gate nd_get_default(queue_t *q, MBLKP mp, caddr_t data, cred_t *ioc_cr) 1467c478bd9Sstevel@tonic-gate { 1477c478bd9Sstevel@tonic-gate return (EACCES); 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* 1517c478bd9Sstevel@tonic-gate * This routine may be used as the get dispatch routine in nd tables 1527c478bd9Sstevel@tonic-gate * for long variables. To use this routine instead of a module 1537c478bd9Sstevel@tonic-gate * specific routine, call nd_load as 1547c478bd9Sstevel@tonic-gate * nd_load(&nd_ptr, "name", nd_get_long, set_pfi, &long_variable) 1557c478bd9Sstevel@tonic-gate * The name of the variable followed by a space and the value of the 1567c478bd9Sstevel@tonic-gate * variable will be printed in response to a get_status call. 1577c478bd9Sstevel@tonic-gate */ 1587c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1597c478bd9Sstevel@tonic-gate int 1607c478bd9Sstevel@tonic-gate nd_get_long(queue_t *q, MBLKP mp, caddr_t data, cred_t *ioc_cr) 1617c478bd9Sstevel@tonic-gate { 1627c478bd9Sstevel@tonic-gate ulong_t *lp; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate lp = (ulong_t *)data; 1657c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, "%ld", *lp); 1667c478bd9Sstevel@tonic-gate return (0); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1707c478bd9Sstevel@tonic-gate int 1717c478bd9Sstevel@tonic-gate nd_get_names(queue_t *q, MBLKP mp, caddr_t nd_param, cred_t *ioc_cr) 1727c478bd9Sstevel@tonic-gate { 1737c478bd9Sstevel@tonic-gate ND *nd; 1747c478bd9Sstevel@tonic-gate NDE *nde; 1757c478bd9Sstevel@tonic-gate char *rwtag; 1767c478bd9Sstevel@tonic-gate boolean_t get_ok, set_ok; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate nd = (ND *)nd_param; 1797c478bd9Sstevel@tonic-gate if (!nd) 1807c478bd9Sstevel@tonic-gate return (ENOENT); 1817c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name; nde++) { 1827c478bd9Sstevel@tonic-gate get_ok = nde->nde_get_pfi != nd_get_default; 1837c478bd9Sstevel@tonic-gate set_ok = nde->nde_set_pfi != nd_set_default; 1847c478bd9Sstevel@tonic-gate if (get_ok) { 1857c478bd9Sstevel@tonic-gate if (set_ok) 1867c478bd9Sstevel@tonic-gate rwtag = "read and write"; 1877c478bd9Sstevel@tonic-gate else 1887c478bd9Sstevel@tonic-gate rwtag = "read only"; 1897c478bd9Sstevel@tonic-gate } else if (set_ok) 1907c478bd9Sstevel@tonic-gate rwtag = "write only"; 1917c478bd9Sstevel@tonic-gate else 1927c478bd9Sstevel@tonic-gate rwtag = "no read or write"; 1937c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, "%s (%s)", nde->nde_name, rwtag); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate return (0); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * Load 'name' into the named dispatch table pointed to by 'ndp'. 2007c478bd9Sstevel@tonic-gate * 'ndp' should be the address of a char pointer cell. If the table 2017c478bd9Sstevel@tonic-gate * does not exist (*ndp == 0), a new table is allocated and 'ndp' 2027c478bd9Sstevel@tonic-gate * is stuffed. If there is not enough space in the table for a new 2037c478bd9Sstevel@tonic-gate * entry, more space is allocated. 204f4b3ec61Sdh155122 * Never fails due to memory allocation failures. 2057c478bd9Sstevel@tonic-gate */ 2067c478bd9Sstevel@tonic-gate boolean_t 2077c478bd9Sstevel@tonic-gate nd_load(caddr_t *nd_pparam, char *name, ndgetf_t get_pfi, ndsetf_t set_pfi, 2087c478bd9Sstevel@tonic-gate caddr_t data) 2097c478bd9Sstevel@tonic-gate { 2107c478bd9Sstevel@tonic-gate ND *nd; 2117c478bd9Sstevel@tonic-gate NDE *nde; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate if (!nd_pparam) 2147c478bd9Sstevel@tonic-gate return (B_FALSE); 2157c478bd9Sstevel@tonic-gate if ((nd = (ND *)(*nd_pparam)) == NULL) { 216f4b3ec61Sdh155122 nd = (ND *)mi_alloc_sleep(sizeof (ND), BPRI_MED); 2177c478bd9Sstevel@tonic-gate bzero((caddr_t)nd, sizeof (ND)); 2187c478bd9Sstevel@tonic-gate *nd_pparam = (caddr_t)nd; 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate if (nd->nd_tbl) { 2217c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name; nde++) { 2227c478bd9Sstevel@tonic-gate if (mi_strcmp(name, nde->nde_name) == 0) 2237c478bd9Sstevel@tonic-gate goto fill_it; 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate if (nd->nd_free_count <= 1) { 227f4b3ec61Sdh155122 nde = (NDE *)mi_alloc_sleep(nd->nd_size + 228f4b3ec61Sdh155122 NDE_ALLOC_SIZE, BPRI_MED); 2297c478bd9Sstevel@tonic-gate bzero((char *)nde, nd->nd_size + NDE_ALLOC_SIZE); 2307c478bd9Sstevel@tonic-gate nd->nd_free_count += NDE_ALLOC_COUNT; 2317c478bd9Sstevel@tonic-gate if (nd->nd_tbl) { 2327c478bd9Sstevel@tonic-gate bcopy((char *)nd->nd_tbl, (char *)nde, nd->nd_size); 2337c478bd9Sstevel@tonic-gate mi_free((char *)nd->nd_tbl); 2347c478bd9Sstevel@tonic-gate } else { 2357c478bd9Sstevel@tonic-gate nd->nd_free_count--; 2367c478bd9Sstevel@tonic-gate nde->nde_name = "?"; 2377c478bd9Sstevel@tonic-gate nde->nde_get_pfi = nd_get_names; 2387c478bd9Sstevel@tonic-gate nde->nde_set_pfi = nd_set_default; 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate nde->nde_data = (caddr_t)nd; 2417c478bd9Sstevel@tonic-gate nd->nd_tbl = nde; 2427c478bd9Sstevel@tonic-gate nd->nd_size += NDE_ALLOC_SIZE; 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name; nde++) 2457c478bd9Sstevel@tonic-gate noop; 2467c478bd9Sstevel@tonic-gate nd->nd_free_count--; 2477c478bd9Sstevel@tonic-gate fill_it: 2487c478bd9Sstevel@tonic-gate nde->nde_name = name; 2497c478bd9Sstevel@tonic-gate nde->nde_get_pfi = get_pfi ? get_pfi : nd_get_default; 2507c478bd9Sstevel@tonic-gate nde->nde_set_pfi = set_pfi ? set_pfi : nd_set_default; 2517c478bd9Sstevel@tonic-gate nde->nde_data = data; 2527c478bd9Sstevel@tonic-gate return (B_TRUE); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate /* 2567c478bd9Sstevel@tonic-gate * Unload 'name' from the named dispatch table. If the table does not 2577c478bd9Sstevel@tonic-gate * exist, I return. I do not free up space, but I do raise the 2587c478bd9Sstevel@tonic-gate * free count so future nd_load()s don't take as much memory. 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate void 2627c478bd9Sstevel@tonic-gate nd_unload(caddr_t *nd_pparam, char *name) 2637c478bd9Sstevel@tonic-gate { 2647c478bd9Sstevel@tonic-gate ND *nd; 2657c478bd9Sstevel@tonic-gate NDE *nde; 2667c478bd9Sstevel@tonic-gate boolean_t foundit = B_FALSE; 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate /* My apologies for the in-boolean assignment. */ 2697c478bd9Sstevel@tonic-gate if (nd_pparam == NULL || (nd = (ND *)(*nd_pparam)) == NULL || 2707c478bd9Sstevel@tonic-gate nd->nd_tbl == NULL) 2717c478bd9Sstevel@tonic-gate return; 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name != NULL; nde++) { 2747c478bd9Sstevel@tonic-gate if (foundit) 2757c478bd9Sstevel@tonic-gate *(nde - 1) = *nde; 2767c478bd9Sstevel@tonic-gate if (mi_strcmp(name, nde->nde_name) == 0) 2777c478bd9Sstevel@tonic-gate foundit = B_TRUE; 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate if (foundit) 2807c478bd9Sstevel@tonic-gate bzero(nde - 1, sizeof (NDE)); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2847c478bd9Sstevel@tonic-gate int 2857c478bd9Sstevel@tonic-gate nd_set_default(queue_t *q, MBLKP mp, char *value, caddr_t data, cred_t *ioc_cr) 2867c478bd9Sstevel@tonic-gate { 2877c478bd9Sstevel@tonic-gate return (EACCES); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2917c478bd9Sstevel@tonic-gate int 2927c478bd9Sstevel@tonic-gate nd_set_long(queue_t *q, MBLKP mp, char *value, caddr_t data, cred_t *ioc_cr) 2937c478bd9Sstevel@tonic-gate { 2947c478bd9Sstevel@tonic-gate ulong_t *lp; 2957c478bd9Sstevel@tonic-gate long new_value; 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate if (ddi_strtol(value, NULL, 10, &new_value) != 0) 2987c478bd9Sstevel@tonic-gate return (EINVAL); 2997c478bd9Sstevel@tonic-gate lp = (ulong_t *)data; 3007c478bd9Sstevel@tonic-gate *lp = new_value; 3017c478bd9Sstevel@tonic-gate return (0); 3027c478bd9Sstevel@tonic-gate } 303