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