1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * This is used to support the hidden __sin6_src_id in the sockaddr_in6 31*0Sstevel@tonic-gate * structure which is there to ensure that applications (such as UDP apps) 32*0Sstevel@tonic-gate * which get an address from recvfrom and use that address in a sendto 33*0Sstevel@tonic-gate * or connect will by default use the same source address in the "response" 34*0Sstevel@tonic-gate * as the destination address in the "request" they received. 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * This is built using some new functions (in IP - doing their own locking 37*0Sstevel@tonic-gate * so they can be called from the transports) to map between integer IDs 38*0Sstevel@tonic-gate * and in6_addr_t. 39*0Sstevel@tonic-gate * The use applies to sockaddr_in6 - whether or not mapped addresses are used. 40*0Sstevel@tonic-gate * 41*0Sstevel@tonic-gate * This file contains the functions used by both IP and the transports 42*0Sstevel@tonic-gate * to implement __sin6_src_id. 43*0Sstevel@tonic-gate * The routines do their own locking since they are called from 44*0Sstevel@tonic-gate * the transports (to map between a source id and an address) 45*0Sstevel@tonic-gate * and from IP proper when IP addresses are added and removed. 46*0Sstevel@tonic-gate * 47*0Sstevel@tonic-gate * The routines handle both IPv4 and IPv6 with the IPv4 addresses represented 48*0Sstevel@tonic-gate * as IPv4-mapped addresses. 49*0Sstevel@tonic-gate */ 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #include <sys/types.h> 52*0Sstevel@tonic-gate #include <sys/stream.h> 53*0Sstevel@tonic-gate #include <sys/dlpi.h> 54*0Sstevel@tonic-gate #include <sys/stropts.h> 55*0Sstevel@tonic-gate #include <sys/sysmacros.h> 56*0Sstevel@tonic-gate #include <sys/strsubr.h> 57*0Sstevel@tonic-gate #include <sys/strlog.h> 58*0Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 59*0Sstevel@tonic-gate #include <sys/tihdr.h> 60*0Sstevel@tonic-gate #include <sys/xti_inet.h> 61*0Sstevel@tonic-gate #include <sys/ddi.h> 62*0Sstevel@tonic-gate #include <sys/cmn_err.h> 63*0Sstevel@tonic-gate #include <sys/debug.h> 64*0Sstevel@tonic-gate #include <sys/modctl.h> 65*0Sstevel@tonic-gate #include <sys/atomic.h> 66*0Sstevel@tonic-gate #include <sys/zone.h> 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate #include <sys/systm.h> 69*0Sstevel@tonic-gate #include <sys/param.h> 70*0Sstevel@tonic-gate #include <sys/kmem.h> 71*0Sstevel@tonic-gate #include <sys/callb.h> 72*0Sstevel@tonic-gate #include <sys/socket.h> 73*0Sstevel@tonic-gate #include <sys/vtrace.h> 74*0Sstevel@tonic-gate #include <sys/isa_defs.h> 75*0Sstevel@tonic-gate #include <sys/kmem.h> 76*0Sstevel@tonic-gate #include <net/if.h> 77*0Sstevel@tonic-gate #include <net/if_arp.h> 78*0Sstevel@tonic-gate #include <net/route.h> 79*0Sstevel@tonic-gate #include <sys/sockio.h> 80*0Sstevel@tonic-gate #include <netinet/in.h> 81*0Sstevel@tonic-gate #include <net/if_dl.h> 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate #include <inet/common.h> 84*0Sstevel@tonic-gate #include <inet/mi.h> 85*0Sstevel@tonic-gate #include <inet/mib2.h> 86*0Sstevel@tonic-gate #include <inet/nd.h> 87*0Sstevel@tonic-gate #include <inet/arp.h> 88*0Sstevel@tonic-gate #include <inet/snmpcom.h> 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate #include <netinet/igmp_var.h> 91*0Sstevel@tonic-gate #include <netinet/ip6.h> 92*0Sstevel@tonic-gate #include <netinet/icmp6.h> 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate #include <inet/ip.h> 95*0Sstevel@tonic-gate #include <inet/ip6.h> 96*0Sstevel@tonic-gate #include <inet/tcp.h> 97*0Sstevel@tonic-gate #include <inet/ip_multi.h> 98*0Sstevel@tonic-gate #include <inet/ip_if.h> 99*0Sstevel@tonic-gate #include <inet/ip_ire.h> 100*0Sstevel@tonic-gate #include <inet/ip_rts.h> 101*0Sstevel@tonic-gate #include <inet/optcom.h> 102*0Sstevel@tonic-gate #include <inet/ip_ndp.h> 103*0Sstevel@tonic-gate #include <netinet/igmp.h> 104*0Sstevel@tonic-gate #include <netinet/ip_mroute.h> 105*0Sstevel@tonic-gate #include <inet/ipclassifier.h> 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate #include <net/pfkeyv2.h> 108*0Sstevel@tonic-gate #include <inet/ipsec_info.h> 109*0Sstevel@tonic-gate #include <inet/sadb.h> 110*0Sstevel@tonic-gate #include <sys/kmem.h> 111*0Sstevel@tonic-gate #include <inet/ipsec_impl.h> 112*0Sstevel@tonic-gate #include <inet/tun.h> 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate /* Data structure to represent addresses */ 115*0Sstevel@tonic-gate struct srcid_map { 116*0Sstevel@tonic-gate struct srcid_map *sm_next; 117*0Sstevel@tonic-gate in6_addr_t sm_addr; /* Local address */ 118*0Sstevel@tonic-gate uint_t sm_srcid; /* source id */ 119*0Sstevel@tonic-gate uint_t sm_refcnt; /* > 1 ipif with same addr? */ 120*0Sstevel@tonic-gate zoneid_t sm_zoneid; /* zone id */ 121*0Sstevel@tonic-gate }; 122*0Sstevel@tonic-gate typedef struct srcid_map srcid_map_t; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate static uint_t srcid_nextid(void); 125*0Sstevel@tonic-gate static srcid_map_t **srcid_lookup_addr(const in6_addr_t *addr, 126*0Sstevel@tonic-gate zoneid_t zoneid); 127*0Sstevel@tonic-gate static srcid_map_t **srcid_lookup_id(uint_t id); 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* 131*0Sstevel@tonic-gate * ID used to assign next free one. 132*0Sstevel@tonic-gate * Increases by one. Once it wraps we search for an unused ID. 133*0Sstevel@tonic-gate */ 134*0Sstevel@tonic-gate static uint_t ip_src_id = 1; 135*0Sstevel@tonic-gate static boolean_t srcid_wrapped = B_FALSE; 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate static srcid_map_t *srcid_head; 138*0Sstevel@tonic-gate krwlock_t srcid_lock; 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate /* 141*0Sstevel@tonic-gate * Insert/add a new address to the map. 142*0Sstevel@tonic-gate * Returns zero if ok; otherwise errno (e.g. for memory allocation failure). 143*0Sstevel@tonic-gate */ 144*0Sstevel@tonic-gate int 145*0Sstevel@tonic-gate ip_srcid_insert(const in6_addr_t *addr, zoneid_t zoneid) 146*0Sstevel@tonic-gate { 147*0Sstevel@tonic-gate srcid_map_t **smpp; 148*0Sstevel@tonic-gate #ifdef DEBUG 149*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate ip1dbg(("ip_srcid_insert(%s, %d)\n", 152*0Sstevel@tonic-gate inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid)); 153*0Sstevel@tonic-gate #endif 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate rw_enter(&srcid_lock, RW_WRITER); 156*0Sstevel@tonic-gate smpp = srcid_lookup_addr(addr, zoneid); 157*0Sstevel@tonic-gate if (*smpp != NULL) { 158*0Sstevel@tonic-gate /* Already present - increment refcount */ 159*0Sstevel@tonic-gate (*smpp)->sm_refcnt++; 160*0Sstevel@tonic-gate ASSERT((*smpp)->sm_refcnt != 0); /* wraparound */ 161*0Sstevel@tonic-gate rw_exit(&srcid_lock); 162*0Sstevel@tonic-gate return (0); 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate /* Insert new */ 165*0Sstevel@tonic-gate *smpp = kmem_alloc(sizeof (srcid_map_t), KM_NOSLEEP); 166*0Sstevel@tonic-gate if (*smpp == NULL) { 167*0Sstevel@tonic-gate rw_exit(&srcid_lock); 168*0Sstevel@tonic-gate return (ENOMEM); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate (*smpp)->sm_next = NULL; 171*0Sstevel@tonic-gate (*smpp)->sm_addr = *addr; 172*0Sstevel@tonic-gate (*smpp)->sm_srcid = srcid_nextid(); 173*0Sstevel@tonic-gate (*smpp)->sm_refcnt = 1; 174*0Sstevel@tonic-gate (*smpp)->sm_zoneid = zoneid; 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate rw_exit(&srcid_lock); 177*0Sstevel@tonic-gate return (0); 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate /* 181*0Sstevel@tonic-gate * Remove an new address from the map. 182*0Sstevel@tonic-gate * Returns zero if ok; otherwise errno (e.g. for nonexistent address). 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate int 185*0Sstevel@tonic-gate ip_srcid_remove(const in6_addr_t *addr, zoneid_t zoneid) 186*0Sstevel@tonic-gate { 187*0Sstevel@tonic-gate srcid_map_t **smpp; 188*0Sstevel@tonic-gate srcid_map_t *smp; 189*0Sstevel@tonic-gate #ifdef DEBUG 190*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate ip1dbg(("ip_srcid_remove(%s, %d)\n", 193*0Sstevel@tonic-gate inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid)); 194*0Sstevel@tonic-gate #endif 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate rw_enter(&srcid_lock, RW_WRITER); 197*0Sstevel@tonic-gate smpp = srcid_lookup_addr(addr, zoneid); 198*0Sstevel@tonic-gate smp = *smpp; 199*0Sstevel@tonic-gate if (smp == NULL) { 200*0Sstevel@tonic-gate /* Not preset */ 201*0Sstevel@tonic-gate rw_exit(&srcid_lock); 202*0Sstevel@tonic-gate return (ENOENT); 203*0Sstevel@tonic-gate } 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate /* Decrement refcount */ 206*0Sstevel@tonic-gate ASSERT(smp->sm_refcnt != 0); 207*0Sstevel@tonic-gate smp->sm_refcnt--; 208*0Sstevel@tonic-gate if (smp->sm_refcnt != 0) { 209*0Sstevel@tonic-gate rw_exit(&srcid_lock); 210*0Sstevel@tonic-gate return (0); 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate /* Remove entry */ 213*0Sstevel@tonic-gate *smpp = smp->sm_next; 214*0Sstevel@tonic-gate rw_exit(&srcid_lock); 215*0Sstevel@tonic-gate smp->sm_next = NULL; 216*0Sstevel@tonic-gate kmem_free(smp, sizeof (srcid_map_t)); 217*0Sstevel@tonic-gate return (0); 218*0Sstevel@tonic-gate } 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate /* 221*0Sstevel@tonic-gate * Map from an address to a source id. 222*0Sstevel@tonic-gate * If the address is unknown return the unknown id (zero). 223*0Sstevel@tonic-gate */ 224*0Sstevel@tonic-gate uint_t 225*0Sstevel@tonic-gate ip_srcid_find_addr(const in6_addr_t *addr, zoneid_t zoneid) 226*0Sstevel@tonic-gate { 227*0Sstevel@tonic-gate srcid_map_t **smpp; 228*0Sstevel@tonic-gate srcid_map_t *smp; 229*0Sstevel@tonic-gate uint_t id; 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate rw_enter(&srcid_lock, RW_READER); 232*0Sstevel@tonic-gate smpp = srcid_lookup_addr(addr, zoneid); 233*0Sstevel@tonic-gate smp = *smpp; 234*0Sstevel@tonic-gate if (smp == NULL) { 235*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate /* Not present - could be broadcast or multicast address */ 238*0Sstevel@tonic-gate ip1dbg(("ip_srcid_find_addr: unknown %s in zone %d\n", 239*0Sstevel@tonic-gate inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid)); 240*0Sstevel@tonic-gate id = 0; 241*0Sstevel@tonic-gate } else { 242*0Sstevel@tonic-gate ASSERT(smp->sm_refcnt != 0); 243*0Sstevel@tonic-gate id = smp->sm_srcid; 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate rw_exit(&srcid_lock); 246*0Sstevel@tonic-gate return (id); 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate /* 250*0Sstevel@tonic-gate * Map from a source id to an address. 251*0Sstevel@tonic-gate * If the id is unknown return the unspecified address. 252*0Sstevel@tonic-gate */ 253*0Sstevel@tonic-gate void 254*0Sstevel@tonic-gate ip_srcid_find_id(uint_t id, in6_addr_t *addr, zoneid_t zoneid) 255*0Sstevel@tonic-gate { 256*0Sstevel@tonic-gate srcid_map_t **smpp; 257*0Sstevel@tonic-gate srcid_map_t *smp; 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate rw_enter(&srcid_lock, RW_READER); 260*0Sstevel@tonic-gate smpp = srcid_lookup_id(id); 261*0Sstevel@tonic-gate smp = *smpp; 262*0Sstevel@tonic-gate if (smp == NULL || smp->sm_zoneid != zoneid) { 263*0Sstevel@tonic-gate /* Not preset */ 264*0Sstevel@tonic-gate ip1dbg(("ip_srcid_find_id: unknown %u or in wrong zone\n", id)); 265*0Sstevel@tonic-gate *addr = ipv6_all_zeros; 266*0Sstevel@tonic-gate } else { 267*0Sstevel@tonic-gate ASSERT(smp->sm_refcnt != 0); 268*0Sstevel@tonic-gate *addr = smp->sm_addr; 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate rw_exit(&srcid_lock); 271*0Sstevel@tonic-gate } 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate /* 274*0Sstevel@tonic-gate * ndd report function 275*0Sstevel@tonic-gate */ 276*0Sstevel@tonic-gate /*ARGSUSED*/ 277*0Sstevel@tonic-gate int 278*0Sstevel@tonic-gate ip_srcid_report(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *ioc_cr) 279*0Sstevel@tonic-gate { 280*0Sstevel@tonic-gate srcid_map_t *smp; 281*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 282*0Sstevel@tonic-gate zoneid_t zoneid; 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate zoneid = Q_TO_CONN(q)->conn_zoneid; 285*0Sstevel@tonic-gate (void) mi_mpprintf(mp, 286*0Sstevel@tonic-gate "addr " 287*0Sstevel@tonic-gate "id zone refcnt"); 288*0Sstevel@tonic-gate rw_enter(&srcid_lock, RW_READER); 289*0Sstevel@tonic-gate for (smp = srcid_head; smp != NULL; smp = smp->sm_next) { 290*0Sstevel@tonic-gate if (zoneid != GLOBAL_ZONEID && zoneid != smp->sm_zoneid) 291*0Sstevel@tonic-gate continue; 292*0Sstevel@tonic-gate (void) mi_mpprintf(mp, "%46s %5u %5d %5u", 293*0Sstevel@tonic-gate inet_ntop(AF_INET6, &smp->sm_addr, abuf, sizeof (abuf)), 294*0Sstevel@tonic-gate smp->sm_srcid, smp->sm_zoneid, smp->sm_refcnt); 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate rw_exit(&srcid_lock); 297*0Sstevel@tonic-gate return (0); 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* Assign the next available ID */ 301*0Sstevel@tonic-gate static uint_t 302*0Sstevel@tonic-gate srcid_nextid(void) 303*0Sstevel@tonic-gate { 304*0Sstevel@tonic-gate uint_t id; 305*0Sstevel@tonic-gate srcid_map_t **smpp; 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate ASSERT(rw_owner(&srcid_lock) == curthread); 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate if (!srcid_wrapped) { 310*0Sstevel@tonic-gate id = ip_src_id++; 311*0Sstevel@tonic-gate if (ip_src_id == 0) 312*0Sstevel@tonic-gate srcid_wrapped = B_TRUE; 313*0Sstevel@tonic-gate return (id); 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate /* Once it wraps we search for an unused ID. */ 316*0Sstevel@tonic-gate for (id = 0; id < 0xffffffff; id++) { 317*0Sstevel@tonic-gate smpp = srcid_lookup_id(id); 318*0Sstevel@tonic-gate if (*smpp == NULL) 319*0Sstevel@tonic-gate return (id); 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate panic("srcid_nextid: No free identifiers!"); 322*0Sstevel@tonic-gate /* NOTREACHED */ 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate /* 326*0Sstevel@tonic-gate * Lookup based on address. 327*0Sstevel@tonic-gate * Always returns a non-null pointer. 328*0Sstevel@tonic-gate * If found then *ptr will be the found object. 329*0Sstevel@tonic-gate * Otherwise *ptr will be NULL and can be used to insert a new object. 330*0Sstevel@tonic-gate */ 331*0Sstevel@tonic-gate static srcid_map_t ** 332*0Sstevel@tonic-gate srcid_lookup_addr(const in6_addr_t *addr, zoneid_t zoneid) 333*0Sstevel@tonic-gate { 334*0Sstevel@tonic-gate srcid_map_t **smpp; 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&srcid_lock)); 337*0Sstevel@tonic-gate smpp = &srcid_head; 338*0Sstevel@tonic-gate while (*smpp != NULL) { 339*0Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&(*smpp)->sm_addr, addr) && 340*0Sstevel@tonic-gate zoneid == (*smpp)->sm_zoneid) 341*0Sstevel@tonic-gate return (smpp); 342*0Sstevel@tonic-gate smpp = &(*smpp)->sm_next; 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate return (smpp); 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate /* 348*0Sstevel@tonic-gate * Lookup based on address. 349*0Sstevel@tonic-gate * Always returns a non-null pointer. 350*0Sstevel@tonic-gate * If found then *ptr will be the found object. 351*0Sstevel@tonic-gate * Otherwise *ptr will be NULL and can be used to insert a new object. 352*0Sstevel@tonic-gate */ 353*0Sstevel@tonic-gate static srcid_map_t ** 354*0Sstevel@tonic-gate srcid_lookup_id(uint_t id) 355*0Sstevel@tonic-gate { 356*0Sstevel@tonic-gate srcid_map_t **smpp; 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&srcid_lock)); 359*0Sstevel@tonic-gate smpp = &srcid_head; 360*0Sstevel@tonic-gate while (*smpp != NULL) { 361*0Sstevel@tonic-gate if ((*smpp)->sm_srcid == id) 362*0Sstevel@tonic-gate return (smpp); 363*0Sstevel@tonic-gate smpp = &(*smpp)->sm_next; 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate return (smpp); 366*0Sstevel@tonic-gate } 367