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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
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.
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
38 * The use applies to sockaddr_in6 - whether or not mapped addresses are used.
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.
46 * The routines handle both IPv4 and IPv6 with the IPv4 addresses represented
47 * as IPv4-mapped addresses.
50 #include <sys/types.h>
51 #include <sys/stream.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>
61 #include <sys/cmn_err.h>
62 #include <sys/debug.h>
63 #include <sys/modctl.h>
64 #include <sys/atomic.h>
67 #include <sys/systm.h>
68 #include <sys/param.h>
70 #include <sys/callb.h>
71 #include <sys/socket.h>
72 #include <sys/vtrace.h>
73 #include <sys/isa_defs.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>
82 #include <inet/common.h>
84 #include <inet/mib2.h>
87 #include <inet/snmpcom.h>
89 #include <netinet/igmp_var.h>
90 #include <netinet/ip6.h>
91 #include <netinet/icmp6.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>
106 #include <sys/kmem.h>
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
*);
115 * Insert/add a new address to the map.
116 * Returns zero if ok; otherwise errno (e.g. for memory allocation failure).
119 ip_srcid_insert(const in6_addr_t
*addr
, zoneid_t zoneid
, ip_stack_t
*ipst
)
123 char abuf
[INET6_ADDRSTRLEN
];
125 ip1dbg(("ip_srcid_insert(%s, %d)\n",
126 inet_ntop(AF_INET6
, addr
, abuf
, sizeof (abuf
)), zoneid
));
129 rw_enter(&ipst
->ips_srcid_lock
, RW_WRITER
);
130 smpp
= srcid_lookup_addr(addr
, zoneid
, ipst
);
132 /* Already present - increment refcount */
133 (*smpp
)->sm_refcnt
++;
134 ASSERT((*smpp
)->sm_refcnt
!= 0); /* wraparound */
135 rw_exit(&ipst
->ips_srcid_lock
);
139 *smpp
= kmem_alloc(sizeof (srcid_map_t
), KM_NOSLEEP
);
141 rw_exit(&ipst
->ips_srcid_lock
);
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
;
150 rw_exit(&ipst
->ips_srcid_lock
);
155 * Remove an new address from the map.
156 * Returns zero if ok; otherwise errno (e.g. for nonexistent address).
159 ip_srcid_remove(const in6_addr_t
*addr
, zoneid_t zoneid
, ip_stack_t
*ipst
)
164 char abuf
[INET6_ADDRSTRLEN
];
166 ip1dbg(("ip_srcid_remove(%s, %d)\n",
167 inet_ntop(AF_INET6
, addr
, abuf
, sizeof (abuf
)), zoneid
));
170 rw_enter(&ipst
->ips_srcid_lock
, RW_WRITER
);
171 smpp
= srcid_lookup_addr(addr
, zoneid
, ipst
);
175 rw_exit(&ipst
->ips_srcid_lock
);
179 /* Decrement refcount */
180 ASSERT(smp
->sm_refcnt
!= 0);
182 if (smp
->sm_refcnt
!= 0) {
183 rw_exit(&ipst
->ips_srcid_lock
);
187 *smpp
= smp
->sm_next
;
188 rw_exit(&ipst
->ips_srcid_lock
);
190 kmem_free(smp
, sizeof (srcid_map_t
));
195 * Map from an address to a source id.
196 * If the address is unknown return the unknown id (zero).
199 ip_srcid_find_addr(const in6_addr_t
*addr
, zoneid_t zoneid
,
205 ip_stack_t
*ipst
= ns
->netstack_ip
;
207 rw_enter(&ipst
->ips_srcid_lock
, RW_READER
);
208 smpp
= srcid_lookup_addr(addr
, zoneid
, ipst
);
211 char abuf
[INET6_ADDRSTRLEN
];
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
));
218 ASSERT(smp
->sm_refcnt
!= 0);
221 rw_exit(&ipst
->ips_srcid_lock
);
226 * Map from a source id to an address.
227 * If the id is unknown return the unspecified address.
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.
234 * "addr" will not be set if we return B_FALSE.
237 ip_srcid_find_id(uint_t id
, in6_addr_t
*addr
, zoneid_t zoneid
,
238 boolean_t v4mapped
, netstack_t
*ns
)
242 ip_stack_t
*ipst
= ns
->netstack_ip
;
245 rw_enter(&ipst
->ips_srcid_lock
, RW_READER
);
246 smpp
= srcid_lookup_id(id
, ipst
);
248 if (smp
== NULL
|| (smp
->sm_zoneid
!= zoneid
&& zoneid
!= ALL_ZONES
)) {
250 ip1dbg(("ip_srcid_find_id: unknown %u or in wrong zone\n", id
));
251 *addr
= ipv6_all_zeros
;
254 ASSERT(smp
->sm_refcnt
!= 0);
256 * The caller tells us if it expects a v4mapped address.
257 * Use it, along with the property of "addr" to set the rc.
259 if (IN6_IS_ADDR_V4MAPPED(&smp
->sm_addr
))
260 rc
= v4mapped
; /* We want a v4mapped address. */
262 rc
= !v4mapped
; /* We don't want a v4mapped address. */
265 *addr
= smp
->sm_addr
;
268 rw_exit(&ipst
->ips_srcid_lock
);
272 /* Assign the next available ID */
274 srcid_nextid(ip_stack_t
*ipst
)
279 ASSERT(rw_owner(&ipst
->ips_srcid_lock
) == curthread
);
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
;
287 /* Once it wraps we search for an unused ID. */
288 for (id
= 0; id
< 0xffffffff; id
++) {
289 smpp
= srcid_lookup_id(id
, ipst
);
293 panic("srcid_nextid: No free identifiers!");
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.
303 static srcid_map_t
**
304 srcid_lookup_addr(const in6_addr_t
*addr
, zoneid_t zoneid
, ip_stack_t
*ipst
)
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
))
314 smpp
= &(*smpp
)->sm_next
;
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.
325 static srcid_map_t
**
326 srcid_lookup_id(uint_t id
, ip_stack_t
*ipst
)
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
)
335 smpp
= &(*smpp
)->sm_next
;