16e91bba0SGirish Moodalbail /*
26e91bba0SGirish Moodalbail  * CDDL HEADER START
36e91bba0SGirish Moodalbail  *
46e91bba0SGirish Moodalbail  * The contents of this file are subject to the terms of the
56e91bba0SGirish Moodalbail  * Common Development and Distribution License (the "License").
66e91bba0SGirish Moodalbail  * You may not use this file except in compliance with the License.
76e91bba0SGirish Moodalbail  *
86e91bba0SGirish Moodalbail  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96e91bba0SGirish Moodalbail  * or http://www.opensolaris.org/os/licensing.
106e91bba0SGirish Moodalbail  * See the License for the specific language governing permissions
116e91bba0SGirish Moodalbail  * and limitations under the License.
126e91bba0SGirish Moodalbail  *
136e91bba0SGirish Moodalbail  * When distributing Covered Code, include this CDDL HEADER in each
146e91bba0SGirish Moodalbail  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156e91bba0SGirish Moodalbail  * If applicable, add the following below this CDDL HEADER, with the
166e91bba0SGirish Moodalbail  * fields enclosed by brackets "[]" replaced with your own identifying
176e91bba0SGirish Moodalbail  * information: Portions Copyright [yyyy] [name of copyright owner]
186e91bba0SGirish Moodalbail  *
196e91bba0SGirish Moodalbail  * CDDL HEADER END
206e91bba0SGirish Moodalbail  */
216e91bba0SGirish Moodalbail /*
22f1e9465bSSowmini Varadhan  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23299625c6SSebastien Roy  * Copyright (c) 2013 by Delphix. All rights reserved.
247c6d7024SJerry Jelinek  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
256e91bba0SGirish Moodalbail  */
268887b57dSGirish Moodalbail /* Copyright (c) 1990 Mentat Inc. */
276e91bba0SGirish Moodalbail 
286e91bba0SGirish Moodalbail #include <inet/ip.h>
296e91bba0SGirish Moodalbail #include <inet/ip6.h>
306e91bba0SGirish Moodalbail #include <inet/ip_if.h>
316e91bba0SGirish Moodalbail #include <inet/ip_ire.h>
326e91bba0SGirish Moodalbail #include <inet/ipclassifier.h>
336e91bba0SGirish Moodalbail #include <inet/ip_impl.h>
346e91bba0SGirish Moodalbail #include <inet/tunables.h>
356e91bba0SGirish Moodalbail #include <sys/sunddi.h>
366e91bba0SGirish Moodalbail #include <sys/policy.h>
376e91bba0SGirish Moodalbail 
386e91bba0SGirish Moodalbail /* How long, in seconds, we allow frags to hang around. */
396e91bba0SGirish Moodalbail #define	IP_REASM_TIMEOUT	15
406e91bba0SGirish Moodalbail #define	IPV6_REASM_TIMEOUT	60
416e91bba0SGirish Moodalbail 
426e91bba0SGirish Moodalbail /*
436e91bba0SGirish Moodalbail  * Set ip{,6}_forwarding values. If the value is being set on an ill,
446e91bba0SGirish Moodalbail  * find the ill and set the value on it. On the other hand if we are modifying
456e91bba0SGirish Moodalbail  * global property, modify the global value and set the value on all the ills.
466e91bba0SGirish Moodalbail  */
476e91bba0SGirish Moodalbail /* ARGSUSED */
486e91bba0SGirish Moodalbail static int
ip_set_forwarding(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)49299625c6SSebastien Roy ip_set_forwarding(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
506e91bba0SGirish Moodalbail     const char *ifname, const void* pval, uint_t flags)
516e91bba0SGirish Moodalbail {
526e91bba0SGirish Moodalbail 	char			*end;
536e91bba0SGirish Moodalbail 	unsigned long		new_value;
54299625c6SSebastien Roy 	boolean_t		per_ill, isv6;
55299625c6SSebastien Roy 	ill_walk_context_t	ctx;
56299625c6SSebastien Roy 	ill_t			*ill;
57299625c6SSebastien Roy 	ip_stack_t		*ipst = stack->netstack_ip;
586e91bba0SGirish Moodalbail 
596e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_DEFAULT) {
606e91bba0SGirish Moodalbail 		new_value = pinfo->prop_def_bval;
616e91bba0SGirish Moodalbail 	} else {
626e91bba0SGirish Moodalbail 		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
636e91bba0SGirish Moodalbail 		    *end != '\0')
646e91bba0SGirish Moodalbail 			return (EINVAL);
656e91bba0SGirish Moodalbail 		if (new_value != B_TRUE && new_value != B_FALSE)
666e91bba0SGirish Moodalbail 			return (EINVAL);
676e91bba0SGirish Moodalbail 	}
686e91bba0SGirish Moodalbail 
696e91bba0SGirish Moodalbail 	per_ill = (ifname != NULL && ifname[0] != '\0');
706e91bba0SGirish Moodalbail 	/*
716e91bba0SGirish Moodalbail 	 * if it's not per ill then set the global property and bring all the
726e91bba0SGirish Moodalbail 	 * ills up to date with the new global value.
736e91bba0SGirish Moodalbail 	 */
746e91bba0SGirish Moodalbail 	if (!per_ill)
756e91bba0SGirish Moodalbail 		pinfo->prop_cur_bval = (new_value == 1 ? B_TRUE : B_FALSE);
766e91bba0SGirish Moodalbail 
776e91bba0SGirish Moodalbail 	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
786e91bba0SGirish Moodalbail 	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
796e91bba0SGirish Moodalbail 	if (isv6)
806e91bba0SGirish Moodalbail 		ill = ILL_START_WALK_V6(&ctx, ipst);
816e91bba0SGirish Moodalbail 	else
826e91bba0SGirish Moodalbail 		ill = ILL_START_WALK_V4(&ctx, ipst);
836e91bba0SGirish Moodalbail 
846e91bba0SGirish Moodalbail 	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
856e91bba0SGirish Moodalbail 		/*
866e91bba0SGirish Moodalbail 		 * if the property needs to be set on a particular
876e91bba0SGirish Moodalbail 		 * interface, look for that interface.
886e91bba0SGirish Moodalbail 		 */
896e91bba0SGirish Moodalbail 		if (per_ill && strcmp(ifname, ill->ill_name) != 0)
906e91bba0SGirish Moodalbail 			continue;
916e91bba0SGirish Moodalbail 		(void) ill_forward_set(ill, new_value != 0);
926e91bba0SGirish Moodalbail 	}
936e91bba0SGirish Moodalbail 	rw_exit(&ipst->ips_ill_g_lock);
946e91bba0SGirish Moodalbail 
956e91bba0SGirish Moodalbail 	return (0);
966e91bba0SGirish Moodalbail }
976e91bba0SGirish Moodalbail 
986e91bba0SGirish Moodalbail static int
ip_get_forwarding(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t pr_size,uint_t flags)99299625c6SSebastien Roy ip_get_forwarding(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
1006e91bba0SGirish Moodalbail     void *pval, uint_t pr_size, uint_t flags)
1016e91bba0SGirish Moodalbail {
102299625c6SSebastien Roy 	boolean_t		value;
103299625c6SSebastien Roy 	ill_walk_context_t	ctx;
104299625c6SSebastien Roy 	ill_t			*ill;
105299625c6SSebastien Roy 	ip_stack_t		*ipst = stack->netstack_ip;
1066e91bba0SGirish Moodalbail 	boolean_t		get_def = (flags & MOD_PROP_DEFAULT);
1076e91bba0SGirish Moodalbail 	boolean_t		get_perm = (flags & MOD_PROP_PERM);
1086e91bba0SGirish Moodalbail 	boolean_t		isv6;
1096e91bba0SGirish Moodalbail 	size_t			nbytes = 0;
1106e91bba0SGirish Moodalbail 
1116e91bba0SGirish Moodalbail 	if (get_perm) {
1126e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, pr_size, "%d", MOD_PROP_PERM_RW);
1136e91bba0SGirish Moodalbail 		goto ret;
1146e91bba0SGirish Moodalbail 	} else if (get_def) {
1156e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, pr_size, "%d", pinfo->prop_def_bval);
1166e91bba0SGirish Moodalbail 		goto ret;
1176e91bba0SGirish Moodalbail 	}
1186e91bba0SGirish Moodalbail 
1196e91bba0SGirish Moodalbail 	/*
1206e91bba0SGirish Moodalbail 	 * if per interface value is not asked for return the current
1216e91bba0SGirish Moodalbail 	 * global value
1226e91bba0SGirish Moodalbail 	 */
1236e91bba0SGirish Moodalbail 	if (ifname == NULL || ifname[0] == '\0') {
1246e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, pr_size, "%d", pinfo->prop_cur_bval);
1256e91bba0SGirish Moodalbail 		goto ret;
1266e91bba0SGirish Moodalbail 	}
1276e91bba0SGirish Moodalbail 
1286e91bba0SGirish Moodalbail 	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
1296e91bba0SGirish Moodalbail 	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
1306e91bba0SGirish Moodalbail 	if (isv6)
1316e91bba0SGirish Moodalbail 		ill = ILL_START_WALK_V6(&ctx, ipst);
1326e91bba0SGirish Moodalbail 	else
1336e91bba0SGirish Moodalbail 		ill = ILL_START_WALK_V4(&ctx, ipst);
1346e91bba0SGirish Moodalbail 	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
1356e91bba0SGirish Moodalbail 		/*
1366e91bba0SGirish Moodalbail 		 * if the property needs to be obtained on a particular
1376e91bba0SGirish Moodalbail 		 * interface, look for that interface.
1386e91bba0SGirish Moodalbail 		 */
1396e91bba0SGirish Moodalbail 		if (strcmp(ifname, ill->ill_name) == 0)
1406e91bba0SGirish Moodalbail 			break;
1416e91bba0SGirish Moodalbail 	}
1426e91bba0SGirish Moodalbail 	if (ill == NULL) {
1436e91bba0SGirish Moodalbail 		rw_exit(&ipst->ips_ill_g_lock);
1446e91bba0SGirish Moodalbail 		return (ENXIO);
1456e91bba0SGirish Moodalbail 	}
1466e91bba0SGirish Moodalbail 	value = ((ill->ill_flags & ILLF_ROUTER) ? B_TRUE : B_FALSE);
1476e91bba0SGirish Moodalbail 	rw_exit(&ipst->ips_ill_g_lock);
1486e91bba0SGirish Moodalbail 	nbytes = snprintf(pval, pr_size, "%d", value);
1496e91bba0SGirish Moodalbail ret:
1506e91bba0SGirish Moodalbail 	if (nbytes >= pr_size)
1516e91bba0SGirish Moodalbail 		return (ENOBUFS);
1526e91bba0SGirish Moodalbail 	return (0);
1536e91bba0SGirish Moodalbail }
1546e91bba0SGirish Moodalbail 
1556e91bba0SGirish Moodalbail /*
1566e91bba0SGirish Moodalbail  * `ip_debug' is a global variable. So, we will be modifying the global
1576e91bba0SGirish Moodalbail  * variable here.
1586e91bba0SGirish Moodalbail  */
1596e91bba0SGirish Moodalbail /* ARGSUSED */
1606e91bba0SGirish Moodalbail int
ip_set_debug(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)161299625c6SSebastien Roy ip_set_debug(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
1626e91bba0SGirish Moodalbail     const char *ifname, const void* pval, uint_t flags)
1636e91bba0SGirish Moodalbail {
164299625c6SSebastien Roy 	unsigned long	new_value;
165f1e9465bSSowmini Varadhan 	int		err;
1666e91bba0SGirish Moodalbail 
1676e91bba0SGirish Moodalbail 	if (cr != NULL && secpolicy_net_config(cr, B_FALSE) != 0)
1686e91bba0SGirish Moodalbail 		return (EPERM);
1696e91bba0SGirish Moodalbail 
170f1e9465bSSowmini Varadhan 	if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
171f1e9465bSSowmini Varadhan 		return (err);
1726e91bba0SGirish Moodalbail 	ip_debug = (uint32_t)new_value;
1736e91bba0SGirish Moodalbail 	return (0);
1746e91bba0SGirish Moodalbail }
1756e91bba0SGirish Moodalbail 
1766e91bba0SGirish Moodalbail /*
1776e91bba0SGirish Moodalbail  * ip_debug is a global property. For default, permission and value range
1786e91bba0SGirish Moodalbail  * we retrieve the value from `pinfo'. However for the current value we
1796e91bba0SGirish Moodalbail  * retrieve the value from the global variable `ip_debug'
1806e91bba0SGirish Moodalbail  */
1816e91bba0SGirish Moodalbail /* ARGSUSED */
1826e91bba0SGirish Moodalbail int
ip_get_debug(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)183299625c6SSebastien Roy ip_get_debug(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
1846e91bba0SGirish Moodalbail     void *pval, uint_t psize, uint_t flags)
1856e91bba0SGirish Moodalbail {
1866e91bba0SGirish Moodalbail 	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
1876e91bba0SGirish Moodalbail 	boolean_t	get_perm = (flags & MOD_PROP_PERM);
1886e91bba0SGirish Moodalbail 	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
1896e91bba0SGirish Moodalbail 	size_t		nbytes;
1906e91bba0SGirish Moodalbail 
1916e91bba0SGirish Moodalbail 	bzero(pval, psize);
1926e91bba0SGirish Moodalbail 	if (get_perm)
1936e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
1946e91bba0SGirish Moodalbail 	else if (get_range)
1956e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u-%u",
1966e91bba0SGirish Moodalbail 		    pinfo->prop_min_uval, pinfo->prop_max_uval);
1976e91bba0SGirish Moodalbail 	else if (get_def)
1986e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
1996e91bba0SGirish Moodalbail 	else
2006e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", ip_debug);
2016e91bba0SGirish Moodalbail 	if (nbytes >= psize)
2026e91bba0SGirish Moodalbail 		return (ENOBUFS);
2036e91bba0SGirish Moodalbail 	return (0);
2046e91bba0SGirish Moodalbail }
2056e91bba0SGirish Moodalbail 
2066e91bba0SGirish Moodalbail /*
2076e91bba0SGirish Moodalbail  * Set the CGTP (multirouting) filtering status. If the status is changed
2086e91bba0SGirish Moodalbail  * from active to transparent or from transparent to active, forward the
2096e91bba0SGirish Moodalbail  * new status to the filtering module (if loaded).
2106e91bba0SGirish Moodalbail  */
2116e91bba0SGirish Moodalbail /* ARGSUSED */
2126e91bba0SGirish Moodalbail static int
ip_set_cgtp_filter(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)213299625c6SSebastien Roy ip_set_cgtp_filter(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
2146e91bba0SGirish Moodalbail     const char *ifname, const void* pval, uint_t flags)
2156e91bba0SGirish Moodalbail {
2166e91bba0SGirish Moodalbail 	unsigned long	new_value;
217299625c6SSebastien Roy 	ip_stack_t	*ipst = stack->netstack_ip;
2186e91bba0SGirish Moodalbail 	char		*end;
2196e91bba0SGirish Moodalbail 
2206e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_DEFAULT) {
2216e91bba0SGirish Moodalbail 		new_value = pinfo->prop_def_bval;
2226e91bba0SGirish Moodalbail 	} else {
2236e91bba0SGirish Moodalbail 		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
2246e91bba0SGirish Moodalbail 		    *end != '\0' || new_value > 1) {
2256e91bba0SGirish Moodalbail 			return (EINVAL);
2266e91bba0SGirish Moodalbail 		}
2276e91bba0SGirish Moodalbail 	}
2286e91bba0SGirish Moodalbail 	if (!pinfo->prop_cur_bval && new_value) {
2296e91bba0SGirish Moodalbail 		cmn_err(CE_NOTE, "IP: enabling CGTP filtering%s",
2306e91bba0SGirish Moodalbail 		    ipst->ips_ip_cgtp_filter_ops == NULL ?
2316e91bba0SGirish Moodalbail 		    " (module not loaded)" : "");
2326e91bba0SGirish Moodalbail 	}
2336e91bba0SGirish Moodalbail 	if (pinfo->prop_cur_bval && !new_value) {
2346e91bba0SGirish Moodalbail 		cmn_err(CE_NOTE, "IP: disabling CGTP filtering%s",
2356e91bba0SGirish Moodalbail 		    ipst->ips_ip_cgtp_filter_ops == NULL ?
2366e91bba0SGirish Moodalbail 		    " (module not loaded)" : "");
2376e91bba0SGirish Moodalbail 	}
2386e91bba0SGirish Moodalbail 	if (ipst->ips_ip_cgtp_filter_ops != NULL) {
2396e91bba0SGirish Moodalbail 		int	res;
2406e91bba0SGirish Moodalbail 		netstackid_t stackid = ipst->ips_netstack->netstack_stackid;
2416e91bba0SGirish Moodalbail 
2426e91bba0SGirish Moodalbail 		res = ipst->ips_ip_cgtp_filter_ops->cfo_change_state(stackid,
2436e91bba0SGirish Moodalbail 		    new_value);
2446e91bba0SGirish Moodalbail 		if (res)
2456e91bba0SGirish Moodalbail 			return (res);
2466e91bba0SGirish Moodalbail 	}
2476e91bba0SGirish Moodalbail 	pinfo->prop_cur_bval = (new_value == 1 ? B_TRUE : B_FALSE);
2486e91bba0SGirish Moodalbail 	ill_set_inputfn_all(ipst);
2496e91bba0SGirish Moodalbail 	return (0);
2506e91bba0SGirish Moodalbail }
2516e91bba0SGirish Moodalbail 
2526e91bba0SGirish Moodalbail /*
2536e91bba0SGirish Moodalbail  * Retrieve the default MTU or min-max MTU range for a given interface.
2546e91bba0SGirish Moodalbail  *
2556e91bba0SGirish Moodalbail  *  -- ill_max_frag value tells us the maximum MTU that can be handled by the
2566e91bba0SGirish Moodalbail  *     datalink. This value is advertised by the driver via DLPI messages
2576e91bba0SGirish Moodalbail  *     (DL_NOTE_SDU_SIZE/DL_INFO_ACK).
2586e91bba0SGirish Moodalbail  *
2596e91bba0SGirish Moodalbail  *  -- ill_current_frag for the most link-types will be same as ill_max_frag
2606e91bba0SGirish Moodalbail  *     to begin with. However it is dynamically computed for some link-types
2616e91bba0SGirish Moodalbail  *     like tunnels, based on the tunnel PMTU.
2626e91bba0SGirish Moodalbail  *
2636e91bba0SGirish Moodalbail  *  -- ill_mtu is the user set MTU using SIOCSLIFMTU and must lie between
2646e91bba0SGirish Moodalbail  *     (IPV6_MIN_MTU/IP_MIN_MTU) and ill_max_frag.
2656e91bba0SGirish Moodalbail  *
2666e91bba0SGirish Moodalbail  *  -- ill_user_mtu is set by in.ndpd using SIOCSLIFLNKINFO and must lie between
2676e91bba0SGirish Moodalbail  *     (IPV6_MIN_MTU/IP_MIN_MTU) and ill_max_frag.
2686e91bba0SGirish Moodalbail  */
2696e91bba0SGirish Moodalbail int
ip_get_mtu(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)270299625c6SSebastien Roy ip_get_mtu(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
2716e91bba0SGirish Moodalbail     void *pval, uint_t psize, uint_t flags)
2726e91bba0SGirish Moodalbail {
273299625c6SSebastien Roy 	ill_walk_context_t	ctx;
274299625c6SSebastien Roy 	ill_t			*ill;
275299625c6SSebastien Roy 	ip_stack_t		*ipst = stack->netstack_ip;
2766e91bba0SGirish Moodalbail 	boolean_t		isv6;
2776e91bba0SGirish Moodalbail 	uint32_t		max_mtu, def_mtu;
2786e91bba0SGirish Moodalbail 	size_t			nbytes = 0;
2796e91bba0SGirish Moodalbail 
2806e91bba0SGirish Moodalbail 	if (!(flags & (MOD_PROP_DEFAULT|MOD_PROP_POSSIBLE)))
2816e91bba0SGirish Moodalbail 		return (ENOTSUP);
2826e91bba0SGirish Moodalbail 
2836e91bba0SGirish Moodalbail 	if (ifname == NULL || ifname[0] == '\0')
2846e91bba0SGirish Moodalbail 		return (ENOTSUP);
2856e91bba0SGirish Moodalbail 
2866e91bba0SGirish Moodalbail 	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
2876e91bba0SGirish Moodalbail 	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
2886e91bba0SGirish Moodalbail 	if (isv6)
2896e91bba0SGirish Moodalbail 		ill = ILL_START_WALK_V6(&ctx, ipst);
2906e91bba0SGirish Moodalbail 	else
2916e91bba0SGirish Moodalbail 		ill = ILL_START_WALK_V4(&ctx, ipst);
2926e91bba0SGirish Moodalbail 	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
2936e91bba0SGirish Moodalbail 		if (strcmp(ifname, ill->ill_name) == 0)
2946e91bba0SGirish Moodalbail 			break;
2956e91bba0SGirish Moodalbail 	}
2966e91bba0SGirish Moodalbail 	if (ill == NULL) {
2976e91bba0SGirish Moodalbail 		rw_exit(&ipst->ips_ill_g_lock);
2986e91bba0SGirish Moodalbail 		return (ENXIO);
2996e91bba0SGirish Moodalbail 	}
3006e91bba0SGirish Moodalbail 	max_mtu = ill->ill_max_frag;
3016e91bba0SGirish Moodalbail 	def_mtu = ill->ill_current_frag;
3026e91bba0SGirish Moodalbail 	rw_exit(&ipst->ips_ill_g_lock);
3036e91bba0SGirish Moodalbail 
3046e91bba0SGirish Moodalbail 	if (flags & MOD_PROP_DEFAULT) {
3056e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u", def_mtu);
3066e91bba0SGirish Moodalbail 	} else if (flags & MOD_PROP_POSSIBLE) {
3076e91bba0SGirish Moodalbail 		uint32_t	min_mtu;
3086e91bba0SGirish Moodalbail 
3096e91bba0SGirish Moodalbail 		min_mtu = isv6 ? IPV6_MIN_MTU : IP_MIN_MTU;
3106e91bba0SGirish Moodalbail 		nbytes = snprintf(pval, psize, "%u-%u", min_mtu, max_mtu);
3116e91bba0SGirish Moodalbail 	} else {
3126e91bba0SGirish Moodalbail 		return (ENOTSUP);
3136e91bba0SGirish Moodalbail 	}
3146e91bba0SGirish Moodalbail 
3156e91bba0SGirish Moodalbail 	if (nbytes >= psize)
3166e91bba0SGirish Moodalbail 		return (ENOBUFS);
3176e91bba0SGirish Moodalbail 	return (0);
3186e91bba0SGirish Moodalbail }
3196e91bba0SGirish Moodalbail 
3206e91bba0SGirish Moodalbail /*
3216e91bba0SGirish Moodalbail  * See the comments for ip[6]_strict_src_multihoming for an explanation
3226e91bba0SGirish Moodalbail  * of the semanitcs.
3236e91bba0SGirish Moodalbail  */
324f1e9465bSSowmini Varadhan void
ip_set_src_multihoming_common(ulong_t new_value,ulong_t old_value,boolean_t isv6,ip_stack_t * ipst)325f1e9465bSSowmini Varadhan ip_set_src_multihoming_common(ulong_t new_value, ulong_t old_value,
326f1e9465bSSowmini Varadhan     boolean_t isv6, ip_stack_t *ipst)
3276e91bba0SGirish Moodalbail {
328f1e9465bSSowmini Varadhan 	if (isv6)
329f1e9465bSSowmini Varadhan 		ipst->ips_ipv6_strict_src_multihoming = new_value;
330f1e9465bSSowmini Varadhan 	else
331f1e9465bSSowmini Varadhan 		ipst->ips_ip_strict_src_multihoming = new_value;
3326e91bba0SGirish Moodalbail 	if (new_value != old_value) {
3336e91bba0SGirish Moodalbail 		if (!isv6) {
3346e91bba0SGirish Moodalbail 			if (old_value == 0) {
3356e91bba0SGirish Moodalbail 				ire_walk_v4(ip_ire_rebind_walker, NULL,
3366e91bba0SGirish Moodalbail 				    ALL_ZONES, ipst);
337f1e9465bSSowmini Varadhan 			} else if (new_value == 0) {
3386e91bba0SGirish Moodalbail 				ire_walk_v4(ip_ire_unbind_walker, NULL,
3396e91bba0SGirish Moodalbail 				    ALL_ZONES, ipst);
3406e91bba0SGirish Moodalbail 			}
3416e91bba0SGirish Moodalbail 			ipcl_walk(conn_ire_revalidate, (void *)B_FALSE, ipst);
3426e91bba0SGirish Moodalbail 		} else {
3436e91bba0SGirish Moodalbail 			if (old_value == 0) {
3446e91bba0SGirish Moodalbail 				ire_walk_v6(ip_ire_rebind_walker, NULL,
3456e91bba0SGirish Moodalbail 				    ALL_ZONES, ipst);
346f1e9465bSSowmini Varadhan 			} else if (new_value == 0) {
3476e91bba0SGirish Moodalbail 				ire_walk_v6(ip_ire_unbind_walker, NULL,
3486e91bba0SGirish Moodalbail 				    ALL_ZONES, ipst);
3496e91bba0SGirish Moodalbail 			}
3506e91bba0SGirish Moodalbail 			ipcl_walk(conn_ire_revalidate, (void *)B_TRUE, ipst);
3516e91bba0SGirish Moodalbail 		}
3526e91bba0SGirish Moodalbail 	}
353f1e9465bSSowmini Varadhan }
354f1e9465bSSowmini Varadhan 
355f1e9465bSSowmini Varadhan /* ARGSUSED */
356f1e9465bSSowmini Varadhan static int
ip_set_src_multihoming(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)357299625c6SSebastien Roy ip_set_src_multihoming(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
358f1e9465bSSowmini Varadhan     const char *ifname, const void* pval, uint_t flags)
359f1e9465bSSowmini Varadhan {
360299625c6SSebastien Roy 	unsigned long	new_value, old_value;
361f1e9465bSSowmini Varadhan 	boolean_t	isv6;
362299625c6SSebastien Roy 	ip_stack_t	*ipst = stack->netstack_ip;
363f1e9465bSSowmini Varadhan 	int		err;
364f1e9465bSSowmini Varadhan 
365f1e9465bSSowmini Varadhan 	old_value = pinfo->prop_cur_uval;
366f1e9465bSSowmini Varadhan 
367f1e9465bSSowmini Varadhan 	if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
368f1e9465bSSowmini Varadhan 		return (err);
369f1e9465bSSowmini Varadhan 	pinfo->prop_cur_uval = new_value;
370f1e9465bSSowmini Varadhan 	isv6 = (strcmp(pinfo->mpi_name, "ip6_strict_src_multihoming") == 0);
371f1e9465bSSowmini Varadhan 	ip_set_src_multihoming_common(new_value, old_value, isv6, ipst);
372f1e9465bSSowmini Varadhan 	return (0);
373f1e9465bSSowmini Varadhan }
374f1e9465bSSowmini Varadhan 
375f1e9465bSSowmini Varadhan 
376f1e9465bSSowmini Varadhan /* ARGSUSED */
377f1e9465bSSowmini Varadhan static int
ip_set_hostmodel(netstack_t * stack,cred_t * cr,mod_prop_info_t * pinfo,const char * ifname,const void * pval,uint_t flags)378299625c6SSebastien Roy ip_set_hostmodel(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
379f1e9465bSSowmini Varadhan     const char *ifname, const void* pval, uint_t flags)
380f1e9465bSSowmini Varadhan {
381f1e9465bSSowmini Varadhan 	ip_hostmodel_t	new_value, old_value;
382299625c6SSebastien Roy 	ip_stack_t	*ipst = stack->netstack_ip;
383f1e9465bSSowmini Varadhan 	uint32_t	old_src_multihoming;
384f1e9465bSSowmini Varadhan 	int		err;
385f1e9465bSSowmini Varadhan 	ulong_t		tmp;
386f1e9465bSSowmini Varadhan 	boolean_t	isv6;
387f1e9465bSSowmini Varadhan 
388f1e9465bSSowmini Varadhan 	old_value = pinfo->prop_cur_uval;
389f1e9465bSSowmini Varadhan 
390f1e9465bSSowmini Varadhan 	if ((err = mod_uint32_value(pval, pinfo, flags, &tmp)) != 0)
391f1e9465bSSowmini Varadhan 		return (err);
392f1e9465bSSowmini Varadhan 	new_value = tmp;
393f1e9465bSSowmini Varadhan 	pinfo->prop_cur_uval = new_value;
394f1e9465bSSowmini Varadhan 
395f1e9465bSSowmini Varadhan 	switch (old_value) {
396f1e9465bSSowmini Varadhan 	case IP_WEAK_ES:
397f1e9465bSSowmini Varadhan 		old_src_multihoming = 0;
398f1e9465bSSowmini Varadhan 		break;
399f1e9465bSSowmini Varadhan 	case IP_SRC_PRI_ES:
400f1e9465bSSowmini Varadhan 		old_src_multihoming = 1;
401f1e9465bSSowmini Varadhan 		break;
402f1e9465bSSowmini Varadhan 	case IP_STRONG_ES:
403f1e9465bSSowmini Varadhan 		old_src_multihoming = 2;
404f1e9465bSSowmini Varadhan 		break;
405f1e9465bSSowmini Varadhan 	default:
406f1e9465bSSowmini Varadhan 		ASSERT(0);
407f1e9465bSSowmini Varadhan 		old_src_multihoming = IP_MAXVAL_ES;
408f1e9465bSSowmini Varadhan 		break;
409f1e9465bSSowmini Varadhan 	}
410f1e9465bSSowmini Varadhan 	/*
411f1e9465bSSowmini Varadhan 	 * Changes to src_multihoming may require ire's to be rebound/unbound,
412f1e9465bSSowmini Varadhan 	 * and also require generation number resets. Changes to dst_multihoming
413f1e9465bSSowmini Varadhan 	 * require a simple reset of the value.
414f1e9465bSSowmini Varadhan 	 */
415f1e9465bSSowmini Varadhan 	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6);
416f1e9465bSSowmini Varadhan 	if (new_value != old_value) {
417f1e9465bSSowmini Varadhan 		switch (new_value) {
418f1e9465bSSowmini Varadhan 		case IP_WEAK_ES:
419f1e9465bSSowmini Varadhan 			ip_set_src_multihoming_common(0, old_src_multihoming,
420f1e9465bSSowmini Varadhan 			    isv6, ipst);
421f1e9465bSSowmini Varadhan 			if (isv6)
422f1e9465bSSowmini Varadhan 				ipst->ips_ipv6_strict_dst_multihoming = 0;
423f1e9465bSSowmini Varadhan 			else
424f1e9465bSSowmini Varadhan 				ipst->ips_ip_strict_dst_multihoming = 0;
425f1e9465bSSowmini Varadhan 			break;
426f1e9465bSSowmini Varadhan 		case IP_SRC_PRI_ES:
427f1e9465bSSowmini Varadhan 			ip_set_src_multihoming_common(1, old_src_multihoming,
428f1e9465bSSowmini Varadhan 			    isv6, ipst);
429f1e9465bSSowmini Varadhan 			if (isv6)
430f1e9465bSSowmini Varadhan 				ipst->ips_ipv6_strict_dst_multihoming = 0;
431f1e9465bSSowmini Varadhan 			else
432f1e9465bSSowmini Varadhan 				ipst->ips_ip_strict_dst_multihoming = 0;
433f1e9465bSSowmini Varadhan 			break;
434f1e9465bSSowmini Varadhan 		case IP_STRONG_ES:
435f1e9465bSSowmini Varadhan 			ip_set_src_multihoming_common(2, old_src_multihoming,
436f1e9465bSSowmini Varadhan 			    isv6, ipst);
437f1e9465bSSowmini Varadhan 			if (isv6)
438f1e9465bSSowmini Varadhan 				ipst->ips_ipv6_strict_dst_multihoming = 1;
439f1e9465bSSowmini Varadhan 			else
440f1e9465bSSowmini Varadhan 				ipst->ips_ip_strict_dst_multihoming = 1;
441f1e9465bSSowmini Varadhan 			break;
442f1e9465bSSowmini Varadhan 		default:
443f1e9465bSSowmini Varadhan 			return (EINVAL);
444f1e9465bSSowmini Varadhan 		}
445f1e9465bSSowmini Varadhan 	}
446f1e9465bSSowmini Varadhan 	return (0);
447f1e9465bSSowmini Varadhan }
448f1e9465bSSowmini Varadhan 
449f1e9465bSSowmini Varadhan /* ARGSUSED */
450f1e9465bSSowmini Varadhan int
ip_get_hostmodel(netstack_t * stack,mod_prop_info_t * pinfo,const char * ifname,void * pval,uint_t psize,uint_t flags)451299625c6SSebastien Roy ip_get_hostmodel(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
452f1e9465bSSowmini Varadhan     void *pval, uint_t psize, uint_t flags)
453f1e9465bSSowmini Varadhan {
454f1e9465bSSowmini Varadhan 	boolean_t	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6);
455299625c6SSebastien Roy 	ip_stack_t	*ipst = stack->netstack_ip;
456f1e9465bSSowmini Varadhan 	ip_hostmodel_t	hostmodel;
457f1e9465bSSowmini Varadhan 
458f1e9465bSSowmini Varadhan 	if (psize < sizeof (hostmodel))
459f1e9465bSSowmini Varadhan 		return (ENOBUFS);
460f1e9465bSSowmini Varadhan 	bzero(pval, psize);
461f1e9465bSSowmini Varadhan 	if (!isv6) {
462f1e9465bSSowmini Varadhan 		if (ipst->ips_ip_strict_src_multihoming == 0 &&
463f1e9465bSSowmini Varadhan 		    ipst->ips_ip_strict_dst_multihoming == 0)
464f1e9465bSSowmini Varadhan 			hostmodel = IP_WEAK_ES;
465f1e9465bSSowmini Varadhan 		else if (ipst->ips_ip_strict_src_multihoming == 1 &&
466f1e9465bSSowmini Varadhan 		    ipst->ips_ip_strict_dst_multihoming == 0)
467f1e9465bSSowmini Varadhan 			hostmodel = IP_SRC_PRI_ES;
468f1e9465bSSowmini Varadhan 		else if (ipst->ips_ip_strict_src_multihoming == 2 &&
469f1e9465bSSowmini Varadhan 		    ipst->ips_ip_strict_dst_multihoming == 1)
470f1e9465bSSowmini Varadhan 			hostmodel = IP_STRONG_ES;
471f1e9465bSSowmini Varadhan 		else
472f1e9465bSSowmini Varadhan 			hostmodel = IP_MAXVAL_ES;
473f1e9465bSSowmini Varadhan 	} else {
474f1e9465bSSowmini Varadhan 		if (ipst->ips_ipv6_strict_src_multihoming == 0 &&
475f1e9465bSSowmini Varadhan 		    ipst->ips_ipv6_strict_dst_multihoming == 0)
476f1e9465bSSowmini Varadhan 			hostmodel = IP_WEAK_ES;
477f1e9465bSSowmini Varadhan 		else if (ipst->ips_ipv6_strict_src_multihoming == 1 &&
478f1e9465bSSowmini Varadhan 		    ipst->ips_ipv6_strict_dst_multihoming == 0)
479f1e9465bSSowmini Varadhan 			hostmodel = IP_SRC_PRI_ES;
480f1e9465bSSowmini Varadhan 		else if (ipst->ips_ipv6_strict_src_multihoming == 2 &&
481f1e9465bSSowmini Varadhan 		    ipst->ips_ipv6_strict_dst_multihoming == 1)
482f1e9465bSSowmini Varadhan 			hostmodel = IP_STRONG_ES;
483f1e9465bSSowmini Varadhan 		else
484f1e9465bSSowmini Varadhan 			hostmodel = IP_MAXVAL_ES;
485f1e9465bSSowmini Varadhan 	}
486f1e9465bSSowmini Varadhan 	bcopy(&hostmodel, pval, sizeof (hostmodel));
4876e91bba0SGirish Moodalbail 	return (0);
4886e91bba0SGirish Moodalbail }
4896e91bba0SGirish Moodalbail 
4906e91bba0SGirish Moodalbail /*
4916e91bba0SGirish Moodalbail  * All of these are alterable, within the min/max values given, at run time.
4926e91bba0SGirish Moodalbail  *
4938887b57dSGirish Moodalbail  * Note: All those tunables which do not start with "_" are Committed and
4948887b57dSGirish Moodalbail  * therefore are public. See PSARC 2010/080.
4956e91bba0SGirish Moodalbail  */
4966e91bba0SGirish Moodalbail mod_prop_info_t ip_propinfo_tbl[] = {
4976e91bba0SGirish Moodalbail 	/* tunable - 0 */
4988887b57dSGirish Moodalbail 	{ "_respond_to_address_mask_broadcast", MOD_PROTO_IP,
4996e91bba0SGirish Moodalbail 	    mod_set_boolean, mod_get_boolean,
5006e91bba0SGirish Moodalbail 	    {B_FALSE}, {B_FALSE} },
5016e91bba0SGirish Moodalbail 
5028887b57dSGirish Moodalbail 	{ "_respond_to_echo_broadcast", MOD_PROTO_IP,
5036e91bba0SGirish Moodalbail 	    mod_set_boolean, mod_get_boolean,
5046e91bba0SGirish Moodalbail 	    {B_TRUE},  {B_TRUE} },
5056e91bba0SGirish Moodalbail 
5068887b57dSGirish Moodalbail 	{ "_respond_to_echo_multicast", MOD_PROTO_IPV4,
5076e91bba0SGirish Moodalbail 	    mod_set_boolean, mod_get_boolean,
5086e91bba0SGirish Moodalbail 	    {B_TRUE}, {B_TRUE} },
5096e91bba0SGirish Moodalbail 
5108887b57dSGirish Moodalbail 	{ "_respond_to_timestamp", MOD_PROTO_IP,
5116e91bba0SGirish Moodalbail 	    mod_set_boolean, mod_get_boolean,
5126e91bba0SGirish Moodalbail 	    {B_FALSE}, {B_FALSE} },
5136e91bba0SGirish Moodalbail 
5148887b57dSGirish Moodalbail 	{ "_respond_to_timestamp_broadcast", MOD_PROTO_IP,
5156e91bba0SGirish Moodalbail 	    mod_set_boolean, mod_get_boolean,
5166e91bba0SGirish Moodalbail 	    {B_FALSE}, {B_FALSE} },
5176e91bba0SGirish Moodalbail 
5188887b57dSGirish Moodalbail 	{ "_send_redirects", MOD_PROTO_IPV4,
5196e91bba0SGirish Moodalbail 	    mod_set_boolean, mod_get_boolean,
5206e91bba0SGirish Moodalbail 	    {B_TRUE}, {B_TRUE} },
5216e91bba0SGirish Moodalbail 
5228887b57dSGirish Moodalbail 	{ "_forward_directed_broadcasts", MOD_PROTO_IP,
5236e91bba0SGirish Moodalbail 	    mod_set_boolean, mod_get_boolean,
5246e91bba0SGirish Moodalbail 	    {B_FALSE}, {B_FALSE} },
5256e91bba0SGirish Moodalbail 
5268887b57dSGirish Moodalbail 	{ "_mrtdebug", MOD_PROTO_IP,
5276e91bba0SGirish Moodalbail 	    mod_set_uint32, mod_get_uint32,
5286e91bba0SGirish Moodalbail 	    {0, 10, 0}, {0} },
5296e91bba0SGirish Moodalbail