Home | History | Annotate | Download | only in ip
      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