12958Sdr146992 /* 22958Sdr146992 * CDDL HEADER START 32958Sdr146992 * 42958Sdr146992 * The contents of this file are subject to the terms of the 52958Sdr146992 * Common Development and Distribution License (the "License"). 62958Sdr146992 * You may not use this file except in compliance with the License. 72958Sdr146992 * 82958Sdr146992 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92958Sdr146992 * or http://www.opensolaris.org/os/licensing. 102958Sdr146992 * See the License for the specific language governing permissions 112958Sdr146992 * and limitations under the License. 122958Sdr146992 * 132958Sdr146992 * When distributing Covered Code, include this CDDL HEADER in each 142958Sdr146992 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152958Sdr146992 * If applicable, add the following below this CDDL HEADER, with the 162958Sdr146992 * fields enclosed by brackets "[]" replaced with your own identifying 172958Sdr146992 * information: Portions Copyright [yyyy] [name of copyright owner] 182958Sdr146992 * 192958Sdr146992 * CDDL HEADER END 202958Sdr146992 */ 212958Sdr146992 /* 223448Sdh155122 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 232958Sdr146992 * Use is subject to license terms. 242958Sdr146992 */ 252958Sdr146992 262958Sdr146992 #pragma ident "%Z%%M% %I% %E% SMI" 272958Sdr146992 282958Sdr146992 #include <sys/param.h> 292958Sdr146992 #include <sys/types.h> 302958Sdr146992 #include <sys/systm.h> 312958Sdr146992 #include <sys/stream.h> 322958Sdr146992 #include <sys/strsubr.h> 332958Sdr146992 #include <sys/pattr.h> 342958Sdr146992 #include <sys/dlpi.h> 352958Sdr146992 #include <sys/atomic.h> 362958Sdr146992 #include <sys/sunddi.h> 372958Sdr146992 #include <sys/socket.h> 382958Sdr146992 #include <sys/neti.h> 392958Sdr146992 402958Sdr146992 #include <netinet/in.h> 412958Sdr146992 #include <inet/common.h> 422958Sdr146992 #include <inet/mib2.h> 432958Sdr146992 #include <inet/ip.h> 442958Sdr146992 #include <inet/ip6.h> 452958Sdr146992 #include <inet/ip_if.h> 462958Sdr146992 #include <inet/ip_ire.h> 472958Sdr146992 #include <inet/ip_impl.h> 482958Sdr146992 #include <inet/ip_ndp.h> 492958Sdr146992 #include <inet/ipclassifier.h> 502958Sdr146992 #include <inet/ipp_common.h> 512958Sdr146992 #include <inet/ip_ftable.h> 522958Sdr146992 532958Sdr146992 /* 542958Sdr146992 * IPv4 netinfo entry point declarations. 552958Sdr146992 */ 563448Sdh155122 static int ip_getifname(phy_if_t, char *, const size_t, 573448Sdh155122 netstack_t *); 583448Sdh155122 static int ip_getmtu(phy_if_t, lif_if_t, netstack_t *); 593448Sdh155122 static int ip_getpmtuenabled(netstack_t *); 602958Sdr146992 static int ip_getlifaddr(phy_if_t, lif_if_t, size_t, 613448Sdh155122 net_ifaddr_t [], void *, netstack_t *); 623448Sdh155122 static phy_if_t ip_phygetnext(phy_if_t, netstack_t *); 633448Sdh155122 static phy_if_t ip_phylookup(const char *, netstack_t *); 643448Sdh155122 static lif_if_t ip_lifgetnext(phy_if_t, lif_if_t, netstack_t *); 653448Sdh155122 static int ip_inject(inject_t, net_inject_t *, netstack_t *); 663448Sdh155122 static phy_if_t ip_routeto(struct sockaddr *, netstack_t *); 672958Sdr146992 static int ip_ispartialchecksum(mblk_t *); 682958Sdr146992 static int ip_isvalidchecksum(mblk_t *); 692958Sdr146992 703448Sdh155122 static int ipv6_getifname(phy_if_t, char *, const size_t, 713448Sdh155122 netstack_t *); 723448Sdh155122 static int ipv6_getmtu(phy_if_t, lif_if_t, netstack_t *); 732958Sdr146992 static int ipv6_getlifaddr(phy_if_t, lif_if_t, size_t, 743448Sdh155122 net_ifaddr_t [], void *, netstack_t *); 753448Sdh155122 static phy_if_t ipv6_phygetnext(phy_if_t, netstack_t *); 763448Sdh155122 static phy_if_t ipv6_phylookup(const char *, netstack_t *); 773448Sdh155122 static lif_if_t ipv6_lifgetnext(phy_if_t, lif_if_t, netstack_t *); 783448Sdh155122 static int ipv6_inject(inject_t, net_inject_t *, netstack_t *); 793448Sdh155122 static phy_if_t ipv6_routeto(struct sockaddr *, netstack_t *); 802958Sdr146992 static int ipv6_isvalidchecksum(mblk_t *); 812958Sdr146992 822958Sdr146992 /* Netinfo private functions */ 832958Sdr146992 static int ip_getifname_impl(phy_if_t, char *, 843448Sdh155122 const size_t, boolean_t, ip_stack_t *); 853448Sdh155122 static int ip_getmtu_impl(phy_if_t, lif_if_t, boolean_t, 863448Sdh155122 ip_stack_t *); 873448Sdh155122 static phy_if_t ip_phylookup_impl(const char *, boolean_t, 883448Sdh155122 ip_stack_t *ipst); 893448Sdh155122 static lif_if_t ip_lifgetnext_impl(phy_if_t, lif_if_t, boolean_t, 903448Sdh155122 ip_stack_t *ipst); 913448Sdh155122 static int ip_inject_impl(inject_t, net_inject_t *, boolean_t, 923448Sdh155122 ip_stack_t *); 932958Sdr146992 static int ip_getifaddr_type(sa_family_t, ipif_t *, lif_if_t, 942958Sdr146992 void *); 953448Sdh155122 static phy_if_t ip_routeto_impl(struct sockaddr *, ip_stack_t *); 962958Sdr146992 static int ip_getlifaddr_impl(sa_family_t, phy_if_t, lif_if_t, 973448Sdh155122 size_t, net_ifaddr_t [], struct sockaddr *, 983448Sdh155122 ip_stack_t *); 992958Sdr146992 static void ip_ni_queue_in_func(void *); 1002958Sdr146992 static void ip_ni_queue_out_func(void *); 1012958Sdr146992 static void ip_ni_queue_func_impl(injection_t *, boolean_t); 1022958Sdr146992 1032958Sdr146992 1042958Sdr146992 static net_info_t ipv4info = { 1052958Sdr146992 NETINFO_VERSION, 1062958Sdr146992 NHF_INET, 1072958Sdr146992 ip_getifname, 1082958Sdr146992 ip_getmtu, 1092958Sdr146992 ip_getpmtuenabled, 1102958Sdr146992 ip_getlifaddr, 1112958Sdr146992 ip_phygetnext, 1122958Sdr146992 ip_phylookup, 1132958Sdr146992 ip_lifgetnext, 1142958Sdr146992 ip_inject, 1152958Sdr146992 ip_routeto, 1162958Sdr146992 ip_ispartialchecksum, 1172958Sdr146992 ip_isvalidchecksum 1182958Sdr146992 }; 1192958Sdr146992 1202958Sdr146992 1212958Sdr146992 static net_info_t ipv6info = { 1222958Sdr146992 NETINFO_VERSION, 1232958Sdr146992 NHF_INET6, 1242958Sdr146992 ipv6_getifname, 1252958Sdr146992 ipv6_getmtu, 1262958Sdr146992 ip_getpmtuenabled, 1272958Sdr146992 ipv6_getlifaddr, 1282958Sdr146992 ipv6_phygetnext, 1292958Sdr146992 ipv6_phylookup, 1302958Sdr146992 ipv6_lifgetnext, 1312958Sdr146992 ipv6_inject, 1322958Sdr146992 ipv6_routeto, 1332958Sdr146992 ip_ispartialchecksum, 1342958Sdr146992 ipv6_isvalidchecksum 1352958Sdr146992 }; 1362958Sdr146992 1372958Sdr146992 /* 1382958Sdr146992 * The taskq eventq_queue_in is used to process the upside inject messages. 1392958Sdr146992 * The taskq eventq_queue_out is used to process the downside inject messages. 1402958Sdr146992 * The taskq eventq_queue_nic is used to process the nic event messages. 1412958Sdr146992 */ 1422958Sdr146992 static ddi_taskq_t *eventq_queue_in = NULL; 1432958Sdr146992 static ddi_taskq_t *eventq_queue_out = NULL; 1442958Sdr146992 ddi_taskq_t *eventq_queue_nic = NULL; 1452958Sdr146992 1462958Sdr146992 /* 1473448Sdh155122 * Initialize queues for inject. 1482958Sdr146992 */ 1492958Sdr146992 void 1503448Sdh155122 ip_net_g_init() 1512958Sdr146992 { 1522958Sdr146992 if (eventq_queue_out == NULL) { 1532958Sdr146992 eventq_queue_out = ddi_taskq_create(NULL, 1542958Sdr146992 "IP_INJECT_QUEUE_OUT", 1, TASKQ_DEFAULTPRI, 0); 1552958Sdr146992 1562958Sdr146992 if (eventq_queue_out == NULL) 1572958Sdr146992 cmn_err(CE_NOTE, "ipv4_net_init: " 1582958Sdr146992 "ddi_taskq_create failed for IP_INJECT_QUEUE_OUT"); 1592958Sdr146992 } 1602958Sdr146992 1612958Sdr146992 if (eventq_queue_in == NULL) { 1622958Sdr146992 eventq_queue_in = ddi_taskq_create(NULL, 1632958Sdr146992 "IP_INJECT_QUEUE_IN", 1, TASKQ_DEFAULTPRI, 0); 1642958Sdr146992 1652958Sdr146992 if (eventq_queue_in == NULL) 1662958Sdr146992 cmn_err(CE_NOTE, "ipv4_net_init: " 1672958Sdr146992 "ddi_taskq_create failed for IP_INJECT_QUEUE_IN"); 1682958Sdr146992 } 1692958Sdr146992 1702958Sdr146992 if (eventq_queue_nic == NULL) { 1712958Sdr146992 eventq_queue_nic = ddi_taskq_create(NULL, 1722958Sdr146992 "IP_NIC_EVENT_QUEUE", 1, TASKQ_DEFAULTPRI, 0); 1732958Sdr146992 1742958Sdr146992 if (eventq_queue_nic == NULL) 1752958Sdr146992 cmn_err(CE_NOTE, "ipv4_net_init: " 1762958Sdr146992 "ddi_taskq_create failed for IP_NIC_EVENT_QUEUE"); 1772958Sdr146992 } 1782958Sdr146992 } 1792958Sdr146992 1802958Sdr146992 /* 1813448Sdh155122 * Destroy inject queues 1822958Sdr146992 */ 1832958Sdr146992 void 1843448Sdh155122 ip_net_g_destroy() 1852958Sdr146992 { 1862958Sdr146992 if (eventq_queue_nic != NULL) { 1872958Sdr146992 ddi_taskq_destroy(eventq_queue_nic); 1882958Sdr146992 eventq_queue_nic = NULL; 1892958Sdr146992 } 1902958Sdr146992 1912958Sdr146992 if (eventq_queue_in != NULL) { 1922958Sdr146992 ddi_taskq_destroy(eventq_queue_in); 1932958Sdr146992 eventq_queue_in = NULL; 1942958Sdr146992 } 1952958Sdr146992 1962958Sdr146992 if (eventq_queue_out != NULL) { 1972958Sdr146992 ddi_taskq_destroy(eventq_queue_out); 1982958Sdr146992 eventq_queue_out = NULL; 1992958Sdr146992 } 2003448Sdh155122 } 2012958Sdr146992 2023448Sdh155122 /* 2033448Sdh155122 * Register IPv4 and IPv6 netinfo functions and initialize queues for inject. 2043448Sdh155122 */ 2053448Sdh155122 void 2063448Sdh155122 ip_net_init(ip_stack_t *ipst, netstack_t *ns) 2073448Sdh155122 { 2083448Sdh155122 2093448Sdh155122 ipst->ips_ipv4_net_data = net_register_impl(&ipv4info, ns); 2103448Sdh155122 ASSERT(ipst->ips_ipv4_net_data != NULL); 2113448Sdh155122 2123448Sdh155122 ipst->ips_ipv6_net_data = net_register_impl(&ipv6info, ns); 2133448Sdh155122 ASSERT(ipst->ips_ipv6_net_data != NULL); 2143448Sdh155122 } 2153448Sdh155122 2163448Sdh155122 2173448Sdh155122 /* 2183448Sdh155122 * Unregister IPv4 and IPv6 functions and inject queues 2193448Sdh155122 */ 2203448Sdh155122 void 2213448Sdh155122 ip_net_destroy(ip_stack_t *ipst) 2223448Sdh155122 { 2233448Sdh155122 if (ipst->ips_ipv4_net_data != NULL) { 2243448Sdh155122 if (net_unregister(ipst->ips_ipv4_net_data) == 0) 2253448Sdh155122 ipst->ips_ipv4_net_data = NULL; 2262958Sdr146992 } 2272958Sdr146992 2283448Sdh155122 if (ipst->ips_ipv6_net_data != NULL) { 2293448Sdh155122 if (net_unregister(ipst->ips_ipv6_net_data) == 0) 2303448Sdh155122 ipst->ips_ipv6_net_data = NULL; 2312958Sdr146992 } 2322958Sdr146992 } 2332958Sdr146992 2342958Sdr146992 /* 2352958Sdr146992 * Initialize IPv4 hooks family the event 2362958Sdr146992 */ 2372958Sdr146992 void 2383448Sdh155122 ipv4_hook_init(ip_stack_t *ipst) 2392958Sdr146992 { 2403448Sdh155122 HOOK_FAMILY_INIT(&ipst->ips_ipv4root, Hn_IPV4); 2413448Sdh155122 if (net_register_family(ipst->ips_ipv4_net_data, &ipst->ips_ipv4root) 2423448Sdh155122 != 0) { 2432958Sdr146992 cmn_err(CE_NOTE, "ipv4_hook_init: " 2442958Sdr146992 "net_register_family failed for ipv4"); 2452958Sdr146992 } 2462958Sdr146992 2473448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip4_physical_in_event, NH_PHYSICAL_IN); 2483448Sdh155122 ipst->ips_ipv4firewall_physical_in = net_register_event( 2493448Sdh155122 ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_in_event); 2503448Sdh155122 if (ipst->ips_ipv4firewall_physical_in == NULL) { 2512958Sdr146992 cmn_err(CE_NOTE, "ipv4_hook_init: " 2522958Sdr146992 "net_register_event failed for ipv4/physical_in"); 2532958Sdr146992 } 2542958Sdr146992 2553448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip4_physical_out_event, NH_PHYSICAL_OUT); 2563448Sdh155122 ipst->ips_ipv4firewall_physical_out = net_register_event( 2573448Sdh155122 ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_out_event); 2583448Sdh155122 if (ipst->ips_ipv4firewall_physical_out == NULL) { 2592958Sdr146992 cmn_err(CE_NOTE, "ipv4_hook_init: " 2602958Sdr146992 "net_register_event failed for ipv4/physical_out"); 2612958Sdr146992 } 2622958Sdr146992 2633448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip4_forwarding_event, NH_FORWARDING); 2643448Sdh155122 ipst->ips_ipv4firewall_forwarding = net_register_event( 2653448Sdh155122 ipst->ips_ipv4_net_data, &ipst->ips_ip4_forwarding_event); 2663448Sdh155122 if (ipst->ips_ipv4firewall_forwarding == NULL) { 2672958Sdr146992 cmn_err(CE_NOTE, "ipv4_hook_init: " 2682958Sdr146992 "net_register_event failed for ipv4/forwarding"); 2692958Sdr146992 } 2702958Sdr146992 2713448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_in_event, NH_LOOPBACK_IN); 2723448Sdh155122 ipst->ips_ipv4firewall_loopback_in = net_register_event( 2733448Sdh155122 ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_in_event); 2743448Sdh155122 if (ipst->ips_ipv4firewall_loopback_in == NULL) { 2752958Sdr146992 cmn_err(CE_NOTE, "ipv4_hook_init: " 2762958Sdr146992 "net_register_event failed for ipv4/loopback_in"); 2772958Sdr146992 } 2782958Sdr146992 2793448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_out_event, NH_LOOPBACK_OUT); 2803448Sdh155122 ipst->ips_ipv4firewall_loopback_out = net_register_event( 2813448Sdh155122 ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_out_event); 2823448Sdh155122 if (ipst->ips_ipv4firewall_loopback_out == NULL) { 2832958Sdr146992 cmn_err(CE_NOTE, "ipv4_hook_init: " 2842958Sdr146992 "net_register_event failed for ipv4/loopback_out"); 2852958Sdr146992 } 2862958Sdr146992 2873448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip4_nic_events, NH_NIC_EVENTS); 2883448Sdh155122 ipst->ips_ip4_nic_events.he_flags = HOOK_RDONLY; 2893448Sdh155122 ipst->ips_ipv4nicevents = net_register_event( 2903448Sdh155122 ipst->ips_ipv4_net_data, &ipst->ips_ip4_nic_events); 2913448Sdh155122 if (ipst->ips_ipv4nicevents == NULL) { 2922958Sdr146992 cmn_err(CE_NOTE, "ipv4_hook_init: " 2932958Sdr146992 "net_register_event failed for ipv4/nic_events"); 2942958Sdr146992 } 2952958Sdr146992 } 2962958Sdr146992 2972958Sdr146992 void 2983448Sdh155122 ipv4_hook_destroy(ip_stack_t *ipst) 2992958Sdr146992 { 3003448Sdh155122 if (ipst->ips_ipv4firewall_forwarding != NULL) { 3013448Sdh155122 if (net_unregister_event(ipst->ips_ipv4_net_data, 3023448Sdh155122 &ipst->ips_ip4_forwarding_event) == 0) 3033448Sdh155122 ipst->ips_ipv4firewall_forwarding = NULL; 3042958Sdr146992 } 3052958Sdr146992 3063448Sdh155122 if (ipst->ips_ipv4firewall_physical_in != NULL) { 3073448Sdh155122 if (net_unregister_event(ipst->ips_ipv4_net_data, 3083448Sdh155122 &ipst->ips_ip4_physical_in_event) == 0) 3093448Sdh155122 ipst->ips_ipv4firewall_physical_in = NULL; 3102958Sdr146992 } 3112958Sdr146992 3123448Sdh155122 if (ipst->ips_ipv4firewall_physical_out != NULL) { 3133448Sdh155122 if (net_unregister_event(ipst->ips_ipv4_net_data, 3143448Sdh155122 &ipst->ips_ip4_physical_out_event) == 0) 3153448Sdh155122 ipst->ips_ipv4firewall_physical_out = NULL; 3162958Sdr146992 } 3172958Sdr146992 3183448Sdh155122 if (ipst->ips_ipv4firewall_loopback_in != NULL) { 3193448Sdh155122 if (net_unregister_event(ipst->ips_ipv4_net_data, 3203448Sdh155122 &ipst->ips_ip4_loopback_in_event) == 0) 3213448Sdh155122 ipst->ips_ipv4firewall_loopback_in = NULL; 3222958Sdr146992 } 3232958Sdr146992 3243448Sdh155122 if (ipst->ips_ipv4firewall_loopback_out != NULL) { 3253448Sdh155122 if (net_unregister_event(ipst->ips_ipv4_net_data, 3263448Sdh155122 &ipst->ips_ip4_loopback_out_event) == 0) 3273448Sdh155122 ipst->ips_ipv4firewall_loopback_out = NULL; 3282958Sdr146992 } 3292958Sdr146992 3303448Sdh155122 if (ipst->ips_ipv4nicevents != NULL) { 3313448Sdh155122 if (net_unregister_event(ipst->ips_ipv4_net_data, 3323448Sdh155122 &ipst->ips_ip4_nic_events) == 0) 3333448Sdh155122 ipst->ips_ipv4nicevents = NULL; 3342958Sdr146992 } 3352958Sdr146992 3363448Sdh155122 (void) net_unregister_family(ipst->ips_ipv4_net_data, 3373448Sdh155122 &ipst->ips_ipv4root); 3382958Sdr146992 } 3392958Sdr146992 3402958Sdr146992 /* 3412958Sdr146992 * Initialize IPv6 hooks family and event 3422958Sdr146992 */ 3432958Sdr146992 void 3443448Sdh155122 ipv6_hook_init(ip_stack_t *ipst) 3452958Sdr146992 { 3462958Sdr146992 3473448Sdh155122 HOOK_FAMILY_INIT(&ipst->ips_ipv6root, Hn_IPV6); 3483448Sdh155122 if (net_register_family(ipst->ips_ipv6_net_data, &ipst->ips_ipv6root) 3493448Sdh155122 != 0) { 3502958Sdr146992 cmn_err(CE_NOTE, "ipv6_hook_init: " 3512958Sdr146992 "net_register_family failed for ipv6"); 3522958Sdr146992 } 3532958Sdr146992 3543448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip6_physical_in_event, NH_PHYSICAL_IN); 3553448Sdh155122 ipst->ips_ipv6firewall_physical_in = net_register_event( 3563448Sdh155122 ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_in_event); 3573448Sdh155122 if (ipst->ips_ipv6firewall_physical_in == NULL) { 3582958Sdr146992 cmn_err(CE_NOTE, "ipv6_hook_init: " 3592958Sdr146992 "net_register_event failed for ipv6/physical_in"); 3602958Sdr146992 } 3612958Sdr146992 3623448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip6_physical_out_event, NH_PHYSICAL_OUT); 3633448Sdh155122 ipst->ips_ipv6firewall_physical_out = net_register_event( 3643448Sdh155122 ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_out_event); 3653448Sdh155122 if (ipst->ips_ipv6firewall_physical_out == NULL) { 3662958Sdr146992 cmn_err(CE_NOTE, "ipv6_hook_init: " 3672958Sdr146992 "net_register_event failed for ipv6/physical_out"); 3682958Sdr146992 } 3692958Sdr146992 3703448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip6_forwarding_event, NH_FORWARDING); 3713448Sdh155122 ipst->ips_ipv6firewall_forwarding = net_register_event( 3723448Sdh155122 ipst->ips_ipv6_net_data, &ipst->ips_ip6_forwarding_event); 3733448Sdh155122 if (ipst->ips_ipv6firewall_forwarding == NULL) { 3742958Sdr146992 cmn_err(CE_NOTE, "ipv6_hook_init: " 3752958Sdr146992 "net_register_event failed for ipv6/forwarding"); 3762958Sdr146992 } 3772958Sdr146992 3783448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_in_event, NH_LOOPBACK_IN); 3793448Sdh155122 ipst->ips_ipv6firewall_loopback_in = net_register_event( 3803448Sdh155122 ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_in_event); 3813448Sdh155122 if (ipst->ips_ipv6firewall_loopback_in == NULL) { 3822958Sdr146992 cmn_err(CE_NOTE, "ipv6_hook_init: " 3832958Sdr146992 "net_register_event failed for ipv6/loopback_in"); 3842958Sdr146992 } 3852958Sdr146992 3863448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_out_event, NH_LOOPBACK_OUT); 3873448Sdh155122 ipst->ips_ipv6firewall_loopback_out = net_register_event( 3883448Sdh155122 ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_out_event); 3893448Sdh155122 if (ipst->ips_ipv6firewall_loopback_out == NULL) { 3902958Sdr146992 cmn_err(CE_NOTE, "ipv6_hook_init: " 3912958Sdr146992 "net_register_event failed for ipv6/loopback_out"); 3922958Sdr146992 } 3932958Sdr146992 3943448Sdh155122 HOOK_EVENT_INIT(&ipst->ips_ip6_nic_events, NH_NIC_EVENTS); 3953448Sdh155122 ipst->ips_ip6_nic_events.he_flags = HOOK_RDONLY; 3963448Sdh155122 ipst->ips_ipv6nicevents = net_register_event( 3973448Sdh155122 ipst->ips_ipv6_net_data, &ipst->ips_ip6_nic_events); 3983448Sdh155122 if (ipst->ips_ipv6nicevents == NULL) { 3992958Sdr146992 cmn_err(CE_NOTE, "ipv6_hook_init: " 4002958Sdr146992 "net_register_event failed for ipv6/nic_events"); 4012958Sdr146992 } 4022958Sdr146992 } 4032958Sdr146992 4042958Sdr146992 void 4053448Sdh155122 ipv6_hook_destroy(ip_stack_t *ipst) 4062958Sdr146992 { 4073448Sdh155122 if (ipst->ips_ipv6firewall_forwarding != NULL) { 4083448Sdh155122 if (net_unregister_event(ipst->ips_ipv6_net_data, 4093448Sdh155122 &ipst->ips_ip6_forwarding_event) == 0) 4103448Sdh155122 ipst->ips_ipv6firewall_forwarding = NULL; 4112958Sdr146992 } 4122958Sdr146992 4133448Sdh155122 if (ipst->ips_ipv6firewall_physical_in != NULL) { 4143448Sdh155122 if (net_unregister_event(ipst->ips_ipv6_net_data, 4153448Sdh155122 &ipst->ips_ip6_physical_in_event) == 0) 4163448Sdh155122 ipst->ips_ipv6firewall_physical_in = NULL; 4172958Sdr146992 } 4182958Sdr146992 4193448Sdh155122 if (ipst->ips_ipv6firewall_physical_out != NULL) { 4203448Sdh155122 if (net_unregister_event(ipst->ips_ipv6_net_data, 4213448Sdh155122 &ipst->ips_ip6_physical_out_event) == 0) 4223448Sdh155122 ipst->ips_ipv6firewall_physical_out = NULL; 4232958Sdr146992 } 4242958Sdr146992 4253448Sdh155122 if (ipst->ips_ipv6firewall_loopback_in != NULL) { 4263448Sdh155122 if (net_unregister_event(ipst->ips_ipv6_net_data, 4273448Sdh155122 &ipst->ips_ip6_loopback_in_event) == 0) 4283448Sdh155122 ipst->ips_ipv6firewall_loopback_in = NULL; 4292958Sdr146992 } 4302958Sdr146992 4313448Sdh155122 if (ipst->ips_ipv6firewall_loopback_out != NULL) { 4323448Sdh155122 if (net_unregister_event(ipst->ips_ipv6_net_data, 4333448Sdh155122 &ipst->ips_ip6_loopback_out_event) == 0) 4343448Sdh155122 ipst->ips_ipv6firewall_loopback_out = NULL; 4352958Sdr146992 } 4362958Sdr146992 4373448Sdh155122 if (ipst->ips_ipv6nicevents != NULL) { 4383448Sdh155122 if (net_unregister_event(ipst->ips_ipv6_net_data, 4393448Sdh155122 &ipst->ips_ip6_nic_events) == 0) 4403448Sdh155122 ipst->ips_ipv6nicevents = NULL; 4412958Sdr146992 } 4422958Sdr146992 4433448Sdh155122 (void) net_unregister_family(ipst->ips_ipv6_net_data, 4443448Sdh155122 &ipst->ips_ipv6root); 4452958Sdr146992 } 4462958Sdr146992 4472958Sdr146992 /* 4482958Sdr146992 * Determine the name of an IPv4 interface 4492958Sdr146992 */ 4502958Sdr146992 static int 4513448Sdh155122 ip_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen, 4523448Sdh155122 netstack_t *ns) 4532958Sdr146992 { 4543448Sdh155122 return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_FALSE, 4553448Sdh155122 ns->netstack_ip)); 4562958Sdr146992 } 4572958Sdr146992 4582958Sdr146992 /* 4592958Sdr146992 * Determine the name of an IPv6 interface 4602958Sdr146992 */ 4612958Sdr146992 static int 4623448Sdh155122 ipv6_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen, 4633448Sdh155122 netstack_t *ns) 4642958Sdr146992 { 4653448Sdh155122 return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_TRUE, 4663448Sdh155122 ns->netstack_ip)); 4672958Sdr146992 } 4682958Sdr146992 4692958Sdr146992 /* 4702958Sdr146992 * Shared implementation to determine the name of a given network interface 4712958Sdr146992 */ 4722958Sdr146992 /* ARGSUSED */ 4732958Sdr146992 static int 4742958Sdr146992 ip_getifname_impl(phy_if_t phy_ifdata, 4753448Sdh155122 char *buffer, const size_t buflen, boolean_t isv6, ip_stack_t *ipst) 4762958Sdr146992 { 4772958Sdr146992 ill_t *ill; 478*4041Snordmark char *name; 4792958Sdr146992 4802958Sdr146992 ASSERT(buffer != NULL); 4812958Sdr146992 4822958Sdr146992 ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6, NULL, NULL, 4833448Sdh155122 NULL, NULL, ipst); 484*4041Snordmark if (ill != NULL) { 485*4041Snordmark name = ill->ill_name; 486*4041Snordmark } else { 487*4041Snordmark /* Fallback to group names only if hook_emulation is set */ 488*4041Snordmark if (ipst->ips_ipmp_hook_emulation) { 489*4041Snordmark ill = ill_group_lookup_on_ifindex((uint_t)phy_ifdata, 490*4041Snordmark isv6, ipst); 491*4041Snordmark } 492*4041Snordmark if (ill == NULL) 493*4041Snordmark return (1); 494*4041Snordmark name = ill->ill_phyint->phyint_groupname; 495*4041Snordmark } 496*4041Snordmark if (name != NULL) { 497*4041Snordmark (void) strlcpy(buffer, name, buflen); 4982958Sdr146992 ill_refrele(ill); 4992958Sdr146992 return (0); 5002958Sdr146992 } else { 5012958Sdr146992 ill_refrele(ill); 5022958Sdr146992 return (1); 5032958Sdr146992 } 5042958Sdr146992 5052958Sdr146992 } 5062958Sdr146992 5072958Sdr146992 /* 5082958Sdr146992 * Determine the MTU of an IPv4 network interface 5092958Sdr146992 */ 5102958Sdr146992 static int 5113448Sdh155122 ip_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) 5122958Sdr146992 { 5133448Sdh155122 ASSERT(ns != NULL); 5143448Sdh155122 return (ip_getmtu_impl(phy_ifdata, ifdata, B_FALSE, ns->netstack_ip)); 5152958Sdr146992 } 5162958Sdr146992 5172958Sdr146992 /* 5182958Sdr146992 * Determine the MTU of an IPv6 network interface 5192958Sdr146992 */ 5202958Sdr146992 static int 5213448Sdh155122 ipv6_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) 5222958Sdr146992 { 5233448Sdh155122 ASSERT(ns != NULL); 5243448Sdh155122 return (ip_getmtu_impl(phy_ifdata, ifdata, B_TRUE, ns->netstack_ip)); 5252958Sdr146992 } 5262958Sdr146992 5272958Sdr146992 /* 5282958Sdr146992 * Shared implementation to determine the MTU of a network interface 529*4041Snordmark * 530*4041Snordmark * Note: this does not handle a non-zero ifdata when ipmp_hook_emulation is set. 531*4041Snordmark * But IP Filter only uses a zero ifdata. 5322958Sdr146992 */ 5332958Sdr146992 /* ARGSUSED */ 5342958Sdr146992 static int 5353448Sdh155122 ip_getmtu_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6, 5363448Sdh155122 ip_stack_t *ipst) 5372958Sdr146992 { 5382958Sdr146992 lif_if_t ipifid; 5392958Sdr146992 ipif_t *ipif; 5402958Sdr146992 int mtu; 5412958Sdr146992 5422958Sdr146992 ipifid = UNMAP_IPIF_ID(ifdata); 5432958Sdr146992 5443448Sdh155122 ipif = ipif_getby_indexes((uint_t)phy_ifdata, (uint_t)ipifid, 5453448Sdh155122 isv6, ipst); 5462958Sdr146992 if (ipif == NULL) 5472958Sdr146992 return (0); 5482958Sdr146992 5492958Sdr146992 mtu = ipif->ipif_mtu; 5502958Sdr146992 ipif_refrele(ipif); 5512958Sdr146992 5522958Sdr146992 if (mtu == 0) { 5532958Sdr146992 ill_t *ill; 5542958Sdr146992 5552958Sdr146992 if ((ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6, 5563448Sdh155122 NULL, NULL, NULL, NULL, ipst)) == NULL) { 557*4041Snordmark /* 558*4041Snordmark * Fallback to group names only if hook_emulation 559*4041Snordmark * is set 560*4041Snordmark */ 561*4041Snordmark if (ipst->ips_ipmp_hook_emulation) { 562*4041Snordmark ill = ill_group_lookup_on_ifindex( 563*4041Snordmark (uint_t)phy_ifdata, isv6, ipst); 564*4041Snordmark } 565*4041Snordmark if (ill == NULL) 566*4041Snordmark return (0); 5672958Sdr146992 } 5682958Sdr146992 mtu = ill->ill_max_frag; 5692958Sdr146992 ill_refrele(ill); 5702958Sdr146992 } 5712958Sdr146992 5722958Sdr146992 return (mtu); 5732958Sdr146992 } 5742958Sdr146992 5752958Sdr146992 /* 5762958Sdr146992 * Determine if path MTU discovery is enabled for IP 5772958Sdr146992 */ 5782958Sdr146992 static int 5793448Sdh155122 ip_getpmtuenabled(netstack_t *ns) 5802958Sdr146992 { 5813448Sdh155122 ASSERT(ns != NULL); 5823448Sdh155122 return ((ns->netstack_ip)->ips_ip_path_mtu_discovery); 5832958Sdr146992 } 5842958Sdr146992 5852958Sdr146992 /* 5862958Sdr146992 * Get next interface from the current list of IPv4 physical network interfaces 587*4041Snordmark * 588*4041Snordmark * Note: this does not handle the case when ipmp_hook_emulation is set. 589*4041Snordmark * But IP Filter does not use this function. 5902958Sdr146992 */ 5912958Sdr146992 static phy_if_t 5923448Sdh155122 ip_phygetnext(phy_if_t phy_ifdata, netstack_t *ns) 5932958Sdr146992 { 5943448Sdh155122 ASSERT(ns != NULL); 5953448Sdh155122 return (ill_get_next_ifindex(phy_ifdata, B_FALSE, ns->netstack_ip)); 5962958Sdr146992 } 5972958Sdr146992 5982958Sdr146992 /* 5992958Sdr146992 * Get next interface from the current list of IPv6 physical network interfaces 6002958Sdr146992 */ 6012958Sdr146992 static phy_if_t 6023448Sdh155122 ipv6_phygetnext(phy_if_t phy_ifdata, netstack_t *ns) 6032958Sdr146992 { 6043448Sdh155122 ASSERT(ns != NULL); 6053448Sdh155122 return (ill_get_next_ifindex(phy_ifdata, B_TRUE, ns->netstack_ip)); 6062958Sdr146992 } 6072958Sdr146992 6082958Sdr146992 /* 6092958Sdr146992 * Determine if a network interface name exists for IPv4 6102958Sdr146992 */ 6112958Sdr146992 static phy_if_t 6123448Sdh155122 ip_phylookup(const char *name, netstack_t *ns) 6132958Sdr146992 { 6143448Sdh155122 ASSERT(ns != NULL); 6153448Sdh155122 return (ip_phylookup_impl(name, B_FALSE, ns->netstack_ip)); 6162958Sdr146992 } 6172958Sdr146992 6182958Sdr146992 /* 6192958Sdr146992 * Determine if a network interface name exists for IPv6 6202958Sdr146992 */ 6212958Sdr146992 static phy_if_t 6223448Sdh155122 ipv6_phylookup(const char *name, netstack_t *ns) 6232958Sdr146992 { 6243448Sdh155122 ASSERT(ns != NULL); 6253448Sdh155122 return (ip_phylookup_impl(name, B_TRUE, ns->netstack_ip)); 6262958Sdr146992 } 6272958Sdr146992 6282958Sdr146992 /* 6292958Sdr146992 * Implement looking up an ill_t based on the name supplied and matching 6302958Sdr146992 * it up with either IPv4 or IPv6. ill_get_ifindex_by_name() is not used 6312958Sdr146992 * because it does not match on the address family in addition to the name. 6322958Sdr146992 */ 6332958Sdr146992 static phy_if_t 6343448Sdh155122 ip_phylookup_impl(const char *name, boolean_t isv6, ip_stack_t *ipst) 6352958Sdr146992 { 6362958Sdr146992 phy_if_t phy; 6372958Sdr146992 ill_t *ill; 6382958Sdr146992 6392958Sdr146992 ill = ill_lookup_on_name((char *)name, B_FALSE, isv6, NULL, NULL, 6403448Sdh155122 NULL, NULL, NULL, ipst); 6412958Sdr146992 642*4041Snordmark /* Fallback to group names only if hook_emulation is set */ 643*4041Snordmark if (ill == NULL && ipst->ips_ipmp_hook_emulation) { 644*4041Snordmark ill = ill_group_lookup_on_name((char *)name, isv6, ipst); 645*4041Snordmark } 6462958Sdr146992 if (ill == NULL) 6472958Sdr146992 return (0); 6482958Sdr146992 649*4041Snordmark phy = ill->ill_phyint->phyint_hook_ifindex; 6502958Sdr146992 6512958Sdr146992 ill_refrele(ill); 6522958Sdr146992 6532958Sdr146992 return (phy); 6542958Sdr146992 } 6552958Sdr146992 6562958Sdr146992 /* 6572958Sdr146992 * Get next interface from the current list of IPv4 logical network interfaces 6582958Sdr146992 */ 6592958Sdr146992 static lif_if_t 6603448Sdh155122 ip_lifgetnext(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) 6612958Sdr146992 { 6623448Sdh155122 ASSERT(ns != NULL); 6633448Sdh155122 return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_FALSE, 6643448Sdh155122 ns->netstack_ip)); 6652958Sdr146992 } 6662958Sdr146992 6672958Sdr146992 /* 6682958Sdr146992 * Get next interface from the current list of IPv6 logical network interfaces 6692958Sdr146992 */ 6702958Sdr146992 static lif_if_t 6713448Sdh155122 ipv6_lifgetnext(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) 6722958Sdr146992 { 6733448Sdh155122 ASSERT(ns != NULL); 6743448Sdh155122 return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_TRUE, 6753448Sdh155122 ns->netstack_ip)); 6762958Sdr146992 } 6772958Sdr146992 6782958Sdr146992 /* 6792958Sdr146992 * Shared implementation to get next interface from the current list of 6802958Sdr146992 * logical network interfaces 681*4041Snordmark * 682*4041Snordmark * Note: this does not handle the case when ipmp_hook_emulation is set. 683*4041Snordmark * But IP Filter does not use this function. 6842958Sdr146992 */ 6852958Sdr146992 static lif_if_t 6863448Sdh155122 ip_lifgetnext_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6, 6873448Sdh155122 ip_stack_t *ipst) 6882958Sdr146992 { 6892958Sdr146992 lif_if_t newidx, oldidx; 6902958Sdr146992 boolean_t nextok; 6912958Sdr146992 ipif_t *ipif; 6922958Sdr146992 ill_t *ill; 6932958Sdr146992 6943448Sdh155122 ill = ill_lookup_on_ifindex(phy_ifdata, isv6, NULL, NULL, 6953448Sdh155122 NULL, NULL, ipst); 6962958Sdr146992 if (ill == NULL) 6972958Sdr146992 return (0); 6982958Sdr146992 6992958Sdr146992 if (ifdata != 0) { 7002958Sdr146992 oldidx = UNMAP_IPIF_ID(ifdata); 7012958Sdr146992 nextok = B_FALSE; 7022958Sdr146992 } else { 7032958Sdr146992 oldidx = 0; 7042958Sdr146992 nextok = B_TRUE; 7052958Sdr146992 } 7062958Sdr146992 7072958Sdr146992 mutex_enter(&ill->ill_lock); 7082958Sdr146992 if (ill->ill_state_flags & ILL_CONDEMNED) { 7092958Sdr146992 mutex_exit(&ill->ill_lock); 7102958Sdr146992 ill_refrele(ill); 7112958Sdr146992 return (0); 7122958Sdr146992 } 7132958Sdr146992 7142958Sdr146992 /* 7152958Sdr146992 * It's safe to iterate the ill_ipif list when holding an ill_lock. 7162958Sdr146992 * And it's also safe to access ipif_id without ipif refhold. 7172958Sdr146992 * See ipif_get_id(). 7182958Sdr146992 */ 7192958Sdr146992 for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) { 7202958Sdr146992 if (!IPIF_CAN_LOOKUP(ipif)) 7212958Sdr146992 continue; 7222958Sdr146992 if (nextok) { 7232958Sdr146992 ipif_refhold_locked(ipif); 7242958Sdr146992 break; 7252958Sdr146992 } else if (oldidx == ipif->ipif_id) { 7262958Sdr146992 nextok = B_TRUE; 7272958Sdr146992 } 7282958Sdr146992 } 7292958Sdr146992 7302958Sdr146992 mutex_exit(&ill->ill_lock); 7312958Sdr146992 ill_refrele(ill); 7322958Sdr146992 7332958Sdr146992 if (ipif == NULL) 7342958Sdr146992 return (0); 7352958Sdr146992 7362958Sdr146992 newidx = ipif->ipif_id; 7372958Sdr146992 ipif_refrele(ipif); 7382958Sdr146992 7392958Sdr146992 return (MAP_IPIF_ID(newidx)); 7402958Sdr146992 } 7412958Sdr146992 7422958Sdr146992 /* 7432958Sdr146992 * Inject an IPv4 packet to or from an interface 7442958Sdr146992 */ 7452958Sdr146992 static int 7463448Sdh155122 ip_inject(inject_t style, net_inject_t *packet, netstack_t *ns) 7472958Sdr146992 { 7483448Sdh155122 ASSERT(ns != NULL); 7493448Sdh155122 return (ip_inject_impl(style, packet, B_FALSE, ns->netstack_ip)); 7502958Sdr146992 } 7512958Sdr146992 7522958Sdr146992 7532958Sdr146992 /* 7542958Sdr146992 * Inject an IPv6 packet to or from an interface 7552958Sdr146992 */ 7562958Sdr146992 static int 7573448Sdh155122 ipv6_inject(inject_t style, net_inject_t *packet, netstack_t *ns) 7582958Sdr146992 { 7593448Sdh155122 ASSERT(ns != NULL); 7603448Sdh155122 return (ip_inject_impl(style, packet, B_TRUE, ns->netstack_ip)); 7612958Sdr146992 } 7622958Sdr146992 7632958Sdr146992 /* 7642958Sdr146992 * Shared implementation to inject a packet to or from an interface 7652958Sdr146992 * Return value: 7662958Sdr146992 * 0: successful 7672958Sdr146992 * -1: memory allocation failed 7682958Sdr146992 * 1: other errors 7692958Sdr146992 */ 7702958Sdr146992 static int 7713448Sdh155122 ip_inject_impl(inject_t style, net_inject_t *packet, boolean_t isv6, 7723448Sdh155122 ip_stack_t *ipst) 7732958Sdr146992 { 7742958Sdr146992 struct sockaddr_in6 *sin6; 7752958Sdr146992 ddi_taskq_t *tq = NULL; 7763448Sdh155122 void (* func)(void *); 7772958Sdr146992 injection_t *inject; 7782958Sdr146992 ip6_t *ip6h; 7792958Sdr146992 ire_t *ire; 7802958Sdr146992 mblk_t *mp; 7812958Sdr146992 7822958Sdr146992 ASSERT(packet != NULL); 7832958Sdr146992 ASSERT(packet->ni_packet != NULL); 7842958Sdr146992 ASSERT(packet->ni_packet->b_datap->db_type == M_DATA); 7852958Sdr146992 7862958Sdr146992 switch (style) { 7872958Sdr146992 case NI_QUEUE_IN: 7882958Sdr146992 inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP); 7892958Sdr146992 if (inject == NULL) 7902958Sdr146992 return (-1); 7912958Sdr146992 inject->inj_data = *packet; 7922958Sdr146992 inject->inj_isv6 = isv6; 7932958Sdr146992 /* 7942958Sdr146992 * deliver up into the kernel, immitating its reception by a 7952958Sdr146992 * network interface, add to list and schedule timeout 7962958Sdr146992 */ 7972958Sdr146992 func = ip_ni_queue_in_func; 7982958Sdr146992 tq = eventq_queue_in; 7992958Sdr146992 break; 8002958Sdr146992 8012958Sdr146992 case NI_QUEUE_OUT: 8022958Sdr146992 inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP); 8032958Sdr146992 if (inject == NULL) 8042958Sdr146992 return (-1); 8052958Sdr146992 inject->inj_data = *packet; 8062958Sdr146992 inject->inj_isv6 = isv6; 8072958Sdr146992 /* 8082958Sdr146992 * deliver out of the kernel, as if it were being sent via a 8092958Sdr146992 * raw socket so that IPFilter will see it again, add to list 8102958Sdr146992 * and schedule timeout 8112958Sdr146992 */ 8122958Sdr146992 func = ip_ni_queue_out_func; 8132958Sdr146992 tq = eventq_queue_out; 8142958Sdr146992 break; 8152958Sdr146992 8162958Sdr146992 case NI_DIRECT_OUT: 8172958Sdr146992 /* 8182958Sdr146992 * Note: 8192958Sdr146992 * For IPv4, the code path below will be greatly simplified 8202958Sdr146992 * with the delivery of surya - it will become a single 8212958Sdr146992 * function call to X. A follow on project is aimed to 8222958Sdr146992 * provide similar functionality for IPv6. 8232958Sdr146992 */ 8242958Sdr146992 mp = packet->ni_packet; 8252958Sdr146992 8262958Sdr146992 if (!isv6) { 8272958Sdr146992 struct sockaddr *sock; 8282958Sdr146992 8292958Sdr146992 sock = (struct sockaddr *)&packet->ni_addr; 8302958Sdr146992 /* 8312958Sdr146992 * ipfil_sendpkt was provided by surya to ease the 8322958Sdr146992 * problems associated with sending out a packet. 8332958Sdr146992 * Currently this function only supports IPv4. 8342958Sdr146992 */ 8352958Sdr146992 switch (ipfil_sendpkt(sock, mp, packet->ni_physical, 8363448Sdh155122 netstackid_to_zoneid( 8373448Sdh155122 ipst->ips_netstack->netstack_stackid))) { 8382958Sdr146992 case 0 : 8392958Sdr146992 case EINPROGRESS: 8402958Sdr146992 return (0); 8412958Sdr146992 case ECOMM : 8422958Sdr146992 case ENONET : 8432958Sdr146992 return (1); 8442958Sdr146992 default : 8452958Sdr146992 return (1); 8462958Sdr146992 } 8472958Sdr146992 /* NOTREACHED */ 8482958Sdr146992 8492958Sdr146992 } 8502958Sdr146992 8512958Sdr146992 ip6h = (ip6_t *)mp->b_rptr; 8522958Sdr146992 sin6 = (struct sockaddr_in6 *)&packet->ni_addr; 8532958Sdr146992 ASSERT(sin6->sin6_family == AF_INET6); 8542958Sdr146992 8552958Sdr146992 ire = ire_route_lookup_v6(&sin6->sin6_addr, 0, 0, 0, 8562958Sdr146992 NULL, NULL, ALL_ZONES, NULL, 8573448Sdh155122 MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE, 8583448Sdh155122 ipst); 8592958Sdr146992 8602958Sdr146992 if (ire == NULL) { 8612958Sdr146992 ip2dbg(("ip_inject: ire_cache_lookup failed\n")); 8622958Sdr146992 freemsg(mp); 8632958Sdr146992 return (1); 8642958Sdr146992 } 8652958Sdr146992 8662958Sdr146992 if (ire->ire_stq == NULL) { 8672958Sdr146992 /* Send to loopback destination. */ 8682958Sdr146992 if (ire->ire_rfq == NULL) { 8692958Sdr146992 ip2dbg(("ip_inject: bad nexthop\n")); 8702958Sdr146992 ire_refrele(ire); 8712958Sdr146992 freemsg(mp); 8722958Sdr146992 return (1); 8732958Sdr146992 } 8742958Sdr146992 ip_wput_local_v6(ire->ire_rfq, 8752958Sdr146992 ire->ire_ipif->ipif_ill, ip6h, mp, ire, 0); 8762958Sdr146992 ire_refrele(ire); 8772958Sdr146992 return (0); 8782958Sdr146992 } 8792958Sdr146992 8802958Sdr146992 mp->b_queue = ire->ire_stq; 8812958Sdr146992 8822958Sdr146992 if (ire->ire_nce == NULL || 8832958Sdr146992 ire->ire_nce->nce_fp_mp == NULL && 8842958Sdr146992 ire->ire_nce->nce_res_mp == NULL) { 8852958Sdr146992 ip_newroute_v6(ire->ire_stq, mp, 8863448Sdh155122 &sin6->sin6_addr, NULL, NULL, ALL_ZONES, ipst); 8872958Sdr146992 8882958Sdr146992 ire_refrele(ire); 8892958Sdr146992 return (0); 8902958Sdr146992 } else { 8912958Sdr146992 /* prepend L2 header for IPv6 packets. */ 8922958Sdr146992 mblk_t *llmp; 8932958Sdr146992 8942958Sdr146992 /* 8952958Sdr146992 * Lock IREs, see 6420438 8962958Sdr146992 */ 8972958Sdr146992 mutex_enter(&ire->ire_lock); 8982958Sdr146992 llmp = ire->ire_nce->nce_fp_mp ? 8992958Sdr146992 ire->ire_nce->nce_fp_mp : 9002958Sdr146992 ire->ire_nce->nce_res_mp; 9012958Sdr146992 9022958Sdr146992 if ((mp = dupb(llmp)) == NULL && 9032958Sdr146992 (mp = copyb(llmp)) == NULL) { 9042958Sdr146992 ip2dbg(("ip_inject: llhdr failed\n")); 9052958Sdr146992 mutex_exit(&ire->ire_lock); 9062958Sdr146992 ire_refrele(ire); 9072958Sdr146992 freemsg(mp); 9082958Sdr146992 return (1); 9092958Sdr146992 } 9102958Sdr146992 mutex_exit(&ire->ire_lock); 9112958Sdr146992 linkb(mp, packet->ni_packet); 9122958Sdr146992 } 9132958Sdr146992 9142958Sdr146992 mp->b_queue = ire->ire_stq; 9152958Sdr146992 9162958Sdr146992 break; 9172958Sdr146992 default: 9182958Sdr146992 freemsg(packet->ni_packet); 9192958Sdr146992 return (1); 9202958Sdr146992 } 9212958Sdr146992 9222958Sdr146992 if (tq) { 9233448Sdh155122 inject->inj_ptr = ipst; 9242958Sdr146992 if (ddi_taskq_dispatch(tq, func, (void *)inject, 9252958Sdr146992 DDI_SLEEP) == DDI_FAILURE) { 9262958Sdr146992 ip2dbg(("ip_inject: ddi_taskq_dispatch failed\n")); 9272958Sdr146992 freemsg(packet->ni_packet); 9282958Sdr146992 return (1); 9292958Sdr146992 } 9302958Sdr146992 } else { 9312958Sdr146992 putnext(ire->ire_stq, mp); 9322958Sdr146992 ire_refrele(ire); 9332958Sdr146992 } 9342958Sdr146992 9352958Sdr146992 return (0); 9362958Sdr146992 } 9372958Sdr146992 9382958Sdr146992 /* 9392958Sdr146992 * Find the interface used for traffic to a given IPv4 address 9402958Sdr146992 */ 9412958Sdr146992 static phy_if_t 9423448Sdh155122 ip_routeto(struct sockaddr *address, netstack_t *ns) 9432958Sdr146992 { 9442958Sdr146992 ASSERT(address != NULL); 9453448Sdh155122 ASSERT(ns != NULL); 9462958Sdr146992 9472958Sdr146992 if (address->sa_family != AF_INET) 9482958Sdr146992 return (0); 9493448Sdh155122 return (ip_routeto_impl(address, ns->netstack_ip)); 9502958Sdr146992 } 9512958Sdr146992 9522958Sdr146992 /* 9532958Sdr146992 * Find the interface used for traffic to a given IPv6 address 9542958Sdr146992 */ 9552958Sdr146992 static phy_if_t 9563448Sdh155122 ipv6_routeto(struct sockaddr *address, netstack_t *ns) 9572958Sdr146992 { 9582958Sdr146992 ASSERT(address != NULL); 9593448Sdh155122 ASSERT(ns != NULL); 9602958Sdr146992 9612958Sdr146992 if (address->sa_family != AF_INET6) 9622958Sdr146992 return (0); 9633448Sdh155122 return (ip_routeto_impl(address, ns->netstack_ip)); 9642958Sdr146992 } 9652958Sdr146992 9662958Sdr146992 9672958Sdr146992 /* 9682958Sdr146992 * Find the interface used for traffic to an address 9692958Sdr146992 */ 9702958Sdr146992 static phy_if_t 9713448Sdh155122 ip_routeto_impl(struct sockaddr *address, ip_stack_t *ipst) 9722958Sdr146992 { 9732958Sdr146992 ire_t *ire; 9742958Sdr146992 ill_t *ill; 9752958Sdr146992 phy_if_t phy_if; 9762958Sdr146992 9772958Sdr146992 if (address->sa_family == AF_INET6) { 9782958Sdr146992 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)address; 9792958Sdr146992 ire = ire_route_lookup_v6(&sin6->sin6_addr, NULL, 9802958Sdr146992 0, 0, NULL, NULL, ALL_ZONES, NULL, 9813448Sdh155122 MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE, 9823448Sdh155122 ipst); 9832958Sdr146992 } else { 9842958Sdr146992 struct sockaddr_in *sin = (struct sockaddr_in *)address; 9852958Sdr146992 ire = ire_route_lookup(sin->sin_addr.s_addr, 0, 9862958Sdr146992 0, 0, NULL, NULL, ALL_ZONES, NULL, 9873448Sdh155122 MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE, 9883448Sdh155122 ipst); 9892958Sdr146992 } 9902958Sdr146992 9912958Sdr146992 if (ire == NULL) 9922958Sdr146992 return (0); 9932958Sdr146992 9942958Sdr146992 ill = ire_to_ill(ire); 995*4041Snordmark if (ill == NULL) { 996*4041Snordmark ire_refrele(ire); 9972958Sdr146992 return (0); 998*4041Snordmark } 9992958Sdr146992 10002958Sdr146992 ASSERT(ill != NULL); 1001*4041Snordmark phy_if = (phy_if_t)ill->ill_phyint->phyint_hook_ifindex; 10022958Sdr146992 ire_refrele(ire); 10032958Sdr146992 10042958Sdr146992 return (phy_if); 10052958Sdr146992 } 10062958Sdr146992 10072958Sdr146992 /* 10082958Sdr146992 * Determine if checksumming is being used for the given packet. 10092958Sdr146992 * 10102958Sdr146992 * Return value: 10112958Sdr146992 * NET_HCK_NONE: full checksum recalculation is required 10122958Sdr146992 * NET_HCK_L3_FULL: full layer 3 checksum 10132958Sdr146992 * NET_HCK_L4_FULL: full layer 4 checksum 10142958Sdr146992 * NET_HCK_L4_PART: partial layer 4 checksum 10152958Sdr146992 */ 10162958Sdr146992 static int 10172958Sdr146992 ip_ispartialchecksum(mblk_t *mp) 10182958Sdr146992 { 10192958Sdr146992 int ret = 0; 10202958Sdr146992 10212958Sdr146992 ASSERT(mp != NULL); 10222958Sdr146992 10232958Sdr146992 if ((DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) != 0) { 10242958Sdr146992 ret |= (int)NET_HCK_L4_FULL; 10252958Sdr146992 if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0) 10262958Sdr146992 ret |= (int)NET_HCK_L3_FULL; 10272958Sdr146992 } 10282958Sdr146992 if ((DB_CKSUMFLAGS(mp) & HCK_PARTIALCKSUM) != 0) { 10292958Sdr146992 ret |= (int)NET_HCK_L4_PART; 10302958Sdr146992 if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0) 10312958Sdr146992 ret |= (int)NET_HCK_L3_FULL; 10322958Sdr146992 } 10332958Sdr146992 10342958Sdr146992 return (ret); 10352958Sdr146992 } 10362958Sdr146992 10372958Sdr146992 /* 10382958Sdr146992 * Return true or false, indicating whether the network and transport 10392958Sdr146992 * headers are correct. Use the capabilities flags and flags set in the 10402958Sdr146992 * dblk_t to determine whether or not the checksum is valid. 10412958Sdr146992 * 10422958Sdr146992 * Return: 10432958Sdr146992 * 0: the checksum was incorrect 10442958Sdr146992 * 1: the original checksum was correct 10452958Sdr146992 */ 10462958Sdr146992 static int 10472958Sdr146992 ip_isvalidchecksum(mblk_t *mp) 10482958Sdr146992 { 10492958Sdr146992 unsigned char *wptr; 10502958Sdr146992 ipha_t *ipha = (ipha_t *)mp->b_rptr; 10512958Sdr146992 int hlen; 10522958Sdr146992 int ret; 10532958Sdr146992 10542958Sdr146992 ASSERT(mp != NULL); 10552958Sdr146992 10562958Sdr146992 if (dohwcksum && 10572958Sdr146992 DB_CKSUM16(mp) != 0xFFFF && 10582958Sdr146992 (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) && 10592958Sdr146992 (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM_OK) && 10602958Sdr146992 (DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM)) 10612958Sdr146992 return (1); 10622958Sdr146992 10632958Sdr146992 hlen = (ipha->ipha_version_and_hdr_length & 0x0F) << 2; 10642958Sdr146992 10652958Sdr146992 /* 10662958Sdr146992 * Check that the mblk being passed in has enough data in it 10672958Sdr146992 * before blindly checking ip_cksum. 10682958Sdr146992 */ 10692958Sdr146992 if (msgdsize(mp) < hlen) 10702958Sdr146992 return (0); 10712958Sdr146992 10722958Sdr146992 if (mp->b_wptr < mp->b_rptr + hlen) { 10732958Sdr146992 if (pullupmsg(mp, hlen) == 0) 10742958Sdr146992 return (0); 10752958Sdr146992 wptr = mp->b_wptr; 10762958Sdr146992 } else { 10772958Sdr146992 wptr = mp->b_wptr; 10782958Sdr146992 mp->b_wptr = mp->b_rptr + hlen; 10792958Sdr146992 } 10802958Sdr146992 10812958Sdr146992 if (ipha->ipha_hdr_checksum == ip_cksum(mp, 0, ipha->ipha_hdr_checksum)) 10822958Sdr146992 ret = 1; 10832958Sdr146992 else 10842958Sdr146992 ret = 0; 10852958Sdr146992 mp->b_wptr = wptr; 10862958Sdr146992 10872958Sdr146992 return (ret); 10882958Sdr146992 } 10892958Sdr146992 10902958Sdr146992 /* 10912958Sdr146992 * Unsupported with IPv6 10922958Sdr146992 */ 10932958Sdr146992 /*ARGSUSED*/ 10942958Sdr146992 static int 10952958Sdr146992 ipv6_isvalidchecksum(mblk_t *mp) 10962958Sdr146992 { 10972958Sdr146992 return (-1); 10982958Sdr146992 } 10992958Sdr146992 11002958Sdr146992 /* 11012958Sdr146992 * Determine the network addresses for an IPv4 interface 11022958Sdr146992 */ 11032958Sdr146992 static int 11042958Sdr146992 ip_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem, 11053448Sdh155122 net_ifaddr_t type[], void *storage, netstack_t *ns) 11062958Sdr146992 { 11073448Sdh155122 ASSERT(ns != NULL); 11082958Sdr146992 return (ip_getlifaddr_impl(AF_INET, phy_ifdata, ifdata, 11093448Sdh155122 nelem, type, storage, ns->netstack_ip)); 11102958Sdr146992 } 11112958Sdr146992 11122958Sdr146992 /* 11132958Sdr146992 * Determine the network addresses for an IPv6 interface 11142958Sdr146992 */ 11152958Sdr146992 static int 11162958Sdr146992 ipv6_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem, 11173448Sdh155122 net_ifaddr_t type[], void *storage, netstack_t *ns) 11182958Sdr146992 { 11193448Sdh155122 ASSERT(ns != NULL); 11202958Sdr146992 return (ip_getlifaddr_impl(AF_INET6, phy_ifdata, ifdata, 11213448Sdh155122 nelem, type, storage, ns->netstack_ip)); 11222958Sdr146992 } 11232958Sdr146992 11242958Sdr146992 /* 11252958Sdr146992 * Shared implementation to determine the network addresses for an interface 1126*4041Snordmark * 1127*4041Snordmark * Note: this does not handle a non-zero ifdata when ipmp_hook_emulation is set. 1128*4041Snordmark * But IP Filter only uses a zero ifdata. 11292958Sdr146992 */ 11302958Sdr146992 /* ARGSUSED */ 11312958Sdr146992 static int 11322958Sdr146992 ip_getlifaddr_impl(sa_family_t family, phy_if_t phy_ifdata, 11332958Sdr146992 lif_if_t ifdata, size_t nelem, net_ifaddr_t type[], 11343448Sdh155122 struct sockaddr *storage, ip_stack_t *ipst) 11352958Sdr146992 { 11362958Sdr146992 struct sockaddr_in6 *sin6; 11372958Sdr146992 struct sockaddr_in *sin; 11382958Sdr146992 lif_if_t ipifid; 11392958Sdr146992 ipif_t *ipif; 11402958Sdr146992 int i; 11412958Sdr146992 11422958Sdr146992 ASSERT(type != NULL); 11432958Sdr146992 ASSERT(storage != NULL); 11442958Sdr146992 11452958Sdr146992 ipifid = UNMAP_IPIF_ID(ifdata); 11462958Sdr146992 11472958Sdr146992 if (family == AF_INET) { 11482958Sdr146992 if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata, 11493448Sdh155122 (uint_t)ipifid, B_FALSE, ipst)) == NULL) 11502958Sdr146992 return (1); 11512958Sdr146992 11522958Sdr146992 sin = (struct sockaddr_in *)storage; 11532958Sdr146992 for (i = 0; i < nelem; i++, sin++) { 11542958Sdr146992 if (ip_getifaddr_type(AF_INET, ipif, type[i], 11552958Sdr146992 &sin->sin_addr) < 0) { 11562958Sdr146992 ip2dbg(("ip_getlifaddr_impl failed type %d\n", 11572958Sdr146992 type[i])); 11582958Sdr146992 ipif_refrele(ipif); 11592958Sdr146992 return (1); 11602958Sdr146992 } 11612958Sdr146992 } 11622958Sdr146992 } else { 11632958Sdr146992 if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata, 11643448Sdh155122 (uint_t)ipifid, B_TRUE, ipst)) == NULL) 11652958Sdr146992 return (1); 11662958Sdr146992 11672958Sdr146992 sin6 = (struct sockaddr_in6 *)storage; 11682958Sdr146992 for (i = 0; i < nelem; i++, sin6++) { 11692958Sdr146992 if (ip_getifaddr_type(AF_INET6, ipif, type[i], 11702958Sdr146992 &sin6->sin6_addr) < 0) { 11712958Sdr146992 ip2dbg(("ip_getlifaddr_impl failed type %d\n", 11722958Sdr146992 type[i])); 11732958Sdr146992 ipif_refrele(ipif); 11742958Sdr146992 return (1); 11752958Sdr146992 } 11762958Sdr146992 } 11772958Sdr146992 } 11782958Sdr146992 ipif_refrele(ipif); 11792958Sdr146992 return (0); 11802958Sdr146992 } 11812958Sdr146992 11822958Sdr146992 /* 11832958Sdr146992 * ip_getlifaddr private function 11842958Sdr146992 */ 11852958Sdr146992 static int 11862958Sdr146992 ip_getifaddr_type(sa_family_t family, ipif_t *ill_ipif, 11872958Sdr146992 lif_if_t type, void *storage) 11882958Sdr146992 { 11892958Sdr146992 void *src_addr; 11902958Sdr146992 int mem_size; 11912958Sdr146992 11922958Sdr146992 ASSERT(ill_ipif != NULL); 11932958Sdr146992 ASSERT(storage != NULL); 11942958Sdr146992 11952958Sdr146992 if (family == AF_INET) { 11962958Sdr146992 mem_size = sizeof (struct in_addr); 11972958Sdr146992 11982958Sdr146992 switch (type) { 11992958Sdr146992 case NA_ADDRESS: 12002958Sdr146992 src_addr = &(ill_ipif->ipif_lcl_addr); 12012958Sdr146992 break; 12022958Sdr146992 case NA_PEER: 12032958Sdr146992 src_addr = &(ill_ipif->ipif_pp_dst_addr); 12042958Sdr146992 break; 12052958Sdr146992 case NA_BROADCAST: 12062958Sdr146992 src_addr = &(ill_ipif->ipif_brd_addr); 12072958Sdr146992 break; 12082958Sdr146992 case NA_NETMASK: 12092958Sdr146992 src_addr = &(ill_ipif->ipif_net_mask); 12102958Sdr146992 break; 12112958Sdr146992 default: 12122958Sdr146992 return (-1); 12132958Sdr146992 /*NOTREACHED*/ 12142958Sdr146992 } 12152958Sdr146992 } else { 12162958Sdr146992 mem_size = sizeof (struct in6_addr); 12172958Sdr146992 12182958Sdr146992 switch (type) { 12192958Sdr146992 case NA_ADDRESS: 12202958Sdr146992 src_addr = &(ill_ipif->ipif_v6lcl_addr); 12212958Sdr146992 break; 12222958Sdr146992 case NA_PEER: 12232958Sdr146992 src_addr = &(ill_ipif->ipif_v6pp_dst_addr); 12242958Sdr146992 break; 12252958Sdr146992 case NA_BROADCAST: 12262958Sdr146992 src_addr = &(ill_ipif->ipif_v6brd_addr); 12272958Sdr146992 break; 12282958Sdr146992 case NA_NETMASK: 12292958Sdr146992 src_addr = &(ill_ipif->ipif_v6net_mask); 12302958Sdr146992 break; 12312958Sdr146992 default: 12322958Sdr146992 return (-1); 12332958Sdr146992 /*NOTREACHED*/ 12342958Sdr146992 } 12352958Sdr146992 } 12362958Sdr146992 12372958Sdr146992 (void) memcpy(storage, src_addr, mem_size); 12382958Sdr146992 return (1); 12392958Sdr146992 } 12402958Sdr146992 12412958Sdr146992 /* 12422958Sdr146992 * Deliver packet up into the kernel, immitating its reception by a 12432958Sdr146992 * network interface. 12442958Sdr146992 */ 12452958Sdr146992 static void 12462958Sdr146992 ip_ni_queue_in_func(void *inject) 12472958Sdr146992 { 12482958Sdr146992 ip_ni_queue_func_impl(inject, B_FALSE); 12492958Sdr146992 } 12502958Sdr146992 12512958Sdr146992 /* 12522958Sdr146992 * Deliver out of the kernel, as if it were being sent via a 12532958Sdr146992 * raw socket so that IPFilter will see it again. 12542958Sdr146992 */ 12552958Sdr146992 static void 12562958Sdr146992 ip_ni_queue_out_func(void *inject) 12572958Sdr146992 { 12582958Sdr146992 ip_ni_queue_func_impl(inject, B_TRUE); 12592958Sdr146992 } 12602958Sdr146992 12612958Sdr146992 /* 12622958Sdr146992 * Shared implementation for inject via ip_output and ip_input 12632958Sdr146992 */ 12642958Sdr146992 static void 12652958Sdr146992 ip_ni_queue_func_impl(injection_t *inject, boolean_t out) 12662958Sdr146992 { 12672958Sdr146992 net_inject_t *packet; 12682958Sdr146992 conn_t *conn; 12692958Sdr146992 ill_t *ill; 12703448Sdh155122 ip_stack_t *ipst = (ip_stack_t *)inject->inj_ptr; 12712958Sdr146992 12722958Sdr146992 ASSERT(inject != NULL); 12732958Sdr146992 packet = &inject->inj_data; 12742958Sdr146992 ASSERT(packet->ni_packet != NULL); 12752958Sdr146992 1276*4041Snordmark ill = ill_lookup_on_ifindex((uint_t)packet->ni_physical, 1277*4041Snordmark B_FALSE, NULL, NULL, NULL, NULL, ipst); 1278*4041Snordmark 1279*4041Snordmark /* Fallback to group names only if hook_emulation is set */ 1280*4041Snordmark if (ill == NULL && ipst->ips_ipmp_hook_emulation) { 1281*4041Snordmark ill = ill_group_lookup_on_ifindex((uint_t)packet->ni_physical, 1282*4041Snordmark B_FALSE, ipst); 1283*4041Snordmark } 1284*4041Snordmark if (ill == NULL) { 12852958Sdr146992 kmem_free(inject, sizeof (*inject)); 12862958Sdr146992 return; 12872958Sdr146992 } 12882958Sdr146992 12892958Sdr146992 if (out == 0) { 12902958Sdr146992 if (inject->inj_isv6) { 12912958Sdr146992 ip_rput_v6(ill->ill_rq, packet->ni_packet); 12922958Sdr146992 } else { 12932958Sdr146992 ip_input(ill, NULL, packet->ni_packet, 0); 12942958Sdr146992 } 12952958Sdr146992 kmem_free(inject, sizeof (*inject)); 12962958Sdr146992 ill_refrele(ill); 12972958Sdr146992 return; 12982958Sdr146992 } 12992958Sdr146992 13002958Sdr146992 /* 13012958Sdr146992 * Even though ipcl_conn_create requests that it be passed 13022958Sdr146992 * a different value for "TCP", in this case there may not 13032958Sdr146992 * be a TCP connection backing the packet and more than 13042958Sdr146992 * likely, non-TCP packets will go here too. 13052958Sdr146992 */ 13063448Sdh155122 conn = ipcl_conn_create(IPCL_IPCCONN, KM_NOSLEEP, ipst->ips_netstack); 13072958Sdr146992 if (conn != NULL) { 13082958Sdr146992 if (inject->inj_isv6) { 13092958Sdr146992 conn->conn_flags |= IPCL_ISV6; 13102958Sdr146992 conn->conn_af_isv6 = B_TRUE; 13112958Sdr146992 conn->conn_src_preferences = IPV6_PREFER_SRC_DEFAULT; 13122958Sdr146992 conn->conn_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; 13132958Sdr146992 ip_output_v6(conn, packet->ni_packet, ill->ill_wq, 13142958Sdr146992 IP_WPUT); 13152958Sdr146992 } else { 13162958Sdr146992 conn->conn_af_isv6 = B_FALSE; 13172958Sdr146992 conn->conn_pkt_isv6 = B_FALSE; 13182958Sdr146992 conn->conn_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; 13192958Sdr146992 ip_output(conn, packet->ni_packet, ill->ill_wq, 13202958Sdr146992 IP_WPUT); 13212958Sdr146992 } 13222958Sdr146992 13232958Sdr146992 CONN_DEC_REF(conn); 13242958Sdr146992 } 13252958Sdr146992 13262958Sdr146992 kmem_free(inject, sizeof (*inject)); 13272958Sdr146992 ill_refrele(ill); 13282958Sdr146992 } 13292958Sdr146992 13302958Sdr146992 /* 13312958Sdr146992 * taskq function for nic events. 13322958Sdr146992 */ 13332958Sdr146992 void 13342958Sdr146992 ip_ne_queue_func(void *arg) 13352958Sdr146992 { 13362958Sdr146992 hook_event_int_t *hr; 13372958Sdr146992 hook_nic_event_t *info = (hook_nic_event_t *)arg; 13383448Sdh155122 netstack_t *ns = info->hne_family->netd_netstack; 13393448Sdh155122 ip_stack_t *ipst = ns->netstack_ip; 13402958Sdr146992 13413448Sdh155122 hr = (info->hne_family == ipst->ips_ipv6_net_data) ? 13423448Sdh155122 ipst->ips_ipv6nicevents : ipst->ips_ipv4nicevents; 13433448Sdh155122 (void) hook_run(hr, (hook_data_t)info, ns); 13442958Sdr146992 13452958Sdr146992 if (info->hne_data != NULL) 13462958Sdr146992 kmem_free(info->hne_data, info->hne_datalen); 13472958Sdr146992 kmem_free(arg, sizeof (hook_nic_event_t)); 13482958Sdr146992 } 1349*4041Snordmark 1350*4041Snordmark /* 1351*4041Snordmark * Temporary function to support IPMP emulation for IP Filter. 1352*4041Snordmark * Lookup an ill based on the ifindex assigned to the group. 1353*4041Snordmark * Skips unusable ones i.e. where any of these flags are set: 1354*4041Snordmark * (PHYI_FAILED|PHYI_STANDBY|PHYI_OFFLINE|PHYI_INACTIVE) 1355*4041Snordmark */ 1356*4041Snordmark ill_t * 1357*4041Snordmark ill_group_lookup_on_ifindex(uint_t index, boolean_t isv6, ip_stack_t *ipst) 1358*4041Snordmark { 1359*4041Snordmark ill_t *ill; 1360*4041Snordmark phyint_t *phyi; 1361*4041Snordmark 1362*4041Snordmark rw_enter(&ipst->ips_ill_g_lock, RW_READER); 1363*4041Snordmark phyi = phyint_lookup_group_ifindex(index, ipst); 1364*4041Snordmark if (phyi != NULL) { 1365*4041Snordmark ill = isv6 ? phyi->phyint_illv6: phyi->phyint_illv4; 1366*4041Snordmark if (ill != NULL) { 1367*4041Snordmark mutex_enter(&ill->ill_lock); 1368*4041Snordmark if (ILL_CAN_LOOKUP(ill)) { 1369*4041Snordmark ill_refhold_locked(ill); 1370*4041Snordmark mutex_exit(&ill->ill_lock); 1371*4041Snordmark rw_exit(&ipst->ips_ill_g_lock); 1372*4041Snordmark return (ill); 1373*4041Snordmark } 1374*4041Snordmark } 1375*4041Snordmark } 1376*4041Snordmark rw_exit(&ipst->ips_ill_g_lock); 1377*4041Snordmark return (NULL); 1378*4041Snordmark } 1379*4041Snordmark 1380*4041Snordmark /* 1381*4041Snordmark * Temporary function to support IPMP emulation for IP Filter. 1382*4041Snordmark * Lookup an ill based on the group name. 1383*4041Snordmark * Skips unusable ones i.e. where any of these flags are set: 1384*4041Snordmark * (PHYI_FAILED|PHYI_STANDBY|PHYI_OFFLINE|PHYI_INACTIVE) 1385*4041Snordmark */ 1386*4041Snordmark ill_t * 1387*4041Snordmark ill_group_lookup_on_name(char *name, boolean_t isv6, ip_stack_t *ipst) 1388*4041Snordmark { 1389*4041Snordmark ill_t *ill; 1390*4041Snordmark phyint_t *phyi; 1391*4041Snordmark 1392*4041Snordmark rw_enter(&ipst->ips_ill_g_lock, RW_READER); 1393*4041Snordmark phyi = phyint_lookup_group(name, B_TRUE, ipst); 1394*4041Snordmark if (phyi != NULL) { 1395*4041Snordmark ill = isv6 ? phyi->phyint_illv6: phyi->phyint_illv4; 1396*4041Snordmark if (ill != NULL) { 1397*4041Snordmark mutex_enter(&ill->ill_lock); 1398*4041Snordmark if (ILL_CAN_LOOKUP(ill)) { 1399*4041Snordmark ill_refhold_locked(ill); 1400*4041Snordmark mutex_exit(&ill->ill_lock); 1401*4041Snordmark rw_exit(&ipst->ips_ill_g_lock); 1402*4041Snordmark return (ill); 1403*4041Snordmark } 1404*4041Snordmark } 1405*4041Snordmark } 1406*4041Snordmark rw_exit(&ipst->ips_ill_g_lock); 1407*4041Snordmark return (NULL); 1408*4041Snordmark } 1409