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