xref: /onnv-gate/usr/src/uts/common/inet/ip/ip_srcid.c (revision 11042:2d6e217af1b4)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53448Sdh155122  * Common Development and Distribution License (the "License").
63448Sdh155122  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
229089SVasumathi.Sundaram@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * This is used to support the hidden __sin6_src_id in the sockaddr_in6
280Sstevel@tonic-gate  * structure which is there to ensure that applications (such as UDP apps)
290Sstevel@tonic-gate  * which get an address from recvfrom and use that address in a sendto
300Sstevel@tonic-gate  * or connect will by default use the same source address in the "response"
310Sstevel@tonic-gate  * as the destination address in the "request" they received.
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * This is built using some new functions (in IP - doing their own locking
340Sstevel@tonic-gate  * so they can be called from the transports) to map between integer IDs
350Sstevel@tonic-gate  * and in6_addr_t.
360Sstevel@tonic-gate  * The use applies to sockaddr_in6 - whether or not mapped addresses are used.
370Sstevel@tonic-gate  *
380Sstevel@tonic-gate  * This file contains the functions used by both IP and the transports
390Sstevel@tonic-gate  * to implement __sin6_src_id.
400Sstevel@tonic-gate  * The routines do their own locking since they are called from
410Sstevel@tonic-gate  * the transports (to map between a source id and an address)
420Sstevel@tonic-gate  * and from IP proper when IP addresses are added and removed.
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * The routines handle both IPv4 and IPv6 with the IPv4 addresses represented
450Sstevel@tonic-gate  * as IPv4-mapped addresses.
460Sstevel@tonic-gate  */
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include <sys/types.h>
490Sstevel@tonic-gate #include <sys/stream.h>
500Sstevel@tonic-gate #include <sys/dlpi.h>
510Sstevel@tonic-gate #include <sys/stropts.h>
520Sstevel@tonic-gate #include <sys/sysmacros.h>
530Sstevel@tonic-gate #include <sys/strsubr.h>
540Sstevel@tonic-gate #include <sys/strlog.h>
550Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
560Sstevel@tonic-gate #include <sys/tihdr.h>
570Sstevel@tonic-gate #include <sys/xti_inet.h>
580Sstevel@tonic-gate #include <sys/ddi.h>
590Sstevel@tonic-gate #include <sys/cmn_err.h>
600Sstevel@tonic-gate #include <sys/debug.h>
610Sstevel@tonic-gate #include <sys/modctl.h>
620Sstevel@tonic-gate #include <sys/atomic.h>
630Sstevel@tonic-gate #include <sys/zone.h>
640Sstevel@tonic-gate 
650Sstevel@tonic-gate #include <sys/systm.h>
660Sstevel@tonic-gate #include <sys/param.h>
670Sstevel@tonic-gate #include <sys/kmem.h>
680Sstevel@tonic-gate #include <sys/callb.h>
690Sstevel@tonic-gate #include <sys/socket.h>
700Sstevel@tonic-gate #include <sys/vtrace.h>
710Sstevel@tonic-gate #include <sys/isa_defs.h>
720Sstevel@tonic-gate #include <sys/kmem.h>
730Sstevel@tonic-gate #include <net/if.h>
740Sstevel@tonic-gate #include <net/if_arp.h>
750Sstevel@tonic-gate #include <net/route.h>
760Sstevel@tonic-gate #include <sys/sockio.h>
770Sstevel@tonic-gate #include <netinet/in.h>
780Sstevel@tonic-gate #include <net/if_dl.h>
790Sstevel@tonic-gate 
800Sstevel@tonic-gate #include <inet/common.h>
810Sstevel@tonic-gate #include <inet/mi.h>
820Sstevel@tonic-gate #include <inet/mib2.h>
830Sstevel@tonic-gate #include <inet/nd.h>
840Sstevel@tonic-gate #include <inet/arp.h>
850Sstevel@tonic-gate #include <inet/snmpcom.h>
860Sstevel@tonic-gate 
870Sstevel@tonic-gate #include <netinet/igmp_var.h>
880Sstevel@tonic-gate #include <netinet/ip6.h>
890Sstevel@tonic-gate #include <netinet/icmp6.h>
900Sstevel@tonic-gate 
910Sstevel@tonic-gate #include <inet/ip.h>
920Sstevel@tonic-gate #include <inet/ip6.h>
930Sstevel@tonic-gate #include <inet/tcp.h>
940Sstevel@tonic-gate #include <inet/ip_multi.h>
950Sstevel@tonic-gate #include <inet/ip_if.h>
960Sstevel@tonic-gate #include <inet/ip_ire.h>
970Sstevel@tonic-gate #include <inet/ip_rts.h>
980Sstevel@tonic-gate #include <inet/optcom.h>
990Sstevel@tonic-gate #include <inet/ip_ndp.h>
1000Sstevel@tonic-gate #include <netinet/igmp.h>
1010Sstevel@tonic-gate #include <netinet/ip_mroute.h>
1020Sstevel@tonic-gate #include <inet/ipclassifier.h>
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #include <sys/kmem.h>
1050Sstevel@tonic-gate 
1063448Sdh155122 static uint_t		srcid_nextid(ip_stack_t *);
1070Sstevel@tonic-gate static srcid_map_t	**srcid_lookup_addr(const in6_addr_t *addr,
1083448Sdh155122     zoneid_t zoneid, ip_stack_t *);
1093448Sdh155122 static srcid_map_t	**srcid_lookup_id(uint_t id, ip_stack_t *);
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate  * Insert/add a new address to the map.
1140Sstevel@tonic-gate  * Returns zero if ok; otherwise errno (e.g. for memory allocation failure).
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate int
ip_srcid_insert(const in6_addr_t * addr,zoneid_t zoneid,ip_stack_t * ipst)1173448Sdh155122 ip_srcid_insert(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate 	srcid_map_t	**smpp;
1200Sstevel@tonic-gate #ifdef DEBUG
1210Sstevel@tonic-gate 	char		abuf[INET6_ADDRSTRLEN];
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	ip1dbg(("ip_srcid_insert(%s, %d)\n",
1240Sstevel@tonic-gate 	    inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid));
1250Sstevel@tonic-gate #endif
1260Sstevel@tonic-gate 
1273448Sdh155122 	rw_enter(&ipst->ips_srcid_lock, RW_WRITER);
1283448Sdh155122 	smpp = srcid_lookup_addr(addr, zoneid, ipst);
1290Sstevel@tonic-gate 	if (*smpp != NULL) {
1300Sstevel@tonic-gate 		/* Already present - increment refcount */
1310Sstevel@tonic-gate 		(*smpp)->sm_refcnt++;
1320Sstevel@tonic-gate 		ASSERT((*smpp)->sm_refcnt != 0);	/* wraparound */
1333448Sdh155122 		rw_exit(&ipst->ips_srcid_lock);
1340Sstevel@tonic-gate 		return (0);
1350Sstevel@tonic-gate 	}
1360Sstevel@tonic-gate 	/* Insert new */
1370Sstevel@tonic-gate 	*smpp = kmem_alloc(sizeof (srcid_map_t), KM_NOSLEEP);
1380Sstevel@tonic-gate 	if (*smpp == NULL) {
1393448Sdh155122 		rw_exit(&ipst->ips_srcid_lock);
1400Sstevel@tonic-gate 		return (ENOMEM);
1410Sstevel@tonic-gate 	}
1420Sstevel@tonic-gate 	(*smpp)->sm_next = NULL;
1430Sstevel@tonic-gate 	(*smpp)->sm_addr = *addr;
1443448Sdh155122 	(*smpp)->sm_srcid = srcid_nextid(ipst);
1450Sstevel@tonic-gate 	(*smpp)->sm_refcnt = 1;
1460Sstevel@tonic-gate 	(*smpp)->sm_zoneid = zoneid;
1470Sstevel@tonic-gate 
1483448Sdh155122 	rw_exit(&ipst->ips_srcid_lock);
1490Sstevel@tonic-gate 	return (0);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate  * Remove an new address from the map.
1540Sstevel@tonic-gate  * Returns zero if ok; otherwise errno (e.g. for nonexistent address).
1550Sstevel@tonic-gate  */
1560Sstevel@tonic-gate int
ip_srcid_remove(const in6_addr_t * addr,zoneid_t zoneid,ip_stack_t * ipst)1573448Sdh155122 ip_srcid_remove(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate 	srcid_map_t	**smpp;
1600Sstevel@tonic-gate 	srcid_map_t	*smp;
1610Sstevel@tonic-gate #ifdef DEBUG
1620Sstevel@tonic-gate 	char		abuf[INET6_ADDRSTRLEN];
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	ip1dbg(("ip_srcid_remove(%s, %d)\n",
1650Sstevel@tonic-gate 	    inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid));
1660Sstevel@tonic-gate #endif
1670Sstevel@tonic-gate 
1683448Sdh155122 	rw_enter(&ipst->ips_srcid_lock, RW_WRITER);
1693448Sdh155122 	smpp = srcid_lookup_addr(addr, zoneid, ipst);
1700Sstevel@tonic-gate 	smp = *smpp;
1710Sstevel@tonic-gate 	if (smp == NULL) {
1720Sstevel@tonic-gate 		/* Not preset */
1733448Sdh155122 		rw_exit(&ipst->ips_srcid_lock);
1740Sstevel@tonic-gate 		return (ENOENT);
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	/* Decrement refcount */
1780Sstevel@tonic-gate 	ASSERT(smp->sm_refcnt != 0);
1790Sstevel@tonic-gate 	smp->sm_refcnt--;
1800Sstevel@tonic-gate 	if (smp->sm_refcnt != 0) {
1813448Sdh155122 		rw_exit(&ipst->ips_srcid_lock);
1820Sstevel@tonic-gate 		return (0);
1830Sstevel@tonic-gate 	}
1840Sstevel@tonic-gate 	/* Remove entry */
1850Sstevel@tonic-gate 	*smpp = smp->sm_next;
1863448Sdh155122 	rw_exit(&ipst->ips_srcid_lock);
1870Sstevel@tonic-gate 	smp->sm_next = NULL;
1880Sstevel@tonic-gate 	kmem_free(smp, sizeof (srcid_map_t));
1890Sstevel@tonic-gate 	return (0);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate /*
1930Sstevel@tonic-gate  * Map from an address to a source id.
1940Sstevel@tonic-gate  * If the address is unknown return the unknown id (zero).
1950Sstevel@tonic-gate  */
1960Sstevel@tonic-gate uint_t
ip_srcid_find_addr(const in6_addr_t * addr,zoneid_t zoneid,netstack_t * ns)1973448Sdh155122 ip_srcid_find_addr(const in6_addr_t *addr, zoneid_t zoneid,
1983448Sdh155122     netstack_t *ns)
1990Sstevel@tonic-gate {
2000Sstevel@tonic-gate 	srcid_map_t	**smpp;
2010Sstevel@tonic-gate 	srcid_map_t	*smp;
2020Sstevel@tonic-gate 	uint_t		id;
2033448Sdh155122 	ip_stack_t	*ipst = ns->netstack_ip;
2040Sstevel@tonic-gate 
2053448Sdh155122 	rw_enter(&ipst->ips_srcid_lock, RW_READER);
2063448Sdh155122 	smpp = srcid_lookup_addr(addr, zoneid, ipst);
2070Sstevel@tonic-gate 	smp = *smpp;
2080Sstevel@tonic-gate 	if (smp == NULL) {
2090Sstevel@tonic-gate 		char		abuf[INET6_ADDRSTRLEN];
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 		/* Not present - could be broadcast or multicast address */
2120Sstevel@tonic-gate 		ip1dbg(("ip_srcid_find_addr: unknown %s in zone %d\n",
2130Sstevel@tonic-gate 		    inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid));
2140Sstevel@tonic-gate 		id = 0;
2150Sstevel@tonic-gate 	} else {
2160Sstevel@tonic-gate 		ASSERT(smp->sm_refcnt != 0);
2170Sstevel@tonic-gate 		id = smp->sm_srcid;
2180Sstevel@tonic-gate 	}
2193448Sdh155122 	rw_exit(&ipst->ips_srcid_lock);
2200Sstevel@tonic-gate 	return (id);
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate /*
2240Sstevel@tonic-gate  * Map from a source id to an address.
2250Sstevel@tonic-gate  * If the id is unknown return the unspecified address.
2260Sstevel@tonic-gate  */
2270Sstevel@tonic-gate void
ip_srcid_find_id(uint_t id,in6_addr_t * addr,zoneid_t zoneid,netstack_t * ns)2283448Sdh155122 ip_srcid_find_id(uint_t id, in6_addr_t *addr, zoneid_t zoneid,
2293448Sdh155122     netstack_t *ns)
2300Sstevel@tonic-gate {
2310Sstevel@tonic-gate 	srcid_map_t	**smpp;
2320Sstevel@tonic-gate 	srcid_map_t	*smp;
2333448Sdh155122 	ip_stack_t	*ipst = ns->netstack_ip;
2340Sstevel@tonic-gate 
2353448Sdh155122 	rw_enter(&ipst->ips_srcid_lock, RW_READER);
2363448Sdh155122 	smpp = srcid_lookup_id(id, ipst);
2370Sstevel@tonic-gate 	smp = *smpp;
238*11042SErik.Nordmark@Sun.COM 	if (smp == NULL || (smp->sm_zoneid != zoneid && zoneid != ALL_ZONES)) {
2390Sstevel@tonic-gate 		/* Not preset */
2400Sstevel@tonic-gate 		ip1dbg(("ip_srcid_find_id: unknown %u or in wrong zone\n", id));
2410Sstevel@tonic-gate 		*addr = ipv6_all_zeros;
2420Sstevel@tonic-gate 	} else {
2430Sstevel@tonic-gate 		ASSERT(smp->sm_refcnt != 0);
2440Sstevel@tonic-gate 		*addr = smp->sm_addr;
2450Sstevel@tonic-gate 	}
2463448Sdh155122 	rw_exit(&ipst->ips_srcid_lock);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate /* Assign the next available ID */
2500Sstevel@tonic-gate static uint_t
srcid_nextid(ip_stack_t * ipst)2513448Sdh155122 srcid_nextid(ip_stack_t *ipst)
2520Sstevel@tonic-gate {
2530Sstevel@tonic-gate 	uint_t id;
2540Sstevel@tonic-gate 	srcid_map_t	**smpp;
2550Sstevel@tonic-gate 
2563448Sdh155122 	ASSERT(rw_owner(&ipst->ips_srcid_lock) == curthread);
2570Sstevel@tonic-gate 
2583448Sdh155122 	if (!ipst->ips_srcid_wrapped) {
2593448Sdh155122 		id = ipst->ips_ip_src_id++;
2603448Sdh155122 		if (ipst->ips_ip_src_id == 0)
2613448Sdh155122 			ipst->ips_srcid_wrapped = B_TRUE;
2620Sstevel@tonic-gate 		return (id);
2630Sstevel@tonic-gate 	}
2640Sstevel@tonic-gate 	/* Once it wraps we search for an unused ID. */
2650Sstevel@tonic-gate 	for (id = 0; id < 0xffffffff; id++) {
2663448Sdh155122 		smpp = srcid_lookup_id(id, ipst);
2670Sstevel@tonic-gate 		if (*smpp == NULL)
2680Sstevel@tonic-gate 			return (id);
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 	panic("srcid_nextid: No free identifiers!");
2710Sstevel@tonic-gate 	/* NOTREACHED */
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate  * Lookup based on address.
2760Sstevel@tonic-gate  * Always returns a non-null pointer.
2770Sstevel@tonic-gate  * If found then *ptr will be the found object.
2780Sstevel@tonic-gate  * Otherwise *ptr will be NULL and can be used to insert a new object.
2790Sstevel@tonic-gate  */
2800Sstevel@tonic-gate static srcid_map_t **
srcid_lookup_addr(const in6_addr_t * addr,zoneid_t zoneid,ip_stack_t * ipst)2813448Sdh155122 srcid_lookup_addr(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst)
2820Sstevel@tonic-gate {
2830Sstevel@tonic-gate 	srcid_map_t	**smpp;
2840Sstevel@tonic-gate 
2853448Sdh155122 	ASSERT(RW_LOCK_HELD(&ipst->ips_srcid_lock));
2863448Sdh155122 	smpp = &ipst->ips_srcid_head;
2870Sstevel@tonic-gate 	while (*smpp != NULL) {
2880Sstevel@tonic-gate 		if (IN6_ARE_ADDR_EQUAL(&(*smpp)->sm_addr, addr) &&
289*11042SErik.Nordmark@Sun.COM 		    (zoneid == (*smpp)->sm_zoneid || zoneid == ALL_ZONES))
2900Sstevel@tonic-gate 			return (smpp);
2910Sstevel@tonic-gate 		smpp = &(*smpp)->sm_next;
2920Sstevel@tonic-gate 	}
2930Sstevel@tonic-gate 	return (smpp);
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate  * Lookup based on address.
2980Sstevel@tonic-gate  * Always returns a non-null pointer.
2990Sstevel@tonic-gate  * If found then *ptr will be the found object.
3000Sstevel@tonic-gate  * Otherwise *ptr will be NULL and can be used to insert a new object.
3010Sstevel@tonic-gate  */
3020Sstevel@tonic-gate static srcid_map_t **
srcid_lookup_id(uint_t id,ip_stack_t * ipst)3033448Sdh155122 srcid_lookup_id(uint_t id, ip_stack_t *ipst)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 	srcid_map_t	**smpp;
3060Sstevel@tonic-gate 
3073448Sdh155122 	ASSERT(RW_LOCK_HELD(&ipst->ips_srcid_lock));
3083448Sdh155122 	smpp = &ipst->ips_srcid_head;
3090Sstevel@tonic-gate 	while (*smpp != NULL) {
3100Sstevel@tonic-gate 		if ((*smpp)->sm_srcid == id)
3110Sstevel@tonic-gate 			return (smpp);
3120Sstevel@tonic-gate 		smpp = &(*smpp)->sm_next;
3130Sstevel@tonic-gate 	}
3140Sstevel@tonic-gate 	return (smpp);
3150Sstevel@tonic-gate }
316