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