xref: /onnv-gate/usr/src/uts/common/inet/ip/ip_srcid.c (revision 9089:f2cd448729f6)
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 /*
22*9089SVasumathi.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 <net/pfkeyv2.h>
1050Sstevel@tonic-gate #include <inet/ipsec_info.h>
1060Sstevel@tonic-gate #include <inet/sadb.h>
1070Sstevel@tonic-gate #include <sys/kmem.h>
1080Sstevel@tonic-gate #include <inet/ipsec_impl.h>
1090Sstevel@tonic-gate #include <inet/tun.h>
1100Sstevel@tonic-gate 
1113448Sdh155122 static uint_t		srcid_nextid(ip_stack_t *);
1120Sstevel@tonic-gate static srcid_map_t	**srcid_lookup_addr(const in6_addr_t *addr,
1133448Sdh155122     zoneid_t zoneid, ip_stack_t *);
1143448Sdh155122 static srcid_map_t	**srcid_lookup_id(uint_t id, ip_stack_t *);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate /*
1180Sstevel@tonic-gate  * Insert/add a new address to the map.
1190Sstevel@tonic-gate  * Returns zero if ok; otherwise errno (e.g. for memory allocation failure).
1200Sstevel@tonic-gate  */
1210Sstevel@tonic-gate int
1223448Sdh155122 ip_srcid_insert(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst)
1230Sstevel@tonic-gate {
1240Sstevel@tonic-gate 	srcid_map_t	**smpp;
1250Sstevel@tonic-gate #ifdef DEBUG
1260Sstevel@tonic-gate 	char		abuf[INET6_ADDRSTRLEN];
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	ip1dbg(("ip_srcid_insert(%s, %d)\n",
1290Sstevel@tonic-gate 	    inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid));
1300Sstevel@tonic-gate #endif
1310Sstevel@tonic-gate 
1323448Sdh155122 	rw_enter(&ipst->ips_srcid_lock, RW_WRITER);
1333448Sdh155122 	smpp = srcid_lookup_addr(addr, zoneid, ipst);
1340Sstevel@tonic-gate 	if (*smpp != NULL) {
1350Sstevel@tonic-gate 		/* Already present - increment refcount */
1360Sstevel@tonic-gate 		(*smpp)->sm_refcnt++;
1370Sstevel@tonic-gate 		ASSERT((*smpp)->sm_refcnt != 0);	/* wraparound */
1383448Sdh155122 		rw_exit(&ipst->ips_srcid_lock);
1390Sstevel@tonic-gate 		return (0);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 	/* Insert new */
1420Sstevel@tonic-gate 	*smpp = kmem_alloc(sizeof (srcid_map_t), KM_NOSLEEP);
1430Sstevel@tonic-gate 	if (*smpp == NULL) {
1443448Sdh155122 		rw_exit(&ipst->ips_srcid_lock);
1450Sstevel@tonic-gate 		return (ENOMEM);
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 	(*smpp)->sm_next = NULL;
1480Sstevel@tonic-gate 	(*smpp)->sm_addr = *addr;
1493448Sdh155122 	(*smpp)->sm_srcid = srcid_nextid(ipst);
1500Sstevel@tonic-gate 	(*smpp)->sm_refcnt = 1;
1510Sstevel@tonic-gate 	(*smpp)->sm_zoneid = zoneid;
1520Sstevel@tonic-gate 
1533448Sdh155122 	rw_exit(&ipst->ips_srcid_lock);
1540Sstevel@tonic-gate 	return (0);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate /*
1580Sstevel@tonic-gate  * Remove an new address from the map.
1590Sstevel@tonic-gate  * Returns zero if ok; otherwise errno (e.g. for nonexistent address).
1600Sstevel@tonic-gate  */
1610Sstevel@tonic-gate int
1623448Sdh155122 ip_srcid_remove(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst)
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate 	srcid_map_t	**smpp;
1650Sstevel@tonic-gate 	srcid_map_t	*smp;
1660Sstevel@tonic-gate #ifdef DEBUG
1670Sstevel@tonic-gate 	char		abuf[INET6_ADDRSTRLEN];
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	ip1dbg(("ip_srcid_remove(%s, %d)\n",
1700Sstevel@tonic-gate 	    inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid));
1710Sstevel@tonic-gate #endif
1720Sstevel@tonic-gate 
1733448Sdh155122 	rw_enter(&ipst->ips_srcid_lock, RW_WRITER);
1743448Sdh155122 	smpp = srcid_lookup_addr(addr, zoneid, ipst);
1750Sstevel@tonic-gate 	smp = *smpp;
1760Sstevel@tonic-gate 	if (smp == NULL) {
1770Sstevel@tonic-gate 		/* Not preset */
1783448Sdh155122 		rw_exit(&ipst->ips_srcid_lock);
1790Sstevel@tonic-gate 		return (ENOENT);
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/* Decrement refcount */
1830Sstevel@tonic-gate 	ASSERT(smp->sm_refcnt != 0);
1840Sstevel@tonic-gate 	smp->sm_refcnt--;
1850Sstevel@tonic-gate 	if (smp->sm_refcnt != 0) {
1863448Sdh155122 		rw_exit(&ipst->ips_srcid_lock);
1870Sstevel@tonic-gate 		return (0);
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 	/* Remove entry */
1900Sstevel@tonic-gate 	*smpp = smp->sm_next;
1913448Sdh155122 	rw_exit(&ipst->ips_srcid_lock);
1920Sstevel@tonic-gate 	smp->sm_next = NULL;
1930Sstevel@tonic-gate 	kmem_free(smp, sizeof (srcid_map_t));
1940Sstevel@tonic-gate 	return (0);
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate /*
1980Sstevel@tonic-gate  * Map from an address to a source id.
1990Sstevel@tonic-gate  * If the address is unknown return the unknown id (zero).
2000Sstevel@tonic-gate  */
2010Sstevel@tonic-gate uint_t
2023448Sdh155122 ip_srcid_find_addr(const in6_addr_t *addr, zoneid_t zoneid,
2033448Sdh155122     netstack_t *ns)
2040Sstevel@tonic-gate {
2050Sstevel@tonic-gate 	srcid_map_t	**smpp;
2060Sstevel@tonic-gate 	srcid_map_t	*smp;
2070Sstevel@tonic-gate 	uint_t		id;
2083448Sdh155122 	ip_stack_t	*ipst = ns->netstack_ip;
2090Sstevel@tonic-gate 
2103448Sdh155122 	rw_enter(&ipst->ips_srcid_lock, RW_READER);
2113448Sdh155122 	smpp = srcid_lookup_addr(addr, zoneid, ipst);
2120Sstevel@tonic-gate 	smp = *smpp;
2130Sstevel@tonic-gate 	if (smp == NULL) {
2140Sstevel@tonic-gate 		char		abuf[INET6_ADDRSTRLEN];
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 		/* Not present - could be broadcast or multicast address */
2170Sstevel@tonic-gate 		ip1dbg(("ip_srcid_find_addr: unknown %s in zone %d\n",
2180Sstevel@tonic-gate 		    inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid));
2190Sstevel@tonic-gate 		id = 0;
2200Sstevel@tonic-gate 	} else {
2210Sstevel@tonic-gate 		ASSERT(smp->sm_refcnt != 0);
2220Sstevel@tonic-gate 		id = smp->sm_srcid;
2230Sstevel@tonic-gate 	}
2243448Sdh155122 	rw_exit(&ipst->ips_srcid_lock);
2250Sstevel@tonic-gate 	return (id);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate  * Map from a source id to an address.
2300Sstevel@tonic-gate  * If the id is unknown return the unspecified address.
2310Sstevel@tonic-gate  */
2320Sstevel@tonic-gate void
2333448Sdh155122 ip_srcid_find_id(uint_t id, in6_addr_t *addr, zoneid_t zoneid,
2343448Sdh155122     netstack_t *ns)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate 	srcid_map_t	**smpp;
2370Sstevel@tonic-gate 	srcid_map_t	*smp;
2383448Sdh155122 	ip_stack_t	*ipst = ns->netstack_ip;
2390Sstevel@tonic-gate 
2403448Sdh155122 	rw_enter(&ipst->ips_srcid_lock, RW_READER);
2413448Sdh155122 	smpp = srcid_lookup_id(id, ipst);
2420Sstevel@tonic-gate 	smp = *smpp;
2430Sstevel@tonic-gate 	if (smp == NULL || smp->sm_zoneid != zoneid) {
2440Sstevel@tonic-gate 		/* Not preset */
2450Sstevel@tonic-gate 		ip1dbg(("ip_srcid_find_id: unknown %u or in wrong zone\n", id));
2460Sstevel@tonic-gate 		*addr = ipv6_all_zeros;
2470Sstevel@tonic-gate 	} else {
2480Sstevel@tonic-gate 		ASSERT(smp->sm_refcnt != 0);
2490Sstevel@tonic-gate 		*addr = smp->sm_addr;
2500Sstevel@tonic-gate 	}
2513448Sdh155122 	rw_exit(&ipst->ips_srcid_lock);
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate /* Assign the next available ID */
2550Sstevel@tonic-gate static uint_t
2563448Sdh155122 srcid_nextid(ip_stack_t *ipst)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate 	uint_t id;
2590Sstevel@tonic-gate 	srcid_map_t	**smpp;
2600Sstevel@tonic-gate 
2613448Sdh155122 	ASSERT(rw_owner(&ipst->ips_srcid_lock) == curthread);
2620Sstevel@tonic-gate 
2633448Sdh155122 	if (!ipst->ips_srcid_wrapped) {
2643448Sdh155122 		id = ipst->ips_ip_src_id++;
2653448Sdh155122 		if (ipst->ips_ip_src_id == 0)
2663448Sdh155122 			ipst->ips_srcid_wrapped = B_TRUE;
2670Sstevel@tonic-gate 		return (id);
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 	/* Once it wraps we search for an unused ID. */
2700Sstevel@tonic-gate 	for (id = 0; id < 0xffffffff; id++) {
2713448Sdh155122 		smpp = srcid_lookup_id(id, ipst);
2720Sstevel@tonic-gate 		if (*smpp == NULL)
2730Sstevel@tonic-gate 			return (id);
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate 	panic("srcid_nextid: No free identifiers!");
2760Sstevel@tonic-gate 	/* NOTREACHED */
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate /*
2800Sstevel@tonic-gate  * Lookup based on address.
2810Sstevel@tonic-gate  * Always returns a non-null pointer.
2820Sstevel@tonic-gate  * If found then *ptr will be the found object.
2830Sstevel@tonic-gate  * Otherwise *ptr will be NULL and can be used to insert a new object.
2840Sstevel@tonic-gate  */
2850Sstevel@tonic-gate static srcid_map_t **
2863448Sdh155122 srcid_lookup_addr(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst)
2870Sstevel@tonic-gate {
2880Sstevel@tonic-gate 	srcid_map_t	**smpp;
2890Sstevel@tonic-gate 
2903448Sdh155122 	ASSERT(RW_LOCK_HELD(&ipst->ips_srcid_lock));
2913448Sdh155122 	smpp = &ipst->ips_srcid_head;
2920Sstevel@tonic-gate 	while (*smpp != NULL) {
2930Sstevel@tonic-gate 		if (IN6_ARE_ADDR_EQUAL(&(*smpp)->sm_addr, addr) &&
2940Sstevel@tonic-gate 		    zoneid == (*smpp)->sm_zoneid)
2950Sstevel@tonic-gate 			return (smpp);
2960Sstevel@tonic-gate 		smpp = &(*smpp)->sm_next;
2970Sstevel@tonic-gate 	}
2980Sstevel@tonic-gate 	return (smpp);
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate /*
3020Sstevel@tonic-gate  * Lookup based on address.
3030Sstevel@tonic-gate  * Always returns a non-null pointer.
3040Sstevel@tonic-gate  * If found then *ptr will be the found object.
3050Sstevel@tonic-gate  * Otherwise *ptr will be NULL and can be used to insert a new object.
3060Sstevel@tonic-gate  */
3070Sstevel@tonic-gate static srcid_map_t **
3083448Sdh155122 srcid_lookup_id(uint_t id, ip_stack_t *ipst)
3090Sstevel@tonic-gate {
3100Sstevel@tonic-gate 	srcid_map_t	**smpp;
3110Sstevel@tonic-gate 
3123448Sdh155122 	ASSERT(RW_LOCK_HELD(&ipst->ips_srcid_lock));
3133448Sdh155122 	smpp = &ipst->ips_srcid_head;
3140Sstevel@tonic-gate 	while (*smpp != NULL) {
3150Sstevel@tonic-gate 		if ((*smpp)->sm_srcid == id)
3160Sstevel@tonic-gate 			return (smpp);
3170Sstevel@tonic-gate 		smpp = &(*smpp)->sm_next;
3180Sstevel@tonic-gate 	}
3190Sstevel@tonic-gate 	return (smpp);
3200Sstevel@tonic-gate }
321