17c478bd9Sstevel@tonic-gate /* 2*a5628610SRamesh Kumar Katla * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 37c478bd9Sstevel@tonic-gate */ 47c478bd9Sstevel@tonic-gate 57c478bd9Sstevel@tonic-gate /* 67c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1991, 1993 77c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 107c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 117c478bd9Sstevel@tonic-gate * are met: 127c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 137c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 147c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 157c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 167c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 177c478bd9Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 187c478bd9Sstevel@tonic-gate * must display the following acknowledgement: 197c478bd9Sstevel@tonic-gate * This product includes software developed by the University of 207c478bd9Sstevel@tonic-gate * California, Berkeley and its contributors. 217c478bd9Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 227c478bd9Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 237c478bd9Sstevel@tonic-gate * without specific prior written permission. 247c478bd9Sstevel@tonic-gate * 257c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 267c478bd9Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 277c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 287c478bd9Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 297c478bd9Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 307c478bd9Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 317c478bd9Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 327c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 337c478bd9Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 347c478bd9Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 357c478bd9Sstevel@tonic-gate * SUCH DAMAGE. 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * @(#)rtsock.c 8.6 (Berkeley) 2/11/95 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate /* 417c478bd9Sstevel@tonic-gate * This file contains routines that processes routing socket requests. 427c478bd9Sstevel@tonic-gate */ 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #include <sys/types.h> 457c478bd9Sstevel@tonic-gate #include <sys/stream.h> 467c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 477c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 48de8c4a14SErik Nordmark #include <sys/strsubr.h> 497c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 507c478bd9Sstevel@tonic-gate #include <sys/debug.h> 517c478bd9Sstevel@tonic-gate #include <sys/policy.h> 527c478bd9Sstevel@tonic-gate #include <sys/zone.h> 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #include <sys/systm.h> 557c478bd9Sstevel@tonic-gate #include <sys/param.h> 567c478bd9Sstevel@tonic-gate #include <sys/socket.h> 577c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 587c478bd9Sstevel@tonic-gate #include <net/if.h> 597c478bd9Sstevel@tonic-gate #include <net/route.h> 607c478bd9Sstevel@tonic-gate #include <netinet/in.h> 617c478bd9Sstevel@tonic-gate #include <net/if_dl.h> 627c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate #include <inet/common.h> 657c478bd9Sstevel@tonic-gate #include <inet/ip.h> 667c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 677c478bd9Sstevel@tonic-gate #include <inet/ip_if.h> 687c478bd9Sstevel@tonic-gate #include <inet/ip_ire.h> 69c793af95Ssangeeta #include <inet/ip_ftable.h> 707c478bd9Sstevel@tonic-gate #include <inet/ip_rts.h> 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 737c478bd9Sstevel@tonic-gate 7445916cd2Sjpk #include <sys/tsol/tndb.h> 7545916cd2Sjpk #include <sys/tsol/tnet.h> 7645916cd2Sjpk 7745916cd2Sjpk #define RTS_MSG_SIZE(type, rtm_addrs, af, sacnt) \ 7845916cd2Sjpk (rts_data_msg_size(rtm_addrs, af, sacnt) + rts_header_msg_size(type)) 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate static size_t rts_copyfromsockaddr(struct sockaddr *sa, in6_addr_t *addrp); 817c478bd9Sstevel@tonic-gate static void rts_fill_msg(int type, int rtm_addrs, ipaddr_t dst, 827c478bd9Sstevel@tonic-gate ipaddr_t mask, ipaddr_t gateway, ipaddr_t src_addr, ipaddr_t brd_addr, 83bd670b35SErik Nordmark ipaddr_t author, ipaddr_t ifaddr, const ill_t *ill, mblk_t *mp, 84bd670b35SErik Nordmark const tsol_gc_t *); 857c478bd9Sstevel@tonic-gate static int rts_getaddrs(rt_msghdr_t *rtm, in6_addr_t *dst_addrp, 867c478bd9Sstevel@tonic-gate in6_addr_t *gw_addrp, in6_addr_t *net_maskp, in6_addr_t *authorp, 877c478bd9Sstevel@tonic-gate in6_addr_t *if_addrp, in6_addr_t *src_addrp, ushort_t *indexp, 885c0b7edeSseb sa_family_t *afp, tsol_rtsecattr_t *rtsecattr, int *error); 8945916cd2Sjpk static void rts_getifdata(if_data_t *if_data, const ipif_t *ipif); 909e3469d3SErik Nordmark static int rts_getmetrics(ire_t *ire, ill_t *ill, rt_metrics_t *metrics); 91bd670b35SErik Nordmark static mblk_t *rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *ifire, 92bd670b35SErik Nordmark const in6_addr_t *setsrc, tsol_ire_gw_secattr_t *attrp, sa_family_t af); 937c478bd9Sstevel@tonic-gate static void rts_setmetrics(ire_t *ire, uint_t which, rt_metrics_t *metrics); 94bd670b35SErik Nordmark static ire_t *ire_lookup_v4(ipaddr_t dst_addr, ipaddr_t net_mask, 95bd670b35SErik Nordmark ipaddr_t gw_addr, const ill_t *ill, zoneid_t zoneid, 96bd670b35SErik Nordmark const ts_label_t *tsl, int match_flags, ip_stack_t *ipst, ire_t **pifire, 97bd670b35SErik Nordmark ipaddr_t *v4setsrcp, tsol_ire_gw_secattr_t **gwattrp); 98bd670b35SErik Nordmark static ire_t *ire_lookup_v6(const in6_addr_t *dst_addr_v6, 99bd670b35SErik Nordmark const in6_addr_t *net_mask_v6, const in6_addr_t *gw_addr_v6, 100bd670b35SErik Nordmark const ill_t *ill, zoneid_t zoneid, const ts_label_t *tsl, int match_flags, 101bd670b35SErik Nordmark ip_stack_t *ipst, ire_t **pifire, 102bd670b35SErik Nordmark in6_addr_t *v6setsrcp, tsol_ire_gw_secattr_t **gwattrp); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate /* 105e11c3f44Smeem * Send `mp' to all eligible routing queues. A queue is ineligible if: 1067c478bd9Sstevel@tonic-gate * 107e11c3f44Smeem * 1. SO_USELOOPBACK is off and it is not the originating queue. 108bd670b35SErik Nordmark * 2. RTA_UNDER_IPMP is on and RTSQ_UNDER_IPMP is not set in `flags'. 109bd670b35SErik Nordmark * 3. RTA_UNDER_IPMP is off and RTSQ_NORMAL is not set in `flags'. 110e11c3f44Smeem * 4. It is not the same address family as `af', and `af' isn't AF_UNSPEC. 1117c478bd9Sstevel@tonic-gate */ 1127c478bd9Sstevel@tonic-gate void 113e11c3f44Smeem rts_queue_input(mblk_t *mp, conn_t *o_connp, sa_family_t af, uint_t flags, 114e11c3f44Smeem ip_stack_t *ipst) 1157c478bd9Sstevel@tonic-gate { 1167c478bd9Sstevel@tonic-gate mblk_t *mp1; 1177c478bd9Sstevel@tonic-gate conn_t *connp, *next_connp; 1187c478bd9Sstevel@tonic-gate 119e11c3f44Smeem /* 120e11c3f44Smeem * Since we don't have an ill_t here, RTSQ_DEFAULT must already be 121bd670b35SErik Nordmark * resolved to one or more of RTSQ_NORMAL|RTSQ_UNDER_IPMP at this point. 122e11c3f44Smeem */ 123e11c3f44Smeem ASSERT(!(flags & RTSQ_DEFAULT)); 124e11c3f44Smeem 125f4b3ec61Sdh155122 mutex_enter(&ipst->ips_rts_clients->connf_lock); 126f4b3ec61Sdh155122 connp = ipst->ips_rts_clients->connf_head; 1277c478bd9Sstevel@tonic-gate 128e11c3f44Smeem for (; connp != NULL; connp = next_connp) { 129e11c3f44Smeem next_connp = connp->conn_next; 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate * If there was a family specified when this routing socket was 1327c478bd9Sstevel@tonic-gate * created and it doesn't match the family of the message to 1337c478bd9Sstevel@tonic-gate * copy, then continue. 1347c478bd9Sstevel@tonic-gate */ 1357c478bd9Sstevel@tonic-gate if ((connp->conn_proto != AF_UNSPEC) && 136e11c3f44Smeem (connp->conn_proto != af)) 137e11c3f44Smeem continue; 138e11c3f44Smeem 139e11c3f44Smeem /* 140e11c3f44Smeem * Queue the message only if the conn_t and flags match. 141e11c3f44Smeem */ 142e11c3f44Smeem if (connp->conn_rtaware & RTAW_UNDER_IPMP) { 143e11c3f44Smeem if (!(flags & RTSQ_UNDER_IPMP)) 144e11c3f44Smeem continue; 145e11c3f44Smeem } else { 146e11c3f44Smeem if (!(flags & RTSQ_NORMAL)) 1477c478bd9Sstevel@tonic-gate continue; 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * For the originating queue, we only copy the message upstream 1517c478bd9Sstevel@tonic-gate * if loopback is set. For others reading on the routing 1527c478bd9Sstevel@tonic-gate * socket, we check if there is room upstream for a copy of the 1537c478bd9Sstevel@tonic-gate * message. 1547c478bd9Sstevel@tonic-gate */ 155bd670b35SErik Nordmark if ((o_connp == connp) && connp->conn_useloopback == 0) { 1567c478bd9Sstevel@tonic-gate connp = connp->conn_next; 1577c478bd9Sstevel@tonic-gate continue; 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate CONN_INC_REF(connp); 160f4b3ec61Sdh155122 mutex_exit(&ipst->ips_rts_clients->connf_lock); 161fc80c0dfSnordmark /* Pass to rts_input */ 162bd670b35SErik Nordmark if (IPCL_IS_NONSTR(connp) ? !connp->conn_flow_cntrld : 163bd670b35SErik Nordmark canputnext(connp->conn_rq)) { 1647c478bd9Sstevel@tonic-gate mp1 = dupmsg(mp); 1657c478bd9Sstevel@tonic-gate if (mp1 == NULL) 1667c478bd9Sstevel@tonic-gate mp1 = copymsg(mp); 167bd670b35SErik Nordmark /* Note that we pass a NULL ira to rts_input */ 1687c478bd9Sstevel@tonic-gate if (mp1 != NULL) 169bd670b35SErik Nordmark (connp->conn_recv)(connp, mp1, NULL, NULL); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 172f4b3ec61Sdh155122 mutex_enter(&ipst->ips_rts_clients->connf_lock); 173e11c3f44Smeem /* reload next_connp since conn_next may have changed */ 1747c478bd9Sstevel@tonic-gate next_connp = connp->conn_next; 1757c478bd9Sstevel@tonic-gate CONN_DEC_REF(connp); 1767c478bd9Sstevel@tonic-gate } 177f4b3ec61Sdh155122 mutex_exit(&ipst->ips_rts_clients->connf_lock); 1787c478bd9Sstevel@tonic-gate freemsg(mp); 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * Takes an ire and sends an ack to all the routing sockets. This 1837c478bd9Sstevel@tonic-gate * routine is used 1847c478bd9Sstevel@tonic-gate * - when a route is created/deleted through the ioctl interface. 185bd670b35SErik Nordmark * - when a stale redirect is deleted 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate void 188f4b3ec61Sdh155122 ip_rts_rtmsg(int type, ire_t *ire, int error, ip_stack_t *ipst) 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate mblk_t *mp; 1917c478bd9Sstevel@tonic-gate rt_msghdr_t *rtm; 1927c478bd9Sstevel@tonic-gate int rtm_addrs = (RTA_DST | RTA_NETMASK | RTA_GATEWAY); 1937c478bd9Sstevel@tonic-gate sa_family_t af; 1947c478bd9Sstevel@tonic-gate in6_addr_t gw_addr_v6; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate if (ire == NULL) 1977c478bd9Sstevel@tonic-gate return; 1987c478bd9Sstevel@tonic-gate ASSERT(ire->ire_ipversion == IPV4_VERSION || 1997c478bd9Sstevel@tonic-gate ire->ire_ipversion == IPV6_VERSION); 2007c478bd9Sstevel@tonic-gate 201bd670b35SErik Nordmark ASSERT(!(ire->ire_type & IRE_IF_CLONE)); 202bd670b35SErik Nordmark 2037c478bd9Sstevel@tonic-gate if (ire->ire_flags & RTF_SETSRC) 2047c478bd9Sstevel@tonic-gate rtm_addrs |= RTA_SRC; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate switch (ire->ire_ipversion) { 2077c478bd9Sstevel@tonic-gate case IPV4_VERSION: 2087c478bd9Sstevel@tonic-gate af = AF_INET; 20945916cd2Sjpk mp = rts_alloc_msg(type, rtm_addrs, af, 0); 2107c478bd9Sstevel@tonic-gate if (mp == NULL) 2117c478bd9Sstevel@tonic-gate return; 2127c478bd9Sstevel@tonic-gate rts_fill_msg(type, rtm_addrs, ire->ire_addr, ire->ire_mask, 213bd670b35SErik Nordmark ire->ire_gateway_addr, ire->ire_setsrc_addr, 0, 0, 0, NULL, 214bd670b35SErik Nordmark mp, NULL); 2157c478bd9Sstevel@tonic-gate break; 2167c478bd9Sstevel@tonic-gate case IPV6_VERSION: 2177c478bd9Sstevel@tonic-gate af = AF_INET6; 21845916cd2Sjpk mp = rts_alloc_msg(type, rtm_addrs, af, 0); 2197c478bd9Sstevel@tonic-gate if (mp == NULL) 2207c478bd9Sstevel@tonic-gate return; 2217c478bd9Sstevel@tonic-gate mutex_enter(&ire->ire_lock); 2227c478bd9Sstevel@tonic-gate gw_addr_v6 = ire->ire_gateway_addr_v6; 2237c478bd9Sstevel@tonic-gate mutex_exit(&ire->ire_lock); 2247c478bd9Sstevel@tonic-gate rts_fill_msg_v6(type, rtm_addrs, &ire->ire_addr_v6, 2257c478bd9Sstevel@tonic-gate &ire->ire_mask_v6, &gw_addr_v6, 226bd670b35SErik Nordmark &ire->ire_setsrc_addr_v6, &ipv6_all_zeros, &ipv6_all_zeros, 227bd670b35SErik Nordmark &ipv6_all_zeros, NULL, mp, NULL); 2287c478bd9Sstevel@tonic-gate break; 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 2317c478bd9Sstevel@tonic-gate mp->b_wptr = (uchar_t *)&mp->b_rptr[rtm->rtm_msglen]; 2327c478bd9Sstevel@tonic-gate rtm->rtm_addrs = rtm_addrs; 2337c478bd9Sstevel@tonic-gate rtm->rtm_flags = ire->ire_flags; 2347c478bd9Sstevel@tonic-gate if (error != 0) 2357c478bd9Sstevel@tonic-gate rtm->rtm_errno = error; 2367c478bd9Sstevel@tonic-gate else 2377c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_DONE; 238e11c3f44Smeem rts_queue_input(mp, NULL, af, RTSQ_ALL, ipst); 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /* 242fc80c0dfSnordmark * This is a call from the RTS module 243fc80c0dfSnordmark * indicating that this is a Routing Socket 244fc80c0dfSnordmark * Stream. Insert this conn_t in routing 245fc80c0dfSnordmark * socket client list. 246fc80c0dfSnordmark */ 247fc80c0dfSnordmark void 248fc80c0dfSnordmark ip_rts_register(conn_t *connp) 249fc80c0dfSnordmark { 250fc80c0dfSnordmark ip_stack_t *ipst = connp->conn_netstack->netstack_ip; 251fc80c0dfSnordmark 252bd670b35SErik Nordmark connp->conn_useloopback = 1; 253fc80c0dfSnordmark ipcl_hash_insert_wildcard(ipst->ips_rts_clients, connp); 254fc80c0dfSnordmark } 255fc80c0dfSnordmark 256fc80c0dfSnordmark /* 257fc80c0dfSnordmark * This is a call from the RTS module indicating that it is closing. 258fc80c0dfSnordmark */ 259fc80c0dfSnordmark void 260fc80c0dfSnordmark ip_rts_unregister(conn_t *connp) 261fc80c0dfSnordmark { 262fc80c0dfSnordmark ipcl_hash_remove(connp); 263fc80c0dfSnordmark } 264fc80c0dfSnordmark 265fc80c0dfSnordmark /* 2667c478bd9Sstevel@tonic-gate * Processes requests received on a routing socket. It extracts all the 2677c478bd9Sstevel@tonic-gate * arguments and calls the appropriate function to process the request. 2687c478bd9Sstevel@tonic-gate * 2695c0b7edeSseb * RTA_SRC bit flag requests are sent by 'route -setsrc'. 2707c478bd9Sstevel@tonic-gate * 2717c478bd9Sstevel@tonic-gate * In general, this function does not consume the message supplied but rather 2727c478bd9Sstevel@tonic-gate * sends the message upstream with an appropriate UNIX errno. 2737c478bd9Sstevel@tonic-gate */ 2747c478bd9Sstevel@tonic-gate int 275bd670b35SErik Nordmark ip_rts_request_common(mblk_t *mp, conn_t *connp, cred_t *ioc_cr) 2767c478bd9Sstevel@tonic-gate { 2777c478bd9Sstevel@tonic-gate rt_msghdr_t *rtm = NULL; 2787c478bd9Sstevel@tonic-gate in6_addr_t dst_addr_v6; 2797c478bd9Sstevel@tonic-gate in6_addr_t src_addr_v6; 2807c478bd9Sstevel@tonic-gate in6_addr_t gw_addr_v6; 2817c478bd9Sstevel@tonic-gate in6_addr_t net_mask_v6; 2827c478bd9Sstevel@tonic-gate in6_addr_t author_v6; 2837c478bd9Sstevel@tonic-gate in6_addr_t if_addr_v6; 284bd670b35SErik Nordmark mblk_t *mp1; 2857c478bd9Sstevel@tonic-gate ire_t *ire = NULL; 286bd670b35SErik Nordmark ire_t *ifire = NULL; 287bd670b35SErik Nordmark ipaddr_t v4setsrc; 288bd670b35SErik Nordmark in6_addr_t v6setsrc = ipv6_all_zeros; 289bd670b35SErik Nordmark tsol_ire_gw_secattr_t *gwattr = NULL; 2907c478bd9Sstevel@tonic-gate int error = 0; 2917c478bd9Sstevel@tonic-gate int match_flags = MATCH_IRE_DSTONLY; 292e34b0294Swy83408 int match_flags_local = MATCH_IRE_TYPE | MATCH_IRE_GW; 2937c478bd9Sstevel@tonic-gate int found_addrs; 2947c478bd9Sstevel@tonic-gate sa_family_t af; 2957c478bd9Sstevel@tonic-gate ipaddr_t dst_addr; 2967c478bd9Sstevel@tonic-gate ipaddr_t gw_addr; 2977c478bd9Sstevel@tonic-gate ipaddr_t src_addr; 2987c478bd9Sstevel@tonic-gate ipaddr_t net_mask; 2997c478bd9Sstevel@tonic-gate ushort_t index; 30045916cd2Sjpk boolean_t gcgrp_xtraref = B_FALSE; 30145916cd2Sjpk tsol_gcgrp_addr_t ga; 30245916cd2Sjpk tsol_rtsecattr_t rtsecattr; 30345916cd2Sjpk struct rtsa_s *rtsap = NULL; 30445916cd2Sjpk tsol_gcgrp_t *gcgrp = NULL; 30545916cd2Sjpk tsol_gc_t *gc = NULL; 306b8965a53Swy83408 ts_label_t *tsl = NULL; 3075597b60aSnordmark zoneid_t zoneid; 308f4b3ec61Sdh155122 ip_stack_t *ipst; 309bd670b35SErik Nordmark ill_t *ill = NULL; 3107c478bd9Sstevel@tonic-gate 3115597b60aSnordmark zoneid = connp->conn_zoneid; 312f4b3ec61Sdh155122 ipst = connp->conn_netstack->netstack_ip; 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL && !pullupmsg(mp, -1)) { 3157c478bd9Sstevel@tonic-gate freemsg(mp); 3167c478bd9Sstevel@tonic-gate error = EINVAL; 3177c478bd9Sstevel@tonic-gate goto done; 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (rt_msghdr_t)) { 3207c478bd9Sstevel@tonic-gate freemsg(mp); 3217c478bd9Sstevel@tonic-gate error = EINVAL; 3227c478bd9Sstevel@tonic-gate goto done; 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate * Check the routing message for basic consistency including the 3277c478bd9Sstevel@tonic-gate * version number and that the number of octets written is the same 3287c478bd9Sstevel@tonic-gate * as specified by the rtm_msglen field. 3297c478bd9Sstevel@tonic-gate * 3307c478bd9Sstevel@tonic-gate * At this point, an error can be delivered back via rtm_errno. 3317c478bd9Sstevel@tonic-gate */ 3327c478bd9Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 3337c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) != rtm->rtm_msglen) { 3347c478bd9Sstevel@tonic-gate error = EINVAL; 3357c478bd9Sstevel@tonic-gate goto done; 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 3387c478bd9Sstevel@tonic-gate error = EPROTONOSUPPORT; 3397c478bd9Sstevel@tonic-gate goto done; 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* Only allow RTM_GET or RTM_RESOLVE for unprivileged process */ 3437c478bd9Sstevel@tonic-gate if (rtm->rtm_type != RTM_GET && 3447c478bd9Sstevel@tonic-gate rtm->rtm_type != RTM_RESOLVE && 3457c478bd9Sstevel@tonic-gate (ioc_cr == NULL || 346f4b3ec61Sdh155122 secpolicy_ip_config(ioc_cr, B_FALSE) != 0)) { 3477c478bd9Sstevel@tonic-gate error = EPERM; 3487c478bd9Sstevel@tonic-gate goto done; 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate found_addrs = rts_getaddrs(rtm, &dst_addr_v6, &gw_addr_v6, &net_mask_v6, 3525c0b7edeSseb &author_v6, &if_addr_v6, &src_addr_v6, &index, &af, &rtsecattr, 3535c0b7edeSseb &error); 35445916cd2Sjpk 35545916cd2Sjpk if (error != 0) 35645916cd2Sjpk goto done; 35745916cd2Sjpk 3587c478bd9Sstevel@tonic-gate if ((found_addrs & RTA_DST) == 0) { 3597c478bd9Sstevel@tonic-gate error = EINVAL; 3607c478bd9Sstevel@tonic-gate goto done; 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate /* 3647c478bd9Sstevel@tonic-gate * Based on the address family of the destination address, determine 3657c478bd9Sstevel@tonic-gate * the destination, gateway and netmask and return the appropriate error 3667c478bd9Sstevel@tonic-gate * if an unknown address family was specified (following the errno 3677c478bd9Sstevel@tonic-gate * values that 4.4BSD-Lite2 returns.) 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate switch (af) { 3707c478bd9Sstevel@tonic-gate case AF_INET: 3717c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&dst_addr_v6, dst_addr); 3727c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&src_addr_v6, src_addr); 3737c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&gw_addr_v6, gw_addr); 3747c478bd9Sstevel@tonic-gate if (((found_addrs & RTA_NETMASK) == 0) || 3757c478bd9Sstevel@tonic-gate (rtm->rtm_flags & RTF_HOST)) 3767c478bd9Sstevel@tonic-gate net_mask = IP_HOST_MASK; 3777c478bd9Sstevel@tonic-gate else 3787c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&net_mask_v6, net_mask); 3797c478bd9Sstevel@tonic-gate break; 3807c478bd9Sstevel@tonic-gate case AF_INET6: 3817c478bd9Sstevel@tonic-gate if (((found_addrs & RTA_NETMASK) == 0) || 3827c478bd9Sstevel@tonic-gate (rtm->rtm_flags & RTF_HOST)) 3837c478bd9Sstevel@tonic-gate net_mask_v6 = ipv6_all_ones; 3847c478bd9Sstevel@tonic-gate break; 3857c478bd9Sstevel@tonic-gate default: 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * These errno values are meant to be compatible with 3887c478bd9Sstevel@tonic-gate * 4.4BSD-Lite2 for the given message types. 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 3917c478bd9Sstevel@tonic-gate case RTM_ADD: 3927c478bd9Sstevel@tonic-gate case RTM_DELETE: 3937c478bd9Sstevel@tonic-gate error = ESRCH; 3947c478bd9Sstevel@tonic-gate goto done; 3957c478bd9Sstevel@tonic-gate case RTM_GET: 3967c478bd9Sstevel@tonic-gate case RTM_CHANGE: 3977c478bd9Sstevel@tonic-gate error = EAFNOSUPPORT; 3987c478bd9Sstevel@tonic-gate goto done; 3997c478bd9Sstevel@tonic-gate default: 4007c478bd9Sstevel@tonic-gate error = EOPNOTSUPP; 4017c478bd9Sstevel@tonic-gate goto done; 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate /* 4067c478bd9Sstevel@tonic-gate * At this point, the address family must be something known. 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate ASSERT(af == AF_INET || af == AF_INET6); 4097c478bd9Sstevel@tonic-gate 410bd670b35SErik Nordmark /* Handle RTA_IFP */ 4117c478bd9Sstevel@tonic-gate if (index != 0) { 412bd670b35SErik Nordmark ipif_t *ipif; 413e11c3f44Smeem lookup: 414bd670b35SErik Nordmark ill = ill_lookup_on_ifindex(index, af == AF_INET6, ipst); 4157c478bd9Sstevel@tonic-gate if (ill == NULL) { 4167c478bd9Sstevel@tonic-gate error = EINVAL; 4177c478bd9Sstevel@tonic-gate goto done; 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate /* 421e11c3f44Smeem * Since all interfaces in an IPMP group must be equivalent, 422e11c3f44Smeem * we prevent changes to a specific underlying interface's 423e11c3f44Smeem * routing configuration. However, for backward compatibility, 424e11c3f44Smeem * we intepret a request to add a route on an underlying 425e11c3f44Smeem * interface as a request to add a route on its IPMP interface. 4267c478bd9Sstevel@tonic-gate */ 427e11c3f44Smeem if (IS_UNDER_IPMP(ill)) { 428e11c3f44Smeem switch (rtm->rtm_type) { 429e11c3f44Smeem case RTM_CHANGE: 430e11c3f44Smeem case RTM_DELETE: 431e11c3f44Smeem error = EINVAL; 432e11c3f44Smeem goto done; 433e11c3f44Smeem case RTM_ADD: 434e11c3f44Smeem index = ipmp_ill_get_ipmp_ifindex(ill); 435e11c3f44Smeem ill_refrele(ill); 436e11c3f44Smeem if (index == 0) { 437bd670b35SErik Nordmark ill = NULL; /* already refrele'd */ 438e11c3f44Smeem error = EINVAL; 4397c478bd9Sstevel@tonic-gate goto done; 4407c478bd9Sstevel@tonic-gate } 441e11c3f44Smeem goto lookup; 442e11c3f44Smeem } 443e11c3f44Smeem } 444e11c3f44Smeem 4457c478bd9Sstevel@tonic-gate match_flags |= MATCH_IRE_ILL; 446bd670b35SErik Nordmark /* 447bd670b35SErik Nordmark * This provides the same zoneid as in Solaris 10 448bd670b35SErik Nordmark * that -ifp picks the zoneid from the first ipif on the ill. 449bd670b35SErik Nordmark * But it might not be useful since the first ipif will always 450bd670b35SErik Nordmark * have the same zoneid as the ill. 451bd670b35SErik Nordmark */ 452bd670b35SErik Nordmark ipif = ipif_get_next_ipif(NULL, ill); 453bd670b35SErik Nordmark if (ipif != NULL) { 454bd670b35SErik Nordmark zoneid = ipif->ipif_zoneid; 455bd670b35SErik Nordmark ipif_refrele(ipif); 456bd670b35SErik Nordmark } 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * If a netmask was supplied in the message, then subsequent route 4617c478bd9Sstevel@tonic-gate * lookups will attempt to match on the netmask as well. 4627c478bd9Sstevel@tonic-gate */ 4637c478bd9Sstevel@tonic-gate if ((found_addrs & RTA_NETMASK) != 0) 4647c478bd9Sstevel@tonic-gate match_flags |= MATCH_IRE_MASK; 4657c478bd9Sstevel@tonic-gate 46645916cd2Sjpk /* 46745916cd2Sjpk * We only process any passed-in route security attributes for 468e34b0294Swy83408 * either RTM_ADD or RTM_CHANGE message; We overload them 469e34b0294Swy83408 * to do an RTM_GET as a different label; ignore otherwise. 47045916cd2Sjpk */ 471e34b0294Swy83408 if (rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE || 472e34b0294Swy83408 rtm->rtm_type == RTM_GET) { 47345916cd2Sjpk ASSERT(rtsecattr.rtsa_cnt <= TSOL_RTSA_REQUEST_MAX); 47445916cd2Sjpk if (rtsecattr.rtsa_cnt > 0) 47545916cd2Sjpk rtsap = &rtsecattr.rtsa_attr[0]; 47645916cd2Sjpk } 47745916cd2Sjpk 4787c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 4797c478bd9Sstevel@tonic-gate case RTM_ADD: 4807c478bd9Sstevel@tonic-gate /* if we are adding a route, gateway is a must */ 4817c478bd9Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) == 0) { 4827c478bd9Sstevel@tonic-gate error = EINVAL; 4837c478bd9Sstevel@tonic-gate goto done; 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* Multirouting does not support net routes. */ 4877c478bd9Sstevel@tonic-gate if ((rtm->rtm_flags & (RTF_MULTIRT | RTF_HOST)) == 4887c478bd9Sstevel@tonic-gate RTF_MULTIRT) { 4897c478bd9Sstevel@tonic-gate error = EADDRNOTAVAIL; 4907c478bd9Sstevel@tonic-gate goto done; 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate /* 4947c478bd9Sstevel@tonic-gate * Multirouting and user-specified source addresses 4957c478bd9Sstevel@tonic-gate * do not support interface based routing. 4967c478bd9Sstevel@tonic-gate * Assigning a source address to an interface based 4977c478bd9Sstevel@tonic-gate * route is achievable by plumbing a new ipif and 4987c478bd9Sstevel@tonic-gate * setting up the interface route via this ipif, 4997c478bd9Sstevel@tonic-gate * though. 5007c478bd9Sstevel@tonic-gate */ 5017c478bd9Sstevel@tonic-gate if (rtm->rtm_flags & (RTF_MULTIRT | RTF_SETSRC)) { 5027c478bd9Sstevel@tonic-gate if ((rtm->rtm_flags & RTF_GATEWAY) == 0) { 5037c478bd9Sstevel@tonic-gate error = EADDRNOTAVAIL; 5047c478bd9Sstevel@tonic-gate goto done; 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate switch (af) { 5097c478bd9Sstevel@tonic-gate case AF_INET: 5107c478bd9Sstevel@tonic-gate if (src_addr != INADDR_ANY) { 511bd670b35SErik Nordmark uint_t type; 512bd670b35SErik Nordmark 5137c478bd9Sstevel@tonic-gate /* 5147c478bd9Sstevel@tonic-gate * The RTF_SETSRC flag is present, check that 5157c478bd9Sstevel@tonic-gate * the supplied src address is not the loopback 5167c478bd9Sstevel@tonic-gate * address. This would produce martian packets. 5177c478bd9Sstevel@tonic-gate */ 5187c478bd9Sstevel@tonic-gate if (src_addr == htonl(INADDR_LOOPBACK)) { 5197c478bd9Sstevel@tonic-gate error = EINVAL; 5207c478bd9Sstevel@tonic-gate goto done; 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate /* 5237c478bd9Sstevel@tonic-gate * Also check that the supplied address is a 524bd670b35SErik Nordmark * valid, local one. Only allow IFF_UP ones 5257c478bd9Sstevel@tonic-gate */ 526bd670b35SErik Nordmark type = ip_type_v4(src_addr, ipst); 527bd670b35SErik Nordmark if (!(type & (IRE_LOCAL|IRE_LOOPBACK))) { 5287c478bd9Sstevel@tonic-gate error = EADDRNOTAVAIL; 5297c478bd9Sstevel@tonic-gate goto done; 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate } else { 5327c478bd9Sstevel@tonic-gate /* 5337c478bd9Sstevel@tonic-gate * The RTF_SETSRC modifier must be associated 5347c478bd9Sstevel@tonic-gate * to a non-null source address. 5357c478bd9Sstevel@tonic-gate */ 5367c478bd9Sstevel@tonic-gate if (rtm->rtm_flags & RTF_SETSRC) { 5377c478bd9Sstevel@tonic-gate error = EINVAL; 5387c478bd9Sstevel@tonic-gate goto done; 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 54245916cd2Sjpk error = ip_rt_add(dst_addr, net_mask, gw_addr, src_addr, 543bd670b35SErik Nordmark rtm->rtm_flags, ill, &ire, B_FALSE, 544bd670b35SErik Nordmark rtsap, ipst, zoneid); 545bd670b35SErik Nordmark if (ill != NULL) 546bd670b35SErik Nordmark ASSERT(!MUTEX_HELD(&ill->ill_lock)); 5477c478bd9Sstevel@tonic-gate break; 5487c478bd9Sstevel@tonic-gate case AF_INET6: 5497c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&src_addr_v6)) { 550bd670b35SErik Nordmark uint_t type; 551bd670b35SErik Nordmark 5527c478bd9Sstevel@tonic-gate /* 5537c478bd9Sstevel@tonic-gate * The RTF_SETSRC flag is present, check that 5547c478bd9Sstevel@tonic-gate * the supplied src address is not the loopback 5557c478bd9Sstevel@tonic-gate * address. This would produce martian packets. 5567c478bd9Sstevel@tonic-gate */ 5577c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_LOOPBACK(&src_addr_v6)) { 5587c478bd9Sstevel@tonic-gate error = EINVAL; 5597c478bd9Sstevel@tonic-gate goto done; 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate /* 5627c478bd9Sstevel@tonic-gate * Also check that the supplied address is a 563bd670b35SErik Nordmark * valid, local one. Only allow UP ones. 5647c478bd9Sstevel@tonic-gate */ 565bd670b35SErik Nordmark type = ip_type_v6(&src_addr_v6, ipst); 566bd670b35SErik Nordmark if (!(type & (IRE_LOCAL|IRE_LOOPBACK))) { 5677c478bd9Sstevel@tonic-gate error = EADDRNOTAVAIL; 5687c478bd9Sstevel@tonic-gate goto done; 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate error = ip_rt_add_v6(&dst_addr_v6, &net_mask_v6, 5727c478bd9Sstevel@tonic-gate &gw_addr_v6, &src_addr_v6, rtm->rtm_flags, 573bd670b35SErik Nordmark ill, &ire, rtsap, ipst, zoneid); 5747c478bd9Sstevel@tonic-gate break; 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * The RTF_SETSRC modifier must be associated 5787c478bd9Sstevel@tonic-gate * to a non-null source address. 5797c478bd9Sstevel@tonic-gate */ 5807c478bd9Sstevel@tonic-gate if (rtm->rtm_flags & RTF_SETSRC) { 5817c478bd9Sstevel@tonic-gate error = EINVAL; 5827c478bd9Sstevel@tonic-gate goto done; 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate error = ip_rt_add_v6(&dst_addr_v6, &net_mask_v6, 5857c478bd9Sstevel@tonic-gate &gw_addr_v6, NULL, rtm->rtm_flags, 586bd670b35SErik Nordmark ill, &ire, rtsap, ipst, zoneid); 587bd670b35SErik Nordmark if (ill != NULL) 588bd670b35SErik Nordmark ASSERT(!MUTEX_HELD(&ill->ill_lock)); 5897c478bd9Sstevel@tonic-gate break; 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate if (error != 0) 5927c478bd9Sstevel@tonic-gate goto done; 5937c478bd9Sstevel@tonic-gate ASSERT(ire != NULL); 5947c478bd9Sstevel@tonic-gate rts_setmetrics(ire, rtm->rtm_inits, &rtm->rtm_rmx); 5957c478bd9Sstevel@tonic-gate break; 5967c478bd9Sstevel@tonic-gate case RTM_DELETE: 5977c478bd9Sstevel@tonic-gate /* if we are deleting a route, gateway is a must */ 5987c478bd9Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) == 0) { 5997c478bd9Sstevel@tonic-gate error = EINVAL; 6007c478bd9Sstevel@tonic-gate goto done; 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate /* 6037c478bd9Sstevel@tonic-gate * The RTF_SETSRC modifier does not make sense 6047c478bd9Sstevel@tonic-gate * when deleting a route. 6057c478bd9Sstevel@tonic-gate */ 6067c478bd9Sstevel@tonic-gate if (rtm->rtm_flags & RTF_SETSRC) { 6077c478bd9Sstevel@tonic-gate error = EINVAL; 6087c478bd9Sstevel@tonic-gate goto done; 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate switch (af) { 6127c478bd9Sstevel@tonic-gate case AF_INET: 6137c478bd9Sstevel@tonic-gate error = ip_rt_delete(dst_addr, net_mask, gw_addr, 614bd670b35SErik Nordmark found_addrs, rtm->rtm_flags, ill, B_FALSE, 615bd670b35SErik Nordmark ipst, zoneid); 6167c478bd9Sstevel@tonic-gate break; 6177c478bd9Sstevel@tonic-gate case AF_INET6: 6187c478bd9Sstevel@tonic-gate error = ip_rt_delete_v6(&dst_addr_v6, &net_mask_v6, 619bd670b35SErik Nordmark &gw_addr_v6, found_addrs, rtm->rtm_flags, ill, 620bd670b35SErik Nordmark ipst, zoneid); 6217c478bd9Sstevel@tonic-gate break; 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate break; 6247c478bd9Sstevel@tonic-gate case RTM_GET: 6257c478bd9Sstevel@tonic-gate case RTM_CHANGE: 6267c478bd9Sstevel@tonic-gate /* 6277c478bd9Sstevel@tonic-gate * In the case of RTM_GET, the forwarding table should be 628bd670b35SErik Nordmark * searched recursively. Also, if a gateway was 6297c478bd9Sstevel@tonic-gate * specified then the gateway address must also be matched. 6307c478bd9Sstevel@tonic-gate * 6317c478bd9Sstevel@tonic-gate * In the case of RTM_CHANGE, the gateway address (if supplied) 6327c478bd9Sstevel@tonic-gate * is the new gateway address so matching on the gateway address 6337c478bd9Sstevel@tonic-gate * is not done. This can lead to ambiguity when looking up the 6347c478bd9Sstevel@tonic-gate * route to change as usually only the destination (and netmask, 6357c478bd9Sstevel@tonic-gate * if supplied) is used for the lookup. However if a RTA_IFP 6367c478bd9Sstevel@tonic-gate * sockaddr is also supplied, it can disambiguate which route to 6377c478bd9Sstevel@tonic-gate * change provided the ambigous routes are tied to distinct 6387c478bd9Sstevel@tonic-gate * ill's (or interface indices). If the routes are not tied to 6397c478bd9Sstevel@tonic-gate * any particular interfaces (for example, with traditional 6407c478bd9Sstevel@tonic-gate * gateway routes), then a RTA_IFP sockaddr will be of no use as 6417c478bd9Sstevel@tonic-gate * it won't match any such routes. 6427c478bd9Sstevel@tonic-gate * RTA_SRC is not supported for RTM_GET and RTM_CHANGE, 6437c478bd9Sstevel@tonic-gate * except when RTM_CHANGE is combined to RTF_SETSRC. 6447c478bd9Sstevel@tonic-gate */ 6457c478bd9Sstevel@tonic-gate if (((found_addrs & RTA_SRC) != 0) && 6467c478bd9Sstevel@tonic-gate ((rtm->rtm_type == RTM_GET) || 6477c478bd9Sstevel@tonic-gate !(rtm->rtm_flags & RTF_SETSRC))) { 6487c478bd9Sstevel@tonic-gate error = EOPNOTSUPP; 6497c478bd9Sstevel@tonic-gate goto done; 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate if (rtm->rtm_type == RTM_GET) { 653bd670b35SErik Nordmark match_flags |= MATCH_IRE_SECATTR; 654e34b0294Swy83408 match_flags_local |= MATCH_IRE_SECATTR; 6557c478bd9Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) != 0) 6567c478bd9Sstevel@tonic-gate match_flags |= MATCH_IRE_GW; 657b8965a53Swy83408 if (ioc_cr) 658b8965a53Swy83408 tsl = crgetlabel(ioc_cr); 659e34b0294Swy83408 if (rtsap != NULL) { 660e34b0294Swy83408 if (rtsa_validate(rtsap) != 0) { 661e34b0294Swy83408 error = EINVAL; 662e34b0294Swy83408 goto done; 663e34b0294Swy83408 } 664b8965a53Swy83408 if (tsl != NULL && 665b8965a53Swy83408 crgetzoneid(ioc_cr) != GLOBAL_ZONEID && 666e34b0294Swy83408 (tsl->tsl_doi != rtsap->rtsa_doi || 667e34b0294Swy83408 !bldominates(&tsl->tsl_label, 668e34b0294Swy83408 &rtsap->rtsa_slrange.lower_bound))) { 669e34b0294Swy83408 error = EPERM; 670e34b0294Swy83408 goto done; 671e34b0294Swy83408 } 672e34b0294Swy83408 tsl = labelalloc( 673e34b0294Swy83408 &rtsap->rtsa_slrange.lower_bound, 674e34b0294Swy83408 rtsap->rtsa_doi, KM_NOSLEEP); 675e34b0294Swy83408 } 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate if (rtm->rtm_type == RTM_CHANGE) { 6787c478bd9Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) && 6797c478bd9Sstevel@tonic-gate (rtm->rtm_flags & RTF_SETSRC)) { 6807c478bd9Sstevel@tonic-gate /* 6817c478bd9Sstevel@tonic-gate * Do not want to change the gateway, 6827c478bd9Sstevel@tonic-gate * but rather the source address. 6837c478bd9Sstevel@tonic-gate */ 6847c478bd9Sstevel@tonic-gate match_flags |= MATCH_IRE_GW; 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate /* 6897c478bd9Sstevel@tonic-gate * If the netmask is all ones (either as supplied or as derived 6907c478bd9Sstevel@tonic-gate * above), then first check for an IRE_LOOPBACK or 6917c478bd9Sstevel@tonic-gate * IRE_LOCAL entry. 6927c478bd9Sstevel@tonic-gate * 6937c478bd9Sstevel@tonic-gate * If we didn't check for or find an IRE_LOOPBACK or IRE_LOCAL 694bd670b35SErik Nordmark * entry, then look for any other type of IRE. 6957c478bd9Sstevel@tonic-gate */ 6967c478bd9Sstevel@tonic-gate switch (af) { 6977c478bd9Sstevel@tonic-gate case AF_INET: 6987c478bd9Sstevel@tonic-gate if (net_mask == IP_HOST_MASK) { 699bd670b35SErik Nordmark ire = ire_ftable_lookup_v4(dst_addr, 0, gw_addr, 7005597b60aSnordmark IRE_LOCAL | IRE_LOOPBACK, NULL, zoneid, 701bd670b35SErik Nordmark tsl, match_flags_local, 0, ipst, NULL); 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate if (ire == NULL) { 704bd670b35SErik Nordmark ire = ire_lookup_v4(dst_addr, net_mask, 705bd670b35SErik Nordmark gw_addr, ill, zoneid, tsl, match_flags, 706bd670b35SErik Nordmark ipst, &ifire, &v4setsrc, &gwattr); 707bd670b35SErik Nordmark IN6_IPADDR_TO_V4MAPPED(v4setsrc, &v6setsrc); 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate break; 7107c478bd9Sstevel@tonic-gate case AF_INET6: 7117c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&net_mask_v6, &ipv6_all_ones)) { 712bd670b35SErik Nordmark ire = ire_ftable_lookup_v6(&dst_addr_v6, NULL, 7137c478bd9Sstevel@tonic-gate &gw_addr_v6, IRE_LOCAL | IRE_LOOPBACK, NULL, 714bd670b35SErik Nordmark zoneid, tsl, match_flags_local, 0, ipst, 715bd670b35SErik Nordmark NULL); 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate if (ire == NULL) { 718bd670b35SErik Nordmark ire = ire_lookup_v6(&dst_addr_v6, 719bd670b35SErik Nordmark &net_mask_v6, &gw_addr_v6, ill, zoneid, 720bd670b35SErik Nordmark tsl, match_flags, ipst, &ifire, &v6setsrc, 721bd670b35SErik Nordmark &gwattr); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate break; 7247c478bd9Sstevel@tonic-gate } 725e34b0294Swy83408 if (tsl != NULL && tsl != crgetlabel(ioc_cr)) 726e34b0294Swy83408 label_rele(tsl); 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate if (ire == NULL) { 7297c478bd9Sstevel@tonic-gate error = ESRCH; 7307c478bd9Sstevel@tonic-gate goto done; 7317c478bd9Sstevel@tonic-gate } 732bd670b35SErik Nordmark /* 733bd670b35SErik Nordmark * Want to return failure if we get an IRE_NOROUTE from 734bd670b35SErik Nordmark * ire_route_recursive 735bd670b35SErik Nordmark */ 736bd670b35SErik Nordmark if (ire->ire_type & IRE_NOROUTE) { 737bd670b35SErik Nordmark ire_refrele(ire); 738bd670b35SErik Nordmark ire = NULL; 739bd670b35SErik Nordmark error = ESRCH; 740bd670b35SErik Nordmark goto done; 741bd670b35SErik Nordmark } 742bd670b35SErik Nordmark 7437c478bd9Sstevel@tonic-gate /* we know the IRE before we come here */ 7447c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 7457c478bd9Sstevel@tonic-gate case RTM_GET: 746bd670b35SErik Nordmark mp1 = rts_rtmget(mp, ire, ifire, &v6setsrc, gwattr, af); 7477c478bd9Sstevel@tonic-gate if (mp1 == NULL) { 7487c478bd9Sstevel@tonic-gate error = ENOBUFS; 7497c478bd9Sstevel@tonic-gate goto done; 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate freemsg(mp); 7527c478bd9Sstevel@tonic-gate mp = mp1; 7537c478bd9Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 7547c478bd9Sstevel@tonic-gate break; 7557c478bd9Sstevel@tonic-gate case RTM_CHANGE: 7567c478bd9Sstevel@tonic-gate /* 7577c478bd9Sstevel@tonic-gate * Do not allow to the multirouting state of a route 7587c478bd9Sstevel@tonic-gate * to be changed. This aims to prevent undesirable 7597c478bd9Sstevel@tonic-gate * stages where both multirt and non-multirt routes 7607c478bd9Sstevel@tonic-gate * for the same destination are declared. 7617c478bd9Sstevel@tonic-gate */ 7627c478bd9Sstevel@tonic-gate if ((ire->ire_flags & RTF_MULTIRT) != 7637c478bd9Sstevel@tonic-gate (rtm->rtm_flags & RTF_MULTIRT)) { 7647c478bd9Sstevel@tonic-gate error = EINVAL; 7657c478bd9Sstevel@tonic-gate goto done; 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate /* 7687c478bd9Sstevel@tonic-gate * Note that we do not need to do 7697c478bd9Sstevel@tonic-gate * ire_flush_cache_*(IRE_FLUSH_ADD) as a change 7707c478bd9Sstevel@tonic-gate * in metrics or gateway will not affect existing 7717c478bd9Sstevel@tonic-gate * routes since it does not create a more specific 7727c478bd9Sstevel@tonic-gate * route. 7737c478bd9Sstevel@tonic-gate */ 7747c478bd9Sstevel@tonic-gate switch (af) { 7757c478bd9Sstevel@tonic-gate case AF_INET: 7767c478bd9Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) != 0 && 7777c478bd9Sstevel@tonic-gate (ire->ire_gateway_addr != gw_addr)) { 7787c478bd9Sstevel@tonic-gate ire->ire_gateway_addr = gw_addr; 7797c478bd9Sstevel@tonic-gate } 78045916cd2Sjpk 78145916cd2Sjpk if (rtsap != NULL) { 78245916cd2Sjpk ga.ga_af = AF_INET; 78345916cd2Sjpk IN6_IPADDR_TO_V4MAPPED( 78445916cd2Sjpk ire->ire_gateway_addr, &ga.ga_addr); 78545916cd2Sjpk 78645916cd2Sjpk gcgrp = gcgrp_lookup(&ga, B_TRUE); 78745916cd2Sjpk if (gcgrp == NULL) { 78845916cd2Sjpk error = ENOMEM; 78945916cd2Sjpk goto done; 79045916cd2Sjpk } 79145916cd2Sjpk } 79245916cd2Sjpk 7937c478bd9Sstevel@tonic-gate if ((found_addrs & RTA_SRC) != 0 && 7947c478bd9Sstevel@tonic-gate (rtm->rtm_flags & RTF_SETSRC) != 0 && 795bd670b35SErik Nordmark (ire->ire_setsrc_addr != src_addr)) { 7967c478bd9Sstevel@tonic-gate if (src_addr != INADDR_ANY) { 797bd670b35SErik Nordmark uint_t type; 798bd670b35SErik Nordmark 7997c478bd9Sstevel@tonic-gate /* 8007c478bd9Sstevel@tonic-gate * The RTF_SETSRC flag is 8017c478bd9Sstevel@tonic-gate * present, check that the 8027c478bd9Sstevel@tonic-gate * supplied src address is not 8037c478bd9Sstevel@tonic-gate * the loopback address. This 8047c478bd9Sstevel@tonic-gate * would produce martian 8057c478bd9Sstevel@tonic-gate * packets. 8067c478bd9Sstevel@tonic-gate */ 8077c478bd9Sstevel@tonic-gate if (src_addr == 8087c478bd9Sstevel@tonic-gate htonl(INADDR_LOOPBACK)) { 8097c478bd9Sstevel@tonic-gate error = EINVAL; 8107c478bd9Sstevel@tonic-gate goto done; 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate /* 813bd670b35SErik Nordmark * Also check that the 8147c478bd9Sstevel@tonic-gate * supplied addr is a valid 8157c478bd9Sstevel@tonic-gate * local address. 8167c478bd9Sstevel@tonic-gate */ 817bd670b35SErik Nordmark type = ip_type_v4(src_addr, 818bd670b35SErik Nordmark ipst); 819bd670b35SErik Nordmark if (!(type & 820bd670b35SErik Nordmark (IRE_LOCAL|IRE_LOOPBACK))) { 821bd670b35SErik Nordmark error = EADDRNOTAVAIL; 8227c478bd9Sstevel@tonic-gate goto done; 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate ire->ire_flags |= RTF_SETSRC; 825bd670b35SErik Nordmark ire->ire_setsrc_addr = 826bd670b35SErik Nordmark src_addr; 8277c478bd9Sstevel@tonic-gate } else { 8287c478bd9Sstevel@tonic-gate ire->ire_flags &= ~RTF_SETSRC; 829bd670b35SErik Nordmark ire->ire_setsrc_addr = 830bd670b35SErik Nordmark INADDR_ANY; 8317c478bd9Sstevel@tonic-gate } 832bd670b35SErik Nordmark /* 833bd670b35SErik Nordmark * Let conn_ixa caching know that 834bd670b35SErik Nordmark * source address selection changed 835bd670b35SErik Nordmark */ 836bd670b35SErik Nordmark ip_update_source_selection(ipst); 8377c478bd9Sstevel@tonic-gate } 838bd670b35SErik Nordmark ire_flush_cache_v4(ire, IRE_FLUSH_GWCHANGE); 8397c478bd9Sstevel@tonic-gate break; 8407c478bd9Sstevel@tonic-gate case AF_INET6: 8417c478bd9Sstevel@tonic-gate mutex_enter(&ire->ire_lock); 8427c478bd9Sstevel@tonic-gate if ((found_addrs & RTA_GATEWAY) != 0 && 8437c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL( 8447c478bd9Sstevel@tonic-gate &ire->ire_gateway_addr_v6, &gw_addr_v6)) { 8457c478bd9Sstevel@tonic-gate ire->ire_gateway_addr_v6 = gw_addr_v6; 8467c478bd9Sstevel@tonic-gate } 847bd670b35SErik Nordmark mutex_exit(&ire->ire_lock); 84845916cd2Sjpk 84945916cd2Sjpk if (rtsap != NULL) { 85045916cd2Sjpk ga.ga_af = AF_INET6; 851bd670b35SErik Nordmark mutex_enter(&ire->ire_lock); 85245916cd2Sjpk ga.ga_addr = ire->ire_gateway_addr_v6; 853bd670b35SErik Nordmark mutex_exit(&ire->ire_lock); 85445916cd2Sjpk 85545916cd2Sjpk gcgrp = gcgrp_lookup(&ga, B_TRUE); 85645916cd2Sjpk if (gcgrp == NULL) { 85745916cd2Sjpk error = ENOMEM; 85845916cd2Sjpk goto done; 85945916cd2Sjpk } 86045916cd2Sjpk } 86145916cd2Sjpk 8627c478bd9Sstevel@tonic-gate if ((found_addrs & RTA_SRC) != 0 && 8637c478bd9Sstevel@tonic-gate (rtm->rtm_flags & RTF_SETSRC) != 0 && 8647c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL( 865bd670b35SErik Nordmark &ire->ire_setsrc_addr_v6, &src_addr_v6)) { 8667c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED( 8677c478bd9Sstevel@tonic-gate &src_addr_v6)) { 868bd670b35SErik Nordmark uint_t type; 869bd670b35SErik Nordmark 8707c478bd9Sstevel@tonic-gate /* 8717c478bd9Sstevel@tonic-gate * The RTF_SETSRC flag is 8727c478bd9Sstevel@tonic-gate * present, check that the 8737c478bd9Sstevel@tonic-gate * supplied src address is not 8747c478bd9Sstevel@tonic-gate * the loopback address. This 8757c478bd9Sstevel@tonic-gate * would produce martian 8767c478bd9Sstevel@tonic-gate * packets. 8777c478bd9Sstevel@tonic-gate */ 8787c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_LOOPBACK( 8797c478bd9Sstevel@tonic-gate &src_addr_v6)) { 8807c478bd9Sstevel@tonic-gate error = EINVAL; 8817c478bd9Sstevel@tonic-gate goto done; 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate /* 884bd670b35SErik Nordmark * Also check that the 8857c478bd9Sstevel@tonic-gate * supplied addr is a valid 8867c478bd9Sstevel@tonic-gate * local address. 8877c478bd9Sstevel@tonic-gate */ 888bd670b35SErik Nordmark type = ip_type_v6(&src_addr_v6, 889bd670b35SErik Nordmark ipst); 890bd670b35SErik Nordmark if (!(type & 891bd670b35SErik Nordmark (IRE_LOCAL|IRE_LOOPBACK))) { 892bd670b35SErik Nordmark error = EADDRNOTAVAIL; 8937c478bd9Sstevel@tonic-gate goto done; 8947c478bd9Sstevel@tonic-gate } 895bd670b35SErik Nordmark mutex_enter(&ire->ire_lock); 8967c478bd9Sstevel@tonic-gate ire->ire_flags |= RTF_SETSRC; 897bd670b35SErik Nordmark ire->ire_setsrc_addr_v6 = 898bd670b35SErik Nordmark src_addr_v6; 8997c478bd9Sstevel@tonic-gate mutex_exit(&ire->ire_lock); 900bd670b35SErik Nordmark } else { 901bd670b35SErik Nordmark mutex_enter(&ire->ire_lock); 902bd670b35SErik Nordmark ire->ire_flags &= ~RTF_SETSRC; 903bd670b35SErik Nordmark ire->ire_setsrc_addr_v6 = 904bd670b35SErik Nordmark ipv6_all_zeros; 905bd670b35SErik Nordmark mutex_exit(&ire->ire_lock); 906bd670b35SErik Nordmark } 907bd670b35SErik Nordmark /* 908bd670b35SErik Nordmark * Let conn_ixa caching know that 909bd670b35SErik Nordmark * source address selection changed 910bd670b35SErik Nordmark */ 911bd670b35SErik Nordmark ip_update_source_selection(ipst); 912bd670b35SErik Nordmark } 913bd670b35SErik Nordmark ire_flush_cache_v6(ire, IRE_FLUSH_GWCHANGE); 9147c478bd9Sstevel@tonic-gate break; 9157c478bd9Sstevel@tonic-gate } 91645916cd2Sjpk 91745916cd2Sjpk if (rtsap != NULL) { 91845916cd2Sjpk ASSERT(gcgrp != NULL); 91945916cd2Sjpk 92045916cd2Sjpk /* 92145916cd2Sjpk * Create and add the security attribute to 92245916cd2Sjpk * prefix IRE; it will add a reference to the 92345916cd2Sjpk * group upon allocating a new entry. If it 92445916cd2Sjpk * finds an already-existing entry for the 92545916cd2Sjpk * security attribute, it simply returns it 92645916cd2Sjpk * and no new group reference is made. 92745916cd2Sjpk */ 92845916cd2Sjpk gc = gc_create(rtsap, gcgrp, &gcgrp_xtraref); 92945916cd2Sjpk if (gc == NULL || 93045916cd2Sjpk (error = tsol_ire_init_gwattr(ire, 931bd670b35SErik Nordmark ire->ire_ipversion, gc)) != 0) { 93245916cd2Sjpk if (gc != NULL) { 93345916cd2Sjpk GC_REFRELE(gc); 93445916cd2Sjpk } else { 93545916cd2Sjpk /* gc_create failed */ 93645916cd2Sjpk error = ENOMEM; 93745916cd2Sjpk } 93845916cd2Sjpk goto done; 93945916cd2Sjpk } 94045916cd2Sjpk } 9417c478bd9Sstevel@tonic-gate rts_setmetrics(ire, rtm->rtm_inits, &rtm->rtm_rmx); 9427c478bd9Sstevel@tonic-gate break; 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate break; 9457c478bd9Sstevel@tonic-gate default: 9467c478bd9Sstevel@tonic-gate error = EOPNOTSUPP; 9477c478bd9Sstevel@tonic-gate break; 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate done: 9507c478bd9Sstevel@tonic-gate if (ire != NULL) 9517c478bd9Sstevel@tonic-gate ire_refrele(ire); 952bd670b35SErik Nordmark if (ifire != NULL) 953bd670b35SErik Nordmark ire_refrele(ifire); 954bd670b35SErik Nordmark if (ill != NULL) 955bd670b35SErik Nordmark ill_refrele(ill); 9567c478bd9Sstevel@tonic-gate 95745916cd2Sjpk if (gcgrp_xtraref) 95845916cd2Sjpk GCGRP_REFRELE(gcgrp); 95945916cd2Sjpk 9607c478bd9Sstevel@tonic-gate if (rtm != NULL) { 9617c478bd9Sstevel@tonic-gate ASSERT(mp->b_wptr <= mp->b_datap->db_lim); 9627c478bd9Sstevel@tonic-gate if (error != 0) { 9637c478bd9Sstevel@tonic-gate rtm->rtm_errno = error; 9647c478bd9Sstevel@tonic-gate /* Send error ACK */ 9657c478bd9Sstevel@tonic-gate ip1dbg(("ip_rts_request: error %d\n", error)); 9667c478bd9Sstevel@tonic-gate } else { 9677c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_DONE; 9687c478bd9Sstevel@tonic-gate /* OK ACK already set up by caller except this */ 9697c478bd9Sstevel@tonic-gate ip2dbg(("ip_rts_request: OK ACK\n")); 9707c478bd9Sstevel@tonic-gate } 971e11c3f44Smeem rts_queue_input(mp, connp, af, RTSQ_ALL, ipst); 9727c478bd9Sstevel@tonic-gate } 973bd670b35SErik Nordmark return (error); 974bd670b35SErik Nordmark } 9750f1702c5SYu Xiangning 976bd670b35SErik Nordmark /* 977bd670b35SErik Nordmark * Helper function that can do recursive lookups including when 978bd670b35SErik Nordmark * MATCH_IRE_GW and/or MATCH_IRE_MASK is set. 979bd670b35SErik Nordmark */ 980bd670b35SErik Nordmark static ire_t * 981bd670b35SErik Nordmark ire_lookup_v4(ipaddr_t dst_addr, ipaddr_t net_mask, ipaddr_t gw_addr, 982bd670b35SErik Nordmark const ill_t *ill, zoneid_t zoneid, const ts_label_t *tsl, 983bd670b35SErik Nordmark int match_flags, ip_stack_t *ipst, ire_t **pifire, ipaddr_t *v4setsrcp, 984bd670b35SErik Nordmark tsol_ire_gw_secattr_t **gwattrp) 985bd670b35SErik Nordmark { 986bd670b35SErik Nordmark ire_t *ire; 987bd670b35SErik Nordmark ire_t *ifire = NULL; 988bd670b35SErik Nordmark uint_t ire_type; 989bd670b35SErik Nordmark 990bd670b35SErik Nordmark *pifire = NULL; 991bd670b35SErik Nordmark *v4setsrcp = INADDR_ANY; 992bd670b35SErik Nordmark *gwattrp = NULL; 993bd670b35SErik Nordmark 994bd670b35SErik Nordmark /* Skip IRE_IF_CLONE */ 995bd670b35SErik Nordmark match_flags |= MATCH_IRE_TYPE; 996bd670b35SErik Nordmark ire_type = (IRE_ONLINK|IRE_OFFLINK) & ~IRE_IF_CLONE; 997bd670b35SErik Nordmark 998bd670b35SErik Nordmark /* 999bd670b35SErik Nordmark * ire_route_recursive can't match gateway or mask thus if they are 1000bd670b35SErik Nordmark * set we have to do two steps of lookups 1001bd670b35SErik Nordmark */ 1002bd670b35SErik Nordmark if (match_flags & (MATCH_IRE_GW|MATCH_IRE_MASK)) { 1003bd670b35SErik Nordmark ire = ire_ftable_lookup_v4(dst_addr, net_mask, gw_addr, 1004bd670b35SErik Nordmark ire_type, ill, zoneid, tsl, match_flags, 0, ipst, NULL); 1005bd670b35SErik Nordmark 1006bd670b35SErik Nordmark if (ire == NULL ||(ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE))) 1007bd670b35SErik Nordmark return (ire); 1008bd670b35SErik Nordmark 1009bd670b35SErik Nordmark if (ire->ire_type & IRE_ONLINK) 1010bd670b35SErik Nordmark return (ire); 1011bd670b35SErik Nordmark 1012bd670b35SErik Nordmark if (ire->ire_flags & RTF_SETSRC) { 1013bd670b35SErik Nordmark ASSERT(ire->ire_setsrc_addr != INADDR_ANY); 1014bd670b35SErik Nordmark *v4setsrcp = ire->ire_setsrc_addr; 1015bd670b35SErik Nordmark v4setsrcp = NULL; 1016bd670b35SErik Nordmark } 1017bd670b35SErik Nordmark 1018bd670b35SErik Nordmark /* The first ire_gw_secattr is passed back */ 1019bd670b35SErik Nordmark if (ire->ire_gw_secattr != NULL) { 1020bd670b35SErik Nordmark *gwattrp = ire->ire_gw_secattr; 1021bd670b35SErik Nordmark gwattrp = NULL; 1022bd670b35SErik Nordmark } 1023bd670b35SErik Nordmark 1024bd670b35SErik Nordmark /* Look for an interface ire recursively based on the gateway */ 1025bd670b35SErik Nordmark dst_addr = ire->ire_gateway_addr; 1026bd670b35SErik Nordmark match_flags &= ~(MATCH_IRE_GW|MATCH_IRE_MASK); 102701685f97SSowmini Varadhan /* 102801685f97SSowmini Varadhan * Don't allow anything unusual past the first iteration. 102901685f97SSowmini Varadhan * After the first lookup, we should no longer look for 103001685f97SSowmini Varadhan * (IRE_LOCAL|IRE_LOOPBACK|IRE_BROADCAST) or RTF_INDIRECT 103101685f97SSowmini Varadhan * routes. 103201685f97SSowmini Varadhan * 103301685f97SSowmini Varadhan * In addition, after we have found a direct IRE_OFFLINK, 103401685f97SSowmini Varadhan * we should only look for interface or clone routes. 103501685f97SSowmini Varadhan */ 103601685f97SSowmini Varadhan match_flags |= MATCH_IRE_DIRECT; /* no more RTF_INDIRECTs */ 103701685f97SSowmini Varadhan 103801685f97SSowmini Varadhan if ((ire->ire_type & IRE_OFFLINK) && 103901685f97SSowmini Varadhan !(ire->ire_flags & RTF_INDIRECT)) { 104001685f97SSowmini Varadhan ire_type = IRE_IF_ALL; 104101685f97SSowmini Varadhan } else { 104201685f97SSowmini Varadhan /* 104301685f97SSowmini Varadhan * no more local, loopback, broadcast routes 104401685f97SSowmini Varadhan */ 104501685f97SSowmini Varadhan if (!(match_flags & MATCH_IRE_TYPE)) 104601685f97SSowmini Varadhan ire_type = (IRE_OFFLINK|IRE_ONLINK); 104701685f97SSowmini Varadhan ire_type &= ~(IRE_LOCAL|IRE_LOOPBACK|IRE_BROADCAST); 104801685f97SSowmini Varadhan } 104901685f97SSowmini Varadhan match_flags |= MATCH_IRE_TYPE; 105001685f97SSowmini Varadhan 1051bd670b35SErik Nordmark ifire = ire_route_recursive_v4(dst_addr, ire_type, ill, zoneid, 10529e3469d3SErik Nordmark tsl, match_flags, IRR_INCOMPLETE, 0, ipst, v4setsrcp, 10539e3469d3SErik Nordmark gwattrp, NULL); 1054bd670b35SErik Nordmark } else { 1055bd670b35SErik Nordmark ire = ire_route_recursive_v4(dst_addr, ire_type, ill, zoneid, 10569e3469d3SErik Nordmark tsl, match_flags, IRR_INCOMPLETE, 0, ipst, v4setsrcp, 10579e3469d3SErik Nordmark gwattrp, NULL); 1058bd670b35SErik Nordmark } 1059bd670b35SErik Nordmark *pifire = ifire; 1060bd670b35SErik Nordmark return (ire); 1061bd670b35SErik Nordmark } 1062bd670b35SErik Nordmark 1063bd670b35SErik Nordmark static ire_t * 1064bd670b35SErik Nordmark ire_lookup_v6(const in6_addr_t *dst_addr_v6, 1065bd670b35SErik Nordmark const in6_addr_t *net_mask_v6, const in6_addr_t *gw_addr_v6, 1066bd670b35SErik Nordmark const ill_t *ill, zoneid_t zoneid, const ts_label_t *tsl, int match_flags, 1067bd670b35SErik Nordmark ip_stack_t *ipst, ire_t **pifire, 1068bd670b35SErik Nordmark in6_addr_t *v6setsrcp, tsol_ire_gw_secattr_t **gwattrp) 1069bd670b35SErik Nordmark { 1070bd670b35SErik Nordmark ire_t *ire; 1071bd670b35SErik Nordmark ire_t *ifire = NULL; 1072bd670b35SErik Nordmark uint_t ire_type; 1073bd670b35SErik Nordmark 1074bd670b35SErik Nordmark *pifire = NULL; 1075bd670b35SErik Nordmark *v6setsrcp = ipv6_all_zeros; 1076bd670b35SErik Nordmark *gwattrp = NULL; 1077bd670b35SErik Nordmark 1078bd670b35SErik Nordmark /* Skip IRE_IF_CLONE */ 1079bd670b35SErik Nordmark match_flags |= MATCH_IRE_TYPE; 1080bd670b35SErik Nordmark ire_type = (IRE_ONLINK|IRE_OFFLINK) & ~IRE_IF_CLONE; 1081bd670b35SErik Nordmark 1082bd670b35SErik Nordmark /* 1083bd670b35SErik Nordmark * ire_route_recursive can't match gateway or mask thus if they are 1084bd670b35SErik Nordmark * set we have to do two steps of lookups 1085bd670b35SErik Nordmark */ 1086bd670b35SErik Nordmark if (match_flags & (MATCH_IRE_GW|MATCH_IRE_MASK)) { 1087bd670b35SErik Nordmark in6_addr_t dst; 1088bd670b35SErik Nordmark 1089bd670b35SErik Nordmark ire = ire_ftable_lookup_v6(dst_addr_v6, net_mask_v6, 1090bd670b35SErik Nordmark gw_addr_v6, ire_type, ill, zoneid, tsl, match_flags, 0, 1091bd670b35SErik Nordmark ipst, NULL); 1092bd670b35SErik Nordmark 1093bd670b35SErik Nordmark if (ire == NULL ||(ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE))) 1094bd670b35SErik Nordmark return (ire); 1095bd670b35SErik Nordmark 1096bd670b35SErik Nordmark if (ire->ire_type & IRE_ONLINK) 1097bd670b35SErik Nordmark return (ire); 1098bd670b35SErik Nordmark 1099bd670b35SErik Nordmark if (ire->ire_flags & RTF_SETSRC) { 1100bd670b35SErik Nordmark ASSERT(!IN6_IS_ADDR_UNSPECIFIED( 1101bd670b35SErik Nordmark &ire->ire_setsrc_addr_v6)); 1102bd670b35SErik Nordmark *v6setsrcp = ire->ire_setsrc_addr_v6; 1103bd670b35SErik Nordmark v6setsrcp = NULL; 1104bd670b35SErik Nordmark } 1105bd670b35SErik Nordmark 1106bd670b35SErik Nordmark /* The first ire_gw_secattr is passed back */ 1107bd670b35SErik Nordmark if (ire->ire_gw_secattr != NULL) { 1108bd670b35SErik Nordmark *gwattrp = ire->ire_gw_secattr; 1109bd670b35SErik Nordmark gwattrp = NULL; 1110bd670b35SErik Nordmark } 1111bd670b35SErik Nordmark 1112bd670b35SErik Nordmark mutex_enter(&ire->ire_lock); 1113bd670b35SErik Nordmark dst = ire->ire_gateway_addr_v6; 1114bd670b35SErik Nordmark mutex_exit(&ire->ire_lock); 1115bd670b35SErik Nordmark match_flags &= ~(MATCH_IRE_GW|MATCH_IRE_MASK); 111601685f97SSowmini Varadhan /* 111701685f97SSowmini Varadhan * Don't allow anything unusual past the first iteration. 111801685f97SSowmini Varadhan * After the first lookup, we should no longer look for 111901685f97SSowmini Varadhan * (IRE_LOCAL|IRE_LOOPBACK|IRE_BROADCAST) or RTF_INDIRECT 112001685f97SSowmini Varadhan * routes. 112101685f97SSowmini Varadhan * 112201685f97SSowmini Varadhan * In addition, after we have found a direct IRE_OFFLINK, 112301685f97SSowmini Varadhan * we should only look for interface or clone routes. 112401685f97SSowmini Varadhan */ 112501685f97SSowmini Varadhan match_flags |= MATCH_IRE_DIRECT; /* no more RTF_INDIRECTs */ 112601685f97SSowmini Varadhan 112701685f97SSowmini Varadhan if ((ire->ire_type & IRE_OFFLINK) && 112801685f97SSowmini Varadhan !(ire->ire_flags & RTF_INDIRECT)) { 112901685f97SSowmini Varadhan ire_type = IRE_IF_ALL; 113001685f97SSowmini Varadhan } else { 113101685f97SSowmini Varadhan /* 113201685f97SSowmini Varadhan * no more local, loopback routes 113301685f97SSowmini Varadhan */ 113401685f97SSowmini Varadhan if (!(match_flags & MATCH_IRE_TYPE)) 113501685f97SSowmini Varadhan ire_type = (IRE_OFFLINK|IRE_ONLINK); 113601685f97SSowmini Varadhan ire_type &= ~(IRE_LOCAL|IRE_LOOPBACK); 113701685f97SSowmini Varadhan } 113801685f97SSowmini Varadhan match_flags |= MATCH_IRE_TYPE; 113901685f97SSowmini Varadhan 1140bd670b35SErik Nordmark ifire = ire_route_recursive_v6(&dst, ire_type, ill, zoneid, tsl, 11419e3469d3SErik Nordmark match_flags, IRR_INCOMPLETE, 0, ipst, v6setsrcp, gwattrp, 11429e3469d3SErik Nordmark NULL); 1143bd670b35SErik Nordmark } else { 1144bd670b35SErik Nordmark ire = ire_route_recursive_v6(dst_addr_v6, ire_type, ill, zoneid, 11459e3469d3SErik Nordmark tsl, match_flags, IRR_INCOMPLETE, 0, ipst, v6setsrcp, 11469e3469d3SErik Nordmark gwattrp, NULL); 1147bd670b35SErik Nordmark } 1148bd670b35SErik Nordmark *pifire = ifire; 1149bd670b35SErik Nordmark return (ire); 1150bd670b35SErik Nordmark } 1151bd670b35SErik Nordmark 1152bd670b35SErik Nordmark 1153bd670b35SErik Nordmark /* 1154bd670b35SErik Nordmark * Handle IP_IOC_RTS_REQUEST ioctls 1155bd670b35SErik Nordmark */ 1156bd670b35SErik Nordmark int 1157bd670b35SErik Nordmark ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) 1158bd670b35SErik Nordmark { 1159bd670b35SErik Nordmark conn_t *connp = Q_TO_CONN(q); 1160bd670b35SErik Nordmark IOCP iocp = (IOCP)mp->b_rptr; 1161bd670b35SErik Nordmark mblk_t *mp1, *ioc_mp = mp; 1162bd670b35SErik Nordmark int error = 0; 1163bd670b35SErik Nordmark ip_stack_t *ipst; 1164bd670b35SErik Nordmark 1165bd670b35SErik Nordmark ipst = connp->conn_netstack->netstack_ip; 1166bd670b35SErik Nordmark 1167bd670b35SErik Nordmark ASSERT(mp->b_cont != NULL); 1168bd670b35SErik Nordmark /* ioc_mp holds mp */ 1169bd670b35SErik Nordmark mp = mp->b_cont; 1170bd670b35SErik Nordmark 1171bd670b35SErik Nordmark /* 1172bd670b35SErik Nordmark * The Routing Socket data starts on 1173bd670b35SErik Nordmark * next block. If there is no next block 1174bd670b35SErik Nordmark * this is an indication from routing module 1175bd670b35SErik Nordmark * that it is a routing socket stream queue. 1176bd670b35SErik Nordmark * We need to support that for compatibility with SDP since 1177bd670b35SErik Nordmark * it has a contract private interface to use IP_IOC_RTS_REQUEST. 1178bd670b35SErik Nordmark * Note: SDP no longer uses IP_IOC_RTS_REQUEST - we can remove this. 1179bd670b35SErik Nordmark */ 1180bd670b35SErik Nordmark if (mp->b_cont == NULL) { 1181bd670b35SErik Nordmark /* 1182bd670b35SErik Nordmark * This is a message from SDP 1183bd670b35SErik Nordmark * indicating that this is a Routing Socket 1184bd670b35SErik Nordmark * Stream. Insert this conn_t in routing 1185bd670b35SErik Nordmark * socket client list. 1186bd670b35SErik Nordmark */ 1187bd670b35SErik Nordmark connp->conn_useloopback = 1; 1188bd670b35SErik Nordmark ipcl_hash_insert_wildcard(ipst->ips_rts_clients, connp); 1189bd670b35SErik Nordmark goto done; 1190bd670b35SErik Nordmark } 1191bd670b35SErik Nordmark mp1 = dupmsg(mp->b_cont); 1192bd670b35SErik Nordmark if (mp1 == NULL) { 1193bd670b35SErik Nordmark error = ENOBUFS; 1194bd670b35SErik Nordmark goto done; 1195bd670b35SErik Nordmark } 1196bd670b35SErik Nordmark mp = mp1; 1197bd670b35SErik Nordmark 1198bd670b35SErik Nordmark error = ip_rts_request_common(mp, connp, ioc_cr); 1199bd670b35SErik Nordmark done: 12007c478bd9Sstevel@tonic-gate iocp->ioc_error = error; 12017c478bd9Sstevel@tonic-gate ioc_mp->b_datap->db_type = M_IOCACK; 12027c478bd9Sstevel@tonic-gate if (iocp->ioc_error != 0) 12037c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 1204bd670b35SErik Nordmark /* Note that we pass a NULL ira to rts_input */ 1205bd670b35SErik Nordmark (connp->conn_recv)(connp, ioc_mp, NULL, NULL); 12060f1702c5SYu Xiangning 12077c478bd9Sstevel@tonic-gate /* conn was refheld in ip_wput_ioctl. */ 1208*a5628610SRamesh Kumar Katla CONN_DEC_IOCTLREF(connp); 12097c478bd9Sstevel@tonic-gate CONN_OPER_PENDING_DONE(connp); 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate return (error); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate /* 12157c478bd9Sstevel@tonic-gate * Build a reply to the RTM_GET request contained in the given message block 12167c478bd9Sstevel@tonic-gate * using the retrieved IRE of the destination address, the parent IRE (if it 12177c478bd9Sstevel@tonic-gate * exists) and the address family. 12187c478bd9Sstevel@tonic-gate * 12197c478bd9Sstevel@tonic-gate * Returns a pointer to a message block containing the reply if successful, 12207c478bd9Sstevel@tonic-gate * otherwise NULL is returned. 12217c478bd9Sstevel@tonic-gate */ 122245916cd2Sjpk static mblk_t * 1223bd670b35SErik Nordmark rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *ifire, const in6_addr_t *setsrc, 1224bd670b35SErik Nordmark tsol_ire_gw_secattr_t *attrp, sa_family_t af) 12257c478bd9Sstevel@tonic-gate { 12267c478bd9Sstevel@tonic-gate rt_msghdr_t *rtm; 12277c478bd9Sstevel@tonic-gate rt_msghdr_t *new_rtm; 12287c478bd9Sstevel@tonic-gate mblk_t *new_mp; 12297c478bd9Sstevel@tonic-gate int rtm_addrs; 12307c478bd9Sstevel@tonic-gate int rtm_flags; 123145916cd2Sjpk tsol_gc_t *gc = NULL; 123245916cd2Sjpk tsol_gcgrp_t *gcgrp = NULL; 1233bd670b35SErik Nordmark ill_t *ill; 1234bd670b35SErik Nordmark ipif_t *ipif = NULL; 1235bd670b35SErik Nordmark ipaddr_t brdaddr; /* IFF_POINTOPOINT destination */ 1236bd670b35SErik Nordmark ipaddr_t ifaddr; 1237bd670b35SErik Nordmark in6_addr_t brdaddr6; /* IFF_POINTOPOINT destination */ 1238bd670b35SErik Nordmark in6_addr_t ifaddr6; 1239bd670b35SErik Nordmark ipaddr_t v4setsrc; 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 12427c478bd9Sstevel@tonic-gate 1243bd670b35SErik Nordmark /* 1244bd670b35SErik Nordmark * Find the ill used to send packets. This will be NULL in case 1245bd670b35SErik Nordmark * of a reject or blackhole. 1246bd670b35SErik Nordmark */ 1247bd670b35SErik Nordmark if (ifire != NULL) 1248bd670b35SErik Nordmark ill = ire_nexthop_ill(ifire); 1249bd670b35SErik Nordmark else 1250bd670b35SErik Nordmark ill = ire_nexthop_ill(ire); 125145916cd2Sjpk 125245916cd2Sjpk if (attrp != NULL) { 125345916cd2Sjpk mutex_enter(&attrp->igsa_lock); 125445916cd2Sjpk if ((gc = attrp->igsa_gc) != NULL) { 125545916cd2Sjpk gcgrp = gc->gc_grp; 125645916cd2Sjpk ASSERT(gcgrp != NULL); 125745916cd2Sjpk rw_enter(&gcgrp->gcgrp_rwlock, RW_READER); 125845916cd2Sjpk } 125945916cd2Sjpk mutex_exit(&attrp->igsa_lock); 126045916cd2Sjpk } 126145916cd2Sjpk 12627c478bd9Sstevel@tonic-gate /* 12637c478bd9Sstevel@tonic-gate * Always return RTA_DST, RTA_GATEWAY and RTA_NETMASK. 12647c478bd9Sstevel@tonic-gate * 12657c478bd9Sstevel@tonic-gate * The 4.4BSD-Lite2 code (net/rtsock.c) returns both 12667c478bd9Sstevel@tonic-gate * RTA_IFP and RTA_IFA if either is defined, and also 12677c478bd9Sstevel@tonic-gate * returns RTA_BRD if the appropriate interface is 12687c478bd9Sstevel@tonic-gate * point-to-point. 12697c478bd9Sstevel@tonic-gate */ 12707c478bd9Sstevel@tonic-gate rtm_addrs = (RTA_DST | RTA_GATEWAY | RTA_NETMASK); 1271bd670b35SErik Nordmark if ((rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) && ill != NULL) { 12727c478bd9Sstevel@tonic-gate rtm_addrs |= (RTA_IFP | RTA_IFA); 1273bd670b35SErik Nordmark /* 1274bd670b35SErik Nordmark * We associate an IRE with an ILL, hence we don't exactly 1275bd670b35SErik Nordmark * know what might make sense for RTA_IFA and RTA_BRD. We 1276bd670b35SErik Nordmark * pick the first ipif on the ill. 1277bd670b35SErik Nordmark */ 1278bd670b35SErik Nordmark ipif = ipif_get_next_ipif(NULL, ill); 1279bd670b35SErik Nordmark if (ipif != NULL) { 1280bd670b35SErik Nordmark if (ipif->ipif_isv6) 1281bd670b35SErik Nordmark ifaddr6 = ipif->ipif_v6lcl_addr; 1282bd670b35SErik Nordmark else 1283bd670b35SErik Nordmark ifaddr = ipif->ipif_lcl_addr; 1284bd670b35SErik Nordmark if (ipif->ipif_flags & IPIF_POINTOPOINT) { 12857c478bd9Sstevel@tonic-gate rtm_addrs |= RTA_BRD; 1286bd670b35SErik Nordmark if (ipif->ipif_isv6) 1287bd670b35SErik Nordmark brdaddr6 = ipif->ipif_v6pp_dst_addr; 1288bd670b35SErik Nordmark else 1289bd670b35SErik Nordmark brdaddr = ipif->ipif_pp_dst_addr; 1290bd670b35SErik Nordmark } 1291bd670b35SErik Nordmark ipif_refrele(ipif); 1292bd670b35SErik Nordmark } 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate 1295bd670b35SErik Nordmark new_mp = rts_alloc_msg(RTM_GET, rtm_addrs, af, gc != NULL ? 1 : 0); 129645916cd2Sjpk if (new_mp == NULL) { 129745916cd2Sjpk if (gcgrp != NULL) 129845916cd2Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 1299bd670b35SErik Nordmark if (ill != NULL) 1300bd670b35SErik Nordmark ill_refrele(ill); 13017c478bd9Sstevel@tonic-gate return (NULL); 130245916cd2Sjpk } 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate /* 13057c478bd9Sstevel@tonic-gate * We set the destination address, gateway address, 13067c478bd9Sstevel@tonic-gate * netmask and flags in the RTM_GET response depending 13077c478bd9Sstevel@tonic-gate * on whether we found a parent IRE or not. 13087c478bd9Sstevel@tonic-gate * In particular, if we did find a parent IRE during the 13097c478bd9Sstevel@tonic-gate * recursive search, use that IRE's gateway address. 13107c478bd9Sstevel@tonic-gate * Otherwise, we use the IRE's source address for the 13117c478bd9Sstevel@tonic-gate * gateway address. 13127c478bd9Sstevel@tonic-gate */ 13137c478bd9Sstevel@tonic-gate ASSERT(af == AF_INET || af == AF_INET6); 13147c478bd9Sstevel@tonic-gate switch (af) { 13157c478bd9Sstevel@tonic-gate case AF_INET: 1316bd670b35SErik Nordmark IN6_V4MAPPED_TO_IPADDR(setsrc, v4setsrc); 1317bd670b35SErik Nordmark if (v4setsrc != INADDR_ANY) 1318bd670b35SErik Nordmark rtm_addrs |= RTA_SRC; 1319bd670b35SErik Nordmark 13207c478bd9Sstevel@tonic-gate rtm_flags = ire->ire_flags; 13217c478bd9Sstevel@tonic-gate rts_fill_msg(RTM_GET, rtm_addrs, ire->ire_addr, 1322bd670b35SErik Nordmark ire->ire_mask, ire->ire_gateway_addr, v4setsrc, 1323bd670b35SErik Nordmark brdaddr, 0, ifaddr, ill, new_mp, gc); 13247c478bd9Sstevel@tonic-gate break; 13257c478bd9Sstevel@tonic-gate case AF_INET6: 1326bd670b35SErik Nordmark if (!IN6_IS_ADDR_UNSPECIFIED(setsrc)) 13277c478bd9Sstevel@tonic-gate rtm_addrs |= RTA_SRC; 13287c478bd9Sstevel@tonic-gate 1329bd670b35SErik Nordmark rtm_flags = ire->ire_flags; 1330bd670b35SErik Nordmark rts_fill_msg_v6(RTM_GET, rtm_addrs, &ire->ire_addr_v6, 1331bd670b35SErik Nordmark &ire->ire_mask_v6, &ire->ire_gateway_addr_v6, 1332bd670b35SErik Nordmark setsrc, &brdaddr6, &ipv6_all_zeros, 1333bd670b35SErik Nordmark &ifaddr6, ill, new_mp, gc); 13347c478bd9Sstevel@tonic-gate break; 13357c478bd9Sstevel@tonic-gate } 133645916cd2Sjpk 133745916cd2Sjpk if (gcgrp != NULL) 133845916cd2Sjpk rw_exit(&gcgrp->gcgrp_rwlock); 133945916cd2Sjpk 13407c478bd9Sstevel@tonic-gate new_rtm = (rt_msghdr_t *)new_mp->b_rptr; 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate /* 13437c478bd9Sstevel@tonic-gate * The rtm_msglen, rtm_version and rtm_type fields in 13447c478bd9Sstevel@tonic-gate * RTM_GET response are filled in by rts_fill_msg. 13457c478bd9Sstevel@tonic-gate * 13467c478bd9Sstevel@tonic-gate * rtm_addrs and rtm_flags are filled in based on what 13477c478bd9Sstevel@tonic-gate * was requested and the state of the IREs looked up 13487c478bd9Sstevel@tonic-gate * above. 13497c478bd9Sstevel@tonic-gate * 13507c478bd9Sstevel@tonic-gate * rtm_inits and rtm_rmx are filled in with metrics 13517c478bd9Sstevel@tonic-gate * based on whether a parent IRE was found or not. 13527c478bd9Sstevel@tonic-gate * 13537c478bd9Sstevel@tonic-gate * TODO: rtm_index and rtm_use should probably be 13547c478bd9Sstevel@tonic-gate * filled in with something resonable here and not just 13557c478bd9Sstevel@tonic-gate * copied from the request. 13567c478bd9Sstevel@tonic-gate */ 13577c478bd9Sstevel@tonic-gate new_rtm->rtm_index = rtm->rtm_index; 13587c478bd9Sstevel@tonic-gate new_rtm->rtm_pid = rtm->rtm_pid; 13597c478bd9Sstevel@tonic-gate new_rtm->rtm_seq = rtm->rtm_seq; 13607c478bd9Sstevel@tonic-gate new_rtm->rtm_use = rtm->rtm_use; 13617c478bd9Sstevel@tonic-gate new_rtm->rtm_addrs = rtm_addrs; 13627c478bd9Sstevel@tonic-gate new_rtm->rtm_flags = rtm_flags; 13639e3469d3SErik Nordmark new_rtm->rtm_inits = rts_getmetrics(ire, ill, &new_rtm->rtm_rmx); 1364bd670b35SErik Nordmark if (ill != NULL) 1365bd670b35SErik Nordmark ill_refrele(ill); 13667c478bd9Sstevel@tonic-gate return (new_mp); 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate /* 13707c478bd9Sstevel@tonic-gate * Fill the given if_data_t with interface statistics. 13717c478bd9Sstevel@tonic-gate */ 13727c478bd9Sstevel@tonic-gate static void 137345916cd2Sjpk rts_getifdata(if_data_t *if_data, const ipif_t *ipif) 13747c478bd9Sstevel@tonic-gate { 1375bd670b35SErik Nordmark if_data->ifi_type = ipif->ipif_ill->ill_type; 1376bd670b35SErik Nordmark /* ethernet, tokenring, etc */ 13777c478bd9Sstevel@tonic-gate if_data->ifi_addrlen = 0; /* media address length */ 13787c478bd9Sstevel@tonic-gate if_data->ifi_hdrlen = 0; /* media header length */ 1379bd670b35SErik Nordmark if_data->ifi_mtu = ipif->ipif_ill->ill_mtu; /* mtu */ 13806e91bba0SGirish Moodalbail /* metric (external only) */ 13816e91bba0SGirish Moodalbail if_data->ifi_metric = ipif->ipif_ill->ill_metric; 13827c478bd9Sstevel@tonic-gate if_data->ifi_baudrate = 0; /* linespeed */ 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate if_data->ifi_ipackets = 0; /* packets received on if */ 13857c478bd9Sstevel@tonic-gate if_data->ifi_ierrors = 0; /* input errors on interface */ 13867c478bd9Sstevel@tonic-gate if_data->ifi_opackets = 0; /* packets sent on interface */ 13877c478bd9Sstevel@tonic-gate if_data->ifi_oerrors = 0; /* output errors on if */ 13887c478bd9Sstevel@tonic-gate if_data->ifi_collisions = 0; /* collisions on csma if */ 13897c478bd9Sstevel@tonic-gate if_data->ifi_ibytes = 0; /* total number received */ 13907c478bd9Sstevel@tonic-gate if_data->ifi_obytes = 0; /* total number sent */ 13917c478bd9Sstevel@tonic-gate if_data->ifi_imcasts = 0; /* multicast packets received */ 13927c478bd9Sstevel@tonic-gate if_data->ifi_omcasts = 0; /* multicast packets sent */ 13937c478bd9Sstevel@tonic-gate if_data->ifi_iqdrops = 0; /* dropped on input */ 13947c478bd9Sstevel@tonic-gate if_data->ifi_noproto = 0; /* destined for unsupported */ 13957c478bd9Sstevel@tonic-gate /* protocol. */ 13967c478bd9Sstevel@tonic-gate } 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate /* 13997c478bd9Sstevel@tonic-gate * Set the metrics on a forwarding table route. 14007c478bd9Sstevel@tonic-gate */ 14017c478bd9Sstevel@tonic-gate static void 14027c478bd9Sstevel@tonic-gate rts_setmetrics(ire_t *ire, uint_t which, rt_metrics_t *metrics) 14037c478bd9Sstevel@tonic-gate { 14047c478bd9Sstevel@tonic-gate clock_t rtt; 14057c478bd9Sstevel@tonic-gate clock_t rtt_sd; 1406bd670b35SErik Nordmark ill_t *ill; 14077c478bd9Sstevel@tonic-gate ifrt_t *ifrt; 14087c478bd9Sstevel@tonic-gate mblk_t *mp; 14097c478bd9Sstevel@tonic-gate in6_addr_t gw_addr_v6; 14107c478bd9Sstevel@tonic-gate 1411bd670b35SErik Nordmark /* Need to add back some metrics to the IRE? */ 14127c478bd9Sstevel@tonic-gate /* 1413bd670b35SErik Nordmark * Bypass obtaining the lock and searching ill_saved_ire_mp in the 14147c478bd9Sstevel@tonic-gate * common case of no metrics. 14157c478bd9Sstevel@tonic-gate */ 14167c478bd9Sstevel@tonic-gate if (which == 0) 14177c478bd9Sstevel@tonic-gate return; 1418bd670b35SErik Nordmark ire->ire_metrics.iulp_set = B_TRUE; 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate /* 14217c478bd9Sstevel@tonic-gate * iulp_rtt and iulp_rtt_sd are in milliseconds, but 4.4BSD-Lite2's 14227c478bd9Sstevel@tonic-gate * <net/route.h> says: rmx_rtt and rmx_rttvar are stored as 14237c478bd9Sstevel@tonic-gate * microseconds. 14247c478bd9Sstevel@tonic-gate */ 14257c478bd9Sstevel@tonic-gate if (which & RTV_RTT) 14267c478bd9Sstevel@tonic-gate rtt = metrics->rmx_rtt / 1000; 14277c478bd9Sstevel@tonic-gate if (which & RTV_RTTVAR) 14287c478bd9Sstevel@tonic-gate rtt_sd = metrics->rmx_rttvar / 1000; 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate /* 14317c478bd9Sstevel@tonic-gate * Update the metrics in the IRE itself. 14327c478bd9Sstevel@tonic-gate */ 14337c478bd9Sstevel@tonic-gate mutex_enter(&ire->ire_lock); 14347c478bd9Sstevel@tonic-gate if (which & RTV_MTU) 1435bd670b35SErik Nordmark ire->ire_metrics.iulp_mtu = metrics->rmx_mtu; 14367c478bd9Sstevel@tonic-gate if (which & RTV_RTT) 1437bd670b35SErik Nordmark ire->ire_metrics.iulp_rtt = rtt; 14387c478bd9Sstevel@tonic-gate if (which & RTV_SSTHRESH) 1439bd670b35SErik Nordmark ire->ire_metrics.iulp_ssthresh = metrics->rmx_ssthresh; 14407c478bd9Sstevel@tonic-gate if (which & RTV_RTTVAR) 1441bd670b35SErik Nordmark ire->ire_metrics.iulp_rtt_sd = rtt_sd; 14427c478bd9Sstevel@tonic-gate if (which & RTV_SPIPE) 1443bd670b35SErik Nordmark ire->ire_metrics.iulp_spipe = metrics->rmx_sendpipe; 14447c478bd9Sstevel@tonic-gate if (which & RTV_RPIPE) 1445bd670b35SErik Nordmark ire->ire_metrics.iulp_rpipe = metrics->rmx_recvpipe; 14467c478bd9Sstevel@tonic-gate mutex_exit(&ire->ire_lock); 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate /* 1449bd670b35SErik Nordmark * Search through the ifrt_t chain hanging off the ILL in order to 14507c478bd9Sstevel@tonic-gate * reflect the metric change there. 14517c478bd9Sstevel@tonic-gate */ 1452bd670b35SErik Nordmark ill = ire->ire_ill; 1453bd670b35SErik Nordmark if (ill == NULL) 14547c478bd9Sstevel@tonic-gate return; 1455bd670b35SErik Nordmark ASSERT((ill->ill_isv6 && ire->ire_ipversion == IPV6_VERSION) || 1456bd670b35SErik Nordmark ((!ill->ill_isv6 && ire->ire_ipversion == IPV4_VERSION))); 1457bd670b35SErik Nordmark if (ill->ill_isv6) { 14587c478bd9Sstevel@tonic-gate mutex_enter(&ire->ire_lock); 14597c478bd9Sstevel@tonic-gate gw_addr_v6 = ire->ire_gateway_addr_v6; 14607c478bd9Sstevel@tonic-gate mutex_exit(&ire->ire_lock); 14617c478bd9Sstevel@tonic-gate } 1462bd670b35SErik Nordmark mutex_enter(&ill->ill_saved_ire_lock); 1463bd670b35SErik Nordmark for (mp = ill->ill_saved_ire_mp; mp != NULL; mp = mp->b_cont) { 14647c478bd9Sstevel@tonic-gate /* 1465bd670b35SErik Nordmark * On a given ill, the tuple of address, gateway, mask, 1466bd670b35SErik Nordmark * ire_type and zoneid unique for each saved IRE. 14677c478bd9Sstevel@tonic-gate */ 14687c478bd9Sstevel@tonic-gate ifrt = (ifrt_t *)mp->b_rptr; 1469bd670b35SErik Nordmark if (ill->ill_isv6) { 14707c478bd9Sstevel@tonic-gate if (!IN6_ARE_ADDR_EQUAL(&ifrt->ifrt_v6addr, 14717c478bd9Sstevel@tonic-gate &ire->ire_addr_v6) || 14727c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(&ifrt->ifrt_v6gateway_addr, 14737c478bd9Sstevel@tonic-gate &gw_addr_v6) || 14747c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(&ifrt->ifrt_v6mask, 14757c478bd9Sstevel@tonic-gate &ire->ire_mask_v6)) 14767c478bd9Sstevel@tonic-gate continue; 14777c478bd9Sstevel@tonic-gate } else { 14787c478bd9Sstevel@tonic-gate if (ifrt->ifrt_addr != ire->ire_addr || 14797c478bd9Sstevel@tonic-gate ifrt->ifrt_gateway_addr != ire->ire_gateway_addr || 14807c478bd9Sstevel@tonic-gate ifrt->ifrt_mask != ire->ire_mask) 14817c478bd9Sstevel@tonic-gate continue; 14827c478bd9Sstevel@tonic-gate } 1483bd670b35SErik Nordmark if (ifrt->ifrt_zoneid != ire->ire_zoneid || 1484bd670b35SErik Nordmark ifrt->ifrt_type != ire->ire_type) 1485bd670b35SErik Nordmark continue; 1486bd670b35SErik Nordmark 14877c478bd9Sstevel@tonic-gate if (which & RTV_MTU) 1488bd670b35SErik Nordmark ifrt->ifrt_metrics.iulp_mtu = metrics->rmx_mtu; 14897c478bd9Sstevel@tonic-gate if (which & RTV_RTT) 1490bd670b35SErik Nordmark ifrt->ifrt_metrics.iulp_rtt = rtt; 14917c478bd9Sstevel@tonic-gate if (which & RTV_SSTHRESH) { 1492bd670b35SErik Nordmark ifrt->ifrt_metrics.iulp_ssthresh = 14937c478bd9Sstevel@tonic-gate metrics->rmx_ssthresh; 14947c478bd9Sstevel@tonic-gate } 14957c478bd9Sstevel@tonic-gate if (which & RTV_RTTVAR) 1496bd670b35SErik Nordmark ifrt->ifrt_metrics.iulp_rtt_sd = metrics->rmx_rttvar; 14977c478bd9Sstevel@tonic-gate if (which & RTV_SPIPE) 1498bd670b35SErik Nordmark ifrt->ifrt_metrics.iulp_spipe = metrics->rmx_sendpipe; 14997c478bd9Sstevel@tonic-gate if (which & RTV_RPIPE) 1500bd670b35SErik Nordmark ifrt->ifrt_metrics.iulp_rpipe = metrics->rmx_recvpipe; 15017c478bd9Sstevel@tonic-gate break; 15027c478bd9Sstevel@tonic-gate } 1503bd670b35SErik Nordmark mutex_exit(&ill->ill_saved_ire_lock); 1504bd670b35SErik Nordmark 1505bd670b35SErik Nordmark /* 1506bd670b35SErik Nordmark * Update any IRE_IF_CLONE hanging created from this IRE_IF so they 1507bd670b35SErik Nordmark * get any new iulp_mtu. 1508bd670b35SErik Nordmark * We do that by deleting them; ire_create_if_clone will pick 1509bd670b35SErik Nordmark * up the new metrics. 1510bd670b35SErik Nordmark */ 1511bd670b35SErik Nordmark if ((ire->ire_type & IRE_INTERFACE) && ire->ire_dep_children != 0) 1512bd670b35SErik Nordmark ire_dep_delete_if_clone(ire); 15137c478bd9Sstevel@tonic-gate } 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate /* 15167c478bd9Sstevel@tonic-gate * Get the metrics from a forwarding table route. 15177c478bd9Sstevel@tonic-gate */ 15187c478bd9Sstevel@tonic-gate static int 15199e3469d3SErik Nordmark rts_getmetrics(ire_t *ire, ill_t *ill, rt_metrics_t *metrics) 15207c478bd9Sstevel@tonic-gate { 15217c478bd9Sstevel@tonic-gate int metrics_set = 0; 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate bzero(metrics, sizeof (rt_metrics_t)); 1524bd670b35SErik Nordmark 15257c478bd9Sstevel@tonic-gate /* 15267c478bd9Sstevel@tonic-gate * iulp_rtt and iulp_rtt_sd are in milliseconds, but 4.4BSD-Lite2's 15277c478bd9Sstevel@tonic-gate * <net/route.h> says: rmx_rtt and rmx_rttvar are stored as 15287c478bd9Sstevel@tonic-gate * microseconds. 15297c478bd9Sstevel@tonic-gate */ 1530bd670b35SErik Nordmark metrics->rmx_rtt = ire->ire_metrics.iulp_rtt * 1000; 15317c478bd9Sstevel@tonic-gate metrics_set |= RTV_RTT; 15329e3469d3SErik Nordmark if (ire->ire_metrics.iulp_mtu != 0) { 1533bd670b35SErik Nordmark metrics->rmx_mtu = ire->ire_metrics.iulp_mtu; 15347c478bd9Sstevel@tonic-gate metrics_set |= RTV_MTU; 15359e3469d3SErik Nordmark } else if (ill != NULL) { 15369e3469d3SErik Nordmark metrics->rmx_mtu = ill->ill_mtu; 15379e3469d3SErik Nordmark metrics_set |= RTV_MTU; 15389e3469d3SErik Nordmark } 1539bd670b35SErik Nordmark metrics->rmx_ssthresh = ire->ire_metrics.iulp_ssthresh; 15407c478bd9Sstevel@tonic-gate metrics_set |= RTV_SSTHRESH; 1541bd670b35SErik Nordmark metrics->rmx_rttvar = ire->ire_metrics.iulp_rtt_sd * 1000; 15427c478bd9Sstevel@tonic-gate metrics_set |= RTV_RTTVAR; 1543bd670b35SErik Nordmark metrics->rmx_sendpipe = ire->ire_metrics.iulp_spipe; 15447c478bd9Sstevel@tonic-gate metrics_set |= RTV_SPIPE; 1545bd670b35SErik Nordmark metrics->rmx_recvpipe = ire->ire_metrics.iulp_rpipe; 15467c478bd9Sstevel@tonic-gate metrics_set |= RTV_RPIPE; 15477c478bd9Sstevel@tonic-gate return (metrics_set); 15487c478bd9Sstevel@tonic-gate } 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate /* 1551bd670b35SErik Nordmark * Given two sets of metrics (src and dst), use the dst values if they are 1552bd670b35SErik Nordmark * set. If a dst value is not set but the src value is set, then we use 1553bd670b35SErik Nordmark * the src value. 1554bd670b35SErik Nordmark * dst is updated with the new values. 1555bd670b35SErik Nordmark * This is used to merge information from a dce_t and ire_metrics, where the 1556bd670b35SErik Nordmark * dce values takes precedence. 1557bd670b35SErik Nordmark */ 1558bd670b35SErik Nordmark void 1559bd670b35SErik Nordmark rts_merge_metrics(iulp_t *dst, const iulp_t *src) 1560bd670b35SErik Nordmark { 1561bd670b35SErik Nordmark if (!src->iulp_set) 1562bd670b35SErik Nordmark return; 1563bd670b35SErik Nordmark 1564bd670b35SErik Nordmark if (dst->iulp_ssthresh == 0) 1565bd670b35SErik Nordmark dst->iulp_ssthresh = src->iulp_ssthresh; 1566bd670b35SErik Nordmark if (dst->iulp_rtt == 0) 1567bd670b35SErik Nordmark dst->iulp_rtt = src->iulp_rtt; 1568bd670b35SErik Nordmark if (dst->iulp_rtt_sd == 0) 1569bd670b35SErik Nordmark dst->iulp_rtt_sd = src->iulp_rtt_sd; 1570bd670b35SErik Nordmark if (dst->iulp_spipe == 0) 1571bd670b35SErik Nordmark dst->iulp_spipe = src->iulp_spipe; 1572bd670b35SErik Nordmark if (dst->iulp_rpipe == 0) 1573bd670b35SErik Nordmark dst->iulp_rpipe = src->iulp_rpipe; 1574bd670b35SErik Nordmark if (dst->iulp_rtomax == 0) 1575bd670b35SErik Nordmark dst->iulp_rtomax = src->iulp_rtomax; 1576bd670b35SErik Nordmark if (dst->iulp_sack == 0) 1577bd670b35SErik Nordmark dst->iulp_sack = src->iulp_sack; 1578bd670b35SErik Nordmark if (dst->iulp_tstamp_ok == 0) 1579bd670b35SErik Nordmark dst->iulp_tstamp_ok = src->iulp_tstamp_ok; 1580bd670b35SErik Nordmark if (dst->iulp_wscale_ok == 0) 1581bd670b35SErik Nordmark dst->iulp_wscale_ok = src->iulp_wscale_ok; 1582bd670b35SErik Nordmark if (dst->iulp_ecn_ok == 0) 1583bd670b35SErik Nordmark dst->iulp_ecn_ok = src->iulp_ecn_ok; 1584bd670b35SErik Nordmark if (dst->iulp_pmtud_ok == 0) 1585bd670b35SErik Nordmark dst->iulp_pmtud_ok = src->iulp_pmtud_ok; 1586bd670b35SErik Nordmark if (dst->iulp_mtu == 0) 1587bd670b35SErik Nordmark dst->iulp_mtu = src->iulp_mtu; 1588bd670b35SErik Nordmark } 1589bd670b35SErik Nordmark 1590bd670b35SErik Nordmark 1591bd670b35SErik Nordmark /* 15927c478bd9Sstevel@tonic-gate * Takes a pointer to a routing message and extracts necessary info by looking 15937c478bd9Sstevel@tonic-gate * at the rtm->rtm_addrs bits and store the requested sockaddrs in the pointers 15947c478bd9Sstevel@tonic-gate * passed (all of which must be valid). 15957c478bd9Sstevel@tonic-gate * 15967c478bd9Sstevel@tonic-gate * The bitmask of sockaddrs actually found in the message is returned, or zero 15977c478bd9Sstevel@tonic-gate * is returned in the case of an error. 15987c478bd9Sstevel@tonic-gate */ 15997c478bd9Sstevel@tonic-gate static int 16007c478bd9Sstevel@tonic-gate rts_getaddrs(rt_msghdr_t *rtm, in6_addr_t *dst_addrp, in6_addr_t *gw_addrp, 16017c478bd9Sstevel@tonic-gate in6_addr_t *net_maskp, in6_addr_t *authorp, in6_addr_t *if_addrp, 16025c0b7edeSseb in6_addr_t *in_src_addrp, ushort_t *indexp, sa_family_t *afp, 16035c0b7edeSseb tsol_rtsecattr_t *rtsecattr, int *error) 16047c478bd9Sstevel@tonic-gate { 16057c478bd9Sstevel@tonic-gate struct sockaddr *sa; 16067c478bd9Sstevel@tonic-gate int i; 16077c478bd9Sstevel@tonic-gate int addr_bits; 16087c478bd9Sstevel@tonic-gate int length; 16097c478bd9Sstevel@tonic-gate int found_addrs = 0; 16107c478bd9Sstevel@tonic-gate caddr_t cp; 16117c478bd9Sstevel@tonic-gate size_t size; 16127c478bd9Sstevel@tonic-gate struct sockaddr_dl *sdl; 16137c478bd9Sstevel@tonic-gate 16147c478bd9Sstevel@tonic-gate *dst_addrp = ipv6_all_zeros; 16157c478bd9Sstevel@tonic-gate *gw_addrp = ipv6_all_zeros; 16167c478bd9Sstevel@tonic-gate *net_maskp = ipv6_all_zeros; 16177c478bd9Sstevel@tonic-gate *authorp = ipv6_all_zeros; 16187c478bd9Sstevel@tonic-gate *if_addrp = ipv6_all_zeros; 16197c478bd9Sstevel@tonic-gate *in_src_addrp = ipv6_all_zeros; 16207c478bd9Sstevel@tonic-gate *indexp = 0; 16217c478bd9Sstevel@tonic-gate *afp = AF_UNSPEC; 162245916cd2Sjpk rtsecattr->rtsa_cnt = 0; 162345916cd2Sjpk *error = 0; 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate /* 16267c478bd9Sstevel@tonic-gate * At present we handle only RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_IFP, 16277c478bd9Sstevel@tonic-gate * RTA_IFA and RTA_AUTHOR. The rest will be added as we need them. 16287c478bd9Sstevel@tonic-gate */ 16297c478bd9Sstevel@tonic-gate cp = (caddr_t)&rtm[1]; 16307c478bd9Sstevel@tonic-gate length = rtm->rtm_msglen; 16317c478bd9Sstevel@tonic-gate for (i = 0; (i < RTA_NUMBITS) && ((cp - (caddr_t)rtm) < length); i++) { 16327c478bd9Sstevel@tonic-gate /* 16337c478bd9Sstevel@tonic-gate * The address family we are working with starts out as 16347c478bd9Sstevel@tonic-gate * AF_UNSPEC, but is set to the one specified with the 16357c478bd9Sstevel@tonic-gate * destination address. 16367c478bd9Sstevel@tonic-gate * 16377c478bd9Sstevel@tonic-gate * If the "working" address family that has been set to 16387c478bd9Sstevel@tonic-gate * something other than AF_UNSPEC, then the address family of 16397c478bd9Sstevel@tonic-gate * subsequent sockaddrs must either be AF_UNSPEC (for 16407c478bd9Sstevel@tonic-gate * compatibility with older programs) or must be the same as our 16417c478bd9Sstevel@tonic-gate * "working" one. 16427c478bd9Sstevel@tonic-gate * 16437c478bd9Sstevel@tonic-gate * This code assumes that RTA_DST (1) comes first in the loop. 16447c478bd9Sstevel@tonic-gate */ 16457c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 16467c478bd9Sstevel@tonic-gate addr_bits = (rtm->rtm_addrs & (1 << i)); 16477c478bd9Sstevel@tonic-gate if (addr_bits == 0) 16487c478bd9Sstevel@tonic-gate continue; 16497c478bd9Sstevel@tonic-gate switch (addr_bits) { 16507c478bd9Sstevel@tonic-gate case RTA_DST: 16517c478bd9Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, dst_addrp); 16527c478bd9Sstevel@tonic-gate *afp = sa->sa_family; 16537c478bd9Sstevel@tonic-gate break; 16547c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 16557c478bd9Sstevel@tonic-gate if (sa->sa_family != *afp && sa->sa_family != AF_UNSPEC) 16567c478bd9Sstevel@tonic-gate return (0); 16577c478bd9Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, gw_addrp); 16587c478bd9Sstevel@tonic-gate break; 16597c478bd9Sstevel@tonic-gate case RTA_NETMASK: 16607c478bd9Sstevel@tonic-gate if (sa->sa_family != *afp && sa->sa_family != AF_UNSPEC) 16617c478bd9Sstevel@tonic-gate return (0); 16627c478bd9Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, net_maskp); 16637c478bd9Sstevel@tonic-gate break; 16647c478bd9Sstevel@tonic-gate case RTA_IFP: 16657c478bd9Sstevel@tonic-gate if (sa->sa_family != AF_LINK && 16667c478bd9Sstevel@tonic-gate sa->sa_family != AF_UNSPEC) 16677c478bd9Sstevel@tonic-gate return (0); 16687c478bd9Sstevel@tonic-gate sdl = (struct sockaddr_dl *)cp; 16697c478bd9Sstevel@tonic-gate *indexp = sdl->sdl_index; 16707c478bd9Sstevel@tonic-gate size = sizeof (struct sockaddr_dl); 16717c478bd9Sstevel@tonic-gate break; 16727c478bd9Sstevel@tonic-gate case RTA_SRC: 16737c478bd9Sstevel@tonic-gate /* Source address of the incoming packet */ 16747c478bd9Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, in_src_addrp); 16757c478bd9Sstevel@tonic-gate *afp = sa->sa_family; 16767c478bd9Sstevel@tonic-gate break; 16777c478bd9Sstevel@tonic-gate case RTA_IFA: 16787c478bd9Sstevel@tonic-gate if (sa->sa_family != *afp && sa->sa_family != AF_UNSPEC) 16797c478bd9Sstevel@tonic-gate return (0); 16807c478bd9Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, if_addrp); 16817c478bd9Sstevel@tonic-gate break; 16827c478bd9Sstevel@tonic-gate case RTA_AUTHOR: 16837c478bd9Sstevel@tonic-gate if (sa->sa_family != *afp && sa->sa_family != AF_UNSPEC) 16847c478bd9Sstevel@tonic-gate return (0); 16857c478bd9Sstevel@tonic-gate size = rts_copyfromsockaddr(sa, authorp); 16867c478bd9Sstevel@tonic-gate break; 16877c478bd9Sstevel@tonic-gate default: 16887c478bd9Sstevel@tonic-gate return (0); 16897c478bd9Sstevel@tonic-gate } 16907c478bd9Sstevel@tonic-gate if (size == 0) 16917c478bd9Sstevel@tonic-gate return (0); 16927c478bd9Sstevel@tonic-gate cp += size; 16937c478bd9Sstevel@tonic-gate found_addrs |= addr_bits; 16947c478bd9Sstevel@tonic-gate } 169545916cd2Sjpk 169645916cd2Sjpk /* 169745916cd2Sjpk * Parse the routing message and look for any security- 169845916cd2Sjpk * related attributes for the route. For each valid 169945916cd2Sjpk * attribute, allocate/obtain the corresponding kernel 170045916cd2Sjpk * route security attributes. 170145916cd2Sjpk */ 17026323a21dSVijay HN if (((cp - (caddr_t)rtm) < length) && is_system_labeled()) { 170345916cd2Sjpk *error = tsol_rtsa_init(rtm, rtsecattr, cp); 170445916cd2Sjpk ASSERT(rtsecattr->rtsa_cnt <= TSOL_RTSA_REQUEST_MAX); 17056323a21dSVijay HN } 170645916cd2Sjpk 17077c478bd9Sstevel@tonic-gate return (found_addrs); 17087c478bd9Sstevel@tonic-gate } 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate /* 17117c478bd9Sstevel@tonic-gate * Fills the message with the given info. 17127c478bd9Sstevel@tonic-gate */ 17137c478bd9Sstevel@tonic-gate static void 17147c478bd9Sstevel@tonic-gate rts_fill_msg(int type, int rtm_addrs, ipaddr_t dst, ipaddr_t mask, 17157c478bd9Sstevel@tonic-gate ipaddr_t gateway, ipaddr_t src_addr, ipaddr_t brd_addr, ipaddr_t author, 1716bd670b35SErik Nordmark ipaddr_t ifaddr, const ill_t *ill, mblk_t *mp, 1717bd670b35SErik Nordmark const tsol_gc_t *gc) 17187c478bd9Sstevel@tonic-gate { 17197c478bd9Sstevel@tonic-gate rt_msghdr_t *rtm; 17207c478bd9Sstevel@tonic-gate sin_t *sin; 17217c478bd9Sstevel@tonic-gate size_t data_size, header_size; 17227c478bd9Sstevel@tonic-gate uchar_t *cp; 17237c478bd9Sstevel@tonic-gate int i; 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 17267c478bd9Sstevel@tonic-gate /* 17277c478bd9Sstevel@tonic-gate * First find the type of the message 17287c478bd9Sstevel@tonic-gate * and its length. 17297c478bd9Sstevel@tonic-gate */ 17307c478bd9Sstevel@tonic-gate header_size = rts_header_msg_size(type); 17317c478bd9Sstevel@tonic-gate /* 17327c478bd9Sstevel@tonic-gate * Now find the size of the data 17337c478bd9Sstevel@tonic-gate * that follows the message header. 17347c478bd9Sstevel@tonic-gate */ 1735bd670b35SErik Nordmark data_size = rts_data_msg_size(rtm_addrs, AF_INET, gc != NULL ? 1 : 0); 17367c478bd9Sstevel@tonic-gate 17377c478bd9Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 17387c478bd9Sstevel@tonic-gate mp->b_wptr = &mp->b_rptr[header_size]; 17397c478bd9Sstevel@tonic-gate cp = mp->b_wptr; 17407c478bd9Sstevel@tonic-gate bzero(cp, data_size); 17417c478bd9Sstevel@tonic-gate for (i = 0; i < RTA_NUMBITS; i++) { 17427c478bd9Sstevel@tonic-gate sin = (sin_t *)cp; 17437c478bd9Sstevel@tonic-gate switch (rtm_addrs & (1 << i)) { 17447c478bd9Sstevel@tonic-gate case RTA_DST: 17457c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = dst; 17467c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 17477c478bd9Sstevel@tonic-gate cp += sizeof (sin_t); 17487c478bd9Sstevel@tonic-gate break; 17497c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 17507c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = gateway; 17517c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 17527c478bd9Sstevel@tonic-gate cp += sizeof (sin_t); 17537c478bd9Sstevel@tonic-gate break; 17547c478bd9Sstevel@tonic-gate case RTA_NETMASK: 17557c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = mask; 17567c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 17577c478bd9Sstevel@tonic-gate cp += sizeof (sin_t); 17587c478bd9Sstevel@tonic-gate break; 17597c478bd9Sstevel@tonic-gate case RTA_IFP: 1760bd670b35SErik Nordmark cp += ill_dls_info((struct sockaddr_dl *)cp, ill); 17617c478bd9Sstevel@tonic-gate break; 17627c478bd9Sstevel@tonic-gate case RTA_IFA: 1763bd670b35SErik Nordmark sin->sin_addr.s_addr = ifaddr; 1764bd670b35SErik Nordmark sin->sin_family = AF_INET; 1765bd670b35SErik Nordmark cp += sizeof (sin_t); 1766bd670b35SErik Nordmark break; 17677c478bd9Sstevel@tonic-gate case RTA_SRC: 17687c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = src_addr; 17697c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 17707c478bd9Sstevel@tonic-gate cp += sizeof (sin_t); 17717c478bd9Sstevel@tonic-gate break; 17727c478bd9Sstevel@tonic-gate case RTA_AUTHOR: 17737c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = author; 17747c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 17757c478bd9Sstevel@tonic-gate cp += sizeof (sin_t); 17767c478bd9Sstevel@tonic-gate break; 17777c478bd9Sstevel@tonic-gate case RTA_BRD: 17787c478bd9Sstevel@tonic-gate /* 17797c478bd9Sstevel@tonic-gate * RTA_BRD is used typically to specify a point-to-point 17807c478bd9Sstevel@tonic-gate * destination address. 17817c478bd9Sstevel@tonic-gate */ 17827c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = brd_addr; 17837c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 17847c478bd9Sstevel@tonic-gate cp += sizeof (sin_t); 17857c478bd9Sstevel@tonic-gate break; 17867c478bd9Sstevel@tonic-gate } 17877c478bd9Sstevel@tonic-gate } 178845916cd2Sjpk 178945916cd2Sjpk if (gc != NULL) { 179045916cd2Sjpk rtm_ext_t *rtm_ext; 179145916cd2Sjpk struct rtsa_s *rp_dst; 179245916cd2Sjpk tsol_rtsecattr_t *rsap; 179345916cd2Sjpk 179445916cd2Sjpk ASSERT(gc->gc_grp != NULL); 179545916cd2Sjpk ASSERT(RW_LOCK_HELD(&gc->gc_grp->gcgrp_rwlock)); 179645916cd2Sjpk 179745916cd2Sjpk rtm_ext = (rtm_ext_t *)cp; 179845916cd2Sjpk rtm_ext->rtmex_type = RTMEX_GATEWAY_SECATTR; 1799bd670b35SErik Nordmark rtm_ext->rtmex_len = TSOL_RTSECATTR_SIZE(1); 180045916cd2Sjpk 180145916cd2Sjpk rsap = (tsol_rtsecattr_t *)(rtm_ext + 1); 1802bd670b35SErik Nordmark rsap->rtsa_cnt = 1; 180345916cd2Sjpk rp_dst = rsap->rtsa_attr; 180445916cd2Sjpk 180545916cd2Sjpk ASSERT(gc->gc_db != NULL); 180645916cd2Sjpk bcopy(&gc->gc_db->gcdb_attr, rp_dst, sizeof (*rp_dst)); 180745916cd2Sjpk cp = (uchar_t *)rp_dst; 180845916cd2Sjpk } 180945916cd2Sjpk 18107c478bd9Sstevel@tonic-gate mp->b_wptr = cp; 18117c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 18127c478bd9Sstevel@tonic-gate /* 18137c478bd9Sstevel@tonic-gate * set the fields that are common to 18147c478bd9Sstevel@tonic-gate * to different messages. 18157c478bd9Sstevel@tonic-gate */ 18167c478bd9Sstevel@tonic-gate rtm->rtm_msglen = (short)(header_size + data_size); 18177c478bd9Sstevel@tonic-gate rtm->rtm_version = RTM_VERSION; 18187c478bd9Sstevel@tonic-gate rtm->rtm_type = (uchar_t)type; 18197c478bd9Sstevel@tonic-gate } 18207c478bd9Sstevel@tonic-gate 18217c478bd9Sstevel@tonic-gate /* 18227c478bd9Sstevel@tonic-gate * Allocates and initializes a routing socket message. 1823bd670b35SErik Nordmark * Note that sacnt is either zero or one. 18247c478bd9Sstevel@tonic-gate */ 18257c478bd9Sstevel@tonic-gate mblk_t * 182645916cd2Sjpk rts_alloc_msg(int type, int rtm_addrs, sa_family_t af, uint_t sacnt) 18277c478bd9Sstevel@tonic-gate { 18287c478bd9Sstevel@tonic-gate size_t length; 18297c478bd9Sstevel@tonic-gate mblk_t *mp; 18307c478bd9Sstevel@tonic-gate 183145916cd2Sjpk length = RTS_MSG_SIZE(type, rtm_addrs, af, sacnt); 18327c478bd9Sstevel@tonic-gate mp = allocb(length, BPRI_MED); 18337c478bd9Sstevel@tonic-gate if (mp == NULL) 18347c478bd9Sstevel@tonic-gate return (mp); 18357c478bd9Sstevel@tonic-gate bzero(mp->b_rptr, length); 18367c478bd9Sstevel@tonic-gate return (mp); 18377c478bd9Sstevel@tonic-gate } 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate /* 18407c478bd9Sstevel@tonic-gate * Returns the size of the routing 18417c478bd9Sstevel@tonic-gate * socket message header size. 18427c478bd9Sstevel@tonic-gate */ 18437c478bd9Sstevel@tonic-gate size_t 18447c478bd9Sstevel@tonic-gate rts_header_msg_size(int type) 18457c478bd9Sstevel@tonic-gate { 18467c478bd9Sstevel@tonic-gate switch (type) { 18477c478bd9Sstevel@tonic-gate case RTM_DELADDR: 18487c478bd9Sstevel@tonic-gate case RTM_NEWADDR: 18491cb875aeSCathy Zhou case RTM_CHGADDR: 18501cb875aeSCathy Zhou case RTM_FREEADDR: 18517c478bd9Sstevel@tonic-gate return (sizeof (ifa_msghdr_t)); 18527c478bd9Sstevel@tonic-gate case RTM_IFINFO: 18537c478bd9Sstevel@tonic-gate return (sizeof (if_msghdr_t)); 18547c478bd9Sstevel@tonic-gate default: 18557c478bd9Sstevel@tonic-gate return (sizeof (rt_msghdr_t)); 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate } 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate /* 18607c478bd9Sstevel@tonic-gate * Returns the size of the message needed with the given rtm_addrs and family. 18617c478bd9Sstevel@tonic-gate * 18627c478bd9Sstevel@tonic-gate * It is assumed that all of the sockaddrs (with the exception of RTA_IFP) are 18637c478bd9Sstevel@tonic-gate * of the same family (currently either AF_INET or AF_INET6). 18647c478bd9Sstevel@tonic-gate */ 18657c478bd9Sstevel@tonic-gate size_t 186645916cd2Sjpk rts_data_msg_size(int rtm_addrs, sa_family_t af, uint_t sacnt) 18677c478bd9Sstevel@tonic-gate { 18687c478bd9Sstevel@tonic-gate int i; 18697c478bd9Sstevel@tonic-gate size_t length = 0; 18707c478bd9Sstevel@tonic-gate 18717c478bd9Sstevel@tonic-gate for (i = 0; i < RTA_NUMBITS; i++) { 18727c478bd9Sstevel@tonic-gate switch (rtm_addrs & (1 << i)) { 18737c478bd9Sstevel@tonic-gate case RTA_IFP: 18747c478bd9Sstevel@tonic-gate length += sizeof (struct sockaddr_dl); 18757c478bd9Sstevel@tonic-gate break; 18767c478bd9Sstevel@tonic-gate case RTA_DST: 18777c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 18787c478bd9Sstevel@tonic-gate case RTA_NETMASK: 18797c478bd9Sstevel@tonic-gate case RTA_SRC: 18807c478bd9Sstevel@tonic-gate case RTA_IFA: 18817c478bd9Sstevel@tonic-gate case RTA_AUTHOR: 18827c478bd9Sstevel@tonic-gate case RTA_BRD: 18837c478bd9Sstevel@tonic-gate ASSERT(af == AF_INET || af == AF_INET6); 18847c478bd9Sstevel@tonic-gate switch (af) { 18857c478bd9Sstevel@tonic-gate case AF_INET: 18867c478bd9Sstevel@tonic-gate length += sizeof (sin_t); 18877c478bd9Sstevel@tonic-gate break; 18887c478bd9Sstevel@tonic-gate case AF_INET6: 18897c478bd9Sstevel@tonic-gate length += sizeof (sin6_t); 18907c478bd9Sstevel@tonic-gate break; 18917c478bd9Sstevel@tonic-gate } 18927c478bd9Sstevel@tonic-gate break; 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate } 189545916cd2Sjpk if (sacnt > 0) 189645916cd2Sjpk length += sizeof (rtm_ext_t) + TSOL_RTSECATTR_SIZE(sacnt); 189745916cd2Sjpk 18987c478bd9Sstevel@tonic-gate return (length); 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate /* 19027c478bd9Sstevel@tonic-gate * This routine is called to generate a message to the routing 19037c478bd9Sstevel@tonic-gate * socket indicating that a redirect has occured, a routing lookup 19047c478bd9Sstevel@tonic-gate * has failed, or that a protocol has detected timeouts to a particular 19057c478bd9Sstevel@tonic-gate * destination. This routine is called for message types RTM_LOSING, 19067c478bd9Sstevel@tonic-gate * RTM_REDIRECT, and RTM_MISS. 19077c478bd9Sstevel@tonic-gate */ 19087c478bd9Sstevel@tonic-gate void 19097c478bd9Sstevel@tonic-gate ip_rts_change(int type, ipaddr_t dst_addr, ipaddr_t gw_addr, ipaddr_t net_mask, 1910f4b3ec61Sdh155122 ipaddr_t source, ipaddr_t author, int flags, int error, int rtm_addrs, 1911f4b3ec61Sdh155122 ip_stack_t *ipst) 19127c478bd9Sstevel@tonic-gate { 19137c478bd9Sstevel@tonic-gate rt_msghdr_t *rtm; 19147c478bd9Sstevel@tonic-gate mblk_t *mp; 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate if (rtm_addrs == 0) 19177c478bd9Sstevel@tonic-gate return; 191845916cd2Sjpk mp = rts_alloc_msg(type, rtm_addrs, AF_INET, 0); 19197c478bd9Sstevel@tonic-gate if (mp == NULL) 19207c478bd9Sstevel@tonic-gate return; 19217c478bd9Sstevel@tonic-gate rts_fill_msg(type, rtm_addrs, dst_addr, net_mask, gw_addr, source, 0, 1922bd670b35SErik Nordmark author, 0, NULL, mp, NULL); 19237c478bd9Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 19247c478bd9Sstevel@tonic-gate rtm->rtm_flags = flags; 19257c478bd9Sstevel@tonic-gate rtm->rtm_errno = error; 19267c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_DONE; 19277c478bd9Sstevel@tonic-gate rtm->rtm_addrs = rtm_addrs; 1928e11c3f44Smeem rts_queue_input(mp, NULL, AF_INET, RTSQ_ALL, ipst); 19297c478bd9Sstevel@tonic-gate } 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate /* 19327c478bd9Sstevel@tonic-gate * This routine is called to generate a message to the routing 19337c478bd9Sstevel@tonic-gate * socket indicating that the status of a network interface has changed. 19347c478bd9Sstevel@tonic-gate * Message type generated RTM_IFINFO. 19357c478bd9Sstevel@tonic-gate */ 19367c478bd9Sstevel@tonic-gate void 1937e11c3f44Smeem ip_rts_ifmsg(const ipif_t *ipif, uint_t flags) 1938e11c3f44Smeem { 1939e11c3f44Smeem ip_rts_xifmsg(ipif, 0, 0, flags); 1940e11c3f44Smeem } 1941e11c3f44Smeem 1942e11c3f44Smeem void 1943e11c3f44Smeem ip_rts_xifmsg(const ipif_t *ipif, uint64_t set, uint64_t clear, uint_t flags) 19447c478bd9Sstevel@tonic-gate { 19457c478bd9Sstevel@tonic-gate if_msghdr_t *ifm; 19467c478bd9Sstevel@tonic-gate mblk_t *mp; 19477c478bd9Sstevel@tonic-gate sa_family_t af; 1948f4b3ec61Sdh155122 ip_stack_t *ipst = ipif->ipif_ill->ill_ipst; 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate /* 1951bd670b35SErik Nordmark * This message should be generated only 1952bd670b35SErik Nordmark * when the physical device is changing 1953bd670b35SErik Nordmark * state. 19547c478bd9Sstevel@tonic-gate */ 19557c478bd9Sstevel@tonic-gate if (ipif->ipif_id != 0) 19567c478bd9Sstevel@tonic-gate return; 19577c478bd9Sstevel@tonic-gate if (ipif->ipif_isv6) { 19587c478bd9Sstevel@tonic-gate af = AF_INET6; 195945916cd2Sjpk mp = rts_alloc_msg(RTM_IFINFO, RTA_IFP, af, 0); 19607c478bd9Sstevel@tonic-gate if (mp == NULL) 19617c478bd9Sstevel@tonic-gate return; 19627c478bd9Sstevel@tonic-gate rts_fill_msg_v6(RTM_IFINFO, RTA_IFP, &ipv6_all_zeros, 19637c478bd9Sstevel@tonic-gate &ipv6_all_zeros, &ipv6_all_zeros, &ipv6_all_zeros, 1964bd670b35SErik Nordmark &ipv6_all_zeros, &ipv6_all_zeros, &ipv6_all_zeros, 1965bd670b35SErik Nordmark ipif->ipif_ill, mp, NULL); 19667c478bd9Sstevel@tonic-gate } else { 19677c478bd9Sstevel@tonic-gate af = AF_INET; 196845916cd2Sjpk mp = rts_alloc_msg(RTM_IFINFO, RTA_IFP, af, 0); 19697c478bd9Sstevel@tonic-gate if (mp == NULL) 19707c478bd9Sstevel@tonic-gate return; 1971bd670b35SErik Nordmark rts_fill_msg(RTM_IFINFO, RTA_IFP, 0, 0, 0, 0, 0, 0, 0, 1972bd670b35SErik Nordmark ipif->ipif_ill, mp, NULL); 19737c478bd9Sstevel@tonic-gate } 19747c478bd9Sstevel@tonic-gate ifm = (if_msghdr_t *)mp->b_rptr; 19757c478bd9Sstevel@tonic-gate ifm->ifm_index = ipif->ipif_ill->ill_phyint->phyint_ifindex; 1976e11c3f44Smeem ifm->ifm_flags = (ipif->ipif_flags | ipif->ipif_ill->ill_flags | 1977e11c3f44Smeem ipif->ipif_ill->ill_phyint->phyint_flags | set) & ~clear; 19787c478bd9Sstevel@tonic-gate rts_getifdata(&ifm->ifm_data, ipif); 19797c478bd9Sstevel@tonic-gate ifm->ifm_addrs = RTA_IFP; 1980e11c3f44Smeem 1981e11c3f44Smeem if (flags & RTSQ_DEFAULT) { 1982e11c3f44Smeem flags = RTSQ_ALL; 1983e11c3f44Smeem /* 1984e11c3f44Smeem * If this message is for an underlying interface, prevent 1985e11c3f44Smeem * "normal" (IPMP-unaware) routing sockets from seeing it. 1986e11c3f44Smeem */ 1987e11c3f44Smeem if (IS_UNDER_IPMP(ipif->ipif_ill)) 1988e11c3f44Smeem flags &= ~RTSQ_NORMAL; 1989e11c3f44Smeem } 1990e11c3f44Smeem 1991e11c3f44Smeem rts_queue_input(mp, NULL, af, flags, ipst); 19927c478bd9Sstevel@tonic-gate } 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate /* 19951cb875aeSCathy Zhou * If cmd is RTM_ADD or RTM_DELETE, generate the rt_msghdr_t message; 19961cb875aeSCathy Zhou * otherwise (RTM_NEWADDR, RTM_DELADDR, RTM_CHGADDR and RTM_FREEADDR) 19971cb875aeSCathy Zhou * generate the ifa_msghdr_t message. 19987c478bd9Sstevel@tonic-gate */ 19991cb875aeSCathy Zhou static void 20001cb875aeSCathy Zhou rts_new_rtsmsg(int cmd, int error, const ipif_t *ipif, uint_t flags) 20017c478bd9Sstevel@tonic-gate { 20027c478bd9Sstevel@tonic-gate int rtm_addrs; 20037c478bd9Sstevel@tonic-gate mblk_t *mp; 20047c478bd9Sstevel@tonic-gate ifa_msghdr_t *ifam; 20057c478bd9Sstevel@tonic-gate rt_msghdr_t *rtm; 20067c478bd9Sstevel@tonic-gate sa_family_t af; 2007f4b3ec61Sdh155122 ip_stack_t *ipst = ipif->ipif_ill->ill_ipst; 20087c478bd9Sstevel@tonic-gate 2009bd670b35SErik Nordmark /* 20101cb875aeSCathy Zhou * Do not report unspecified address if this is the RTM_CHGADDR or 20111cb875aeSCathy Zhou * RTM_FREEADDR message. 2012bd670b35SErik Nordmark */ 20131cb875aeSCathy Zhou if (cmd == RTM_CHGADDR || cmd == RTM_FREEADDR) { 20141cb875aeSCathy Zhou if (!ipif->ipif_isv6) { 20151cb875aeSCathy Zhou if (ipif->ipif_lcl_addr == INADDR_ANY) 20161cb875aeSCathy Zhou return; 20171cb875aeSCathy Zhou } else if (IN6_IS_ADDR_UNSPECIFIED(&ipif->ipif_v6lcl_addr)) { 20181cb875aeSCathy Zhou return; 20191cb875aeSCathy Zhou } 20201cb875aeSCathy Zhou } 2021bd670b35SErik Nordmark 20227c478bd9Sstevel@tonic-gate if (ipif->ipif_isv6) 20237c478bd9Sstevel@tonic-gate af = AF_INET6; 20247c478bd9Sstevel@tonic-gate else 20257c478bd9Sstevel@tonic-gate af = AF_INET; 2026e11c3f44Smeem 20271cb875aeSCathy Zhou if (cmd == RTM_ADD || cmd == RTM_DELETE) 20281cb875aeSCathy Zhou rtm_addrs = (RTA_DST | RTA_NETMASK); 20291cb875aeSCathy Zhou else 20305d0bc3edSsommerfe rtm_addrs = (RTA_IFA | RTA_NETMASK | RTA_BRD | RTA_IFP); 20311cb875aeSCathy Zhou 20321cb875aeSCathy Zhou mp = rts_alloc_msg(cmd, rtm_addrs, af, 0); 20337c478bd9Sstevel@tonic-gate if (mp == NULL) 20341cb875aeSCathy Zhou return; 20351cb875aeSCathy Zhou 20361cb875aeSCathy Zhou if (cmd != RTM_ADD && cmd != RTM_DELETE) { 20377c478bd9Sstevel@tonic-gate switch (af) { 20387c478bd9Sstevel@tonic-gate case AF_INET: 20391cb875aeSCathy Zhou rts_fill_msg(cmd, rtm_addrs, 0, 20407c478bd9Sstevel@tonic-gate ipif->ipif_net_mask, 0, ipif->ipif_lcl_addr, 2041bd670b35SErik Nordmark ipif->ipif_pp_dst_addr, 0, 2042bd670b35SErik Nordmark ipif->ipif_lcl_addr, ipif->ipif_ill, 2043bd670b35SErik Nordmark mp, NULL); 20447c478bd9Sstevel@tonic-gate break; 20457c478bd9Sstevel@tonic-gate case AF_INET6: 20461cb875aeSCathy Zhou rts_fill_msg_v6(cmd, rtm_addrs, 20477c478bd9Sstevel@tonic-gate &ipv6_all_zeros, &ipif->ipif_v6net_mask, 20487c478bd9Sstevel@tonic-gate &ipv6_all_zeros, &ipif->ipif_v6lcl_addr, 20497c478bd9Sstevel@tonic-gate &ipif->ipif_v6pp_dst_addr, &ipv6_all_zeros, 2050bd670b35SErik Nordmark &ipif->ipif_v6lcl_addr, ipif->ipif_ill, 2051bd670b35SErik Nordmark mp, NULL); 20527c478bd9Sstevel@tonic-gate break; 20537c478bd9Sstevel@tonic-gate } 20547c478bd9Sstevel@tonic-gate ifam = (ifa_msghdr_t *)mp->b_rptr; 20557c478bd9Sstevel@tonic-gate ifam->ifam_index = 20567c478bd9Sstevel@tonic-gate ipif->ipif_ill->ill_phyint->phyint_ifindex; 20576e91bba0SGirish Moodalbail ifam->ifam_metric = ipif->ipif_ill->ill_metric; 20581cb875aeSCathy Zhou ifam->ifam_flags = ((cmd == RTM_NEWADDR) ? RTF_UP : 0); 20597c478bd9Sstevel@tonic-gate ifam->ifam_addrs = rtm_addrs; 20601cb875aeSCathy Zhou } else { 20617c478bd9Sstevel@tonic-gate switch (af) { 20627c478bd9Sstevel@tonic-gate case AF_INET: 20637c478bd9Sstevel@tonic-gate rts_fill_msg(cmd, rtm_addrs, 20647c478bd9Sstevel@tonic-gate ipif->ipif_lcl_addr, ipif->ipif_net_mask, 0, 2065bd670b35SErik Nordmark 0, 0, 0, 0, NULL, mp, NULL); 20667c478bd9Sstevel@tonic-gate break; 20677c478bd9Sstevel@tonic-gate case AF_INET6: 20687c478bd9Sstevel@tonic-gate rts_fill_msg_v6(cmd, rtm_addrs, 20697c478bd9Sstevel@tonic-gate &ipif->ipif_v6lcl_addr, 20707c478bd9Sstevel@tonic-gate &ipif->ipif_v6net_mask, &ipv6_all_zeros, 20717c478bd9Sstevel@tonic-gate &ipv6_all_zeros, &ipv6_all_zeros, 2072bd670b35SErik Nordmark &ipv6_all_zeros, &ipv6_all_zeros, 2073bd670b35SErik Nordmark NULL, mp, NULL); 20747c478bd9Sstevel@tonic-gate break; 20757c478bd9Sstevel@tonic-gate } 20767c478bd9Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 20777c478bd9Sstevel@tonic-gate rtm->rtm_index = 20787c478bd9Sstevel@tonic-gate ipif->ipif_ill->ill_phyint->phyint_ifindex; 20797c478bd9Sstevel@tonic-gate rtm->rtm_flags = ((cmd == RTM_ADD) ? RTF_UP : 0); 20807c478bd9Sstevel@tonic-gate rtm->rtm_errno = error; 20817c478bd9Sstevel@tonic-gate if (error == 0) 20827c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_DONE; 20837c478bd9Sstevel@tonic-gate rtm->rtm_addrs = rtm_addrs; 20841cb875aeSCathy Zhou } 2085e11c3f44Smeem rts_queue_input(mp, NULL, af, flags, ipst); 20867c478bd9Sstevel@tonic-gate } 20871cb875aeSCathy Zhou 20881cb875aeSCathy Zhou /* 20891cb875aeSCathy Zhou * This is called to generate messages to the routing socket 20901cb875aeSCathy Zhou * indicating a network interface has had addresses associated with it. 20911cb875aeSCathy Zhou * The structure of the code is based on the 4.4BSD-Lite2 <net/rtsock.c>. 20921cb875aeSCathy Zhou */ 20931cb875aeSCathy Zhou void 20941cb875aeSCathy Zhou ip_rts_newaddrmsg(int cmd, int error, const ipif_t *ipif, uint_t flags) 20951cb875aeSCathy Zhou { 20961cb875aeSCathy Zhou ip_stack_t *ipst = ipif->ipif_ill->ill_ipst; 20971cb875aeSCathy Zhou 20981cb875aeSCathy Zhou if (flags & RTSQ_DEFAULT) { 20991cb875aeSCathy Zhou flags = RTSQ_ALL; 21001cb875aeSCathy Zhou /* 21011cb875aeSCathy Zhou * If this message is for an underlying interface, prevent 21021cb875aeSCathy Zhou * "normal" (IPMP-unaware) routing sockets from seeing it. 21031cb875aeSCathy Zhou */ 21041cb875aeSCathy Zhou if (IS_UNDER_IPMP(ipif->ipif_ill)) 21051cb875aeSCathy Zhou flags &= ~RTSQ_NORMAL; 21061cb875aeSCathy Zhou } 21071cb875aeSCathy Zhou 21081cb875aeSCathy Zhou /* 21091cb875aeSCathy Zhou * Let conn_ixa caching know that source address selection 21101cb875aeSCathy Zhou * changed 21111cb875aeSCathy Zhou */ 21121cb875aeSCathy Zhou if (cmd == RTM_ADD || cmd == RTM_DELETE) 21131cb875aeSCathy Zhou ip_update_source_selection(ipst); 21141cb875aeSCathy Zhou 21151cb875aeSCathy Zhou /* 21161cb875aeSCathy Zhou * If the request is DELETE, send RTM_DELETE and RTM_DELADDR. 21171cb875aeSCathy Zhou * if the request is ADD, send RTM_NEWADDR and RTM_ADD. 21181cb875aeSCathy Zhou * otherwise simply send the request. 21191cb875aeSCathy Zhou */ 21201cb875aeSCathy Zhou switch (cmd) { 21211cb875aeSCathy Zhou case RTM_ADD: 21221cb875aeSCathy Zhou rts_new_rtsmsg(RTM_NEWADDR, error, ipif, flags); 21231cb875aeSCathy Zhou rts_new_rtsmsg(RTM_ADD, error, ipif, flags); 21241cb875aeSCathy Zhou break; 21251cb875aeSCathy Zhou case RTM_DELETE: 21261cb875aeSCathy Zhou rts_new_rtsmsg(RTM_DELETE, error, ipif, flags); 21271cb875aeSCathy Zhou rts_new_rtsmsg(RTM_DELADDR, error, ipif, flags); 21281cb875aeSCathy Zhou break; 21291cb875aeSCathy Zhou default: 21301cb875aeSCathy Zhou rts_new_rtsmsg(cmd, error, ipif, flags); 21311cb875aeSCathy Zhou break; 21327c478bd9Sstevel@tonic-gate } 21337c478bd9Sstevel@tonic-gate } 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate /* 21367c478bd9Sstevel@tonic-gate * Based on the address family specified in a sockaddr, copy the address field 21377c478bd9Sstevel@tonic-gate * into an in6_addr_t. 21387c478bd9Sstevel@tonic-gate * 21397c478bd9Sstevel@tonic-gate * In the case of AF_UNSPEC, we assume the family is actually AF_INET for 21407c478bd9Sstevel@tonic-gate * compatibility with programs that leave the family cleared in the sockaddr. 21417c478bd9Sstevel@tonic-gate * Callers of rts_copyfromsockaddr should check the family themselves if they 21427c478bd9Sstevel@tonic-gate * wish to verify its value. 21437c478bd9Sstevel@tonic-gate * 21447c478bd9Sstevel@tonic-gate * In the case of AF_INET6, a check is made to ensure that address is not an 21457c478bd9Sstevel@tonic-gate * IPv4-mapped address. 21467c478bd9Sstevel@tonic-gate */ 21477c478bd9Sstevel@tonic-gate size_t 21487c478bd9Sstevel@tonic-gate rts_copyfromsockaddr(struct sockaddr *sa, in6_addr_t *addrp) 21497c478bd9Sstevel@tonic-gate { 21507c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 21517c478bd9Sstevel@tonic-gate case AF_INET: 21527c478bd9Sstevel@tonic-gate case AF_UNSPEC: 21537c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(((sin_t *)sa)->sin_addr.s_addr, addrp); 21547c478bd9Sstevel@tonic-gate return (sizeof (sin_t)); 21557c478bd9Sstevel@tonic-gate case AF_INET6: 21567c478bd9Sstevel@tonic-gate *addrp = ((sin6_t *)sa)->sin6_addr; 21577c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(addrp)) 21587c478bd9Sstevel@tonic-gate return (0); 21597c478bd9Sstevel@tonic-gate return (sizeof (sin6_t)); 21607c478bd9Sstevel@tonic-gate default: 21617c478bd9Sstevel@tonic-gate return (0); 21627c478bd9Sstevel@tonic-gate } 21637c478bd9Sstevel@tonic-gate } 2164