10Sstevel@tonic-gate /* 28485SPeter.Memishian@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate /* 70Sstevel@tonic-gate * Copyright (c) 1988, 1991, 1993 80Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 90Sstevel@tonic-gate * 100Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 110Sstevel@tonic-gate * modification, are permitted provided that the following conditions 120Sstevel@tonic-gate * are met: 130Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 140Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 150Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 160Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 170Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 180Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 190Sstevel@tonic-gate * must display the following acknowledgement: 200Sstevel@tonic-gate * This product includes software developed by the University of 210Sstevel@tonic-gate * California, Berkeley and its contributors. 220Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 230Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 240Sstevel@tonic-gate * without specific prior written permission. 250Sstevel@tonic-gate * 260Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 270Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 280Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 290Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 300Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 310Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 320Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 330Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 340Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 350Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 360Sstevel@tonic-gate * SUCH DAMAGE. 370Sstevel@tonic-gate * 380Sstevel@tonic-gate * @(#)rtsock.c 8.6 (Berkeley) 2/11/95 390Sstevel@tonic-gate */ 400Sstevel@tonic-gate 410Sstevel@tonic-gate /* 420Sstevel@tonic-gate * This file contains routines that processes routing socket requests. 430Sstevel@tonic-gate */ 440Sstevel@tonic-gate 450Sstevel@tonic-gate #include <sys/types.h> 460Sstevel@tonic-gate #include <sys/stream.h> 470Sstevel@tonic-gate #include <sys/stropts.h> 480Sstevel@tonic-gate #include <sys/ddi.h> 498778SErik.Nordmark@Sun.COM #include <sys/strsubr.h> 500Sstevel@tonic-gate #include <sys/cmn_err.h> 510Sstevel@tonic-gate #include <sys/debug.h> 520Sstevel@tonic-gate #include <sys/policy.h> 530Sstevel@tonic-gate #include <sys/zone.h> 540Sstevel@tonic-gate 550Sstevel@tonic-gate #include <sys/systm.h> 560Sstevel@tonic-gate #include <sys/param.h> 570Sstevel@tonic-gate #include <sys/socket.h> 580Sstevel@tonic-gate #include <sys/strsun.h> 590Sstevel@tonic-gate #include <net/if.h> 600Sstevel@tonic-gate #include <net/route.h> 610Sstevel@tonic-gate #include <netinet/in.h> 620Sstevel@tonic-gate #include <net/if_dl.h> 630Sstevel@tonic-gate #include <netinet/ip6.h> 640Sstevel@tonic-gate 650Sstevel@tonic-gate #include <inet/common.h> 660Sstevel@tonic-gate #include <inet/ip.h> 670Sstevel@tonic-gate #include <inet/ip6.h> 680Sstevel@tonic-gate #include <inet/ip_if.h> 690Sstevel@tonic-gate #include <inet/ip_ire.h> 702535Ssangeeta #include <inet/ip_ftable.h> 710Sstevel@tonic-gate #include <inet/ip_rts.h> 720Sstevel@tonic-gate 730Sstevel@tonic-gate #include <inet/ipclassifier.h> 740Sstevel@tonic-gate 751676Sjpk #include <sys/tsol/tndb.h> 761676Sjpk #include <sys/tsol/tnet.h> 771676Sjpk 781676Sjpk #define RTS_MSG_SIZE(type, rtm_addrs, af, sacnt) \ 791676Sjpk (rts_data_msg_size(rtm_addrs, af, sacnt) + rts_header_msg_size(type)) 800Sstevel@tonic-gate 810Sstevel@tonic-gate static size_t rts_copyfromsockaddr(struct sockaddr *sa, in6_addr_t *addrp); 820Sstevel@tonic-gate static void rts_fill_msg(int type, int rtm_addrs, ipaddr_t dst, 830Sstevel@tonic-gate ipaddr_t mask, ipaddr_t gateway, ipaddr_t src_addr, ipaddr_t brd_addr, 8411042SErik.Nordmark@Sun.COM ipaddr_t author, ipaddr_t ifaddr, const ill_t *ill, mblk_t *mp, 8511042SErik.Nordmark@Sun.COM const tsol_gc_t *); 860Sstevel@tonic-gate static int rts_getaddrs(rt_msghdr_t *rtm, in6_addr_t *dst_addrp, 870Sstevel@tonic-gate in6_addr_t *gw_addrp, in6_addr_t *net_maskp, in6_addr_t *authorp, 880Sstevel@tonic-gate in6_addr_t *if_addrp, in6_addr_t *src_addrp, ushort_t *indexp, 894823Sseb sa_family_t *afp, tsol_rtsecattr_t *rtsecattr, int *error); 901676Sjpk static void rts_getifdata(if_data_t *if_data, const ipif_t *ipif); 910Sstevel@tonic-gate static int rts_getmetrics(ire_t *ire, rt_metrics_t *metrics); 9211042SErik.Nordmark@Sun.COM static mblk_t *rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *ifire, 9311042SErik.Nordmark@Sun.COM const in6_addr_t *setsrc, tsol_ire_gw_secattr_t *attrp, sa_family_t af); 940Sstevel@tonic-gate static void rts_setmetrics(ire_t *ire, uint_t which, rt_metrics_t *metrics); 9511042SErik.Nordmark@Sun.COM static ire_t *ire_lookup_v4(ipaddr_t dst_addr, ipaddr_t net_mask, 9611042SErik.Nordmark@Sun.COM ipaddr_t gw_addr, const ill_t *ill, zoneid_t zoneid, 9711042SErik.Nordmark@Sun.COM const ts_label_t *tsl, int match_flags, ip_stack_t *ipst, ire_t **pifire, 9811042SErik.Nordmark@Sun.COM ipaddr_t *v4setsrcp, tsol_ire_gw_secattr_t **gwattrp); 9911042SErik.Nordmark@Sun.COM static ire_t *ire_lookup_v6(const in6_addr_t *dst_addr_v6, 10011042SErik.Nordmark@Sun.COM const in6_addr_t *net_mask_v6, const in6_addr_t *gw_addr_v6, 10111042SErik.Nordmark@Sun.COM const ill_t *ill, zoneid_t zoneid, const ts_label_t *tsl, int match_flags, 10211042SErik.Nordmark@Sun.COM ip_stack_t *ipst, ire_t **pifire, 10311042SErik.Nordmark@Sun.COM in6_addr_t *v6setsrcp, tsol_ire_gw_secattr_t **gwattrp); 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate /* 1068485SPeter.Memishian@Sun.COM * Send `mp' to all eligible routing queues. A queue is ineligible if: 1070Sstevel@tonic-gate * 1088485SPeter.Memishian@Sun.COM * 1. SO_USELOOPBACK is off and it is not the originating queue. 10911042SErik.Nordmark@Sun.COM * 2. RTA_UNDER_IPMP is on and RTSQ_UNDER_IPMP is not set in `flags'. 11011042SErik.Nordmark@Sun.COM * 3. RTA_UNDER_IPMP is off and RTSQ_NORMAL is not set in `flags'. 1118485SPeter.Memishian@Sun.COM * 4. It is not the same address family as `af', and `af' isn't AF_UNSPEC. 1120Sstevel@tonic-gate */ 1130Sstevel@tonic-gate void 1148485SPeter.Memishian@Sun.COM rts_queue_input(mblk_t *mp, conn_t *o_connp, sa_family_t af, uint_t flags, 1158485SPeter.Memishian@Sun.COM ip_stack_t *ipst) 1160Sstevel@tonic-gate { 1170Sstevel@tonic-gate mblk_t *mp1; 1180Sstevel@tonic-gate conn_t *connp, *next_connp; 1190Sstevel@tonic-gate 1208485SPeter.Memishian@Sun.COM /* 1218485SPeter.Memishian@Sun.COM * Since we don't have an ill_t here, RTSQ_DEFAULT must already be 12211042SErik.Nordmark@Sun.COM * resolved to one or more of RTSQ_NORMAL|RTSQ_UNDER_IPMP at this point. 1238485SPeter.Memishian@Sun.COM */ 1248485SPeter.Memishian@Sun.COM ASSERT(!(flags & RTSQ_DEFAULT)); 1258485SPeter.Memishian@Sun.COM 1263448Sdh155122 mutex_enter(&ipst->ips_rts_clients->connf_lock); 1273448Sdh155122 connp = ipst->ips_rts_clients->connf_head; 1280Sstevel@tonic-gate 1298485SPeter.Memishian@Sun.COM for (; connp != NULL; connp = next_connp) { 1308485SPeter.Memishian@Sun.COM next_connp = connp->conn_next; 1310Sstevel@tonic-gate /* 1320Sstevel@tonic-gate * If there was a family specified when this routing socket was 1330Sstevel@tonic-gate * created and it doesn't match the family of the message to 1340Sstevel@tonic-gate * copy, then continue. 1350Sstevel@tonic-gate */ 1360Sstevel@tonic-gate if ((connp->conn_proto != AF_UNSPEC) && 1378485SPeter.Memishian@Sun.COM (connp->conn_proto != af)) 1380Sstevel@tonic-gate continue; 1398485SPeter.Memishian@Sun.COM 1408485SPeter.Memishian@Sun.COM /* 1418485SPeter.Memishian@Sun.COM * Queue the message only if the conn_t and flags match. 1428485SPeter.Memishian@Sun.COM */ 1438485SPeter.Memishian@Sun.COM if (connp->conn_rtaware & RTAW_UNDER_IPMP) { 1448485SPeter.Memishian@Sun.COM if (!(flags & RTSQ_UNDER_IPMP)) 1458485SPeter.Memishian@Sun.COM continue; 1468485SPeter.Memishian@Sun.COM } else { 1478485SPeter.Memishian@Sun.COM if (!(flags & RTSQ_NORMAL)) 1488485SPeter.Memishian@Sun.COM continue; 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate /* 1510Sstevel@tonic-gate * For the originating queue, we only copy the message upstream 1520Sstevel@tonic-gate * if loopback is set. For others reading on the routing 1530Sstevel@tonic-gate * socket, we check if there is room upstream for a copy of the 1540Sstevel@tonic-gate * message. 1550Sstevel@tonic-gate */ 15611042SErik.Nordmark@Sun.COM if ((o_connp == connp) && connp->conn_useloopback == 0) { 1578485SPeter.Memishian@Sun.COM connp = connp->conn_next; 1588485SPeter.Memishian@Sun.COM continue; 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate CONN_INC_REF(connp); 1613448Sdh155122 mutex_exit(&ipst->ips_rts_clients->connf_lock); 1625240Snordmark /* Pass to rts_input */ 16311042SErik.Nordmark@Sun.COM if (IPCL_IS_NONSTR(connp) ? !connp->conn_flow_cntrld : 16411042SErik.Nordmark@Sun.COM canputnext(connp->conn_rq)) { 1650Sstevel@tonic-gate mp1 = dupmsg(mp); 1660Sstevel@tonic-gate if (mp1 == NULL) 1670Sstevel@tonic-gate mp1 = copymsg(mp); 16811042SErik.Nordmark@Sun.COM /* Note that we pass a NULL ira to rts_input */ 1690Sstevel@tonic-gate if (mp1 != NULL) 17011042SErik.Nordmark@Sun.COM (connp->conn_recv)(connp, mp1, NULL, NULL); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate 1733448Sdh155122 mutex_enter(&ipst->ips_rts_clients->connf_lock); 1748485SPeter.Memishian@Sun.COM /* reload next_connp since conn_next may have changed */ 1750Sstevel@tonic-gate next_connp = connp->conn_next; 1760Sstevel@tonic-gate CONN_DEC_REF(connp); 1770Sstevel@tonic-gate } 1783448Sdh155122 mutex_exit(&ipst->ips_rts_clients->connf_lock); 1790Sstevel@tonic-gate freemsg(mp); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate /* 1830Sstevel@tonic-gate * Takes an ire and sends an ack to all the routing sockets. This 1840Sstevel@tonic-gate * routine is used 1850Sstevel@tonic-gate * - when a route is created/deleted through the ioctl interface. 18611042SErik.Nordmark@Sun.COM * - when a stale redirect is deleted 1870Sstevel@tonic-gate */ 1880Sstevel@tonic-gate void 1893448Sdh155122 ip_rts_rtmsg(int type, ire_t *ire, int error, ip_stack_t *ipst) 1900Sstevel@tonic-gate { 1910Sstevel@tonic-gate mblk_t *mp; 1920Sstevel@tonic-gate rt_msghdr_t *rtm; 1930Sstevel@tonic-gate int rtm_addrs = (RTA_DST | RTA_NETMASK | RTA_GATEWAY); 1940Sstevel@tonic-gate sa_family_t af; 1950Sstevel@tonic-gate in6_addr_t gw_addr_v6; 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate if (ire == NULL) 1980Sstevel@tonic-gate return; 1990Sstevel@tonic-gate ASSERT(ire->ire_ipversion == IPV4_VERSION || 2000Sstevel@tonic-gate ire->ire_ipversion == IPV6_VERSION); 2010Sstevel@tonic-gate 20211042SErik.Nordmark@Sun.COM ASSERT(!(ire->ire_type & IRE_IF_CLONE)); 20311042SErik.Nordmark@Sun.COM 2040Sstevel@tonic-gate if (ire->ire_flags & RTF_SETSRC) 2050Sstevel@tonic-gate rtm_addrs |= RTA_SRC; 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate switch (ire->ire_ipversion) { 2080Sstevel@tonic-gate case IPV4_VERSION: 2090Sstevel@tonic-gate af = AF_INET; 2101676Sjpk mp = rts_alloc_msg(type, rtm_addrs, af, 0); 2110Sstevel@tonic-gate if (mp == NULL) 2120Sstevel@tonic-gate return; 2130Sstevel@tonic-gate rts_fill_msg(type, rtm_addrs, ire->ire_addr, ire->ire_mask, 21411042SErik.Nordmark@Sun.COM ire->ire_gateway_addr, ire->ire_setsrc_addr, 0, 0, 0, NULL, 21511042SErik.Nordmark@Sun.COM mp, NULL); 2160Sstevel@tonic-gate break; 2170Sstevel@tonic-gate case IPV6_VERSION: 2180Sstevel@tonic-gate af = AF_INET6; 2191676Sjpk mp = rts_alloc_msg(type, rtm_addrs, af, 0); 2200Sstevel@tonic-gate if (mp == NULL) 2210Sstevel@tonic-gate return; 2220Sstevel@tonic-gate mutex_enter(&ire->ire_lock); 2230Sstevel@tonic-gate gw_addr_v6 = ire->ire_gateway_addr_v6; 2240Sstevel@tonic-gate mutex_exit(&ire->ire_lock); 2250Sstevel@tonic-gate rts_fill_msg_v6(type, rtm_addrs, &ire->ire_addr_v6, 2260Sstevel@tonic-gate &ire->ire_mask_v6, &gw_addr_v6, 22711042SErik.Nordmark@Sun.COM &ire->ire_setsrc_addr_v6, &ipv6_all_zeros, &ipv6_all_zeros, 22811042SErik.Nordmark@Sun.COM &ipv6_all_zeros, NULL, mp, NULL); 2290Sstevel@tonic-gate break; 2300Sstevel@tonic-gate } 2310Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 2320Sstevel@tonic-gate mp->b_wptr = (uchar_t *)&mp->b_rptr[rtm->rtm_msglen]; 2330Sstevel@tonic-gate rtm->rtm_addrs = rtm_addrs; 2340Sstevel@tonic-gate rtm->rtm_flags = ire->ire_flags; 2350Sstevel@tonic-gate if (error != 0) 2360Sstevel@tonic-gate rtm->rtm_errno = error; 2370Sstevel@tonic-gate else 2380Sstevel@tonic-gate rtm->rtm_flags |= RTF_DONE; 2398485SPeter.Memishian@Sun.COM rts_queue_input(mp, NULL, af, RTSQ_ALL, ipst); 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate /* 2435240Snordmark * This is a call from the RTS module 2445240Snordmark * indicating that this is a Routing Socket 2455240Snordmark * Stream. Insert this conn_t in routing 2465240Snordmark * socket client list. 2475240Snordmark */ 2485240Snordmark void 2495240Snordmark ip_rts_register(conn_t *connp) 2505240Snordmark { 2515240Snordmark ip_stack_t *ipst = connp->conn_netstack->netstack_ip; 2525240Snordmark 25311042SErik.Nordmark@Sun.COM connp->conn_useloopback = 1; 2545240Snordmark ipcl_hash_insert_wildcard(ipst->ips_rts_clients, connp); 2555240Snordmark } 2565240Snordmark 2575240Snordmark /* 2585240Snordmark * This is a call from the RTS module indicating that it is closing. 2595240Snordmark */ 2605240Snordmark void 2615240Snordmark ip_rts_unregister(conn_t *connp) 2625240Snordmark { 2635240Snordmark ipcl_hash_remove(connp); 2645240Snordmark } 2655240Snordmark 2665240Snordmark /* 2670Sstevel@tonic-gate * Processes requests received on a routing socket. It extracts all the 2680Sstevel@tonic-gate * arguments and calls the appropriate function to process the request. 2690Sstevel@tonic-gate * 2704823Sseb * RTA_SRC bit flag requests are sent by 'route -setsrc'. 2710Sstevel@tonic-gate * 2720Sstevel@tonic-gate * In general, this function does not consume the message supplied but rather 2730Sstevel@tonic-gate * sends the message upstream with an appropriate UNIX errno. 2740Sstevel@tonic-gate */ 2750Sstevel@tonic-gate int 27611042SErik.Nordmark@Sun.COM ip_rts_request_common(mblk_t *mp, conn_t *connp, cred_t *ioc_cr) 2770Sstevel@tonic-gate { 2780Sstevel@tonic-gate rt_msghdr_t *rtm = NULL; 2790Sstevel@tonic-gate in6_addr_t dst_addr_v6; 2800Sstevel@tonic-gate in6_addr_t src_addr_v6; 2810Sstevel@tonic-gate in6_addr_t gw_addr_v6; 2820Sstevel@tonic-gate in6_addr_t net_mask_v6; 2830Sstevel@tonic-gate in6_addr_t author_v6; 2840Sstevel@tonic-gate in6_addr_t if_addr_v6; 28511042SErik.Nordmark@Sun.COM mblk_t *mp1; 2860Sstevel@tonic-gate ire_t *ire = NULL; 28711042SErik.Nordmark@Sun.COM ire_t *ifire = NULL; 28811042SErik.Nordmark@Sun.COM ipaddr_t v4setsrc; 28911042SErik.Nordmark@Sun.COM in6_addr_t v6setsrc = ipv6_all_zeros; 29011042SErik.Nordmark@Sun.COM tsol_ire_gw_secattr_t *gwattr = NULL; 2910Sstevel@tonic-gate int error = 0; 2920Sstevel@tonic-gate int match_flags = MATCH_IRE_DSTONLY; 2932304Swy83408 int match_flags_local = MATCH_IRE_TYPE | MATCH_IRE_GW; 2940Sstevel@tonic-gate int found_addrs; 2950Sstevel@tonic-gate sa_family_t af; 2960Sstevel@tonic-gate ipaddr_t dst_addr; 2970Sstevel@tonic-gate ipaddr_t gw_addr; 2980Sstevel@tonic-gate ipaddr_t src_addr; 2990Sstevel@tonic-gate ipaddr_t net_mask; 3000Sstevel@tonic-gate ushort_t index; 3011676Sjpk boolean_t gcgrp_xtraref = B_FALSE; 3021676Sjpk tsol_gcgrp_addr_t ga; 3031676Sjpk tsol_rtsecattr_t rtsecattr; 3041676Sjpk struct rtsa_s *rtsap = NULL; 3051676Sjpk tsol_gcgrp_t *gcgrp = NULL; 3061676Sjpk tsol_gc_t *gc = NULL; 3072601Swy83408 ts_label_t *tsl = NULL; 3082733Snordmark zoneid_t zoneid; 3093448Sdh155122 ip_stack_t *ipst; 31011042SErik.Nordmark@Sun.COM ill_t *ill = NULL; 3110Sstevel@tonic-gate 3122733Snordmark zoneid = connp->conn_zoneid; 3133448Sdh155122 ipst = connp->conn_netstack->netstack_ip; 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate if (mp->b_cont != NULL && !pullupmsg(mp, -1)) { 3160Sstevel@tonic-gate freemsg(mp); 3170Sstevel@tonic-gate error = EINVAL; 3180Sstevel@tonic-gate goto done; 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (rt_msghdr_t)) { 3210Sstevel@tonic-gate freemsg(mp); 3220Sstevel@tonic-gate error = EINVAL; 3230Sstevel@tonic-gate goto done; 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate /* 3270Sstevel@tonic-gate * Check the routing message for basic consistency including the 3280Sstevel@tonic-gate * version number and that the number of octets written is the same 3290Sstevel@tonic-gate * as specified by the rtm_msglen field. 3300Sstevel@tonic-gate * 3310Sstevel@tonic-gate * At this point, an error can be delivered back via rtm_errno. 3320Sstevel@tonic-gate */ 3330Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 3340Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) != rtm->rtm_msglen) { 3350Sstevel@tonic-gate error = EINVAL; 3360Sstevel@tonic-gate goto done; 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 3390Sstevel@tonic-gate error = EPROTONOSUPPORT; 3400Sstevel@tonic-gate goto done; 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate /* Only allow RTM_GET or RTM_RESOLVE for unprivileged process */ 3440Sstevel@tonic-gate if (rtm->rtm_type != RTM_GET && 3450Sstevel@tonic-gate rtm->rtm_type != RTM_RESOLVE && 3460Sstevel@tonic-gate (ioc_cr == NULL || 3473448Sdh155122 secpolicy_ip_config(ioc_cr, B_FALSE) != 0)) { 3480Sstevel@tonic-gate error = EPERM; 3490Sstevel@tonic-gate goto done; 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate found_addrs = rts_getaddrs(rtm, &dst_addr_v6, &gw_addr_v6, &net_mask_v6, 3534823Sseb &author_v6, &if_addr_v6, &src_addr_v6, &index, &af, &rtsecattr, 3544823Sseb &error); 3551676Sjpk 3561676Sjpk if (error != 0) 3571676Sjpk goto done; 3581676Sjpk 3590Sstevel@tonic-gate if ((found_addrs & RTA_DST) == 0) { 3600Sstevel@tonic-gate error = EINVAL; 3610Sstevel@tonic-gate goto done; 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate /* 3650Sstevel@tonic-gate * Based on the address family of the destination address, determine 3660Sstevel@tonic-gate * the destination, gateway and netmask and return the appropriate error 3670Sstevel@tonic-gate * if an unknown address family was specified (following the errno 3680Sstevel@tonic-gate * values that 4.4BSD-Lite2 returns.) 3690Sstevel@tonic-gate */ 3700Sstevel@tonic-gate switch (af) { 3710Sstevel@tonic-gate case AF_INET: 3720Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&dst_addr_v6, dst_addr); 3730Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&src_addr_v6, src_addr); 3740Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&gw_addr_v6, gw_addr); 3750Sstevel@tonic-gate if (((found_addrs & RTA_NETMASK) == 0) || 3760Sstevel@tonic-gate (rtm->rtm_flags & RTF_HOST)) 3770Sstevel@tonic-gate net_mask = IP_HOST_MASK; 3780Sstevel@tonic-gate else 3790Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&net_mask_v6, net_mask); 3800Sstevel@tonic-gate break; 3810Sstevel@tonic-gate case AF_INET6: 3820Sstevel@tonic-gate if (((found_addrs & RTA_NETMASK) == 0) || 3830Sstevel@tonic-gate (rtm->rtm_flags & RTF_HOST)) 3840Sstevel@tonic-gate net_mask_v6 = ipv6_all_ones; 3850Sstevel@tonic-gate break; 3860Sstevel@tonic-gate default: 3870Sstevel@tonic-gate /* 3880Sstevel@tonic-gate * These errno values are meant to be compatible with 3890Sstevel@tonic-gate * 4.4BSD-Lite2 for the given message types. 3900Sstevel@tonic-gate */ 3910Sstevel@tonic-gate switch (rtm->rtm_type) { 3920Sstevel@tonic-gate case RTM_ADD: 3930Sstevel@tonic-gate case RTM_DELETE: 3940Sstevel@tonic-gate error = ESRCH; 3950Sstevel@tonic-gate goto done; 3960Sstevel@tonic-gate case RTM_GET: 3970Sstevel@tonic-gate case RTM_CHANGE: 3980Sstevel@tonic-gate error = EAFNOSUPPORT; 3990Sstevel@tonic-gate goto done; 4000Sstevel@tonic-gate default: 4010Sstevel@tonic-gate error = EOPNOTSUPP; 4020Sstevel@tonic-gate goto done; 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate /* 4070Sstevel@tonic-gate * At this point, the address family must be something known. 4080Sstevel@tonic-gate */ 4090Sstevel@tonic-gate ASSERT(af == AF_INET || af == AF_INET6); 4100Sstevel@tonic-gate 41111042SErik.Nordmark@Sun.COM /* Handle RTA_IFP */ 4120Sstevel@tonic-gate if (index != 0) { 41311042SErik.Nordmark@Sun.COM ipif_t *ipif; 4148485SPeter.Memishian@Sun.COM lookup: 41511042SErik.Nordmark@Sun.COM ill = ill_lookup_on_ifindex(index, af == AF_INET6, ipst); 4160Sstevel@tonic-gate if (ill == NULL) { 41711042SErik.Nordmark@Sun.COM error = EINVAL; 4180Sstevel@tonic-gate goto done; 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4218485SPeter.Memishian@Sun.COM /* 4228485SPeter.Memishian@Sun.COM * Since all interfaces in an IPMP group must be equivalent, 4238485SPeter.Memishian@Sun.COM * we prevent changes to a specific underlying interface's 4248485SPeter.Memishian@Sun.COM * routing configuration. However, for backward compatibility, 4258485SPeter.Memishian@Sun.COM * we intepret a request to add a route on an underlying 4268485SPeter.Memishian@Sun.COM * interface as a request to add a route on its IPMP interface. 4278485SPeter.Memishian@Sun.COM */ 4288485SPeter.Memishian@Sun.COM if (IS_UNDER_IPMP(ill)) { 4298485SPeter.Memishian@Sun.COM switch (rtm->rtm_type) { 4308485SPeter.Memishian@Sun.COM case RTM_CHANGE: 4318485SPeter.Memishian@Sun.COM case RTM_DELETE: 4328485SPeter.Memishian@Sun.COM error = EINVAL; 4338485SPeter.Memishian@Sun.COM goto done; 4348485SPeter.Memishian@Sun.COM case RTM_ADD: 4358485SPeter.Memishian@Sun.COM index = ipmp_ill_get_ipmp_ifindex(ill); 4368485SPeter.Memishian@Sun.COM ill_refrele(ill); 4378485SPeter.Memishian@Sun.COM if (index == 0) { 43811042SErik.Nordmark@Sun.COM ill = NULL; /* already refrele'd */ 4398485SPeter.Memishian@Sun.COM error = EINVAL; 4408485SPeter.Memishian@Sun.COM goto done; 4418485SPeter.Memishian@Sun.COM } 4428485SPeter.Memishian@Sun.COM goto lookup; 4438485SPeter.Memishian@Sun.COM } 4448485SPeter.Memishian@Sun.COM } 4458485SPeter.Memishian@Sun.COM 44611042SErik.Nordmark@Sun.COM match_flags |= MATCH_IRE_ILL; 44711042SErik.Nordmark@Sun.COM /* 44811042SErik.Nordmark@Sun.COM * This provides the same zoneid as in Solaris 10 44911042SErik.Nordmark@Sun.COM * that -ifp picks the zoneid from the first ipif on the ill. 45011042SErik.Nordmark@Sun.COM * But it might not be useful since the first ipif will always 45111042SErik.Nordmark@Sun.COM * have the same zoneid as the ill. 45211042SErik.Nordmark@Sun.COM */ 4530Sstevel@tonic-gate ipif = ipif_get_next_ipif(NULL, ill); 45411042SErik.Nordmark@Sun.COM if (ipif != NULL) { 45511042SErik.Nordmark@Sun.COM zoneid = ipif->ipif_zoneid; 45611042SErik.Nordmark@Sun.COM ipif_refrele(ipif); 45711042SErik.Nordmark@Sun.COM } 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate /* 4610Sstevel@tonic-gate * If a netmask was supplied in the message, then subsequent route 4620Sstevel@tonic-gate * lookups will attempt to match on the netmask as well. 4630Sstevel@tonic-gate */ 4640Sstevel@tonic-gate if ((found_addrs & RTA_NETMASK) != 0) 4650Sstevel@tonic-gate match_flags |= MATCH_IRE_MASK; 4660Sstevel@tonic-gate 4671676Sjpk /* 4681676Sjpk * We only process any passed-in route security attributes for 4692304Swy83408 * either RTM_ADD or RTM_CHANGE message; We overload them 4702304Swy83408 * to do an RTM_GET as a different label; ignore otherwise. 4711676Sjpk */ 4722304Swy83408 if (rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE || 4732304Swy83408 rtm->rtm_type == RTM_GET) { 4741676Sjpk ASSERT(rtsecattr.rtsa_cnt <= TSOL_RTSA_REQUEST_MAX); 4751676Sjpk if (rtsecattr.rtsa_cnt > 0) 4761676Sjpk rtsap = &rtsecattr.rtsa_attr[0]; 4771676Sjpk } 4781676Sjpk 4790Sstevel@tonic-gate switch (rtm->rtm_type) { 4800Sstevel@tonic-gate case RTM_ADD: 4810Sstevel@tonic-gate /* if we are adding a route, gateway is a must */ 4820Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) == 0) { 4830Sstevel@tonic-gate error = EINVAL; 4840Sstevel@tonic-gate goto done; 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate /* Multirouting does not support net routes. */ 4880Sstevel@tonic-gate if ((rtm->rtm_flags & (RTF_MULTIRT | RTF_HOST)) == 4890Sstevel@tonic-gate RTF_MULTIRT) { 4900Sstevel@tonic-gate error = EADDRNOTAVAIL; 4910Sstevel@tonic-gate goto done; 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate /* 4950Sstevel@tonic-gate * Multirouting and user-specified source addresses 4960Sstevel@tonic-gate * do not support interface based routing. 4970Sstevel@tonic-gate * Assigning a source address to an interface based 4980Sstevel@tonic-gate * route is achievable by plumbing a new ipif and 4990Sstevel@tonic-gate * setting up the interface route via this ipif, 5000Sstevel@tonic-gate * though. 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate if (rtm->rtm_flags & (RTF_MULTIRT | RTF_SETSRC)) { 5030Sstevel@tonic-gate if ((rtm->rtm_flags & RTF_GATEWAY) == 0) { 5040Sstevel@tonic-gate error = EADDRNOTAVAIL; 5050Sstevel@tonic-gate goto done; 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate switch (af) { 5100Sstevel@tonic-gate case AF_INET: 5110Sstevel@tonic-gate if (src_addr != INADDR_ANY) { 51211042SErik.Nordmark@Sun.COM uint_t type; 51311042SErik.Nordmark@Sun.COM 5140Sstevel@tonic-gate /* 5150Sstevel@tonic-gate * The RTF_SETSRC flag is present, check that 5160Sstevel@tonic-gate * the supplied src address is not the loopback 5170Sstevel@tonic-gate * address. This would produce martian packets. 5180Sstevel@tonic-gate */ 5190Sstevel@tonic-gate if (src_addr == htonl(INADDR_LOOPBACK)) { 5200Sstevel@tonic-gate error = EINVAL; 5210Sstevel@tonic-gate goto done; 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate /* 5240Sstevel@tonic-gate * Also check that the supplied address is a 52511042SErik.Nordmark@Sun.COM * valid, local one. Only allow IFF_UP ones 5260Sstevel@tonic-gate */ 52711042SErik.Nordmark@Sun.COM type = ip_type_v4(src_addr, ipst); 52811042SErik.Nordmark@Sun.COM if (!(type & (IRE_LOCAL|IRE_LOOPBACK))) { 52911042SErik.Nordmark@Sun.COM error = EADDRNOTAVAIL; 5300Sstevel@tonic-gate goto done; 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate } else { 5330Sstevel@tonic-gate /* 5340Sstevel@tonic-gate * The RTF_SETSRC modifier must be associated 5350Sstevel@tonic-gate * to a non-null source address. 5360Sstevel@tonic-gate */ 5370Sstevel@tonic-gate if (rtm->rtm_flags & RTF_SETSRC) { 5380Sstevel@tonic-gate error = EINVAL; 5390Sstevel@tonic-gate goto done; 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5431676Sjpk error = ip_rt_add(dst_addr, net_mask, gw_addr, src_addr, 54411042SErik.Nordmark@Sun.COM rtm->rtm_flags, ill, &ire, B_FALSE, 54511042SErik.Nordmark@Sun.COM rtsap, ipst, zoneid); 54611042SErik.Nordmark@Sun.COM if (ill != NULL) 54711042SErik.Nordmark@Sun.COM ASSERT(!MUTEX_HELD(&ill->ill_lock)); 5480Sstevel@tonic-gate break; 5490Sstevel@tonic-gate case AF_INET6: 5500Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&src_addr_v6)) { 55111042SErik.Nordmark@Sun.COM uint_t type; 55211042SErik.Nordmark@Sun.COM 5530Sstevel@tonic-gate /* 5540Sstevel@tonic-gate * The RTF_SETSRC flag is present, check that 5550Sstevel@tonic-gate * the supplied src address is not the loopback 5560Sstevel@tonic-gate * address. This would produce martian packets. 5570Sstevel@tonic-gate */ 5580Sstevel@tonic-gate if (IN6_IS_ADDR_LOOPBACK(&src_addr_v6)) { 5590Sstevel@tonic-gate error = EINVAL; 5600Sstevel@tonic-gate goto done; 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate /* 5630Sstevel@tonic-gate * Also check that the supplied address is a 56411042SErik.Nordmark@Sun.COM * valid, local one. Only allow UP ones. 5650Sstevel@tonic-gate */ 56611042SErik.Nordmark@Sun.COM type = ip_type_v6(&src_addr_v6, ipst); 56711042SErik.Nordmark@Sun.COM if (!(type & (IRE_LOCAL|IRE_LOOPBACK))) { 56811042SErik.Nordmark@Sun.COM error = EADDRNOTAVAIL; 5690Sstevel@tonic-gate goto done; 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate error = ip_rt_add_v6(&dst_addr_v6, &net_mask_v6, 5730Sstevel@tonic-gate &gw_addr_v6, &src_addr_v6, rtm->rtm_flags, 57411042SErik.Nordmark@Sun.COM ill, &ire, rtsap, ipst, zoneid); 5750Sstevel@tonic-gate break; 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate /* 5780Sstevel@tonic-gate * The RTF_SETSRC modifier must be associated 5790Sstevel@tonic-gate * to a non-null source address. 5800Sstevel@tonic-gate */ 5810Sstevel@tonic-gate if (rtm->rtm_flags & RTF_SETSRC) { 5820Sstevel@tonic-gate error = EINVAL; 5830Sstevel@tonic-gate goto done; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate error = ip_rt_add_v6(&dst_addr_v6, &net_mask_v6, 5860Sstevel@tonic-gate &gw_addr_v6, NULL, rtm->rtm_flags, 58711042SErik.Nordmark@Sun.COM ill, &ire, rtsap, ipst, zoneid); 58811042SErik.Nordmark@Sun.COM if (ill != NULL) 58911042SErik.Nordmark@Sun.COM ASSERT(!MUTEX_HELD(&ill->ill_lock)); 5900Sstevel@tonic-gate break; 5910Sstevel@tonic-gate } 5920Sstevel@tonic-gate if (error != 0) 5930Sstevel@tonic-gate goto done; 5940Sstevel@tonic-gate ASSERT(ire != NULL); 5950Sstevel@tonic-gate rts_setmetrics(ire, rtm->rtm_inits, &rtm->rtm_rmx); 5960Sstevel@tonic-gate break; 5970Sstevel@tonic-gate case RTM_DELETE: 5980Sstevel@tonic-gate /* if we are deleting a route, gateway is a must */ 5990Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) == 0) { 6000Sstevel@tonic-gate error = EINVAL; 6010Sstevel@tonic-gate goto done; 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate /* 6040Sstevel@tonic-gate * The RTF_SETSRC modifier does not make sense 6050Sstevel@tonic-gate * when deleting a route. 6060Sstevel@tonic-gate */ 6070Sstevel@tonic-gate if (rtm->rtm_flags & RTF_SETSRC) { 6080Sstevel@tonic-gate error = EINVAL; 6090Sstevel@tonic-gate goto done; 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate switch (af) { 6130Sstevel@tonic-gate case AF_INET: 6140Sstevel@tonic-gate error = ip_rt_delete(dst_addr, net_mask, gw_addr, 61511042SErik.Nordmark@Sun.COM found_addrs, rtm->rtm_flags, ill, B_FALSE, 61611042SErik.Nordmark@Sun.COM ipst, zoneid); 6170Sstevel@tonic-gate break; 6180Sstevel@tonic-gate case AF_INET6: 6190Sstevel@tonic-gate error = ip_rt_delete_v6(&dst_addr_v6, &net_mask_v6, 62011042SErik.Nordmark@Sun.COM &gw_addr_v6, found_addrs, rtm->rtm_flags, ill, 62111042SErik.Nordmark@Sun.COM ipst, zoneid); 6220Sstevel@tonic-gate break; 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate break; 6250Sstevel@tonic-gate case RTM_GET: 6260Sstevel@tonic-gate case RTM_CHANGE: 6270Sstevel@tonic-gate /* 6280Sstevel@tonic-gate * In the case of RTM_GET, the forwarding table should be 62911042SErik.Nordmark@Sun.COM * searched recursively. Also, if a gateway was 6300Sstevel@tonic-gate * specified then the gateway address must also be matched. 6310Sstevel@tonic-gate * 6320Sstevel@tonic-gate * In the case of RTM_CHANGE, the gateway address (if supplied) 6330Sstevel@tonic-gate * is the new gateway address so matching on the gateway address 6340Sstevel@tonic-gate * is not done. This can lead to ambiguity when looking up the 6350Sstevel@tonic-gate * route to change as usually only the destination (and netmask, 6360Sstevel@tonic-gate * if supplied) is used for the lookup. However if a RTA_IFP 6370Sstevel@tonic-gate * sockaddr is also supplied, it can disambiguate which route to 6380Sstevel@tonic-gate * change provided the ambigous routes are tied to distinct 6390Sstevel@tonic-gate * ill's (or interface indices). If the routes are not tied to 6400Sstevel@tonic-gate * any particular interfaces (for example, with traditional 6410Sstevel@tonic-gate * gateway routes), then a RTA_IFP sockaddr will be of no use as 6420Sstevel@tonic-gate * it won't match any such routes. 6430Sstevel@tonic-gate * RTA_SRC is not supported for RTM_GET and RTM_CHANGE, 6440Sstevel@tonic-gate * except when RTM_CHANGE is combined to RTF_SETSRC. 6450Sstevel@tonic-gate */ 6460Sstevel@tonic-gate if (((found_addrs & RTA_SRC) != 0) && 6470Sstevel@tonic-gate ((rtm->rtm_type == RTM_GET) || 6480Sstevel@tonic-gate !(rtm->rtm_flags & RTF_SETSRC))) { 6490Sstevel@tonic-gate error = EOPNOTSUPP; 6500Sstevel@tonic-gate goto done; 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate if (rtm->rtm_type == RTM_GET) { 65411042SErik.Nordmark@Sun.COM match_flags |= MATCH_IRE_SECATTR; 6552304Swy83408 match_flags_local |= MATCH_IRE_SECATTR; 6560Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) != 0) 6570Sstevel@tonic-gate match_flags |= MATCH_IRE_GW; 6582601Swy83408 if (ioc_cr) 6592601Swy83408 tsl = crgetlabel(ioc_cr); 6602304Swy83408 if (rtsap != NULL) { 6612304Swy83408 if (rtsa_validate(rtsap) != 0) { 6622304Swy83408 error = EINVAL; 6632304Swy83408 goto done; 6642304Swy83408 } 6652601Swy83408 if (tsl != NULL && 6662601Swy83408 crgetzoneid(ioc_cr) != GLOBAL_ZONEID && 6672304Swy83408 (tsl->tsl_doi != rtsap->rtsa_doi || 6682304Swy83408 !bldominates(&tsl->tsl_label, 6692304Swy83408 &rtsap->rtsa_slrange.lower_bound))) { 6702304Swy83408 error = EPERM; 6712304Swy83408 goto done; 6722304Swy83408 } 6732304Swy83408 tsl = labelalloc( 6742304Swy83408 &rtsap->rtsa_slrange.lower_bound, 6752304Swy83408 rtsap->rtsa_doi, KM_NOSLEEP); 6762304Swy83408 } 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate if (rtm->rtm_type == RTM_CHANGE) { 6790Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) && 6800Sstevel@tonic-gate (rtm->rtm_flags & RTF_SETSRC)) { 6810Sstevel@tonic-gate /* 6820Sstevel@tonic-gate * Do not want to change the gateway, 6830Sstevel@tonic-gate * but rather the source address. 6840Sstevel@tonic-gate */ 6850Sstevel@tonic-gate match_flags |= MATCH_IRE_GW; 6860Sstevel@tonic-gate } 6870Sstevel@tonic-gate } 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate /* 6900Sstevel@tonic-gate * If the netmask is all ones (either as supplied or as derived 6910Sstevel@tonic-gate * above), then first check for an IRE_LOOPBACK or 6920Sstevel@tonic-gate * IRE_LOCAL entry. 6930Sstevel@tonic-gate * 6940Sstevel@tonic-gate * If we didn't check for or find an IRE_LOOPBACK or IRE_LOCAL 69511042SErik.Nordmark@Sun.COM * entry, then look for any other type of IRE. 6960Sstevel@tonic-gate */ 6970Sstevel@tonic-gate switch (af) { 6980Sstevel@tonic-gate case AF_INET: 6990Sstevel@tonic-gate if (net_mask == IP_HOST_MASK) { 70011042SErik.Nordmark@Sun.COM ire = ire_ftable_lookup_v4(dst_addr, 0, gw_addr, 7012733Snordmark IRE_LOCAL | IRE_LOOPBACK, NULL, zoneid, 70211042SErik.Nordmark@Sun.COM tsl, match_flags_local, 0, ipst, NULL); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate if (ire == NULL) { 70511042SErik.Nordmark@Sun.COM ire = ire_lookup_v4(dst_addr, net_mask, 70611042SErik.Nordmark@Sun.COM gw_addr, ill, zoneid, tsl, match_flags, 70711042SErik.Nordmark@Sun.COM ipst, &ifire, &v4setsrc, &gwattr); 70811042SErik.Nordmark@Sun.COM IN6_IPADDR_TO_V4MAPPED(v4setsrc, &v6setsrc); 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate break; 7110Sstevel@tonic-gate case AF_INET6: 7120Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&net_mask_v6, &ipv6_all_ones)) { 71311042SErik.Nordmark@Sun.COM ire = ire_ftable_lookup_v6(&dst_addr_v6, NULL, 7140Sstevel@tonic-gate &gw_addr_v6, IRE_LOCAL | IRE_LOOPBACK, NULL, 71511042SErik.Nordmark@Sun.COM zoneid, tsl, match_flags_local, 0, ipst, 71611042SErik.Nordmark@Sun.COM NULL); 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate if (ire == NULL) { 71911042SErik.Nordmark@Sun.COM ire = ire_lookup_v6(&dst_addr_v6, 72011042SErik.Nordmark@Sun.COM &net_mask_v6, &gw_addr_v6, ill, zoneid, 72111042SErik.Nordmark@Sun.COM tsl, match_flags, ipst, &ifire, &v6setsrc, 72211042SErik.Nordmark@Sun.COM &gwattr); 7230Sstevel@tonic-gate } 7240Sstevel@tonic-gate break; 7250Sstevel@tonic-gate } 7262304Swy83408 if (tsl != NULL && tsl != crgetlabel(ioc_cr)) 7272304Swy83408 label_rele(tsl); 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate if (ire == NULL) { 7300Sstevel@tonic-gate error = ESRCH; 7310Sstevel@tonic-gate goto done; 7320Sstevel@tonic-gate } 73311042SErik.Nordmark@Sun.COM /* 73411042SErik.Nordmark@Sun.COM * Want to return failure if we get an IRE_NOROUTE from 73511042SErik.Nordmark@Sun.COM * ire_route_recursive 73611042SErik.Nordmark@Sun.COM */ 73711042SErik.Nordmark@Sun.COM if (ire->ire_type & IRE_NOROUTE) { 73811042SErik.Nordmark@Sun.COM ire_refrele(ire); 73911042SErik.Nordmark@Sun.COM ire = NULL; 74011042SErik.Nordmark@Sun.COM error = ESRCH; 74111042SErik.Nordmark@Sun.COM goto done; 74211042SErik.Nordmark@Sun.COM } 74311042SErik.Nordmark@Sun.COM 7440Sstevel@tonic-gate /* we know the IRE before we come here */ 7450Sstevel@tonic-gate switch (rtm->rtm_type) { 7460Sstevel@tonic-gate case RTM_GET: 74711042SErik.Nordmark@Sun.COM mp1 = rts_rtmget(mp, ire, ifire, &v6setsrc, gwattr, af); 7480Sstevel@tonic-gate if (mp1 == NULL) { 7490Sstevel@tonic-gate error = ENOBUFS; 7500Sstevel@tonic-gate goto done; 7510Sstevel@tonic-gate } 7520Sstevel@tonic-gate freemsg(mp); 7530Sstevel@tonic-gate mp = mp1; 7540Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 7550Sstevel@tonic-gate break; 7560Sstevel@tonic-gate case RTM_CHANGE: 7570Sstevel@tonic-gate /* 7580Sstevel@tonic-gate * Do not allow to the multirouting state of a route 7590Sstevel@tonic-gate * to be changed. This aims to prevent undesirable 7600Sstevel@tonic-gate * stages where both multirt and non-multirt routes 7610Sstevel@tonic-gate * for the same destination are declared. 7620Sstevel@tonic-gate */ 7630Sstevel@tonic-gate if ((ire->ire_flags & RTF_MULTIRT) != 7640Sstevel@tonic-gate (rtm->rtm_flags & RTF_MULTIRT)) { 7650Sstevel@tonic-gate error = EINVAL; 7660Sstevel@tonic-gate goto done; 7670Sstevel@tonic-gate } 7680Sstevel@tonic-gate /* 7690Sstevel@tonic-gate * Note that we do not need to do 7700Sstevel@tonic-gate * ire_flush_cache_*(IRE_FLUSH_ADD) as a change 7710Sstevel@tonic-gate * in metrics or gateway will not affect existing 7720Sstevel@tonic-gate * routes since it does not create a more specific 7730Sstevel@tonic-gate * route. 7740Sstevel@tonic-gate */ 7750Sstevel@tonic-gate switch (af) { 7760Sstevel@tonic-gate case AF_INET: 7770Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) != 0 && 7780Sstevel@tonic-gate (ire->ire_gateway_addr != gw_addr)) { 7790Sstevel@tonic-gate ire->ire_gateway_addr = gw_addr; 7800Sstevel@tonic-gate } 7811676Sjpk 7821676Sjpk if (rtsap != NULL) { 7831676Sjpk ga.ga_af = AF_INET; 7841676Sjpk IN6_IPADDR_TO_V4MAPPED( 7851676Sjpk ire->ire_gateway_addr, &ga.ga_addr); 7861676Sjpk 7871676Sjpk gcgrp = gcgrp_lookup(&ga, B_TRUE); 7881676Sjpk if (gcgrp == NULL) { 7891676Sjpk error = ENOMEM; 7901676Sjpk goto done; 7911676Sjpk } 7921676Sjpk } 7931676Sjpk 7940Sstevel@tonic-gate if ((found_addrs & RTA_SRC) != 0 && 7950Sstevel@tonic-gate (rtm->rtm_flags & RTF_SETSRC) != 0 && 79611042SErik.Nordmark@Sun.COM (ire->ire_setsrc_addr != src_addr)) { 79711042SErik.Nordmark@Sun.COM if (src_addr != INADDR_ANY) { 79811042SErik.Nordmark@Sun.COM uint_t type; 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate /* 8010Sstevel@tonic-gate * The RTF_SETSRC flag is 8020Sstevel@tonic-gate * present, check that the 8030Sstevel@tonic-gate * supplied src address is not 8040Sstevel@tonic-gate * the loopback address. This 8050Sstevel@tonic-gate * would produce martian 8060Sstevel@tonic-gate * packets. 8070Sstevel@tonic-gate */ 8080Sstevel@tonic-gate if (src_addr == 8090Sstevel@tonic-gate htonl(INADDR_LOOPBACK)) { 8100Sstevel@tonic-gate error = EINVAL; 8110Sstevel@tonic-gate goto done; 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate /* 81411042SErik.Nordmark@Sun.COM * Also check that the 8150Sstevel@tonic-gate * supplied addr is a valid 8160Sstevel@tonic-gate * local address. 8170Sstevel@tonic-gate */ 81811042SErik.Nordmark@Sun.COM type = ip_type_v4(src_addr, 81911042SErik.Nordmark@Sun.COM ipst); 82011042SErik.Nordmark@Sun.COM if (!(type & 82111042SErik.Nordmark@Sun.COM (IRE_LOCAL|IRE_LOOPBACK))) { 82211042SErik.Nordmark@Sun.COM error = EADDRNOTAVAIL; 8230Sstevel@tonic-gate goto done; 8240Sstevel@tonic-gate } 8250Sstevel@tonic-gate ire->ire_flags |= RTF_SETSRC; 82611042SErik.Nordmark@Sun.COM ire->ire_setsrc_addr = 82711042SErik.Nordmark@Sun.COM src_addr; 8280Sstevel@tonic-gate } else { 8290Sstevel@tonic-gate ire->ire_flags &= ~RTF_SETSRC; 83011042SErik.Nordmark@Sun.COM ire->ire_setsrc_addr = 83111042SErik.Nordmark@Sun.COM INADDR_ANY; 8320Sstevel@tonic-gate } 83311042SErik.Nordmark@Sun.COM /* 83411042SErik.Nordmark@Sun.COM * Let conn_ixa caching know that 83511042SErik.Nordmark@Sun.COM * source address selection changed 83611042SErik.Nordmark@Sun.COM */ 83711042SErik.Nordmark@Sun.COM ip_update_source_selection(ipst); 8380Sstevel@tonic-gate } 83911042SErik.Nordmark@Sun.COM ire_flush_cache_v4(ire, IRE_FLUSH_GWCHANGE); 8400Sstevel@tonic-gate break; 8410Sstevel@tonic-gate case AF_INET6: 8420Sstevel@tonic-gate mutex_enter(&ire->ire_lock); 8430Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) != 0 && 8440Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL( 8450Sstevel@tonic-gate &ire->ire_gateway_addr_v6, &gw_addr_v6)) { 8460Sstevel@tonic-gate ire->ire_gateway_addr_v6 = gw_addr_v6; 8470Sstevel@tonic-gate } 84811042SErik.Nordmark@Sun.COM mutex_exit(&ire->ire_lock); 8491676Sjpk 8501676Sjpk if (rtsap != NULL) { 8511676Sjpk ga.ga_af = AF_INET6; 85211042SErik.Nordmark@Sun.COM mutex_enter(&ire->ire_lock); 8531676Sjpk ga.ga_addr = ire->ire_gateway_addr_v6; 85411042SErik.Nordmark@Sun.COM mutex_exit(&ire->ire_lock); 8551676Sjpk 8561676Sjpk gcgrp = gcgrp_lookup(&ga, B_TRUE); 8571676Sjpk if (gcgrp == NULL) { 8581676Sjpk error = ENOMEM; 8591676Sjpk goto done; 8601676Sjpk } 8611676Sjpk } 8621676Sjpk 8630Sstevel@tonic-gate if ((found_addrs & RTA_SRC) != 0 && 8640Sstevel@tonic-gate (rtm->rtm_flags & RTF_SETSRC) != 0 && 8650Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL( 86611042SErik.Nordmark@Sun.COM &ire->ire_setsrc_addr_v6, &src_addr_v6)) { 8670Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED( 8680Sstevel@tonic-gate &src_addr_v6)) { 86911042SErik.Nordmark@Sun.COM uint_t type; 87011042SErik.Nordmark@Sun.COM 8710Sstevel@tonic-gate /* 8720Sstevel@tonic-gate * The RTF_SETSRC flag is 8730Sstevel@tonic-gate * present, check that the 8740Sstevel@tonic-gate * supplied src address is not 8750Sstevel@tonic-gate * the loopback address. This 8760Sstevel@tonic-gate * would produce martian 8770Sstevel@tonic-gate * packets. 8780Sstevel@tonic-gate */ 8790Sstevel@tonic-gate if (IN6_IS_ADDR_LOOPBACK( 8800Sstevel@tonic-gate &src_addr_v6)) { 8810Sstevel@tonic-gate error = EINVAL; 8820Sstevel@tonic-gate goto done; 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate /* 88511042SErik.Nordmark@Sun.COM * Also check that the 8860Sstevel@tonic-gate * supplied addr is a valid 8870Sstevel@tonic-gate * local address. 8880Sstevel@tonic-gate */ 88911042SErik.Nordmark@Sun.COM type = ip_type_v6(&src_addr_v6, 89011042SErik.Nordmark@Sun.COM ipst); 89111042SErik.Nordmark@Sun.COM if (!(type & 89211042SErik.Nordmark@Sun.COM (IRE_LOCAL|IRE_LOOPBACK))) { 89311042SErik.Nordmark@Sun.COM error = EADDRNOTAVAIL; 8940Sstevel@tonic-gate goto done; 8950Sstevel@tonic-gate } 89611042SErik.Nordmark@Sun.COM mutex_enter(&ire->ire_lock); 8970Sstevel@tonic-gate ire->ire_flags |= RTF_SETSRC; 89811042SErik.Nordmark@Sun.COM ire->ire_setsrc_addr_v6 = 89911042SErik.Nordmark@Sun.COM src_addr_v6; 90011042SErik.Nordmark@Sun.COM mutex_exit(&ire->ire_lock); 9010Sstevel@tonic-gate } else { 90211042SErik.Nordmark@Sun.COM mutex_enter(&ire->ire_lock); 9030Sstevel@tonic-gate ire->ire_flags &= ~RTF_SETSRC; 90411042SErik.Nordmark@Sun.COM ire->ire_setsrc_addr_v6 = 90511042SErik.Nordmark@Sun.COM ipv6_all_zeros; 90611042SErik.Nordmark@Sun.COM mutex_exit(&ire->ire_lock); 9070Sstevel@tonic-gate } 90811042SErik.Nordmark@Sun.COM /* 90911042SErik.Nordmark@Sun.COM * Let conn_ixa caching know that 91011042SErik.Nordmark@Sun.COM * source address selection changed 91111042SErik.Nordmark@Sun.COM */ 91211042SErik.Nordmark@Sun.COM ip_update_source_selection(ipst); 9130Sstevel@tonic-gate } 91411042SErik.Nordmark@Sun.COM ire_flush_cache_v6(ire, IRE_FLUSH_GWCHANGE); 9150Sstevel@tonic-gate break; 9160Sstevel@tonic-gate } 9171676Sjpk 9181676Sjpk if (rtsap != NULL) { 9191676Sjpk ASSERT(gcgrp != NULL); 9201676Sjpk 9211676Sjpk /* 9221676Sjpk * Create and add the security attribute to 9231676Sjpk * prefix IRE; it will add a reference to the 9241676Sjpk * group upon allocating a new entry. If it 9251676Sjpk * finds an already-existing entry for the 9261676Sjpk * security attribute, it simply returns it 9271676Sjpk * and no new group reference is made. 9281676Sjpk */ 9291676Sjpk gc = gc_create(rtsap, gcgrp, &gcgrp_xtraref); 9301676Sjpk if (gc == NULL || 9311676Sjpk (error = tsol_ire_init_gwattr(ire, 93211042SErik.Nordmark@Sun.COM ire->ire_ipversion, gc)) != 0) { 9331676Sjpk if (gc != NULL) { 9341676Sjpk GC_REFRELE(gc); 9351676Sjpk } else { 9361676Sjpk /* gc_create failed */ 9371676Sjpk error = ENOMEM; 9381676Sjpk } 9391676Sjpk goto done; 9401676Sjpk } 9411676Sjpk } 9420Sstevel@tonic-gate rts_setmetrics(ire, rtm->rtm_inits, &rtm->rtm_rmx); 9430Sstevel@tonic-gate break; 9440Sstevel@tonic-gate } 9450Sstevel@tonic-gate break; 9460Sstevel@tonic-gate default: 9470Sstevel@tonic-gate error = EOPNOTSUPP; 9480Sstevel@tonic-gate break; 9490Sstevel@tonic-gate } 9500Sstevel@tonic-gate done: 9510Sstevel@tonic-gate if (ire != NULL) 9520Sstevel@tonic-gate ire_refrele(ire); 95311042SErik.Nordmark@Sun.COM if (ifire != NULL) 95411042SErik.Nordmark@Sun.COM ire_refrele(ifire); 95511042SErik.Nordmark@Sun.COM if (ill != NULL) 95611042SErik.Nordmark@Sun.COM ill_refrele(ill); 9570Sstevel@tonic-gate 9581676Sjpk if (gcgrp_xtraref) 9591676Sjpk GCGRP_REFRELE(gcgrp); 9601676Sjpk 9610Sstevel@tonic-gate if (rtm != NULL) { 9620Sstevel@tonic-gate ASSERT(mp->b_wptr <= mp->b_datap->db_lim); 9630Sstevel@tonic-gate if (error != 0) { 9640Sstevel@tonic-gate rtm->rtm_errno = error; 9650Sstevel@tonic-gate /* Send error ACK */ 9660Sstevel@tonic-gate ip1dbg(("ip_rts_request: error %d\n", error)); 9670Sstevel@tonic-gate } else { 9680Sstevel@tonic-gate rtm->rtm_flags |= RTF_DONE; 9690Sstevel@tonic-gate /* OK ACK already set up by caller except this */ 9700Sstevel@tonic-gate ip2dbg(("ip_rts_request: OK ACK\n")); 9710Sstevel@tonic-gate } 9728485SPeter.Memishian@Sun.COM rts_queue_input(mp, connp, af, RTSQ_ALL, ipst); 9730Sstevel@tonic-gate } 97411042SErik.Nordmark@Sun.COM return (error); 97511042SErik.Nordmark@Sun.COM } 9768348SEric.Yu@Sun.COM 97711042SErik.Nordmark@Sun.COM /* 97811042SErik.Nordmark@Sun.COM * Helper function that can do recursive lookups including when 97911042SErik.Nordmark@Sun.COM * MATCH_IRE_GW and/or MATCH_IRE_MASK is set. 98011042SErik.Nordmark@Sun.COM */ 98111042SErik.Nordmark@Sun.COM static ire_t * 98211042SErik.Nordmark@Sun.COM ire_lookup_v4(ipaddr_t dst_addr, ipaddr_t net_mask, ipaddr_t gw_addr, 98311042SErik.Nordmark@Sun.COM const ill_t *ill, zoneid_t zoneid, const ts_label_t *tsl, 98411042SErik.Nordmark@Sun.COM int match_flags, ip_stack_t *ipst, ire_t **pifire, ipaddr_t *v4setsrcp, 98511042SErik.Nordmark@Sun.COM tsol_ire_gw_secattr_t **gwattrp) 98611042SErik.Nordmark@Sun.COM { 98711042SErik.Nordmark@Sun.COM ire_t *ire; 98811042SErik.Nordmark@Sun.COM ire_t *ifire = NULL; 98911042SErik.Nordmark@Sun.COM uint_t ire_type; 99011042SErik.Nordmark@Sun.COM 99111042SErik.Nordmark@Sun.COM *pifire = NULL; 99211042SErik.Nordmark@Sun.COM *v4setsrcp = INADDR_ANY; 99311042SErik.Nordmark@Sun.COM *gwattrp = NULL; 99411042SErik.Nordmark@Sun.COM 99511042SErik.Nordmark@Sun.COM /* Skip IRE_IF_CLONE */ 99611042SErik.Nordmark@Sun.COM match_flags |= MATCH_IRE_TYPE; 99711042SErik.Nordmark@Sun.COM ire_type = (IRE_ONLINK|IRE_OFFLINK) & ~IRE_IF_CLONE; 99811042SErik.Nordmark@Sun.COM 99911042SErik.Nordmark@Sun.COM /* 100011042SErik.Nordmark@Sun.COM * ire_route_recursive can't match gateway or mask thus if they are 100111042SErik.Nordmark@Sun.COM * set we have to do two steps of lookups 100211042SErik.Nordmark@Sun.COM */ 100311042SErik.Nordmark@Sun.COM if (match_flags & (MATCH_IRE_GW|MATCH_IRE_MASK)) { 100411042SErik.Nordmark@Sun.COM ire = ire_ftable_lookup_v4(dst_addr, net_mask, gw_addr, 100511042SErik.Nordmark@Sun.COM ire_type, ill, zoneid, tsl, match_flags, 0, ipst, NULL); 100611042SErik.Nordmark@Sun.COM 100711042SErik.Nordmark@Sun.COM if (ire == NULL ||(ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE))) 100811042SErik.Nordmark@Sun.COM return (ire); 100911042SErik.Nordmark@Sun.COM 101011042SErik.Nordmark@Sun.COM if (ire->ire_type & IRE_ONLINK) 101111042SErik.Nordmark@Sun.COM return (ire); 101211042SErik.Nordmark@Sun.COM 101311042SErik.Nordmark@Sun.COM if (ire->ire_flags & RTF_SETSRC) { 101411042SErik.Nordmark@Sun.COM ASSERT(ire->ire_setsrc_addr != INADDR_ANY); 101511042SErik.Nordmark@Sun.COM *v4setsrcp = ire->ire_setsrc_addr; 101611042SErik.Nordmark@Sun.COM v4setsrcp = NULL; 101711042SErik.Nordmark@Sun.COM } 101811042SErik.Nordmark@Sun.COM 101911042SErik.Nordmark@Sun.COM /* The first ire_gw_secattr is passed back */ 102011042SErik.Nordmark@Sun.COM if (ire->ire_gw_secattr != NULL) { 102111042SErik.Nordmark@Sun.COM *gwattrp = ire->ire_gw_secattr; 102211042SErik.Nordmark@Sun.COM gwattrp = NULL; 102311042SErik.Nordmark@Sun.COM } 102411042SErik.Nordmark@Sun.COM 102511042SErik.Nordmark@Sun.COM /* Look for an interface ire recursively based on the gateway */ 102611042SErik.Nordmark@Sun.COM dst_addr = ire->ire_gateway_addr; 102711042SErik.Nordmark@Sun.COM match_flags &= ~(MATCH_IRE_GW|MATCH_IRE_MASK); 102811042SErik.Nordmark@Sun.COM ifire = ire_route_recursive_v4(dst_addr, ire_type, ill, zoneid, 102911042SErik.Nordmark@Sun.COM tsl, match_flags, B_FALSE, 0, ipst, v4setsrcp, gwattrp, 103011042SErik.Nordmark@Sun.COM NULL); 103111042SErik.Nordmark@Sun.COM } else { 103211042SErik.Nordmark@Sun.COM ire = ire_route_recursive_v4(dst_addr, ire_type, ill, zoneid, 103311042SErik.Nordmark@Sun.COM tsl, match_flags, B_FALSE, 0, ipst, v4setsrcp, gwattrp, 103411042SErik.Nordmark@Sun.COM NULL); 103511042SErik.Nordmark@Sun.COM } 103611042SErik.Nordmark@Sun.COM *pifire = ifire; 103711042SErik.Nordmark@Sun.COM return (ire); 103811042SErik.Nordmark@Sun.COM } 103911042SErik.Nordmark@Sun.COM 104011042SErik.Nordmark@Sun.COM static ire_t * 104111042SErik.Nordmark@Sun.COM ire_lookup_v6(const in6_addr_t *dst_addr_v6, 104211042SErik.Nordmark@Sun.COM const in6_addr_t *net_mask_v6, const in6_addr_t *gw_addr_v6, 104311042SErik.Nordmark@Sun.COM const ill_t *ill, zoneid_t zoneid, const ts_label_t *tsl, int match_flags, 104411042SErik.Nordmark@Sun.COM ip_stack_t *ipst, ire_t **pifire, 104511042SErik.Nordmark@Sun.COM in6_addr_t *v6setsrcp, tsol_ire_gw_secattr_t **gwattrp) 104611042SErik.Nordmark@Sun.COM { 104711042SErik.Nordmark@Sun.COM ire_t *ire; 104811042SErik.Nordmark@Sun.COM ire_t *ifire = NULL; 104911042SErik.Nordmark@Sun.COM uint_t ire_type; 105011042SErik.Nordmark@Sun.COM 105111042SErik.Nordmark@Sun.COM *pifire = NULL; 105211042SErik.Nordmark@Sun.COM *v6setsrcp = ipv6_all_zeros; 105311042SErik.Nordmark@Sun.COM *gwattrp = NULL; 105411042SErik.Nordmark@Sun.COM 105511042SErik.Nordmark@Sun.COM /* Skip IRE_IF_CLONE */ 105611042SErik.Nordmark@Sun.COM match_flags |= MATCH_IRE_TYPE; 105711042SErik.Nordmark@Sun.COM ire_type = (IRE_ONLINK|IRE_OFFLINK) & ~IRE_IF_CLONE; 105811042SErik.Nordmark@Sun.COM 105911042SErik.Nordmark@Sun.COM /* 106011042SErik.Nordmark@Sun.COM * ire_route_recursive can't match gateway or mask thus if they are 106111042SErik.Nordmark@Sun.COM * set we have to do two steps of lookups 106211042SErik.Nordmark@Sun.COM */ 106311042SErik.Nordmark@Sun.COM if (match_flags & (MATCH_IRE_GW|MATCH_IRE_MASK)) { 106411042SErik.Nordmark@Sun.COM in6_addr_t dst; 106511042SErik.Nordmark@Sun.COM 106611042SErik.Nordmark@Sun.COM ire = ire_ftable_lookup_v6(dst_addr_v6, net_mask_v6, 106711042SErik.Nordmark@Sun.COM gw_addr_v6, ire_type, ill, zoneid, tsl, match_flags, 0, 106811042SErik.Nordmark@Sun.COM ipst, NULL); 106911042SErik.Nordmark@Sun.COM 107011042SErik.Nordmark@Sun.COM if (ire == NULL ||(ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE))) 107111042SErik.Nordmark@Sun.COM return (ire); 107211042SErik.Nordmark@Sun.COM 107311042SErik.Nordmark@Sun.COM if (ire->ire_type & IRE_ONLINK) 107411042SErik.Nordmark@Sun.COM return (ire); 107511042SErik.Nordmark@Sun.COM 107611042SErik.Nordmark@Sun.COM if (ire->ire_flags & RTF_SETSRC) { 107711042SErik.Nordmark@Sun.COM ASSERT(!IN6_IS_ADDR_UNSPECIFIED( 107811042SErik.Nordmark@Sun.COM &ire->ire_setsrc_addr_v6)); 107911042SErik.Nordmark@Sun.COM *v6setsrcp = ire->ire_setsrc_addr_v6; 108011042SErik.Nordmark@Sun.COM v6setsrcp = NULL; 108111042SErik.Nordmark@Sun.COM } 108211042SErik.Nordmark@Sun.COM 108311042SErik.Nordmark@Sun.COM /* The first ire_gw_secattr is passed back */ 108411042SErik.Nordmark@Sun.COM if (ire->ire_gw_secattr != NULL) { 108511042SErik.Nordmark@Sun.COM *gwattrp = ire->ire_gw_secattr; 108611042SErik.Nordmark@Sun.COM gwattrp = NULL; 108711042SErik.Nordmark@Sun.COM } 108811042SErik.Nordmark@Sun.COM 108911042SErik.Nordmark@Sun.COM mutex_enter(&ire->ire_lock); 109011042SErik.Nordmark@Sun.COM dst = ire->ire_gateway_addr_v6; 109111042SErik.Nordmark@Sun.COM mutex_exit(&ire->ire_lock); 109211042SErik.Nordmark@Sun.COM match_flags &= ~(MATCH_IRE_GW|MATCH_IRE_MASK); 109311042SErik.Nordmark@Sun.COM ifire = ire_route_recursive_v6(&dst, ire_type, ill, zoneid, tsl, 109411042SErik.Nordmark@Sun.COM match_flags, B_FALSE, 0, ipst, v6setsrcp, gwattrp, NULL); 109511042SErik.Nordmark@Sun.COM } else { 109611042SErik.Nordmark@Sun.COM ire = ire_route_recursive_v6(dst_addr_v6, ire_type, ill, zoneid, 109711042SErik.Nordmark@Sun.COM tsl, match_flags, B_FALSE, 0, ipst, v6setsrcp, gwattrp, 109811042SErik.Nordmark@Sun.COM NULL); 109911042SErik.Nordmark@Sun.COM } 110011042SErik.Nordmark@Sun.COM *pifire = ifire; 110111042SErik.Nordmark@Sun.COM return (ire); 110211042SErik.Nordmark@Sun.COM } 110311042SErik.Nordmark@Sun.COM 110411042SErik.Nordmark@Sun.COM 110511042SErik.Nordmark@Sun.COM /* 110611042SErik.Nordmark@Sun.COM * Handle IP_IOC_RTS_REQUEST ioctls 110711042SErik.Nordmark@Sun.COM */ 110811042SErik.Nordmark@Sun.COM int 110911042SErik.Nordmark@Sun.COM ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) 111011042SErik.Nordmark@Sun.COM { 111111042SErik.Nordmark@Sun.COM conn_t *connp = Q_TO_CONN(q); 111211042SErik.Nordmark@Sun.COM IOCP iocp = (IOCP)mp->b_rptr; 111311042SErik.Nordmark@Sun.COM mblk_t *mp1, *ioc_mp = mp; 111411042SErik.Nordmark@Sun.COM int error = 0; 111511042SErik.Nordmark@Sun.COM ip_stack_t *ipst; 111611042SErik.Nordmark@Sun.COM 111711042SErik.Nordmark@Sun.COM ipst = connp->conn_netstack->netstack_ip; 111811042SErik.Nordmark@Sun.COM 111911042SErik.Nordmark@Sun.COM ASSERT(mp->b_cont != NULL); 112011042SErik.Nordmark@Sun.COM /* ioc_mp holds mp */ 112111042SErik.Nordmark@Sun.COM mp = mp->b_cont; 112211042SErik.Nordmark@Sun.COM 112311042SErik.Nordmark@Sun.COM /* 112411042SErik.Nordmark@Sun.COM * The Routing Socket data starts on 112511042SErik.Nordmark@Sun.COM * next block. If there is no next block 112611042SErik.Nordmark@Sun.COM * this is an indication from routing module 112711042SErik.Nordmark@Sun.COM * that it is a routing socket stream queue. 112811042SErik.Nordmark@Sun.COM * We need to support that for compatibility with SDP since 112911042SErik.Nordmark@Sun.COM * it has a contract private interface to use IP_IOC_RTS_REQUEST. 113011042SErik.Nordmark@Sun.COM * Note: SDP no longer uses IP_IOC_RTS_REQUEST - we can remove this. 113111042SErik.Nordmark@Sun.COM */ 113211042SErik.Nordmark@Sun.COM if (mp->b_cont == NULL) { 113311042SErik.Nordmark@Sun.COM /* 113411042SErik.Nordmark@Sun.COM * This is a message from SDP 113511042SErik.Nordmark@Sun.COM * indicating that this is a Routing Socket 113611042SErik.Nordmark@Sun.COM * Stream. Insert this conn_t in routing 113711042SErik.Nordmark@Sun.COM * socket client list. 113811042SErik.Nordmark@Sun.COM */ 113911042SErik.Nordmark@Sun.COM connp->conn_useloopback = 1; 114011042SErik.Nordmark@Sun.COM ipcl_hash_insert_wildcard(ipst->ips_rts_clients, connp); 114111042SErik.Nordmark@Sun.COM goto done; 114211042SErik.Nordmark@Sun.COM } 114311042SErik.Nordmark@Sun.COM mp1 = dupmsg(mp->b_cont); 114411042SErik.Nordmark@Sun.COM if (mp1 == NULL) { 114511042SErik.Nordmark@Sun.COM error = ENOBUFS; 114611042SErik.Nordmark@Sun.COM goto done; 114711042SErik.Nordmark@Sun.COM } 114811042SErik.Nordmark@Sun.COM mp = mp1; 114911042SErik.Nordmark@Sun.COM 115011042SErik.Nordmark@Sun.COM error = ip_rts_request_common(mp, connp, ioc_cr); 115111042SErik.Nordmark@Sun.COM done: 11520Sstevel@tonic-gate iocp->ioc_error = error; 11530Sstevel@tonic-gate ioc_mp->b_datap->db_type = M_IOCACK; 11540Sstevel@tonic-gate if (iocp->ioc_error != 0) 11550Sstevel@tonic-gate iocp->ioc_count = 0; 115611042SErik.Nordmark@Sun.COM /* Note that we pass a NULL ira to rts_input */ 115711042SErik.Nordmark@Sun.COM (connp->conn_recv)(connp, ioc_mp, NULL, NULL); 11588348SEric.Yu@Sun.COM 11590Sstevel@tonic-gate /* conn was refheld in ip_wput_ioctl. */ 11600Sstevel@tonic-gate CONN_OPER_PENDING_DONE(connp); 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate return (error); 11630Sstevel@tonic-gate } 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate /* 11660Sstevel@tonic-gate * Build a reply to the RTM_GET request contained in the given message block 11670Sstevel@tonic-gate * using the retrieved IRE of the destination address, the parent IRE (if it 11680Sstevel@tonic-gate * exists) and the address family. 11690Sstevel@tonic-gate * 11700Sstevel@tonic-gate * Returns a pointer to a message block containing the reply if successful, 11710Sstevel@tonic-gate * otherwise NULL is returned. 11720Sstevel@tonic-gate */ 11731676Sjpk static mblk_t * 117411042SErik.Nordmark@Sun.COM rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *ifire, const in6_addr_t *setsrc, 117511042SErik.Nordmark@Sun.COM tsol_ire_gw_secattr_t *attrp, sa_family_t af) 11760Sstevel@tonic-gate { 11770Sstevel@tonic-gate rt_msghdr_t *rtm; 11780Sstevel@tonic-gate rt_msghdr_t *new_rtm; 11790Sstevel@tonic-gate mblk_t *new_mp; 11800Sstevel@tonic-gate int rtm_addrs; 11810Sstevel@tonic-gate int rtm_flags; 11821676Sjpk tsol_gc_t *gc = NULL; 11831676Sjpk tsol_gcgrp_t *gcgrp = NULL; 118411042SErik.Nordmark@Sun.COM ill_t *ill; 118511042SErik.Nordmark@Sun.COM ipif_t *ipif = NULL; 118611042SErik.Nordmark@Sun.COM ipaddr_t brdaddr; /* IFF_POINTOPOINT destination */ 118711042SErik.Nordmark@Sun.COM ipaddr_t ifaddr; 118811042SErik.Nordmark@Sun.COM in6_addr_t brdaddr6; /* IFF_POINTOPOINT destination */ 118911042SErik.Nordmark@Sun.COM in6_addr_t ifaddr6; 119011042SErik.Nordmark@Sun.COM ipaddr_t v4setsrc; 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 11930Sstevel@tonic-gate 119411042SErik.Nordmark@Sun.COM /* 119511042SErik.Nordmark@Sun.COM * Find the ill used to send packets. This will be NULL in case 119611042SErik.Nordmark@Sun.COM * of a reject or blackhole. 119711042SErik.Nordmark@Sun.COM */ 119811042SErik.Nordmark@Sun.COM if (ifire != NULL) 119911042SErik.Nordmark@Sun.COM ill = ire_nexthop_ill(ifire); 120011042SErik.Nordmark@Sun.COM else 120111042SErik.Nordmark@Sun.COM ill = ire_nexthop_ill(ire); 12021676Sjpk 12031676Sjpk if (attrp != NULL) { 12041676Sjpk mutex_enter(&attrp->igsa_lock); 12051676Sjpk if ((gc = attrp->igsa_gc) != NULL) { 12061676Sjpk gcgrp = gc->gc_grp; 12071676Sjpk ASSERT(gcgrp != NULL); 12081676Sjpk rw_enter(&gcgrp->gcgrp_rwlock, RW_READER); 12091676Sjpk } 12101676Sjpk mutex_exit(&attrp->igsa_lock); 12111676Sjpk } 12121676Sjpk 12130Sstevel@tonic-gate /* 12140Sstevel@tonic-gate * Always return RTA_DST, RTA_GATEWAY and RTA_NETMASK. 12150Sstevel@tonic-gate * 12160Sstevel@tonic-gate * The 4.4BSD-Lite2 code (net/rtsock.c) returns both 12170Sstevel@tonic-gate * RTA_IFP and RTA_IFA if either is defined, and also 12180Sstevel@tonic-gate * returns RTA_BRD if the appropriate interface is 12190Sstevel@tonic-gate * point-to-point. 12200Sstevel@tonic-gate */ 12210Sstevel@tonic-gate rtm_addrs = (RTA_DST | RTA_GATEWAY | RTA_NETMASK); 122211042SErik.Nordmark@Sun.COM if ((rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) && ill != NULL) { 12230Sstevel@tonic-gate rtm_addrs |= (RTA_IFP | RTA_IFA); 122411042SErik.Nordmark@Sun.COM /* 122511042SErik.Nordmark@Sun.COM * We associate an IRE with an ILL, hence we don't exactly 122611042SErik.Nordmark@Sun.COM * know what might make sense for RTA_IFA and RTA_BRD. We 122711042SErik.Nordmark@Sun.COM * pick the first ipif on the ill. 122811042SErik.Nordmark@Sun.COM */ 122911042SErik.Nordmark@Sun.COM ipif = ipif_get_next_ipif(NULL, ill); 123011042SErik.Nordmark@Sun.COM if (ipif != NULL) { 123111042SErik.Nordmark@Sun.COM if (ipif->ipif_isv6) 123211042SErik.Nordmark@Sun.COM ifaddr6 = ipif->ipif_v6lcl_addr; 123311042SErik.Nordmark@Sun.COM else 123411042SErik.Nordmark@Sun.COM ifaddr = ipif->ipif_lcl_addr; 123511042SErik.Nordmark@Sun.COM if (ipif->ipif_flags & IPIF_POINTOPOINT) { 123611042SErik.Nordmark@Sun.COM rtm_addrs |= RTA_BRD; 123711042SErik.Nordmark@Sun.COM if (ipif->ipif_isv6) 123811042SErik.Nordmark@Sun.COM brdaddr6 = ipif->ipif_v6pp_dst_addr; 123911042SErik.Nordmark@Sun.COM else 124011042SErik.Nordmark@Sun.COM brdaddr = ipif->ipif_pp_dst_addr; 124111042SErik.Nordmark@Sun.COM } 124211042SErik.Nordmark@Sun.COM ipif_refrele(ipif); 124311042SErik.Nordmark@Sun.COM } 12440Sstevel@tonic-gate } 12450Sstevel@tonic-gate 124611042SErik.Nordmark@Sun.COM new_mp = rts_alloc_msg(RTM_GET, rtm_addrs, af, gc != NULL ? 1 : 0); 12471676Sjpk if (new_mp == NULL) { 12481676Sjpk if (gcgrp != NULL) 12491676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 125011042SErik.Nordmark@Sun.COM if (ill != NULL) 125111042SErik.Nordmark@Sun.COM ill_refrele(ill); 12520Sstevel@tonic-gate return (NULL); 12531676Sjpk } 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate /* 12560Sstevel@tonic-gate * We set the destination address, gateway address, 12570Sstevel@tonic-gate * netmask and flags in the RTM_GET response depending 12580Sstevel@tonic-gate * on whether we found a parent IRE or not. 12590Sstevel@tonic-gate * In particular, if we did find a parent IRE during the 12600Sstevel@tonic-gate * recursive search, use that IRE's gateway address. 12610Sstevel@tonic-gate * Otherwise, we use the IRE's source address for the 12620Sstevel@tonic-gate * gateway address. 12630Sstevel@tonic-gate */ 12640Sstevel@tonic-gate ASSERT(af == AF_INET || af == AF_INET6); 12650Sstevel@tonic-gate switch (af) { 12660Sstevel@tonic-gate case AF_INET: 126711042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_IPADDR(setsrc, v4setsrc); 126811042SErik.Nordmark@Sun.COM if (v4setsrc != INADDR_ANY) 126911042SErik.Nordmark@Sun.COM rtm_addrs |= RTA_SRC; 12700Sstevel@tonic-gate 127111042SErik.Nordmark@Sun.COM rtm_flags = ire->ire_flags; 127211042SErik.Nordmark@Sun.COM rts_fill_msg(RTM_GET, rtm_addrs, ire->ire_addr, 127311042SErik.Nordmark@Sun.COM ire->ire_mask, ire->ire_gateway_addr, v4setsrc, 127411042SErik.Nordmark@Sun.COM brdaddr, 0, ifaddr, ill, new_mp, gc); 12750Sstevel@tonic-gate break; 12760Sstevel@tonic-gate case AF_INET6: 127711042SErik.Nordmark@Sun.COM if (!IN6_IS_ADDR_UNSPECIFIED(setsrc)) 127811042SErik.Nordmark@Sun.COM rtm_addrs |= RTA_SRC; 12790Sstevel@tonic-gate 128011042SErik.Nordmark@Sun.COM rtm_flags = ire->ire_flags; 128111042SErik.Nordmark@Sun.COM rts_fill_msg_v6(RTM_GET, rtm_addrs, &ire->ire_addr_v6, 128211042SErik.Nordmark@Sun.COM &ire->ire_mask_v6, &ire->ire_gateway_addr_v6, 128311042SErik.Nordmark@Sun.COM setsrc, &brdaddr6, &ipv6_all_zeros, 128411042SErik.Nordmark@Sun.COM &ifaddr6, ill, new_mp, gc); 12850Sstevel@tonic-gate break; 12860Sstevel@tonic-gate } 12871676Sjpk 12881676Sjpk if (gcgrp != NULL) 12891676Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 12901676Sjpk 12910Sstevel@tonic-gate new_rtm = (rt_msghdr_t *)new_mp->b_rptr; 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate /* 12940Sstevel@tonic-gate * The rtm_msglen, rtm_version and rtm_type fields in 12950Sstevel@tonic-gate * RTM_GET response are filled in by rts_fill_msg. 12960Sstevel@tonic-gate * 12970Sstevel@tonic-gate * rtm_addrs and rtm_flags are filled in based on what 12980Sstevel@tonic-gate * was requested and the state of the IREs looked up 12990Sstevel@tonic-gate * above. 13000Sstevel@tonic-gate * 13010Sstevel@tonic-gate * rtm_inits and rtm_rmx are filled in with metrics 13020Sstevel@tonic-gate * based on whether a parent IRE was found or not. 13030Sstevel@tonic-gate * 13040Sstevel@tonic-gate * TODO: rtm_index and rtm_use should probably be 13050Sstevel@tonic-gate * filled in with something resonable here and not just 13060Sstevel@tonic-gate * copied from the request. 13070Sstevel@tonic-gate */ 13080Sstevel@tonic-gate new_rtm->rtm_index = rtm->rtm_index; 13090Sstevel@tonic-gate new_rtm->rtm_pid = rtm->rtm_pid; 13100Sstevel@tonic-gate new_rtm->rtm_seq = rtm->rtm_seq; 13110Sstevel@tonic-gate new_rtm->rtm_use = rtm->rtm_use; 13120Sstevel@tonic-gate new_rtm->rtm_addrs = rtm_addrs; 13130Sstevel@tonic-gate new_rtm->rtm_flags = rtm_flags; 131411042SErik.Nordmark@Sun.COM new_rtm->rtm_inits = rts_getmetrics(ire, &new_rtm->rtm_rmx); 131511042SErik.Nordmark@Sun.COM if (ill != NULL) 131611042SErik.Nordmark@Sun.COM ill_refrele(ill); 13170Sstevel@tonic-gate return (new_mp); 13180Sstevel@tonic-gate } 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate /* 13210Sstevel@tonic-gate * Fill the given if_data_t with interface statistics. 13220Sstevel@tonic-gate */ 13230Sstevel@tonic-gate static void 13241676Sjpk rts_getifdata(if_data_t *if_data, const ipif_t *ipif) 13250Sstevel@tonic-gate { 132611042SErik.Nordmark@Sun.COM if_data->ifi_type = ipif->ipif_ill->ill_type; 132711042SErik.Nordmark@Sun.COM /* ethernet, tokenring, etc */ 13280Sstevel@tonic-gate if_data->ifi_addrlen = 0; /* media address length */ 13290Sstevel@tonic-gate if_data->ifi_hdrlen = 0; /* media header length */ 133011042SErik.Nordmark@Sun.COM if_data->ifi_mtu = ipif->ipif_ill->ill_mtu; /* mtu */ 13310Sstevel@tonic-gate if_data->ifi_metric = ipif->ipif_metric; /* metric (external only) */ 13320Sstevel@tonic-gate if_data->ifi_baudrate = 0; /* linespeed */ 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate if_data->ifi_ipackets = 0; /* packets received on if */ 13350Sstevel@tonic-gate if_data->ifi_ierrors = 0; /* input errors on interface */ 13360Sstevel@tonic-gate if_data->ifi_opackets = 0; /* packets sent on interface */ 13370Sstevel@tonic-gate if_data->ifi_oerrors = 0; /* output errors on if */ 13380Sstevel@tonic-gate if_data->ifi_collisions = 0; /* collisions on csma if */ 13390Sstevel@tonic-gate if_data->ifi_ibytes = 0; /* total number received */ 13400Sstevel@tonic-gate if_data->ifi_obytes = 0; /* total number sent */ 13410Sstevel@tonic-gate if_data->ifi_imcasts = 0; /* multicast packets received */ 13420Sstevel@tonic-gate if_data->ifi_omcasts = 0; /* multicast packets sent */ 13430Sstevel@tonic-gate if_data->ifi_iqdrops = 0; /* dropped on input */ 13440Sstevel@tonic-gate if_data->ifi_noproto = 0; /* destined for unsupported */ 13450Sstevel@tonic-gate /* protocol. */ 13460Sstevel@tonic-gate } 13470Sstevel@tonic-gate 13480Sstevel@tonic-gate /* 13490Sstevel@tonic-gate * Set the metrics on a forwarding table route. 13500Sstevel@tonic-gate */ 13510Sstevel@tonic-gate static void 13520Sstevel@tonic-gate rts_setmetrics(ire_t *ire, uint_t which, rt_metrics_t *metrics) 13530Sstevel@tonic-gate { 13540Sstevel@tonic-gate clock_t rtt; 13550Sstevel@tonic-gate clock_t rtt_sd; 135611042SErik.Nordmark@Sun.COM ill_t *ill; 13570Sstevel@tonic-gate ifrt_t *ifrt; 13580Sstevel@tonic-gate mblk_t *mp; 13590Sstevel@tonic-gate in6_addr_t gw_addr_v6; 13600Sstevel@tonic-gate 136111042SErik.Nordmark@Sun.COM /* Need to add back some metrics to the IRE? */ 13620Sstevel@tonic-gate /* 136311042SErik.Nordmark@Sun.COM * Bypass obtaining the lock and searching ill_saved_ire_mp in the 13640Sstevel@tonic-gate * common case of no metrics. 13650Sstevel@tonic-gate */ 13660Sstevel@tonic-gate if (which == 0) 13670Sstevel@tonic-gate return; 136811042SErik.Nordmark@Sun.COM ire->ire_metrics.iulp_set = B_TRUE; 13690Sstevel@tonic-gate 13700Sstevel@tonic-gate /* 13710Sstevel@tonic-gate * iulp_rtt and iulp_rtt_sd are in milliseconds, but 4.4BSD-Lite2's 13720Sstevel@tonic-gate * <net/route.h> says: rmx_rtt and rmx_rttvar are stored as 13730Sstevel@tonic-gate * microseconds. 13740Sstevel@tonic-gate */ 13750Sstevel@tonic-gate if (which & RTV_RTT) 13760Sstevel@tonic-gate rtt = metrics->rmx_rtt / 1000; 13770Sstevel@tonic-gate if (which & RTV_RTTVAR) 13780Sstevel@tonic-gate rtt_sd = metrics->rmx_rttvar / 1000; 13790Sstevel@tonic-gate 13800Sstevel@tonic-gate /* 13810Sstevel@tonic-gate * Update the metrics in the IRE itself. 13820Sstevel@tonic-gate */ 13830Sstevel@tonic-gate mutex_enter(&ire->ire_lock); 13840Sstevel@tonic-gate if (which & RTV_MTU) 138511042SErik.Nordmark@Sun.COM ire->ire_metrics.iulp_mtu = metrics->rmx_mtu; 13860Sstevel@tonic-gate if (which & RTV_RTT) 138711042SErik.Nordmark@Sun.COM ire->ire_metrics.iulp_rtt = rtt; 13880Sstevel@tonic-gate if (which & RTV_SSTHRESH) 138911042SErik.Nordmark@Sun.COM ire->ire_metrics.iulp_ssthresh = metrics->rmx_ssthresh; 13900Sstevel@tonic-gate if (which & RTV_RTTVAR) 139111042SErik.Nordmark@Sun.COM ire->ire_metrics.iulp_rtt_sd = rtt_sd; 13920Sstevel@tonic-gate if (which & RTV_SPIPE) 139311042SErik.Nordmark@Sun.COM ire->ire_metrics.iulp_spipe = metrics->rmx_sendpipe; 13940Sstevel@tonic-gate if (which & RTV_RPIPE) 139511042SErik.Nordmark@Sun.COM ire->ire_metrics.iulp_rpipe = metrics->rmx_recvpipe; 13960Sstevel@tonic-gate mutex_exit(&ire->ire_lock); 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate /* 139911042SErik.Nordmark@Sun.COM * Search through the ifrt_t chain hanging off the ILL in order to 14000Sstevel@tonic-gate * reflect the metric change there. 14010Sstevel@tonic-gate */ 140211042SErik.Nordmark@Sun.COM ill = ire->ire_ill; 140311042SErik.Nordmark@Sun.COM if (ill == NULL) 14040Sstevel@tonic-gate return; 140511042SErik.Nordmark@Sun.COM ASSERT((ill->ill_isv6 && ire->ire_ipversion == IPV6_VERSION) || 140611042SErik.Nordmark@Sun.COM ((!ill->ill_isv6 && ire->ire_ipversion == IPV4_VERSION))); 140711042SErik.Nordmark@Sun.COM if (ill->ill_isv6) { 14080Sstevel@tonic-gate mutex_enter(&ire->ire_lock); 14090Sstevel@tonic-gate gw_addr_v6 = ire->ire_gateway_addr_v6; 14100Sstevel@tonic-gate mutex_exit(&ire->ire_lock); 14110Sstevel@tonic-gate } 141211042SErik.Nordmark@Sun.COM mutex_enter(&ill->ill_saved_ire_lock); 141311042SErik.Nordmark@Sun.COM for (mp = ill->ill_saved_ire_mp; mp != NULL; mp = mp->b_cont) { 14140Sstevel@tonic-gate /* 141511042SErik.Nordmark@Sun.COM * On a given ill, the tuple of address, gateway, mask, 141611042SErik.Nordmark@Sun.COM * ire_type and zoneid unique for each saved IRE. 14170Sstevel@tonic-gate */ 14180Sstevel@tonic-gate ifrt = (ifrt_t *)mp->b_rptr; 141911042SErik.Nordmark@Sun.COM if (ill->ill_isv6) { 14200Sstevel@tonic-gate if (!IN6_ARE_ADDR_EQUAL(&ifrt->ifrt_v6addr, 14210Sstevel@tonic-gate &ire->ire_addr_v6) || 14220Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(&ifrt->ifrt_v6gateway_addr, 14230Sstevel@tonic-gate &gw_addr_v6) || 14240Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(&ifrt->ifrt_v6mask, 14250Sstevel@tonic-gate &ire->ire_mask_v6)) 14260Sstevel@tonic-gate continue; 14270Sstevel@tonic-gate } else { 14280Sstevel@tonic-gate if (ifrt->ifrt_addr != ire->ire_addr || 14290Sstevel@tonic-gate ifrt->ifrt_gateway_addr != ire->ire_gateway_addr || 14300Sstevel@tonic-gate ifrt->ifrt_mask != ire->ire_mask) 14310Sstevel@tonic-gate continue; 14320Sstevel@tonic-gate } 143311042SErik.Nordmark@Sun.COM if (ifrt->ifrt_zoneid != ire->ire_zoneid || 143411042SErik.Nordmark@Sun.COM ifrt->ifrt_type != ire->ire_type) 143511042SErik.Nordmark@Sun.COM continue; 143611042SErik.Nordmark@Sun.COM 14370Sstevel@tonic-gate if (which & RTV_MTU) 143811042SErik.Nordmark@Sun.COM ifrt->ifrt_metrics.iulp_mtu = metrics->rmx_mtu; 14390Sstevel@tonic-gate if (which & RTV_RTT) 144011042SErik.Nordmark@Sun.COM ifrt->ifrt_metrics.iulp_rtt = rtt; 14410Sstevel@tonic-gate if (which & RTV_SSTHRESH) { 144211042SErik.Nordmark@Sun.COM ifrt->ifrt_metrics.iulp_ssthresh = 14430Sstevel@tonic-gate metrics->rmx_ssthresh; 14440Sstevel@tonic-gate } 14450Sstevel@tonic-gate if (which & RTV_RTTVAR) 144611042SErik.Nordmark@Sun.COM ifrt->ifrt_metrics.iulp_rtt_sd = metrics->rmx_rttvar; 14470Sstevel@tonic-gate if (which & RTV_SPIPE) 144811042SErik.Nordmark@Sun.COM ifrt->ifrt_metrics.iulp_spipe = metrics->rmx_sendpipe; 14490Sstevel@tonic-gate if (which & RTV_RPIPE) 145011042SErik.Nordmark@Sun.COM ifrt->ifrt_metrics.iulp_rpipe = metrics->rmx_recvpipe; 14510Sstevel@tonic-gate break; 14520Sstevel@tonic-gate } 145311042SErik.Nordmark@Sun.COM mutex_exit(&ill->ill_saved_ire_lock); 145411042SErik.Nordmark@Sun.COM 145511042SErik.Nordmark@Sun.COM /* 145611042SErik.Nordmark@Sun.COM * Update any IRE_IF_CLONE hanging created from this IRE_IF so they 145711042SErik.Nordmark@Sun.COM * get any new iulp_mtu. 145811042SErik.Nordmark@Sun.COM * We do that by deleting them; ire_create_if_clone will pick 145911042SErik.Nordmark@Sun.COM * up the new metrics. 146011042SErik.Nordmark@Sun.COM */ 146111042SErik.Nordmark@Sun.COM if ((ire->ire_type & IRE_INTERFACE) && ire->ire_dep_children != 0) 146211042SErik.Nordmark@Sun.COM ire_dep_delete_if_clone(ire); 14630Sstevel@tonic-gate } 14640Sstevel@tonic-gate 14650Sstevel@tonic-gate /* 14660Sstevel@tonic-gate * Get the metrics from a forwarding table route. 14670Sstevel@tonic-gate */ 14680Sstevel@tonic-gate static int 14690Sstevel@tonic-gate rts_getmetrics(ire_t *ire, rt_metrics_t *metrics) 14700Sstevel@tonic-gate { 14710Sstevel@tonic-gate int metrics_set = 0; 14720Sstevel@tonic-gate 14730Sstevel@tonic-gate bzero(metrics, sizeof (rt_metrics_t)); 147411042SErik.Nordmark@Sun.COM 14750Sstevel@tonic-gate /* 14760Sstevel@tonic-gate * iulp_rtt and iulp_rtt_sd are in milliseconds, but 4.4BSD-Lite2's 14770Sstevel@tonic-gate * <net/route.h> says: rmx_rtt and rmx_rttvar are stored as 14780Sstevel@tonic-gate * microseconds. 14790Sstevel@tonic-gate */ 148011042SErik.Nordmark@Sun.COM metrics->rmx_rtt = ire->ire_metrics.iulp_rtt * 1000; 14810Sstevel@tonic-gate metrics_set |= RTV_RTT; 148211042SErik.Nordmark@Sun.COM metrics->rmx_mtu = ire->ire_metrics.iulp_mtu; 14830Sstevel@tonic-gate metrics_set |= RTV_MTU; 148411042SErik.Nordmark@Sun.COM metrics->rmx_ssthresh = ire->ire_metrics.iulp_ssthresh; 14850Sstevel@tonic-gate metrics_set |= RTV_SSTHRESH; 148611042SErik.Nordmark@Sun.COM metrics->rmx_rttvar = ire->ire_metrics.iulp_rtt_sd * 1000; 14870Sstevel@tonic-gate metrics_set |= RTV_RTTVAR; 148811042SErik.Nordmark@Sun.COM metrics->rmx_sendpipe = ire->ire_metrics.iulp_spipe; 14890Sstevel@tonic-gate metrics_set |= RTV_SPIPE; 149011042SErik.Nordmark@Sun.COM metrics->rmx_recvpipe = ire->ire_metrics.iulp_rpipe; 14910Sstevel@tonic-gate metrics_set |= RTV_RPIPE; 14920Sstevel@tonic-gate return (metrics_set); 14930Sstevel@tonic-gate } 14940Sstevel@tonic-gate 14950Sstevel@tonic-gate /* 149611042SErik.Nordmark@Sun.COM * Given two sets of metrics (src and dst), use the dst values if they are 149711042SErik.Nordmark@Sun.COM * set. If a dst value is not set but the src value is set, then we use 149811042SErik.Nordmark@Sun.COM * the src value. 149911042SErik.Nordmark@Sun.COM * dst is updated with the new values. 150011042SErik.Nordmark@Sun.COM * This is used to merge information from a dce_t and ire_metrics, where the 150111042SErik.Nordmark@Sun.COM * dce values takes precedence. 150211042SErik.Nordmark@Sun.COM */ 150311042SErik.Nordmark@Sun.COM void 150411042SErik.Nordmark@Sun.COM rts_merge_metrics(iulp_t *dst, const iulp_t *src) 150511042SErik.Nordmark@Sun.COM { 150611042SErik.Nordmark@Sun.COM if (!src->iulp_set) 150711042SErik.Nordmark@Sun.COM return; 150811042SErik.Nordmark@Sun.COM 150911042SErik.Nordmark@Sun.COM if (dst->iulp_ssthresh == 0) 151011042SErik.Nordmark@Sun.COM dst->iulp_ssthresh = src->iulp_ssthresh; 151111042SErik.Nordmark@Sun.COM if (dst->iulp_rtt == 0) 151211042SErik.Nordmark@Sun.COM dst->iulp_rtt = src->iulp_rtt; 151311042SErik.Nordmark@Sun.COM if (dst->iulp_rtt_sd == 0) 151411042SErik.Nordmark@Sun.COM dst->iulp_rtt_sd = src->iulp_rtt_sd; 151511042SErik.Nordmark@Sun.COM if (dst->iulp_spipe == 0) 151611042SErik.Nordmark@Sun.COM dst->iulp_spipe = src->iulp_spipe; 151711042SErik.Nordmark@Sun.COM if (dst->iulp_rpipe == 0) 151811042SErik.Nordmark@Sun.COM dst->iulp_rpipe = src->iulp_rpipe; 151911042SErik.Nordmark@Sun.COM if (dst->iulp_rtomax == 0) 152011042SErik.Nordmark@Sun.COM dst->iulp_rtomax = src->iulp_rtomax; 152111042SErik.Nordmark@Sun.COM if (dst->iulp_sack == 0) 152211042SErik.Nordmark@Sun.COM dst->iulp_sack = src->iulp_sack; 152311042SErik.Nordmark@Sun.COM if (dst->iulp_tstamp_ok == 0) 152411042SErik.Nordmark@Sun.COM dst->iulp_tstamp_ok = src->iulp_tstamp_ok; 152511042SErik.Nordmark@Sun.COM if (dst->iulp_wscale_ok == 0) 152611042SErik.Nordmark@Sun.COM dst->iulp_wscale_ok = src->iulp_wscale_ok; 152711042SErik.Nordmark@Sun.COM if (dst->iulp_ecn_ok == 0) 152811042SErik.Nordmark@Sun.COM dst->iulp_ecn_ok = src->iulp_ecn_ok; 152911042SErik.Nordmark@Sun.COM if (dst->iulp_pmtud_ok == 0) 153011042SErik.Nordmark@Sun.COM dst->iulp_pmtud_ok = src->iulp_pmtud_ok; 153111042SErik.Nordmark@Sun.COM if (dst->iulp_mtu == 0) 153211042SErik.Nordmark@Sun.COM dst->iulp_mtu = src->iulp_mtu; 153311042SErik.Nordmark@Sun.COM } 153411042SErik.Nordmark@Sun.COM 153511042SErik.Nordmark@Sun.COM 153611042SErik.Nordmark@Sun.COM /* 15370Sstevel@tonic-gate * Takes a pointer to a routing message and extracts necessary info by looking 15380Sstevel@tonic-gate * at the rtm->rtm_addrs bits and store the requested sockaddrs in the pointers 15390Sstevel@tonic-gate * passed (all of which must be valid). 15400Sstevel@tonic-gate * 15410Sstevel@tonic-gate * The bitmask of sockaddrs actually found in the message is returned, or zero 15420Sstevel@tonic-gate * is returned in the case of an error. 15430Sstevel@tonic-gate */ 15440Sstevel@tonic-gate static int 15450Sstevel@tonic-gate rts_getaddrs(rt_msghdr_t *rtm, in6_addr_t *dst_addrp, in6_addr_t *gw_addrp, 15460Sstevel@tonic-gate in6_addr_t *net_maskp, in6_addr_t *authorp, in6_addr_t *if_addrp, 15474823Sseb in6_addr_t *in_src_addrp, ushort_t *indexp, sa_family_t *afp, 15484823Sseb tsol_rtsecattr_t *rtsecattr, int *error) 15490Sstevel@tonic-gate { 15500Sstevel@tonic-gate struct sockaddr *sa; 15510Sstevel@tonic-gate int i; 15520Sstevel@tonic-gate int addr_bits; 15530Sstevel@tonic-gate int length; 15540Sstevel@tonic-gate int found_addrs = 0; 15550Sstevel@tonic-gate caddr_t cp; 15560Sstevel@tonic-gate size_t size; 15570Sstevel@tonic-gate struct sockaddr_dl *sdl; 15580Sstevel@tonic-gate 15590Sstevel@tonic-gate *dst_addrp = ipv6_all_zeros; 15600Sstevel@tonic-gate *gw_addrp = ipv6_all_zeros; 15610Sstevel@tonic-gate *net_maskp = ipv6_all_zeros; 15620Sstevel@tonic-gate *authorp = ipv6_all_zeros; 15630Sstevel@tonic-gate *if_addrp = ipv6_all_zeros; 15640Sstevel@tonic-gate *in_src_addrp = ipv6_all_zeros; 15650Sstevel@tonic-gate *indexp = 0; 15660Sstevel@tonic-gate *afp = AF_UNSPEC; 15671676Sjpk rtsecattr->rtsa_cnt = 0; 15681676Sjpk *error = 0; 15690Sstevel@tonic-gate 15700Sstevel@tonic-gate /* 15710Sstevel@tonic-gate * At present we handle only RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_IFP, 15720Sstevel@tonic-gate * RTA_IFA and RTA_AUTHOR. The rest will be added as we need them. 15730Sstevel@tonic-gate */ 15740Sstevel@tonic-gate cp = (caddr_t)&rtm[1]; 15750Sstevel@tonic-gate length = rtm->rtm_msglen; 15760Sstevel@tonic-gate for (i = 0; (i < RTA_NUMBITS) && ((cp - (caddr_t)rtm) < length); i++) { 15770Sstevel@tonic-gate /* 15780Sstevel@tonic-gate * The address family we are working with starts out as 15790Sstevel@tonic-gate * AF_UNSPEC, but is set to the one specified with the 15800Sstevel@tonic-gate * destination address. 15810Sstevel@tonic-gate * 15820Sstevel@tonic-gate * If the "working" address family that has been set to 15830Sstevel@tonic-gate * something other than AF_UNSPEC, then the address family of 15840Sstevel@tonic-gate * subsequent sockaddrs must either be AF_UNSPEC (for 15850Sstevel@tonic-gate * compatibility with older programs) or must be the same as our 15860Sstevel@tonic-gate * "working" one. 15870Sstevel@tonic-gate * 15880Sstevel@tonic-gate * This code assumes that RTA_DST (1) comes first in the loop. 15890Sstevel@tonic-gate */ 15900Sstevel@tonic-gate sa = (struct sockaddr *)cp; 15910Sstevel@tonic-gate addr_bits = (rtm->rtm_addrs & (1 << i)); 15920Sstevel@tonic-gate if (addr_bits == 0) 15930Sstevel@tonic-gate continue; 15940Sstevel@tonic-gate switch (addr_bits) { 15950Sstevel@tonic-gate case RTA_DST: 15960Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, dst_addrp); 15970Sstevel@tonic-gate *afp = sa->sa_family; 15980Sstevel@tonic-gate break; 15990Sstevel@tonic-gate case RTA_GATEWAY: 16000Sstevel@tonic-gate if (sa->sa_family != *afp && sa->sa_family != AF_UNSPEC) 16010Sstevel@tonic-gate return (0); 16020Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, gw_addrp); 16030Sstevel@tonic-gate break; 16040Sstevel@tonic-gate case RTA_NETMASK: 16050Sstevel@tonic-gate if (sa->sa_family != *afp && sa->sa_family != AF_UNSPEC) 16060Sstevel@tonic-gate return (0); 16070Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, net_maskp); 16080Sstevel@tonic-gate break; 16090Sstevel@tonic-gate case RTA_IFP: 16100Sstevel@tonic-gate if (sa->sa_family != AF_LINK && 16110Sstevel@tonic-gate sa->sa_family != AF_UNSPEC) 16120Sstevel@tonic-gate return (0); 16130Sstevel@tonic-gate sdl = (struct sockaddr_dl *)cp; 16140Sstevel@tonic-gate *indexp = sdl->sdl_index; 16150Sstevel@tonic-gate size = sizeof (struct sockaddr_dl); 16160Sstevel@tonic-gate break; 16170Sstevel@tonic-gate case RTA_SRC: 16180Sstevel@tonic-gate /* Source address of the incoming packet */ 16190Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, in_src_addrp); 16200Sstevel@tonic-gate *afp = sa->sa_family; 16210Sstevel@tonic-gate break; 16220Sstevel@tonic-gate case RTA_IFA: 16230Sstevel@tonic-gate if (sa->sa_family != *afp && sa->sa_family != AF_UNSPEC) 16240Sstevel@tonic-gate return (0); 16250Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, if_addrp); 16260Sstevel@tonic-gate break; 16270Sstevel@tonic-gate case RTA_AUTHOR: 16280Sstevel@tonic-gate if (sa->sa_family != *afp && sa->sa_family != AF_UNSPEC) 16290Sstevel@tonic-gate return (0); 16300Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, authorp); 16310Sstevel@tonic-gate break; 16320Sstevel@tonic-gate default: 16330Sstevel@tonic-gate return (0); 16340Sstevel@tonic-gate } 16350Sstevel@tonic-gate if (size == 0) 16360Sstevel@tonic-gate return (0); 16370Sstevel@tonic-gate cp += size; 16380Sstevel@tonic-gate found_addrs |= addr_bits; 16390Sstevel@tonic-gate } 16401676Sjpk 16411676Sjpk /* 16421676Sjpk * Parse the routing message and look for any security- 16431676Sjpk * related attributes for the route. For each valid 16441676Sjpk * attribute, allocate/obtain the corresponding kernel 16451676Sjpk * route security attributes. 16461676Sjpk */ 164710138Shn.vijay@Sun.COM if (((cp - (caddr_t)rtm) < length) && is_system_labeled()) { 164810138Shn.vijay@Sun.COM *error = tsol_rtsa_init(rtm, rtsecattr, cp); 164910138Shn.vijay@Sun.COM ASSERT(rtsecattr->rtsa_cnt <= TSOL_RTSA_REQUEST_MAX); 165010138Shn.vijay@Sun.COM } 16511676Sjpk 16520Sstevel@tonic-gate return (found_addrs); 16530Sstevel@tonic-gate } 16540Sstevel@tonic-gate 16550Sstevel@tonic-gate /* 16560Sstevel@tonic-gate * Fills the message with the given info. 16570Sstevel@tonic-gate */ 16580Sstevel@tonic-gate static void 16590Sstevel@tonic-gate rts_fill_msg(int type, int rtm_addrs, ipaddr_t dst, ipaddr_t mask, 16600Sstevel@tonic-gate ipaddr_t gateway, ipaddr_t src_addr, ipaddr_t brd_addr, ipaddr_t author, 166111042SErik.Nordmark@Sun.COM ipaddr_t ifaddr, const ill_t *ill, mblk_t *mp, 166211042SErik.Nordmark@Sun.COM const tsol_gc_t *gc) 16630Sstevel@tonic-gate { 16640Sstevel@tonic-gate rt_msghdr_t *rtm; 16650Sstevel@tonic-gate sin_t *sin; 16660Sstevel@tonic-gate size_t data_size, header_size; 16670Sstevel@tonic-gate uchar_t *cp; 16680Sstevel@tonic-gate int i; 16690Sstevel@tonic-gate 16700Sstevel@tonic-gate ASSERT(mp != NULL); 16710Sstevel@tonic-gate /* 16720Sstevel@tonic-gate * First find the type of the message 16730Sstevel@tonic-gate * and its length. 16740Sstevel@tonic-gate */ 16750Sstevel@tonic-gate header_size = rts_header_msg_size(type); 16760Sstevel@tonic-gate /* 16770Sstevel@tonic-gate * Now find the size of the data 16780Sstevel@tonic-gate * that follows the message header. 16790Sstevel@tonic-gate */ 168011042SErik.Nordmark@Sun.COM data_size = rts_data_msg_size(rtm_addrs, AF_INET, gc != NULL ? 1 : 0); 16810Sstevel@tonic-gate 16820Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 16830Sstevel@tonic-gate mp->b_wptr = &mp->b_rptr[header_size]; 16840Sstevel@tonic-gate cp = mp->b_wptr; 16850Sstevel@tonic-gate bzero(cp, data_size); 16860Sstevel@tonic-gate for (i = 0; i < RTA_NUMBITS; i++) { 16870Sstevel@tonic-gate sin = (sin_t *)cp; 16880Sstevel@tonic-gate switch (rtm_addrs & (1 << i)) { 16890Sstevel@tonic-gate case RTA_DST: 16900Sstevel@tonic-gate sin->sin_addr.s_addr = dst; 16910Sstevel@tonic-gate sin->sin_family = AF_INET; 16920Sstevel@tonic-gate cp += sizeof (sin_t); 16930Sstevel@tonic-gate break; 16940Sstevel@tonic-gate case RTA_GATEWAY: 16950Sstevel@tonic-gate sin->sin_addr.s_addr = gateway; 16960Sstevel@tonic-gate sin->sin_family = AF_INET; 16970Sstevel@tonic-gate cp += sizeof (sin_t); 16980Sstevel@tonic-gate break; 16990Sstevel@tonic-gate case RTA_NETMASK: 17000Sstevel@tonic-gate sin->sin_addr.s_addr = mask; 17010Sstevel@tonic-gate sin->sin_family = AF_INET; 17020Sstevel@tonic-gate cp += sizeof (sin_t); 17030Sstevel@tonic-gate break; 17040Sstevel@tonic-gate case RTA_IFP: 170511042SErik.Nordmark@Sun.COM cp += ill_dls_info((struct sockaddr_dl *)cp, ill); 17060Sstevel@tonic-gate break; 17070Sstevel@tonic-gate case RTA_IFA: 170811042SErik.Nordmark@Sun.COM sin->sin_addr.s_addr = ifaddr; 170911042SErik.Nordmark@Sun.COM sin->sin_family = AF_INET; 171011042SErik.Nordmark@Sun.COM cp += sizeof (sin_t); 171111042SErik.Nordmark@Sun.COM break; 17120Sstevel@tonic-gate case RTA_SRC: 17130Sstevel@tonic-gate sin->sin_addr.s_addr = src_addr; 17140Sstevel@tonic-gate sin->sin_family = AF_INET; 17150Sstevel@tonic-gate cp += sizeof (sin_t); 17160Sstevel@tonic-gate break; 17170Sstevel@tonic-gate case RTA_AUTHOR: 17180Sstevel@tonic-gate sin->sin_addr.s_addr = author; 17190Sstevel@tonic-gate sin->sin_family = AF_INET; 17200Sstevel@tonic-gate cp += sizeof (sin_t); 17210Sstevel@tonic-gate break; 17220Sstevel@tonic-gate case RTA_BRD: 17230Sstevel@tonic-gate /* 17240Sstevel@tonic-gate * RTA_BRD is used typically to specify a point-to-point 17250Sstevel@tonic-gate * destination address. 17260Sstevel@tonic-gate */ 17270Sstevel@tonic-gate sin->sin_addr.s_addr = brd_addr; 17280Sstevel@tonic-gate sin->sin_family = AF_INET; 17290Sstevel@tonic-gate cp += sizeof (sin_t); 17300Sstevel@tonic-gate break; 17310Sstevel@tonic-gate } 17320Sstevel@tonic-gate } 17331676Sjpk 17341676Sjpk if (gc != NULL) { 17351676Sjpk rtm_ext_t *rtm_ext; 17361676Sjpk struct rtsa_s *rp_dst; 17371676Sjpk tsol_rtsecattr_t *rsap; 17381676Sjpk 17391676Sjpk ASSERT(gc->gc_grp != NULL); 17401676Sjpk ASSERT(RW_LOCK_HELD(&gc->gc_grp->gcgrp_rwlock)); 17411676Sjpk 17421676Sjpk rtm_ext = (rtm_ext_t *)cp; 17431676Sjpk rtm_ext->rtmex_type = RTMEX_GATEWAY_SECATTR; 174411042SErik.Nordmark@Sun.COM rtm_ext->rtmex_len = TSOL_RTSECATTR_SIZE(1); 17451676Sjpk 17461676Sjpk rsap = (tsol_rtsecattr_t *)(rtm_ext + 1); 174711042SErik.Nordmark@Sun.COM rsap->rtsa_cnt = 1; 17481676Sjpk rp_dst = rsap->rtsa_attr; 17491676Sjpk 175011042SErik.Nordmark@Sun.COM ASSERT(gc->gc_db != NULL); 175111042SErik.Nordmark@Sun.COM bcopy(&gc->gc_db->gcdb_attr, rp_dst, sizeof (*rp_dst)); 17521676Sjpk cp = (uchar_t *)rp_dst; 17531676Sjpk } 17541676Sjpk 17550Sstevel@tonic-gate mp->b_wptr = cp; 17560Sstevel@tonic-gate mp->b_cont = NULL; 17570Sstevel@tonic-gate /* 17580Sstevel@tonic-gate * set the fields that are common to 17590Sstevel@tonic-gate * to different messages. 17600Sstevel@tonic-gate */ 17610Sstevel@tonic-gate rtm->rtm_msglen = (short)(header_size + data_size); 17620Sstevel@tonic-gate rtm->rtm_version = RTM_VERSION; 17630Sstevel@tonic-gate rtm->rtm_type = (uchar_t)type; 17640Sstevel@tonic-gate } 17650Sstevel@tonic-gate 17660Sstevel@tonic-gate /* 17670Sstevel@tonic-gate * Allocates and initializes a routing socket message. 176811042SErik.Nordmark@Sun.COM * Note that sacnt is either zero or one. 17690Sstevel@tonic-gate */ 17700Sstevel@tonic-gate mblk_t * 17711676Sjpk rts_alloc_msg(int type, int rtm_addrs, sa_family_t af, uint_t sacnt) 17720Sstevel@tonic-gate { 17730Sstevel@tonic-gate size_t length; 17740Sstevel@tonic-gate mblk_t *mp; 17750Sstevel@tonic-gate 17761676Sjpk length = RTS_MSG_SIZE(type, rtm_addrs, af, sacnt); 17770Sstevel@tonic-gate mp = allocb(length, BPRI_MED); 17780Sstevel@tonic-gate if (mp == NULL) 17790Sstevel@tonic-gate return (mp); 17800Sstevel@tonic-gate bzero(mp->b_rptr, length); 17810Sstevel@tonic-gate return (mp); 17820Sstevel@tonic-gate } 17830Sstevel@tonic-gate 17840Sstevel@tonic-gate /* 17850Sstevel@tonic-gate * Returns the size of the routing 17860Sstevel@tonic-gate * socket message header size. 17870Sstevel@tonic-gate */ 17880Sstevel@tonic-gate size_t 17890Sstevel@tonic-gate rts_header_msg_size(int type) 17900Sstevel@tonic-gate { 17910Sstevel@tonic-gate switch (type) { 17920Sstevel@tonic-gate case RTM_DELADDR: 17930Sstevel@tonic-gate case RTM_NEWADDR: 1794*11076SCathy.Zhou@Sun.COM case RTM_CHGADDR: 1795*11076SCathy.Zhou@Sun.COM case RTM_FREEADDR: 17960Sstevel@tonic-gate return (sizeof (ifa_msghdr_t)); 17970Sstevel@tonic-gate case RTM_IFINFO: 17980Sstevel@tonic-gate return (sizeof (if_msghdr_t)); 17990Sstevel@tonic-gate default: 18000Sstevel@tonic-gate return (sizeof (rt_msghdr_t)); 18010Sstevel@tonic-gate } 18020Sstevel@tonic-gate } 18030Sstevel@tonic-gate 18040Sstevel@tonic-gate /* 18050Sstevel@tonic-gate * Returns the size of the message needed with the given rtm_addrs and family. 18060Sstevel@tonic-gate * 18070Sstevel@tonic-gate * It is assumed that all of the sockaddrs (with the exception of RTA_IFP) are 18080Sstevel@tonic-gate * of the same family (currently either AF_INET or AF_INET6). 18090Sstevel@tonic-gate */ 18100Sstevel@tonic-gate size_t 18111676Sjpk rts_data_msg_size(int rtm_addrs, sa_family_t af, uint_t sacnt) 18120Sstevel@tonic-gate { 18130Sstevel@tonic-gate int i; 18140Sstevel@tonic-gate size_t length = 0; 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate for (i = 0; i < RTA_NUMBITS; i++) { 18170Sstevel@tonic-gate switch (rtm_addrs & (1 << i)) { 18180Sstevel@tonic-gate case RTA_IFP: 18190Sstevel@tonic-gate length += sizeof (struct sockaddr_dl); 18200Sstevel@tonic-gate break; 18210Sstevel@tonic-gate case RTA_DST: 18220Sstevel@tonic-gate case RTA_GATEWAY: 18230Sstevel@tonic-gate case RTA_NETMASK: 18240Sstevel@tonic-gate case RTA_SRC: 18250Sstevel@tonic-gate case RTA_IFA: 18260Sstevel@tonic-gate case RTA_AUTHOR: 18270Sstevel@tonic-gate case RTA_BRD: 18280Sstevel@tonic-gate ASSERT(af == AF_INET || af == AF_INET6); 18290Sstevel@tonic-gate switch (af) { 18300Sstevel@tonic-gate case AF_INET: 18310Sstevel@tonic-gate length += sizeof (sin_t); 18320Sstevel@tonic-gate break; 18330Sstevel@tonic-gate case AF_INET6: 18340Sstevel@tonic-gate length += sizeof (sin6_t); 18350Sstevel@tonic-gate break; 18360Sstevel@tonic-gate } 18370Sstevel@tonic-gate break; 18380Sstevel@tonic-gate } 18390Sstevel@tonic-gate } 18401676Sjpk if (sacnt > 0) 18411676Sjpk length += sizeof (rtm_ext_t) + TSOL_RTSECATTR_SIZE(sacnt); 18421676Sjpk 18430Sstevel@tonic-gate return (length); 18440Sstevel@tonic-gate } 18450Sstevel@tonic-gate 18460Sstevel@tonic-gate /* 18470Sstevel@tonic-gate * This routine is called to generate a message to the routing 18480Sstevel@tonic-gate * socket indicating that a redirect has occured, a routing lookup 18490Sstevel@tonic-gate * has failed, or that a protocol has detected timeouts to a particular 18500Sstevel@tonic-gate * destination. This routine is called for message types RTM_LOSING, 18510Sstevel@tonic-gate * RTM_REDIRECT, and RTM_MISS. 18520Sstevel@tonic-gate */ 18530Sstevel@tonic-gate void 18540Sstevel@tonic-gate ip_rts_change(int type, ipaddr_t dst_addr, ipaddr_t gw_addr, ipaddr_t net_mask, 18553448Sdh155122 ipaddr_t source, ipaddr_t author, int flags, int error, int rtm_addrs, 18563448Sdh155122 ip_stack_t *ipst) 18570Sstevel@tonic-gate { 18580Sstevel@tonic-gate rt_msghdr_t *rtm; 18590Sstevel@tonic-gate mblk_t *mp; 18600Sstevel@tonic-gate 18610Sstevel@tonic-gate if (rtm_addrs == 0) 18620Sstevel@tonic-gate return; 18631676Sjpk mp = rts_alloc_msg(type, rtm_addrs, AF_INET, 0); 18640Sstevel@tonic-gate if (mp == NULL) 18650Sstevel@tonic-gate return; 18660Sstevel@tonic-gate rts_fill_msg(type, rtm_addrs, dst_addr, net_mask, gw_addr, source, 0, 186711042SErik.Nordmark@Sun.COM author, 0, NULL, mp, NULL); 18680Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 18690Sstevel@tonic-gate rtm->rtm_flags = flags; 18700Sstevel@tonic-gate rtm->rtm_errno = error; 18710Sstevel@tonic-gate rtm->rtm_flags |= RTF_DONE; 18720Sstevel@tonic-gate rtm->rtm_addrs = rtm_addrs; 18738485SPeter.Memishian@Sun.COM rts_queue_input(mp, NULL, AF_INET, RTSQ_ALL, ipst); 18740Sstevel@tonic-gate } 18750Sstevel@tonic-gate 18760Sstevel@tonic-gate /* 18770Sstevel@tonic-gate * This routine is called to generate a message to the routing 18780Sstevel@tonic-gate * socket indicating that the status of a network interface has changed. 18790Sstevel@tonic-gate * Message type generated RTM_IFINFO. 18800Sstevel@tonic-gate */ 18810Sstevel@tonic-gate void 18828485SPeter.Memishian@Sun.COM ip_rts_ifmsg(const ipif_t *ipif, uint_t flags) 18838485SPeter.Memishian@Sun.COM { 18848485SPeter.Memishian@Sun.COM ip_rts_xifmsg(ipif, 0, 0, flags); 18858485SPeter.Memishian@Sun.COM } 18868485SPeter.Memishian@Sun.COM 18878485SPeter.Memishian@Sun.COM void 18888485SPeter.Memishian@Sun.COM ip_rts_xifmsg(const ipif_t *ipif, uint64_t set, uint64_t clear, uint_t flags) 18890Sstevel@tonic-gate { 18900Sstevel@tonic-gate if_msghdr_t *ifm; 18910Sstevel@tonic-gate mblk_t *mp; 18920Sstevel@tonic-gate sa_family_t af; 18933448Sdh155122 ip_stack_t *ipst = ipif->ipif_ill->ill_ipst; 18940Sstevel@tonic-gate 18950Sstevel@tonic-gate /* 189611042SErik.Nordmark@Sun.COM * This message should be generated only 189711042SErik.Nordmark@Sun.COM * when the physical device is changing 189811042SErik.Nordmark@Sun.COM * state. 18990Sstevel@tonic-gate */ 19000Sstevel@tonic-gate if (ipif->ipif_id != 0) 19010Sstevel@tonic-gate return; 19020Sstevel@tonic-gate if (ipif->ipif_isv6) { 19030Sstevel@tonic-gate af = AF_INET6; 19041676Sjpk mp = rts_alloc_msg(RTM_IFINFO, RTA_IFP, af, 0); 19050Sstevel@tonic-gate if (mp == NULL) 19060Sstevel@tonic-gate return; 19070Sstevel@tonic-gate rts_fill_msg_v6(RTM_IFINFO, RTA_IFP, &ipv6_all_zeros, 19080Sstevel@tonic-gate &ipv6_all_zeros, &ipv6_all_zeros, &ipv6_all_zeros, 190911042SErik.Nordmark@Sun.COM &ipv6_all_zeros, &ipv6_all_zeros, &ipv6_all_zeros, 191011042SErik.Nordmark@Sun.COM ipif->ipif_ill, mp, NULL); 19110Sstevel@tonic-gate } else { 19120Sstevel@tonic-gate af = AF_INET; 19131676Sjpk mp = rts_alloc_msg(RTM_IFINFO, RTA_IFP, af, 0); 19140Sstevel@tonic-gate if (mp == NULL) 19150Sstevel@tonic-gate return; 191611042SErik.Nordmark@Sun.COM rts_fill_msg(RTM_IFINFO, RTA_IFP, 0, 0, 0, 0, 0, 0, 0, 191711042SErik.Nordmark@Sun.COM ipif->ipif_ill, mp, NULL); 19180Sstevel@tonic-gate } 19190Sstevel@tonic-gate ifm = (if_msghdr_t *)mp->b_rptr; 19200Sstevel@tonic-gate ifm->ifm_index = ipif->ipif_ill->ill_phyint->phyint_ifindex; 19218485SPeter.Memishian@Sun.COM ifm->ifm_flags = (ipif->ipif_flags | ipif->ipif_ill->ill_flags | 19228485SPeter.Memishian@Sun.COM ipif->ipif_ill->ill_phyint->phyint_flags | set) & ~clear; 19230Sstevel@tonic-gate rts_getifdata(&ifm->ifm_data, ipif); 19240Sstevel@tonic-gate ifm->ifm_addrs = RTA_IFP; 19258485SPeter.Memishian@Sun.COM 19268485SPeter.Memishian@Sun.COM if (flags & RTSQ_DEFAULT) { 19278485SPeter.Memishian@Sun.COM flags = RTSQ_ALL; 19288485SPeter.Memishian@Sun.COM /* 19298485SPeter.Memishian@Sun.COM * If this message is for an underlying interface, prevent 19308485SPeter.Memishian@Sun.COM * "normal" (IPMP-unaware) routing sockets from seeing it. 19318485SPeter.Memishian@Sun.COM */ 19328485SPeter.Memishian@Sun.COM if (IS_UNDER_IPMP(ipif->ipif_ill)) 19338485SPeter.Memishian@Sun.COM flags &= ~RTSQ_NORMAL; 19348485SPeter.Memishian@Sun.COM } 19358485SPeter.Memishian@Sun.COM 19368485SPeter.Memishian@Sun.COM rts_queue_input(mp, NULL, af, flags, ipst); 19370Sstevel@tonic-gate } 19380Sstevel@tonic-gate 19390Sstevel@tonic-gate /* 1940*11076SCathy.Zhou@Sun.COM * If cmd is RTM_ADD or RTM_DELETE, generate the rt_msghdr_t message; 1941*11076SCathy.Zhou@Sun.COM * otherwise (RTM_NEWADDR, RTM_DELADDR, RTM_CHGADDR and RTM_FREEADDR) 1942*11076SCathy.Zhou@Sun.COM * generate the ifa_msghdr_t message. 19430Sstevel@tonic-gate */ 1944*11076SCathy.Zhou@Sun.COM static void 1945*11076SCathy.Zhou@Sun.COM rts_new_rtsmsg(int cmd, int error, const ipif_t *ipif, uint_t flags) 19460Sstevel@tonic-gate { 19470Sstevel@tonic-gate int rtm_addrs; 19480Sstevel@tonic-gate mblk_t *mp; 19490Sstevel@tonic-gate ifa_msghdr_t *ifam; 19500Sstevel@tonic-gate rt_msghdr_t *rtm; 19510Sstevel@tonic-gate sa_family_t af; 19523448Sdh155122 ip_stack_t *ipst = ipif->ipif_ill->ill_ipst; 19530Sstevel@tonic-gate 195411042SErik.Nordmark@Sun.COM /* 1955*11076SCathy.Zhou@Sun.COM * Do not report unspecified address if this is the RTM_CHGADDR or 1956*11076SCathy.Zhou@Sun.COM * RTM_FREEADDR message. 195711042SErik.Nordmark@Sun.COM */ 1958*11076SCathy.Zhou@Sun.COM if (cmd == RTM_CHGADDR || cmd == RTM_FREEADDR) { 1959*11076SCathy.Zhou@Sun.COM if (!ipif->ipif_isv6) { 1960*11076SCathy.Zhou@Sun.COM if (ipif->ipif_lcl_addr == INADDR_ANY) 1961*11076SCathy.Zhou@Sun.COM return; 1962*11076SCathy.Zhou@Sun.COM } else if (IN6_IS_ADDR_UNSPECIFIED(&ipif->ipif_v6lcl_addr)) { 1963*11076SCathy.Zhou@Sun.COM return; 1964*11076SCathy.Zhou@Sun.COM } 1965*11076SCathy.Zhou@Sun.COM } 196611042SErik.Nordmark@Sun.COM 19670Sstevel@tonic-gate if (ipif->ipif_isv6) 19680Sstevel@tonic-gate af = AF_INET6; 19690Sstevel@tonic-gate else 19700Sstevel@tonic-gate af = AF_INET; 19718485SPeter.Memishian@Sun.COM 1972*11076SCathy.Zhou@Sun.COM if (cmd == RTM_ADD || cmd == RTM_DELETE) 1973*11076SCathy.Zhou@Sun.COM rtm_addrs = (RTA_DST | RTA_NETMASK); 1974*11076SCathy.Zhou@Sun.COM else 1975*11076SCathy.Zhou@Sun.COM rtm_addrs = (RTA_IFA | RTA_NETMASK | RTA_BRD | RTA_IFP); 1976*11076SCathy.Zhou@Sun.COM 1977*11076SCathy.Zhou@Sun.COM mp = rts_alloc_msg(cmd, rtm_addrs, af, 0); 1978*11076SCathy.Zhou@Sun.COM if (mp == NULL) 1979*11076SCathy.Zhou@Sun.COM return; 1980*11076SCathy.Zhou@Sun.COM 1981*11076SCathy.Zhou@Sun.COM if (cmd != RTM_ADD && cmd != RTM_DELETE) { 1982*11076SCathy.Zhou@Sun.COM switch (af) { 1983*11076SCathy.Zhou@Sun.COM case AF_INET: 1984*11076SCathy.Zhou@Sun.COM rts_fill_msg(cmd, rtm_addrs, 0, 1985*11076SCathy.Zhou@Sun.COM ipif->ipif_net_mask, 0, ipif->ipif_lcl_addr, 1986*11076SCathy.Zhou@Sun.COM ipif->ipif_pp_dst_addr, 0, 1987*11076SCathy.Zhou@Sun.COM ipif->ipif_lcl_addr, ipif->ipif_ill, 1988*11076SCathy.Zhou@Sun.COM mp, NULL); 1989*11076SCathy.Zhou@Sun.COM break; 1990*11076SCathy.Zhou@Sun.COM case AF_INET6: 1991*11076SCathy.Zhou@Sun.COM rts_fill_msg_v6(cmd, rtm_addrs, 1992*11076SCathy.Zhou@Sun.COM &ipv6_all_zeros, &ipif->ipif_v6net_mask, 1993*11076SCathy.Zhou@Sun.COM &ipv6_all_zeros, &ipif->ipif_v6lcl_addr, 1994*11076SCathy.Zhou@Sun.COM &ipif->ipif_v6pp_dst_addr, &ipv6_all_zeros, 1995*11076SCathy.Zhou@Sun.COM &ipif->ipif_v6lcl_addr, ipif->ipif_ill, 1996*11076SCathy.Zhou@Sun.COM mp, NULL); 1997*11076SCathy.Zhou@Sun.COM break; 1998*11076SCathy.Zhou@Sun.COM } 1999*11076SCathy.Zhou@Sun.COM ifam = (ifa_msghdr_t *)mp->b_rptr; 2000*11076SCathy.Zhou@Sun.COM ifam->ifam_index = 2001*11076SCathy.Zhou@Sun.COM ipif->ipif_ill->ill_phyint->phyint_ifindex; 2002*11076SCathy.Zhou@Sun.COM ifam->ifam_metric = ipif->ipif_metric; 2003*11076SCathy.Zhou@Sun.COM ifam->ifam_flags = ((cmd == RTM_NEWADDR) ? RTF_UP : 0); 2004*11076SCathy.Zhou@Sun.COM ifam->ifam_addrs = rtm_addrs; 2005*11076SCathy.Zhou@Sun.COM } else { 2006*11076SCathy.Zhou@Sun.COM switch (af) { 2007*11076SCathy.Zhou@Sun.COM case AF_INET: 2008*11076SCathy.Zhou@Sun.COM rts_fill_msg(cmd, rtm_addrs, 2009*11076SCathy.Zhou@Sun.COM ipif->ipif_lcl_addr, ipif->ipif_net_mask, 0, 2010*11076SCathy.Zhou@Sun.COM 0, 0, 0, 0, NULL, mp, NULL); 2011*11076SCathy.Zhou@Sun.COM break; 2012*11076SCathy.Zhou@Sun.COM case AF_INET6: 2013*11076SCathy.Zhou@Sun.COM rts_fill_msg_v6(cmd, rtm_addrs, 2014*11076SCathy.Zhou@Sun.COM &ipif->ipif_v6lcl_addr, 2015*11076SCathy.Zhou@Sun.COM &ipif->ipif_v6net_mask, &ipv6_all_zeros, 2016*11076SCathy.Zhou@Sun.COM &ipv6_all_zeros, &ipv6_all_zeros, 2017*11076SCathy.Zhou@Sun.COM &ipv6_all_zeros, &ipv6_all_zeros, 2018*11076SCathy.Zhou@Sun.COM NULL, mp, NULL); 2019*11076SCathy.Zhou@Sun.COM break; 2020*11076SCathy.Zhou@Sun.COM } 2021*11076SCathy.Zhou@Sun.COM rtm = (rt_msghdr_t *)mp->b_rptr; 2022*11076SCathy.Zhou@Sun.COM rtm->rtm_index = 2023*11076SCathy.Zhou@Sun.COM ipif->ipif_ill->ill_phyint->phyint_ifindex; 2024*11076SCathy.Zhou@Sun.COM rtm->rtm_flags = ((cmd == RTM_ADD) ? RTF_UP : 0); 2025*11076SCathy.Zhou@Sun.COM rtm->rtm_errno = error; 2026*11076SCathy.Zhou@Sun.COM if (error == 0) 2027*11076SCathy.Zhou@Sun.COM rtm->rtm_flags |= RTF_DONE; 2028*11076SCathy.Zhou@Sun.COM rtm->rtm_addrs = rtm_addrs; 2029*11076SCathy.Zhou@Sun.COM } 2030*11076SCathy.Zhou@Sun.COM rts_queue_input(mp, NULL, af, flags, ipst); 2031*11076SCathy.Zhou@Sun.COM } 2032*11076SCathy.Zhou@Sun.COM 2033*11076SCathy.Zhou@Sun.COM /* 2034*11076SCathy.Zhou@Sun.COM * This is called to generate messages to the routing socket 2035*11076SCathy.Zhou@Sun.COM * indicating a network interface has had addresses associated with it. 2036*11076SCathy.Zhou@Sun.COM * The structure of the code is based on the 4.4BSD-Lite2 <net/rtsock.c>. 2037*11076SCathy.Zhou@Sun.COM */ 2038*11076SCathy.Zhou@Sun.COM void 2039*11076SCathy.Zhou@Sun.COM ip_rts_newaddrmsg(int cmd, int error, const ipif_t *ipif, uint_t flags) 2040*11076SCathy.Zhou@Sun.COM { 2041*11076SCathy.Zhou@Sun.COM ip_stack_t *ipst = ipif->ipif_ill->ill_ipst; 2042*11076SCathy.Zhou@Sun.COM 20438485SPeter.Memishian@Sun.COM if (flags & RTSQ_DEFAULT) { 20448485SPeter.Memishian@Sun.COM flags = RTSQ_ALL; 20458485SPeter.Memishian@Sun.COM /* 20468485SPeter.Memishian@Sun.COM * If this message is for an underlying interface, prevent 20478485SPeter.Memishian@Sun.COM * "normal" (IPMP-unaware) routing sockets from seeing it. 20488485SPeter.Memishian@Sun.COM */ 20498485SPeter.Memishian@Sun.COM if (IS_UNDER_IPMP(ipif->ipif_ill)) 20508485SPeter.Memishian@Sun.COM flags &= ~RTSQ_NORMAL; 20518485SPeter.Memishian@Sun.COM } 20528485SPeter.Memishian@Sun.COM 20530Sstevel@tonic-gate /* 2054*11076SCathy.Zhou@Sun.COM * Let conn_ixa caching know that source address selection 2055*11076SCathy.Zhou@Sun.COM * changed 2056*11076SCathy.Zhou@Sun.COM */ 2057*11076SCathy.Zhou@Sun.COM if (cmd == RTM_ADD || cmd == RTM_DELETE) 2058*11076SCathy.Zhou@Sun.COM ip_update_source_selection(ipst); 2059*11076SCathy.Zhou@Sun.COM 2060*11076SCathy.Zhou@Sun.COM /* 20610Sstevel@tonic-gate * If the request is DELETE, send RTM_DELETE and RTM_DELADDR. 20620Sstevel@tonic-gate * if the request is ADD, send RTM_NEWADDR and RTM_ADD. 2063*11076SCathy.Zhou@Sun.COM * otherwise simply send the request. 20640Sstevel@tonic-gate */ 2065*11076SCathy.Zhou@Sun.COM switch (cmd) { 2066*11076SCathy.Zhou@Sun.COM case RTM_ADD: 2067*11076SCathy.Zhou@Sun.COM rts_new_rtsmsg(RTM_NEWADDR, error, ipif, flags); 2068*11076SCathy.Zhou@Sun.COM rts_new_rtsmsg(RTM_ADD, error, ipif, flags); 2069*11076SCathy.Zhou@Sun.COM break; 2070*11076SCathy.Zhou@Sun.COM case RTM_DELETE: 2071*11076SCathy.Zhou@Sun.COM rts_new_rtsmsg(RTM_DELETE, error, ipif, flags); 2072*11076SCathy.Zhou@Sun.COM rts_new_rtsmsg(RTM_DELADDR, error, ipif, flags); 2073*11076SCathy.Zhou@Sun.COM break; 2074*11076SCathy.Zhou@Sun.COM default: 2075*11076SCathy.Zhou@Sun.COM rts_new_rtsmsg(cmd, error, ipif, flags); 2076*11076SCathy.Zhou@Sun.COM break; 20770Sstevel@tonic-gate } 20780Sstevel@tonic-gate } 20790Sstevel@tonic-gate 20800Sstevel@tonic-gate /* 20810Sstevel@tonic-gate * Based on the address family specified in a sockaddr, copy the address field 20820Sstevel@tonic-gate * into an in6_addr_t. 20830Sstevel@tonic-gate * 20840Sstevel@tonic-gate * In the case of AF_UNSPEC, we assume the family is actually AF_INET for 20850Sstevel@tonic-gate * compatibility with programs that leave the family cleared in the sockaddr. 20860Sstevel@tonic-gate * Callers of rts_copyfromsockaddr should check the family themselves if they 20870Sstevel@tonic-gate * wish to verify its value. 20880Sstevel@tonic-gate * 20890Sstevel@tonic-gate * In the case of AF_INET6, a check is made to ensure that address is not an 20900Sstevel@tonic-gate * IPv4-mapped address. 20910Sstevel@tonic-gate */ 20920Sstevel@tonic-gate size_t 20930Sstevel@tonic-gate rts_copyfromsockaddr(struct sockaddr *sa, in6_addr_t *addrp) 20940Sstevel@tonic-gate { 20950Sstevel@tonic-gate switch (sa->sa_family) { 20960Sstevel@tonic-gate case AF_INET: 20970Sstevel@tonic-gate case AF_UNSPEC: 20980Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(((sin_t *)sa)->sin_addr.s_addr, addrp); 20990Sstevel@tonic-gate return (sizeof (sin_t)); 21000Sstevel@tonic-gate case AF_INET6: 21010Sstevel@tonic-gate *addrp = ((sin6_t *)sa)->sin6_addr; 21020Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(addrp)) 21030Sstevel@tonic-gate return (0); 21040Sstevel@tonic-gate return (sizeof (sin6_t)); 21050Sstevel@tonic-gate default: 21060Sstevel@tonic-gate return (0); 21070Sstevel@tonic-gate } 21080Sstevel@tonic-gate } 2109