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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 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 <net/pfkeyv2.h> 107 #include <inet/ipsec_info.h> 108 #include <inet/sadb.h> 109 #include <sys/kmem.h> 110 #include <inet/ipsec_impl.h> 111 #include <inet/tun.h> 112 113 /* Data structure to represent addresses */ 114 struct srcid_map { 115 struct srcid_map *sm_next; 116 in6_addr_t sm_addr; /* Local address */ 117 uint_t sm_srcid; /* source id */ 118 uint_t sm_refcnt; /* > 1 ipif with same addr? */ 119 zoneid_t sm_zoneid; /* zone id */ 120 }; 121 typedef struct srcid_map srcid_map_t; 122 123 static uint_t srcid_nextid(ip_stack_t *); 124 static srcid_map_t **srcid_lookup_addr(const in6_addr_t *addr, 125 zoneid_t zoneid, ip_stack_t *); 126 static srcid_map_t **srcid_lookup_id(uint_t id, ip_stack_t *); 127 128 129 /* 130 * Insert/add a new address to the map. 131 * Returns zero if ok; otherwise errno (e.g. for memory allocation failure). 132 */ 133 int 134 ip_srcid_insert(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst) 135 { 136 srcid_map_t **smpp; 137 #ifdef DEBUG 138 char abuf[INET6_ADDRSTRLEN]; 139 140 ip1dbg(("ip_srcid_insert(%s, %d)\n", 141 inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid)); 142 #endif 143 144 rw_enter(&ipst->ips_srcid_lock, RW_WRITER); 145 smpp = srcid_lookup_addr(addr, zoneid, ipst); 146 if (*smpp != NULL) { 147 /* Already present - increment refcount */ 148 (*smpp)->sm_refcnt++; 149 ASSERT((*smpp)->sm_refcnt != 0); /* wraparound */ 150 rw_exit(&ipst->ips_srcid_lock); 151 return (0); 152 } 153 /* Insert new */ 154 *smpp = kmem_alloc(sizeof (srcid_map_t), KM_NOSLEEP); 155 if (*smpp == NULL) { 156 rw_exit(&ipst->ips_srcid_lock); 157 return (ENOMEM); 158 } 159 (*smpp)->sm_next = NULL; 160 (*smpp)->sm_addr = *addr; 161 (*smpp)->sm_srcid = srcid_nextid(ipst); 162 (*smpp)->sm_refcnt = 1; 163 (*smpp)->sm_zoneid = zoneid; 164 165 rw_exit(&ipst->ips_srcid_lock); 166 return (0); 167 } 168 169 /* 170 * Remove an new address from the map. 171 * Returns zero if ok; otherwise errno (e.g. for nonexistent address). 172 */ 173 int 174 ip_srcid_remove(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst) 175 { 176 srcid_map_t **smpp; 177 srcid_map_t *smp; 178 #ifdef DEBUG 179 char abuf[INET6_ADDRSTRLEN]; 180 181 ip1dbg(("ip_srcid_remove(%s, %d)\n", 182 inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid)); 183 #endif 184 185 rw_enter(&ipst->ips_srcid_lock, RW_WRITER); 186 smpp = srcid_lookup_addr(addr, zoneid, ipst); 187 smp = *smpp; 188 if (smp == NULL) { 189 /* Not preset */ 190 rw_exit(&ipst->ips_srcid_lock); 191 return (ENOENT); 192 } 193 194 /* Decrement refcount */ 195 ASSERT(smp->sm_refcnt != 0); 196 smp->sm_refcnt--; 197 if (smp->sm_refcnt != 0) { 198 rw_exit(&ipst->ips_srcid_lock); 199 return (0); 200 } 201 /* Remove entry */ 202 *smpp = smp->sm_next; 203 rw_exit(&ipst->ips_srcid_lock); 204 smp->sm_next = NULL; 205 kmem_free(smp, sizeof (srcid_map_t)); 206 return (0); 207 } 208 209 /* 210 * Map from an address to a source id. 211 * If the address is unknown return the unknown id (zero). 212 */ 213 uint_t 214 ip_srcid_find_addr(const in6_addr_t *addr, zoneid_t zoneid, 215 netstack_t *ns) 216 { 217 srcid_map_t **smpp; 218 srcid_map_t *smp; 219 uint_t id; 220 ip_stack_t *ipst = ns->netstack_ip; 221 222 rw_enter(&ipst->ips_srcid_lock, RW_READER); 223 smpp = srcid_lookup_addr(addr, zoneid, ipst); 224 smp = *smpp; 225 if (smp == NULL) { 226 char abuf[INET6_ADDRSTRLEN]; 227 228 /* Not present - could be broadcast or multicast address */ 229 ip1dbg(("ip_srcid_find_addr: unknown %s in zone %d\n", 230 inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid)); 231 id = 0; 232 } else { 233 ASSERT(smp->sm_refcnt != 0); 234 id = smp->sm_srcid; 235 } 236 rw_exit(&ipst->ips_srcid_lock); 237 return (id); 238 } 239 240 /* 241 * Map from a source id to an address. 242 * If the id is unknown return the unspecified address. 243 */ 244 void 245 ip_srcid_find_id(uint_t id, in6_addr_t *addr, zoneid_t zoneid, 246 netstack_t *ns) 247 { 248 srcid_map_t **smpp; 249 srcid_map_t *smp; 250 ip_stack_t *ipst = ns->netstack_ip; 251 252 rw_enter(&ipst->ips_srcid_lock, RW_READER); 253 smpp = srcid_lookup_id(id, ipst); 254 smp = *smpp; 255 if (smp == NULL || smp->sm_zoneid != zoneid) { 256 /* Not preset */ 257 ip1dbg(("ip_srcid_find_id: unknown %u or in wrong zone\n", id)); 258 *addr = ipv6_all_zeros; 259 } else { 260 ASSERT(smp->sm_refcnt != 0); 261 *addr = smp->sm_addr; 262 } 263 rw_exit(&ipst->ips_srcid_lock); 264 } 265 266 /* 267 * ndd report function 268 */ 269 /*ARGSUSED*/ 270 int 271 ip_srcid_report(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *ioc_cr) 272 { 273 srcid_map_t *smp; 274 char abuf[INET6_ADDRSTRLEN]; 275 zoneid_t zoneid; 276 ip_stack_t *ipst; 277 278 if (CONN_Q(q)) { 279 ipst = CONNQ_TO_IPST(q); 280 zoneid = Q_TO_CONN(q)->conn_zoneid; 281 } else { 282 ipst = ILLQ_TO_IPST(q); 283 zoneid = ((ill_t *)q->q_ptr)->ill_zoneid; 284 } 285 (void) mi_mpprintf(mp, 286 "addr " 287 "id zone refcnt"); 288 rw_enter(&ipst->ips_srcid_lock, RW_READER); 289 for (smp = ipst->ips_srcid_head; smp != NULL; smp = smp->sm_next) { 290 if (zoneid != GLOBAL_ZONEID && zoneid != smp->sm_zoneid) 291 continue; 292 (void) mi_mpprintf(mp, "%46s %5u %5d %5u", 293 inet_ntop(AF_INET6, &smp->sm_addr, abuf, sizeof (abuf)), 294 smp->sm_srcid, smp->sm_zoneid, smp->sm_refcnt); 295 } 296 rw_exit(&ipst->ips_srcid_lock); 297 return (0); 298 } 299 300 /* Assign the next available ID */ 301 static uint_t 302 srcid_nextid(ip_stack_t *ipst) 303 { 304 uint_t id; 305 srcid_map_t **smpp; 306 307 ASSERT(rw_owner(&ipst->ips_srcid_lock) == curthread); 308 309 if (!ipst->ips_srcid_wrapped) { 310 id = ipst->ips_ip_src_id++; 311 if (ipst->ips_ip_src_id == 0) 312 ipst->ips_srcid_wrapped = B_TRUE; 313 return (id); 314 } 315 /* Once it wraps we search for an unused ID. */ 316 for (id = 0; id < 0xffffffff; id++) { 317 smpp = srcid_lookup_id(id, ipst); 318 if (*smpp == NULL) 319 return (id); 320 } 321 panic("srcid_nextid: No free identifiers!"); 322 /* NOTREACHED */ 323 } 324 325 /* 326 * Lookup based on address. 327 * Always returns a non-null pointer. 328 * If found then *ptr will be the found object. 329 * Otherwise *ptr will be NULL and can be used to insert a new object. 330 */ 331 static srcid_map_t ** 332 srcid_lookup_addr(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst) 333 { 334 srcid_map_t **smpp; 335 336 ASSERT(RW_LOCK_HELD(&ipst->ips_srcid_lock)); 337 smpp = &ipst->ips_srcid_head; 338 while (*smpp != NULL) { 339 if (IN6_ARE_ADDR_EQUAL(&(*smpp)->sm_addr, addr) && 340 zoneid == (*smpp)->sm_zoneid) 341 return (smpp); 342 smpp = &(*smpp)->sm_next; 343 } 344 return (smpp); 345 } 346 347 /* 348 * Lookup based on address. 349 * Always returns a non-null pointer. 350 * If found then *ptr will be the found object. 351 * Otherwise *ptr will be NULL and can be used to insert a new object. 352 */ 353 static srcid_map_t ** 354 srcid_lookup_id(uint_t id, ip_stack_t *ipst) 355 { 356 srcid_map_t **smpp; 357 358 ASSERT(RW_LOCK_HELD(&ipst->ips_srcid_lock)); 359 smpp = &ipst->ips_srcid_head; 360 while (*smpp != NULL) { 361 if ((*smpp)->sm_srcid == id) 362 return (smpp); 363 smpp = &(*smpp)->sm_next; 364 } 365 return (smpp); 366 } 367