1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/stream.h> 31*0Sstevel@tonic-gate #include <sys/stropts.h> 32*0Sstevel@tonic-gate #include <sys/sysmacros.h> 33*0Sstevel@tonic-gate #include <sys/errno.h> 34*0Sstevel@tonic-gate #include <sys/strlog.h> 35*0Sstevel@tonic-gate #include <sys/dlpi.h> 36*0Sstevel@tonic-gate #include <sys/sockio.h> 37*0Sstevel@tonic-gate #include <sys/tiuser.h> 38*0Sstevel@tonic-gate #include <sys/tihdr.h> 39*0Sstevel@tonic-gate #include <sys/socket.h> 40*0Sstevel@tonic-gate #include <sys/ddi.h> 41*0Sstevel@tonic-gate #include <sys/cmn_err.h> 42*0Sstevel@tonic-gate #include <sys/debug.h> 43*0Sstevel@tonic-gate #include <sys/vtrace.h> 44*0Sstevel@tonic-gate #include <sys/kmem.h> 45*0Sstevel@tonic-gate #include <sys/zone.h> 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate #include <net/if.h> 48*0Sstevel@tonic-gate #include <net/if_types.h> 49*0Sstevel@tonic-gate #include <net/if_dl.h> 50*0Sstevel@tonic-gate #include <net/route.h> 51*0Sstevel@tonic-gate #include <sys/sockio.h> 52*0Sstevel@tonic-gate #include <netinet/in.h> 53*0Sstevel@tonic-gate #include <netinet/in_systm.h> 54*0Sstevel@tonic-gate #include <netinet/ip6.h> 55*0Sstevel@tonic-gate #include <netinet/icmp6.h> 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate #include <inet/common.h> 58*0Sstevel@tonic-gate #include <inet/mi.h> 59*0Sstevel@tonic-gate #include <inet/mib2.h> 60*0Sstevel@tonic-gate #include <inet/nd.h> 61*0Sstevel@tonic-gate #include <inet/arp.h> 62*0Sstevel@tonic-gate #include <inet/ip.h> 63*0Sstevel@tonic-gate #include <inet/ip_multi.h> 64*0Sstevel@tonic-gate #include <inet/ip_if.h> 65*0Sstevel@tonic-gate #include <inet/ip_ire.h> 66*0Sstevel@tonic-gate #include <inet/ip_rts.h> 67*0Sstevel@tonic-gate #include <inet/ip6.h> 68*0Sstevel@tonic-gate #include <inet/ip_ndp.h> 69*0Sstevel@tonic-gate #include <inet/ipsec_impl.h> 70*0Sstevel@tonic-gate #include <inet/ipsec_info.h> 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* 73*0Sstevel@tonic-gate * Function names with nce_ prefix are static while function 74*0Sstevel@tonic-gate * names with ndp_ prefix are used by rest of the IP. 75*0Sstevel@tonic-gate */ 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate static boolean_t nce_cmp_ll_addr(nce_t *nce, char *new_ll_addr, 78*0Sstevel@tonic-gate uint32_t ll_addr_len); 79*0Sstevel@tonic-gate static void nce_fastpath(nce_t *nce); 80*0Sstevel@tonic-gate static void nce_ire_delete(nce_t *nce); 81*0Sstevel@tonic-gate static void nce_ire_delete1(ire_t *ire, char *nce_arg); 82*0Sstevel@tonic-gate static void nce_set_ll(nce_t *nce, uchar_t *ll_addr); 83*0Sstevel@tonic-gate static nce_t *nce_lookup_addr(ill_t *ill, const in6_addr_t *addr); 84*0Sstevel@tonic-gate static nce_t *nce_lookup_mapping(ill_t *ill, const in6_addr_t *addr); 85*0Sstevel@tonic-gate static void nce_make_mapping(nce_t *nce, uchar_t *addrpos, 86*0Sstevel@tonic-gate uchar_t *addr); 87*0Sstevel@tonic-gate static int nce_set_multicast(ill_t *ill, const in6_addr_t *addr); 88*0Sstevel@tonic-gate static void nce_queue_mp(nce_t *nce, mblk_t *mp); 89*0Sstevel@tonic-gate static void nce_report1(nce_t *nce, uchar_t *mp_arg); 90*0Sstevel@tonic-gate static mblk_t *nce_udreq_alloc(ill_t *ill); 91*0Sstevel@tonic-gate static void nce_update(nce_t *nce, uint16_t new_state, 92*0Sstevel@tonic-gate uchar_t *new_ll_addr); 93*0Sstevel@tonic-gate static uint32_t nce_solicit(nce_t *nce, mblk_t *mp); 94*0Sstevel@tonic-gate static boolean_t nce_xmit(ill_t *ill, uint32_t operation, 95*0Sstevel@tonic-gate ill_t *hwaddr_ill, boolean_t use_lla_addr, const in6_addr_t *sender, 96*0Sstevel@tonic-gate const in6_addr_t *target, int flag); 97*0Sstevel@tonic-gate static void lla2ascii(uint8_t *lla, int addrlen, uchar_t *buf); 98*0Sstevel@tonic-gate extern void th_trace_rrecord(th_trace_t *); 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate #ifdef NCE_DEBUG 101*0Sstevel@tonic-gate void nce_trace_inactive(nce_t *); 102*0Sstevel@tonic-gate #endif 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate /* NDP Cache Entry Hash Table */ 105*0Sstevel@tonic-gate #define NCE_TABLE_SIZE 256 106*0Sstevel@tonic-gate static nce_t *nce_hash_tbl[NCE_TABLE_SIZE]; 107*0Sstevel@tonic-gate static nce_t *nce_mask_entries; /* mask not all ones */ 108*0Sstevel@tonic-gate static int ndp_g_walker = 0; /* # of active thread */ 109*0Sstevel@tonic-gate /* walking nce hash list */ 110*0Sstevel@tonic-gate /* ndp_g_walker_cleanup will be true, when deletion have to be defered */ 111*0Sstevel@tonic-gate static boolean_t ndp_g_walker_cleanup = B_FALSE; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate #ifdef _BIG_ENDIAN 114*0Sstevel@tonic-gate #define IN6_IS_ADDR_MC_SOLICITEDNODE(addr) \ 115*0Sstevel@tonic-gate ((((addr)->s6_addr32[0] & 0xff020000) == 0xff020000) && \ 116*0Sstevel@tonic-gate ((addr)->s6_addr32[1] == 0x0) && \ 117*0Sstevel@tonic-gate ((addr)->s6_addr32[2] == 0x00000001) && \ 118*0Sstevel@tonic-gate ((addr)->s6_addr32[3] & 0xff000000) == 0xff000000) 119*0Sstevel@tonic-gate #else /* _BIG_ENDIAN */ 120*0Sstevel@tonic-gate #define IN6_IS_ADDR_MC_SOLICITEDNODE(addr) \ 121*0Sstevel@tonic-gate ((((addr)->s6_addr32[0] & 0x000002ff) == 0x000002ff) && \ 122*0Sstevel@tonic-gate ((addr)->s6_addr32[1] == 0x0) && \ 123*0Sstevel@tonic-gate ((addr)->s6_addr32[2] == 0x01000000) && \ 124*0Sstevel@tonic-gate ((addr)->s6_addr32[3] & 0x000000ff) == 0x000000ff) 125*0Sstevel@tonic-gate #endif 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate #define NCE_HASH_PTR(addr) \ 128*0Sstevel@tonic-gate (&(nce_hash_tbl[NCE_ADDR_HASH_V6(addr, NCE_TABLE_SIZE)])) 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* 131*0Sstevel@tonic-gate * NDP Cache Entry creation routine. 132*0Sstevel@tonic-gate * Mapped entries will never do NUD . 133*0Sstevel@tonic-gate * This routine must always be called with ndp_g_lock held. 134*0Sstevel@tonic-gate * Prior to return, nce_refcnt is incremented. 135*0Sstevel@tonic-gate */ 136*0Sstevel@tonic-gate int 137*0Sstevel@tonic-gate ndp_add(ill_t *ill, uchar_t *hw_addr, const in6_addr_t *addr, 138*0Sstevel@tonic-gate const in6_addr_t *mask, const in6_addr_t *extract_mask, 139*0Sstevel@tonic-gate uint32_t hw_extract_start, uint16_t flags, uint16_t state, 140*0Sstevel@tonic-gate nce_t **newnce) 141*0Sstevel@tonic-gate { 142*0Sstevel@tonic-gate static nce_t nce_nil; 143*0Sstevel@tonic-gate nce_t *nce; 144*0Sstevel@tonic-gate mblk_t *mp; 145*0Sstevel@tonic-gate mblk_t *template; 146*0Sstevel@tonic-gate nce_t **ncep; 147*0Sstevel@tonic-gate int err = 0; 148*0Sstevel@tonic-gate boolean_t dropped = B_FALSE; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ndp_g_lock)); 151*0Sstevel@tonic-gate ASSERT(ill != NULL); 152*0Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(addr)) { 153*0Sstevel@tonic-gate ip0dbg(("ndp_add: no addr\n")); 154*0Sstevel@tonic-gate return (EINVAL); 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate if ((flags & ~NCE_EXTERNAL_FLAGS_MASK)) { 157*0Sstevel@tonic-gate ip0dbg(("ndp_add: flags = %x\n", (int)flags)); 158*0Sstevel@tonic-gate return (EINVAL); 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(extract_mask) && 161*0Sstevel@tonic-gate (flags & NCE_F_MAPPING)) { 162*0Sstevel@tonic-gate ip0dbg(("ndp_add: extract mask zero for mapping")); 163*0Sstevel@tonic-gate return (EINVAL); 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate /* 166*0Sstevel@tonic-gate * Allocate the mblk to hold the nce. 167*0Sstevel@tonic-gate * 168*0Sstevel@tonic-gate * XXX This can come out of a separate cache - nce_cache. 169*0Sstevel@tonic-gate * We don't need the mp anymore as there are no more 170*0Sstevel@tonic-gate * "qwriter"s 171*0Sstevel@tonic-gate */ 172*0Sstevel@tonic-gate mp = allocb(sizeof (nce_t), BPRI_MED); 173*0Sstevel@tonic-gate if (mp == NULL) 174*0Sstevel@tonic-gate return (ENOMEM); 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate nce = (nce_t *)mp->b_rptr; 177*0Sstevel@tonic-gate mp->b_wptr = (uchar_t *)&nce[1]; 178*0Sstevel@tonic-gate *nce = nce_nil; 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate /* 181*0Sstevel@tonic-gate * This one holds link layer address 182*0Sstevel@tonic-gate */ 183*0Sstevel@tonic-gate if (ill->ill_net_type == IRE_IF_RESOLVER) { 184*0Sstevel@tonic-gate template = nce_udreq_alloc(ill); 185*0Sstevel@tonic-gate } else { 186*0Sstevel@tonic-gate ASSERT((ill->ill_net_type == IRE_IF_NORESOLVER)); 187*0Sstevel@tonic-gate ASSERT((ill->ill_resolver_mp != NULL)); 188*0Sstevel@tonic-gate template = copyb(ill->ill_resolver_mp); 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate if (template == NULL) { 191*0Sstevel@tonic-gate freeb(mp); 192*0Sstevel@tonic-gate return (ENOMEM); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate nce->nce_ill = ill; 195*0Sstevel@tonic-gate nce->nce_flags = flags; 196*0Sstevel@tonic-gate nce->nce_state = state; 197*0Sstevel@tonic-gate nce->nce_pcnt = ND_MAX_UNICAST_SOLICIT; 198*0Sstevel@tonic-gate nce->nce_rcnt = ill->ill_xmit_count; 199*0Sstevel@tonic-gate nce->nce_addr = *addr; 200*0Sstevel@tonic-gate nce->nce_mask = *mask; 201*0Sstevel@tonic-gate nce->nce_extract_mask = *extract_mask; 202*0Sstevel@tonic-gate nce->nce_ll_extract_start = hw_extract_start; 203*0Sstevel@tonic-gate nce->nce_fp_mp = NULL; 204*0Sstevel@tonic-gate nce->nce_res_mp = template; 205*0Sstevel@tonic-gate if (state == ND_REACHABLE) 206*0Sstevel@tonic-gate nce->nce_last = TICK_TO_MSEC(lbolt64); 207*0Sstevel@tonic-gate else 208*0Sstevel@tonic-gate nce->nce_last = 0; 209*0Sstevel@tonic-gate nce->nce_qd_mp = NULL; 210*0Sstevel@tonic-gate nce->nce_mp = mp; 211*0Sstevel@tonic-gate if (hw_addr != NULL) 212*0Sstevel@tonic-gate nce_set_ll(nce, hw_addr); 213*0Sstevel@tonic-gate /* This one is for nce getting created */ 214*0Sstevel@tonic-gate nce->nce_refcnt = 1; 215*0Sstevel@tonic-gate mutex_init(&nce->nce_lock, NULL, MUTEX_DEFAULT, NULL); 216*0Sstevel@tonic-gate if (nce->nce_flags & NCE_F_MAPPING) { 217*0Sstevel@tonic-gate ASSERT(IN6_IS_ADDR_MULTICAST(addr)); 218*0Sstevel@tonic-gate ASSERT(!IN6_IS_ADDR_UNSPECIFIED(&nce->nce_mask)); 219*0Sstevel@tonic-gate ASSERT(!IN6_IS_ADDR_UNSPECIFIED(&nce->nce_extract_mask)); 220*0Sstevel@tonic-gate ncep = &nce_mask_entries; 221*0Sstevel@tonic-gate } else { 222*0Sstevel@tonic-gate ncep = ((nce_t **)NCE_HASH_PTR(*addr)); 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate #ifdef NCE_DEBUG 226*0Sstevel@tonic-gate bzero(nce->nce_trace, sizeof (th_trace_t *) * IP_TR_HASH_MAX); 227*0Sstevel@tonic-gate #endif 228*0Sstevel@tonic-gate /* 229*0Sstevel@tonic-gate * Atomically ensure that the ill is not CONDEMNED, before 230*0Sstevel@tonic-gate * adding the NCE. 231*0Sstevel@tonic-gate */ 232*0Sstevel@tonic-gate mutex_enter(&ill->ill_lock); 233*0Sstevel@tonic-gate if (ill->ill_state_flags & ILL_CONDEMNED) { 234*0Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 235*0Sstevel@tonic-gate freeb(mp); 236*0Sstevel@tonic-gate return (EINVAL); 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate if ((nce->nce_next = *ncep) != NULL) 239*0Sstevel@tonic-gate nce->nce_next->nce_ptpn = &nce->nce_next; 240*0Sstevel@tonic-gate *ncep = nce; 241*0Sstevel@tonic-gate nce->nce_ptpn = ncep; 242*0Sstevel@tonic-gate *newnce = nce; 243*0Sstevel@tonic-gate /* This one is for nce being used by an active thread */ 244*0Sstevel@tonic-gate NCE_REFHOLD(*newnce); 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate /* Bump up the number of nce's referencing this ill */ 247*0Sstevel@tonic-gate ill->ill_nce_cnt++; 248*0Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate /* 251*0Sstevel@tonic-gate * Before we insert the nce, honor the UNSOL_ADV flag. 252*0Sstevel@tonic-gate * We cannot hold the ndp_g_lock and call nce_xmit 253*0Sstevel@tonic-gate * which does a putnext. 254*0Sstevel@tonic-gate */ 255*0Sstevel@tonic-gate if (flags & NCE_F_UNSOL_ADV) { 256*0Sstevel@tonic-gate flags |= NDP_ORIDE; 257*0Sstevel@tonic-gate /* 258*0Sstevel@tonic-gate * We account for the transmit below by assigning one 259*0Sstevel@tonic-gate * less than the ndd variable. Subsequent decrements 260*0Sstevel@tonic-gate * are done in ndp_timer. 261*0Sstevel@tonic-gate */ 262*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 263*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 264*0Sstevel@tonic-gate nce->nce_unsolicit_count = ip_ndp_unsolicit_count - 1; 265*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 266*0Sstevel@tonic-gate dropped = nce_xmit(ill, 267*0Sstevel@tonic-gate ND_NEIGHBOR_ADVERT, 268*0Sstevel@tonic-gate ill, /* ill to be used for extracting ill_nd_lla */ 269*0Sstevel@tonic-gate B_TRUE, /* use ill_nd_lla */ 270*0Sstevel@tonic-gate addr, /* Source and target of the advertisement pkt */ 271*0Sstevel@tonic-gate &ipv6_all_hosts_mcast, /* Destination of the packet */ 272*0Sstevel@tonic-gate flags); 273*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 274*0Sstevel@tonic-gate if (dropped) 275*0Sstevel@tonic-gate nce->nce_unsolicit_count++; 276*0Sstevel@tonic-gate if (nce->nce_unsolicit_count != 0) { 277*0Sstevel@tonic-gate nce->nce_timeout_id = timeout(ndp_timer, nce, 278*0Sstevel@tonic-gate MSEC_TO_TICK(ip_ndp_unsolicit_interval)); 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 281*0Sstevel@tonic-gate mutex_enter(&ndp_g_lock); 282*0Sstevel@tonic-gate } 283*0Sstevel@tonic-gate done: 284*0Sstevel@tonic-gate return (err); 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate int 288*0Sstevel@tonic-gate ndp_lookup_then_add(ill_t *ill, uchar_t *hw_addr, const in6_addr_t *addr, 289*0Sstevel@tonic-gate const in6_addr_t *mask, const in6_addr_t *extract_mask, 290*0Sstevel@tonic-gate uint32_t hw_extract_start, uint16_t flags, uint16_t state, 291*0Sstevel@tonic-gate nce_t **newnce) 292*0Sstevel@tonic-gate { 293*0Sstevel@tonic-gate int err = 0; 294*0Sstevel@tonic-gate nce_t *nce; 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate mutex_enter(&ndp_g_lock); 297*0Sstevel@tonic-gate nce = nce_lookup_addr(ill, addr); 298*0Sstevel@tonic-gate if (nce == NULL) { 299*0Sstevel@tonic-gate err = ndp_add(ill, 300*0Sstevel@tonic-gate hw_addr, 301*0Sstevel@tonic-gate addr, 302*0Sstevel@tonic-gate mask, 303*0Sstevel@tonic-gate extract_mask, 304*0Sstevel@tonic-gate hw_extract_start, 305*0Sstevel@tonic-gate flags, 306*0Sstevel@tonic-gate state, 307*0Sstevel@tonic-gate newnce); 308*0Sstevel@tonic-gate } else { 309*0Sstevel@tonic-gate *newnce = nce; 310*0Sstevel@tonic-gate err = EEXIST; 311*0Sstevel@tonic-gate } 312*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 313*0Sstevel@tonic-gate return (err); 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate /* 317*0Sstevel@tonic-gate * Remove all the CONDEMNED nces from the appropriate hash table. 318*0Sstevel@tonic-gate * We create a private list of NCEs, these may have ires pointing 319*0Sstevel@tonic-gate * to them, so the list will be passed through to clean up dependent 320*0Sstevel@tonic-gate * ires and only then we can do NCE_REFRELE which can make NCE inactive. 321*0Sstevel@tonic-gate */ 322*0Sstevel@tonic-gate static void 323*0Sstevel@tonic-gate nce_remove(nce_t *nce, nce_t **free_nce_list) 324*0Sstevel@tonic-gate { 325*0Sstevel@tonic-gate nce_t *nce1; 326*0Sstevel@tonic-gate nce_t **ptpn; 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ndp_g_lock)); 329*0Sstevel@tonic-gate ASSERT(ndp_g_walker == 0); 330*0Sstevel@tonic-gate for (; nce; nce = nce1) { 331*0Sstevel@tonic-gate nce1 = nce->nce_next; 332*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 333*0Sstevel@tonic-gate if (nce->nce_flags & NCE_F_CONDEMNED) { 334*0Sstevel@tonic-gate ptpn = nce->nce_ptpn; 335*0Sstevel@tonic-gate nce1 = nce->nce_next; 336*0Sstevel@tonic-gate if (nce1 != NULL) 337*0Sstevel@tonic-gate nce1->nce_ptpn = ptpn; 338*0Sstevel@tonic-gate *ptpn = nce1; 339*0Sstevel@tonic-gate nce->nce_ptpn = NULL; 340*0Sstevel@tonic-gate nce->nce_next = NULL; 341*0Sstevel@tonic-gate nce->nce_next = *free_nce_list; 342*0Sstevel@tonic-gate *free_nce_list = nce; 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate /* 349*0Sstevel@tonic-gate * 1. Mark the nce CONDEMNED. This ensures that no new nce_lookup() 350*0Sstevel@tonic-gate * will return this NCE. Also no new IREs will be created that 351*0Sstevel@tonic-gate * point to this NCE (See ire_add_v6). Also no new timeouts will 352*0Sstevel@tonic-gate * be started (See NDP_RESTART_TIMER). 353*0Sstevel@tonic-gate * 2. Cancel any currently running timeouts. 354*0Sstevel@tonic-gate * 3. If there is an ndp walker, return. The walker will do the cleanup. 355*0Sstevel@tonic-gate * This ensures that walkers see a consistent list of NCEs while walking. 356*0Sstevel@tonic-gate * 4. Otherwise remove the NCE from the list of NCEs 357*0Sstevel@tonic-gate * 5. Delete all IREs pointing to this NCE. 358*0Sstevel@tonic-gate */ 359*0Sstevel@tonic-gate void 360*0Sstevel@tonic-gate ndp_delete(nce_t *nce) 361*0Sstevel@tonic-gate { 362*0Sstevel@tonic-gate nce_t **ptpn; 363*0Sstevel@tonic-gate nce_t *nce1; 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate /* Serialize deletes */ 366*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 367*0Sstevel@tonic-gate if (nce->nce_flags & NCE_F_CONDEMNED) { 368*0Sstevel@tonic-gate /* Some other thread is doing the delete */ 369*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 370*0Sstevel@tonic-gate return; 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate /* 373*0Sstevel@tonic-gate * Caller has a refhold. Also 1 ref for being in the list. Thus 374*0Sstevel@tonic-gate * refcnt has to be >= 2 375*0Sstevel@tonic-gate */ 376*0Sstevel@tonic-gate ASSERT(nce->nce_refcnt >= 2); 377*0Sstevel@tonic-gate nce->nce_flags |= NCE_F_CONDEMNED; 378*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate nce_fastpath_list_delete(nce); 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate /* 383*0Sstevel@tonic-gate * Cancel any running timer. Timeout can't be restarted 384*0Sstevel@tonic-gate * since CONDEMNED is set. Can't hold nce_lock across untimeout. 385*0Sstevel@tonic-gate * Passing invalid timeout id is fine. 386*0Sstevel@tonic-gate */ 387*0Sstevel@tonic-gate if (nce->nce_timeout_id != 0) { 388*0Sstevel@tonic-gate (void) untimeout(nce->nce_timeout_id); 389*0Sstevel@tonic-gate nce->nce_timeout_id = 0; 390*0Sstevel@tonic-gate } 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate mutex_enter(&ndp_g_lock); 393*0Sstevel@tonic-gate if (nce->nce_ptpn == NULL) { 394*0Sstevel@tonic-gate /* 395*0Sstevel@tonic-gate * The last ndp walker has already removed this nce from 396*0Sstevel@tonic-gate * the list after we marked the nce CONDEMNED and before 397*0Sstevel@tonic-gate * we grabbed the ndp_g_lock. 398*0Sstevel@tonic-gate */ 399*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 400*0Sstevel@tonic-gate return; 401*0Sstevel@tonic-gate } 402*0Sstevel@tonic-gate if (ndp_g_walker > 0) { 403*0Sstevel@tonic-gate /* 404*0Sstevel@tonic-gate * Can't unlink. The walker will clean up 405*0Sstevel@tonic-gate */ 406*0Sstevel@tonic-gate ndp_g_walker_cleanup = B_TRUE; 407*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 408*0Sstevel@tonic-gate return; 409*0Sstevel@tonic-gate } 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate /* 412*0Sstevel@tonic-gate * Now remove the nce from the list. NDP_RESTART_TIMER won't restart 413*0Sstevel@tonic-gate * the timer since it is marked CONDEMNED. 414*0Sstevel@tonic-gate */ 415*0Sstevel@tonic-gate ptpn = nce->nce_ptpn; 416*0Sstevel@tonic-gate nce1 = nce->nce_next; 417*0Sstevel@tonic-gate if (nce1 != NULL) 418*0Sstevel@tonic-gate nce1->nce_ptpn = ptpn; 419*0Sstevel@tonic-gate *ptpn = nce1; 420*0Sstevel@tonic-gate nce->nce_ptpn = NULL; 421*0Sstevel@tonic-gate nce->nce_next = NULL; 422*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate nce_ire_delete(nce); 425*0Sstevel@tonic-gate } 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate void 428*0Sstevel@tonic-gate ndp_inactive(nce_t *nce) 429*0Sstevel@tonic-gate { 430*0Sstevel@tonic-gate mblk_t **mpp; 431*0Sstevel@tonic-gate ill_t *ill; 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate ASSERT(nce->nce_refcnt == 0); 434*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nce->nce_lock)); 435*0Sstevel@tonic-gate ASSERT(nce->nce_fastpath == NULL); 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate /* Free all nce allocated messages */ 438*0Sstevel@tonic-gate mpp = &nce->nce_first_mp_to_free; 439*0Sstevel@tonic-gate do { 440*0Sstevel@tonic-gate while (*mpp != NULL) { 441*0Sstevel@tonic-gate mblk_t *mp; 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate mp = *mpp; 444*0Sstevel@tonic-gate *mpp = mp->b_next; 445*0Sstevel@tonic-gate mp->b_next = NULL; 446*0Sstevel@tonic-gate mp->b_prev = NULL; 447*0Sstevel@tonic-gate freemsg(mp); 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate } while (mpp++ != &nce->nce_last_mp_to_free); 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate #ifdef NCE_DEBUG 452*0Sstevel@tonic-gate nce_trace_inactive(nce); 453*0Sstevel@tonic-gate #endif 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate ill = nce->nce_ill; 456*0Sstevel@tonic-gate mutex_enter(&ill->ill_lock); 457*0Sstevel@tonic-gate ill->ill_nce_cnt--; 458*0Sstevel@tonic-gate /* 459*0Sstevel@tonic-gate * If the number of nce's associated with this ill have dropped 460*0Sstevel@tonic-gate * to zero, check whether we need to restart any operation that 461*0Sstevel@tonic-gate * is waiting for this to happen. 462*0Sstevel@tonic-gate */ 463*0Sstevel@tonic-gate if (ill->ill_nce_cnt == 0) { 464*0Sstevel@tonic-gate /* ipif_ill_refrele_tail drops the ill_lock */ 465*0Sstevel@tonic-gate ipif_ill_refrele_tail(ill); 466*0Sstevel@tonic-gate } else { 467*0Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate mutex_destroy(&nce->nce_lock); 470*0Sstevel@tonic-gate freeb(nce->nce_mp); 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate /* 474*0Sstevel@tonic-gate * ndp_walk routine. Delete the nce if it is associated with the ill 475*0Sstevel@tonic-gate * that is going away. Always called as a writer. 476*0Sstevel@tonic-gate */ 477*0Sstevel@tonic-gate void 478*0Sstevel@tonic-gate ndp_delete_per_ill(nce_t *nce, uchar_t *arg) 479*0Sstevel@tonic-gate { 480*0Sstevel@tonic-gate if ((nce != NULL) && nce->nce_ill == (ill_t *)arg) { 481*0Sstevel@tonic-gate ndp_delete(nce); 482*0Sstevel@tonic-gate } 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate /* 486*0Sstevel@tonic-gate * Walk a list of to be inactive NCEs and blow away all the ires. 487*0Sstevel@tonic-gate */ 488*0Sstevel@tonic-gate static void 489*0Sstevel@tonic-gate nce_ire_delete_list(nce_t *nce) 490*0Sstevel@tonic-gate { 491*0Sstevel@tonic-gate nce_t *nce_next; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate ASSERT(nce != NULL); 494*0Sstevel@tonic-gate while (nce != NULL) { 495*0Sstevel@tonic-gate nce_next = nce->nce_next; 496*0Sstevel@tonic-gate nce->nce_next = NULL; 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate /* 499*0Sstevel@tonic-gate * It is possible for the last ndp walker (this thread) 500*0Sstevel@tonic-gate * to come here after ndp_delete has marked the nce CONDEMNED 501*0Sstevel@tonic-gate * and before it has removed the nce from the fastpath list 502*0Sstevel@tonic-gate * or called untimeout. So we need to do it here. It is safe 503*0Sstevel@tonic-gate * for both ndp_delete and this thread to do it twice or 504*0Sstevel@tonic-gate * even simultaneously since each of the threads has a 505*0Sstevel@tonic-gate * reference on the nce. 506*0Sstevel@tonic-gate */ 507*0Sstevel@tonic-gate nce_fastpath_list_delete(nce); 508*0Sstevel@tonic-gate /* 509*0Sstevel@tonic-gate * Cancel any running timer. Timeout can't be restarted 510*0Sstevel@tonic-gate * since CONDEMNED is set. Can't hold nce_lock across untimeout. 511*0Sstevel@tonic-gate * Passing invalid timeout id is fine. 512*0Sstevel@tonic-gate */ 513*0Sstevel@tonic-gate if (nce->nce_timeout_id != 0) { 514*0Sstevel@tonic-gate (void) untimeout(nce->nce_timeout_id); 515*0Sstevel@tonic-gate nce->nce_timeout_id = 0; 516*0Sstevel@tonic-gate } 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate ire_walk_ill_v6(MATCH_IRE_ILL | MATCH_IRE_TYPE, IRE_CACHE, 519*0Sstevel@tonic-gate nce_ire_delete1, (char *)nce, nce->nce_ill); 520*0Sstevel@tonic-gate NCE_REFRELE_NOTR(nce); 521*0Sstevel@tonic-gate nce = nce_next; 522*0Sstevel@tonic-gate } 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate /* 526*0Sstevel@tonic-gate * Delete an ire when the nce goes away. 527*0Sstevel@tonic-gate */ 528*0Sstevel@tonic-gate /* ARGSUSED */ 529*0Sstevel@tonic-gate static void 530*0Sstevel@tonic-gate nce_ire_delete(nce_t *nce) 531*0Sstevel@tonic-gate { 532*0Sstevel@tonic-gate ire_walk_ill_v6(MATCH_IRE_ILL | MATCH_IRE_TYPE, IRE_CACHE, 533*0Sstevel@tonic-gate nce_ire_delete1, (char *)nce, nce->nce_ill); 534*0Sstevel@tonic-gate NCE_REFRELE_NOTR(nce); 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate /* 538*0Sstevel@tonic-gate * ire_walk routine used to delete every IRE that shares this nce 539*0Sstevel@tonic-gate */ 540*0Sstevel@tonic-gate static void 541*0Sstevel@tonic-gate nce_ire_delete1(ire_t *ire, char *nce_arg) 542*0Sstevel@tonic-gate { 543*0Sstevel@tonic-gate nce_t *nce = (nce_t *)nce_arg; 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate ASSERT(ire->ire_type == IRE_CACHE); 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate if (ire->ire_nce == nce) 548*0Sstevel@tonic-gate ire_delete(ire); 549*0Sstevel@tonic-gate } 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate /* 552*0Sstevel@tonic-gate * Cache entry lookup. Try to find an nce matching the parameters passed. 553*0Sstevel@tonic-gate * If one is found, the refcnt on the nce will be incremented. 554*0Sstevel@tonic-gate */ 555*0Sstevel@tonic-gate nce_t * 556*0Sstevel@tonic-gate ndp_lookup(ill_t *ill, const in6_addr_t *addr, boolean_t caller_holds_lock) 557*0Sstevel@tonic-gate { 558*0Sstevel@tonic-gate nce_t *nce; 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate if (!caller_holds_lock) 561*0Sstevel@tonic-gate mutex_enter(&ndp_g_lock); 562*0Sstevel@tonic-gate nce = nce_lookup_addr(ill, addr); 563*0Sstevel@tonic-gate if (nce == NULL) 564*0Sstevel@tonic-gate nce = nce_lookup_mapping(ill, addr); 565*0Sstevel@tonic-gate if (!caller_holds_lock) 566*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 567*0Sstevel@tonic-gate return (nce); 568*0Sstevel@tonic-gate } 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate /* 571*0Sstevel@tonic-gate * Cache entry lookup. Try to find an nce matching the parameters passed. 572*0Sstevel@tonic-gate * Look only for exact entries (no mappings). If an nce is found, increment 573*0Sstevel@tonic-gate * the hold count on that nce. 574*0Sstevel@tonic-gate */ 575*0Sstevel@tonic-gate static nce_t * 576*0Sstevel@tonic-gate nce_lookup_addr(ill_t *ill, const in6_addr_t *addr) 577*0Sstevel@tonic-gate { 578*0Sstevel@tonic-gate nce_t *nce; 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate ASSERT(ill != NULL); 581*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ndp_g_lock)); 582*0Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(addr)) 583*0Sstevel@tonic-gate return (NULL); 584*0Sstevel@tonic-gate nce = *((nce_t **)NCE_HASH_PTR(*addr)); 585*0Sstevel@tonic-gate for (; nce != NULL; nce = nce->nce_next) { 586*0Sstevel@tonic-gate if (nce->nce_ill == ill) { 587*0Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&nce->nce_addr, addr) && 588*0Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&nce->nce_mask, 589*0Sstevel@tonic-gate &ipv6_all_ones)) { 590*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 591*0Sstevel@tonic-gate if (!(nce->nce_flags & NCE_F_CONDEMNED)) { 592*0Sstevel@tonic-gate NCE_REFHOLD_LOCKED(nce); 593*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 594*0Sstevel@tonic-gate break; 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate } 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate return (nce); 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate /* 604*0Sstevel@tonic-gate * Cache entry lookup. Try to find an nce matching the parameters passed. 605*0Sstevel@tonic-gate * Look only for mappings. 606*0Sstevel@tonic-gate */ 607*0Sstevel@tonic-gate static nce_t * 608*0Sstevel@tonic-gate nce_lookup_mapping(ill_t *ill, const in6_addr_t *addr) 609*0Sstevel@tonic-gate { 610*0Sstevel@tonic-gate nce_t *nce; 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate ASSERT(ill != NULL); 613*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ndp_g_lock)); 614*0Sstevel@tonic-gate if (!IN6_IS_ADDR_MULTICAST(addr)) 615*0Sstevel@tonic-gate return (NULL); 616*0Sstevel@tonic-gate nce = nce_mask_entries; 617*0Sstevel@tonic-gate for (; nce != NULL; nce = nce->nce_next) 618*0Sstevel@tonic-gate if (nce->nce_ill == ill && 619*0Sstevel@tonic-gate (V6_MASK_EQ(*addr, nce->nce_mask, nce->nce_addr))) { 620*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 621*0Sstevel@tonic-gate if (!(nce->nce_flags & NCE_F_CONDEMNED)) { 622*0Sstevel@tonic-gate NCE_REFHOLD_LOCKED(nce); 623*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 624*0Sstevel@tonic-gate break; 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate return (nce); 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate /* 632*0Sstevel@tonic-gate * Process passed in parameters either from an incoming packet or via 633*0Sstevel@tonic-gate * user ioctl. 634*0Sstevel@tonic-gate */ 635*0Sstevel@tonic-gate void 636*0Sstevel@tonic-gate ndp_process(nce_t *nce, uchar_t *hw_addr, uint32_t flag, boolean_t is_adv) 637*0Sstevel@tonic-gate { 638*0Sstevel@tonic-gate ill_t *ill = nce->nce_ill; 639*0Sstevel@tonic-gate uint32_t hw_addr_len = ill->ill_nd_lla_len; 640*0Sstevel@tonic-gate mblk_t *mp; 641*0Sstevel@tonic-gate boolean_t ll_updated = B_FALSE; 642*0Sstevel@tonic-gate boolean_t ll_changed; 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate /* 645*0Sstevel@tonic-gate * No updates of link layer address or the neighbor state is 646*0Sstevel@tonic-gate * allowed, when the cache is in NONUD state. This still 647*0Sstevel@tonic-gate * allows for responding to reachability solicitation. 648*0Sstevel@tonic-gate */ 649*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 650*0Sstevel@tonic-gate if (nce->nce_state == ND_INCOMPLETE) { 651*0Sstevel@tonic-gate if (hw_addr == NULL) { 652*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 653*0Sstevel@tonic-gate return; 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate nce_set_ll(nce, hw_addr); 656*0Sstevel@tonic-gate /* 657*0Sstevel@tonic-gate * Update nce state and send the queued packets 658*0Sstevel@tonic-gate * back to ip this time ire will be added. 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate if (flag & ND_NA_FLAG_SOLICITED) { 661*0Sstevel@tonic-gate nce_update(nce, ND_REACHABLE, NULL); 662*0Sstevel@tonic-gate } else { 663*0Sstevel@tonic-gate nce_update(nce, ND_STALE, NULL); 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 666*0Sstevel@tonic-gate nce_fastpath(nce); 667*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 668*0Sstevel@tonic-gate mp = nce->nce_qd_mp; 669*0Sstevel@tonic-gate nce->nce_qd_mp = NULL; 670*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 671*0Sstevel@tonic-gate while (mp != NULL) { 672*0Sstevel@tonic-gate mblk_t *nxt_mp; 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate nxt_mp = mp->b_next; 675*0Sstevel@tonic-gate mp->b_next = NULL; 676*0Sstevel@tonic-gate if (mp->b_prev != NULL) { 677*0Sstevel@tonic-gate ill_t *inbound_ill; 678*0Sstevel@tonic-gate queue_t *fwdq = NULL; 679*0Sstevel@tonic-gate uint_t ifindex; 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate ifindex = (uint_t)(uintptr_t)mp->b_prev; 682*0Sstevel@tonic-gate inbound_ill = ill_lookup_on_ifindex(ifindex, 683*0Sstevel@tonic-gate B_TRUE, NULL, NULL, NULL, NULL); 684*0Sstevel@tonic-gate if (inbound_ill == NULL) { 685*0Sstevel@tonic-gate mp->b_prev = NULL; 686*0Sstevel@tonic-gate freemsg(mp); 687*0Sstevel@tonic-gate return; 688*0Sstevel@tonic-gate } else { 689*0Sstevel@tonic-gate fwdq = inbound_ill->ill_rq; 690*0Sstevel@tonic-gate } 691*0Sstevel@tonic-gate mp->b_prev = NULL; 692*0Sstevel@tonic-gate /* 693*0Sstevel@tonic-gate * Send a forwarded packet back into ip_rput_v6 694*0Sstevel@tonic-gate * just as in ire_send_v6(). 695*0Sstevel@tonic-gate * Extract the queue from b_prev (set in 696*0Sstevel@tonic-gate * ip_rput_data_v6). 697*0Sstevel@tonic-gate */ 698*0Sstevel@tonic-gate if (fwdq != NULL) { 699*0Sstevel@tonic-gate /* 700*0Sstevel@tonic-gate * Forwarded packets hop count will 701*0Sstevel@tonic-gate * get decremented in ip_rput_data_v6 702*0Sstevel@tonic-gate */ 703*0Sstevel@tonic-gate put(fwdq, mp); 704*0Sstevel@tonic-gate } else { 705*0Sstevel@tonic-gate /* 706*0Sstevel@tonic-gate * Send locally originated packets back 707*0Sstevel@tonic-gate * into * ip_wput_v6. 708*0Sstevel@tonic-gate */ 709*0Sstevel@tonic-gate put(ill->ill_wq, mp); 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate ill_refrele(inbound_ill); 712*0Sstevel@tonic-gate } else { 713*0Sstevel@tonic-gate put(ill->ill_wq, mp); 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate mp = nxt_mp; 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate return; 718*0Sstevel@tonic-gate } 719*0Sstevel@tonic-gate ll_changed = nce_cmp_ll_addr(nce, (char *)hw_addr, hw_addr_len); 720*0Sstevel@tonic-gate if (!is_adv) { 721*0Sstevel@tonic-gate /* If this is a SOLICITATION request only */ 722*0Sstevel@tonic-gate if (ll_changed) 723*0Sstevel@tonic-gate nce_update(nce, ND_STALE, hw_addr); 724*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 725*0Sstevel@tonic-gate return; 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate if (!(flag & ND_NA_FLAG_OVERRIDE) && ll_changed) { 728*0Sstevel@tonic-gate /* If in any other state than REACHABLE, ignore */ 729*0Sstevel@tonic-gate if (nce->nce_state == ND_REACHABLE) { 730*0Sstevel@tonic-gate nce_update(nce, ND_STALE, NULL); 731*0Sstevel@tonic-gate } 732*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 733*0Sstevel@tonic-gate return; 734*0Sstevel@tonic-gate } else { 735*0Sstevel@tonic-gate if (ll_changed) { 736*0Sstevel@tonic-gate nce_update(nce, ND_UNCHANGED, hw_addr); 737*0Sstevel@tonic-gate ll_updated = B_TRUE; 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate if (flag & ND_NA_FLAG_SOLICITED) { 740*0Sstevel@tonic-gate nce_update(nce, ND_REACHABLE, NULL); 741*0Sstevel@tonic-gate } else { 742*0Sstevel@tonic-gate if (ll_updated) { 743*0Sstevel@tonic-gate nce_update(nce, ND_STALE, NULL); 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate } 746*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 747*0Sstevel@tonic-gate if (!(flag & ND_NA_FLAG_ROUTER) && (nce->nce_flags & 748*0Sstevel@tonic-gate NCE_F_ISROUTER)) { 749*0Sstevel@tonic-gate ire_t *ire; 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate /* 752*0Sstevel@tonic-gate * Router turned to host. We need to remove the 753*0Sstevel@tonic-gate * entry as well as any default route that may be 754*0Sstevel@tonic-gate * using this as a next hop. This is required by 755*0Sstevel@tonic-gate * section 7.2.5 of RFC 2461. 756*0Sstevel@tonic-gate */ 757*0Sstevel@tonic-gate ire = ire_ftable_lookup_v6(&ipv6_all_zeros, 758*0Sstevel@tonic-gate &ipv6_all_zeros, &nce->nce_addr, IRE_DEFAULT, 759*0Sstevel@tonic-gate nce->nce_ill->ill_ipif, NULL, ALL_ZONES, 0, 760*0Sstevel@tonic-gate MATCH_IRE_ILL | MATCH_IRE_TYPE | MATCH_IRE_GW | 761*0Sstevel@tonic-gate MATCH_IRE_DEFAULT); 762*0Sstevel@tonic-gate if (ire != NULL) { 763*0Sstevel@tonic-gate ip_rts_rtmsg(RTM_DELETE, ire, 0); 764*0Sstevel@tonic-gate ire_delete(ire); 765*0Sstevel@tonic-gate ire_refrele(ire); 766*0Sstevel@tonic-gate } 767*0Sstevel@tonic-gate ndp_delete(nce); 768*0Sstevel@tonic-gate } 769*0Sstevel@tonic-gate } 770*0Sstevel@tonic-gate } 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate /* 773*0Sstevel@tonic-gate * Pass arg1 to the pfi supplied, along with each nce in existence. 774*0Sstevel@tonic-gate * ndp_walk() places a REFHOLD on the nce and drops the lock when 775*0Sstevel@tonic-gate * walking the hash list. 776*0Sstevel@tonic-gate */ 777*0Sstevel@tonic-gate void 778*0Sstevel@tonic-gate ndp_walk_impl(ill_t *ill, pfi_t pfi, uchar_t *arg1, boolean_t trace) 779*0Sstevel@tonic-gate { 780*0Sstevel@tonic-gate 781*0Sstevel@tonic-gate nce_t *nce; 782*0Sstevel@tonic-gate nce_t *nce1; 783*0Sstevel@tonic-gate nce_t **ncep; 784*0Sstevel@tonic-gate nce_t *free_nce_list = NULL; 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate mutex_enter(&ndp_g_lock); 787*0Sstevel@tonic-gate ndp_g_walker++; /* Prevent ndp_delete from unlink and free of NCE */ 788*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 789*0Sstevel@tonic-gate for (ncep = nce_hash_tbl; ncep < A_END(nce_hash_tbl); ncep++) { 790*0Sstevel@tonic-gate for (nce = *ncep; nce; nce = nce1) { 791*0Sstevel@tonic-gate nce1 = nce->nce_next; 792*0Sstevel@tonic-gate if (ill == NULL || nce->nce_ill == ill) { 793*0Sstevel@tonic-gate if (trace) { 794*0Sstevel@tonic-gate NCE_REFHOLD(nce); 795*0Sstevel@tonic-gate (*pfi)(nce, arg1); 796*0Sstevel@tonic-gate NCE_REFRELE(nce); 797*0Sstevel@tonic-gate } else { 798*0Sstevel@tonic-gate NCE_REFHOLD_NOTR(nce); 799*0Sstevel@tonic-gate (*pfi)(nce, arg1); 800*0Sstevel@tonic-gate NCE_REFRELE_NOTR(nce); 801*0Sstevel@tonic-gate } 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate } 805*0Sstevel@tonic-gate for (nce = nce_mask_entries; nce; nce = nce1) { 806*0Sstevel@tonic-gate nce1 = nce->nce_next; 807*0Sstevel@tonic-gate if (ill == NULL || nce->nce_ill == ill) { 808*0Sstevel@tonic-gate if (trace) { 809*0Sstevel@tonic-gate NCE_REFHOLD(nce); 810*0Sstevel@tonic-gate (*pfi)(nce, arg1); 811*0Sstevel@tonic-gate NCE_REFRELE(nce); 812*0Sstevel@tonic-gate } else { 813*0Sstevel@tonic-gate NCE_REFHOLD_NOTR(nce); 814*0Sstevel@tonic-gate (*pfi)(nce, arg1); 815*0Sstevel@tonic-gate NCE_REFRELE_NOTR(nce); 816*0Sstevel@tonic-gate } 817*0Sstevel@tonic-gate } 818*0Sstevel@tonic-gate } 819*0Sstevel@tonic-gate mutex_enter(&ndp_g_lock); 820*0Sstevel@tonic-gate ndp_g_walker--; 821*0Sstevel@tonic-gate /* 822*0Sstevel@tonic-gate * While NCE's are removed from global list they are placed 823*0Sstevel@tonic-gate * in a private list, to be passed to nce_ire_delete_list(). 824*0Sstevel@tonic-gate * The reason is, there may be ires pointing to this nce 825*0Sstevel@tonic-gate * which needs to cleaned up. 826*0Sstevel@tonic-gate */ 827*0Sstevel@tonic-gate if (ndp_g_walker_cleanup && ndp_g_walker == 0) { 828*0Sstevel@tonic-gate /* Time to delete condemned entries */ 829*0Sstevel@tonic-gate for (ncep = nce_hash_tbl; ncep < A_END(nce_hash_tbl); ncep++) { 830*0Sstevel@tonic-gate nce = *ncep; 831*0Sstevel@tonic-gate if (nce != NULL) { 832*0Sstevel@tonic-gate nce_remove(nce, &free_nce_list); 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate nce = nce_mask_entries; 836*0Sstevel@tonic-gate if (nce != NULL) { 837*0Sstevel@tonic-gate nce_remove(nce, &free_nce_list); 838*0Sstevel@tonic-gate } 839*0Sstevel@tonic-gate ndp_g_walker_cleanup = B_FALSE; 840*0Sstevel@tonic-gate } 841*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate if (free_nce_list != NULL) { 844*0Sstevel@tonic-gate nce_ire_delete_list(free_nce_list); 845*0Sstevel@tonic-gate } 846*0Sstevel@tonic-gate } 847*0Sstevel@tonic-gate 848*0Sstevel@tonic-gate void 849*0Sstevel@tonic-gate ndp_walk(ill_t *ill, pfi_t pfi, uchar_t *arg1) 850*0Sstevel@tonic-gate { 851*0Sstevel@tonic-gate ndp_walk_impl(ill, pfi, arg1, B_TRUE); 852*0Sstevel@tonic-gate } 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate /* 855*0Sstevel@tonic-gate * Prepend the zoneid using an ipsec_out_t for later use by functions like 856*0Sstevel@tonic-gate * ip_rput_v6() after neighbor discovery has taken place. If the message 857*0Sstevel@tonic-gate * block already has a M_CTL at the front of it, then simply set the zoneid 858*0Sstevel@tonic-gate * appropriately. 859*0Sstevel@tonic-gate */ 860*0Sstevel@tonic-gate static mblk_t * 861*0Sstevel@tonic-gate ndp_prepend_zone(mblk_t *mp, zoneid_t zoneid) 862*0Sstevel@tonic-gate { 863*0Sstevel@tonic-gate mblk_t *first_mp; 864*0Sstevel@tonic-gate ipsec_out_t *io; 865*0Sstevel@tonic-gate 866*0Sstevel@tonic-gate if (mp->b_datap->db_type == M_CTL) { 867*0Sstevel@tonic-gate io = (ipsec_out_t *)mp->b_rptr; 868*0Sstevel@tonic-gate ASSERT(io->ipsec_out_type == IPSEC_OUT); 869*0Sstevel@tonic-gate io->ipsec_out_zoneid = zoneid; 870*0Sstevel@tonic-gate return (mp); 871*0Sstevel@tonic-gate } 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate first_mp = ipsec_alloc_ipsec_out(); 874*0Sstevel@tonic-gate if (first_mp == NULL) 875*0Sstevel@tonic-gate return (NULL); 876*0Sstevel@tonic-gate io = (ipsec_out_t *)first_mp->b_rptr; 877*0Sstevel@tonic-gate /* This is not a secure packet */ 878*0Sstevel@tonic-gate io->ipsec_out_secure = B_FALSE; 879*0Sstevel@tonic-gate io->ipsec_out_zoneid = zoneid; 880*0Sstevel@tonic-gate first_mp->b_cont = mp; 881*0Sstevel@tonic-gate return (first_mp); 882*0Sstevel@tonic-gate } 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate /* 885*0Sstevel@tonic-gate * Process resolve requests. Handles both mapped entries 886*0Sstevel@tonic-gate * as well as cases that needs to be send out on the wire. 887*0Sstevel@tonic-gate * Lookup a NCE for a given IRE. Regardless of whether one exists 888*0Sstevel@tonic-gate * or one is created, we defer making ire point to nce until the 889*0Sstevel@tonic-gate * ire is actually added at which point the nce_refcnt on the nce is 890*0Sstevel@tonic-gate * incremented. This is done primarily to have symmetry between ire_add() 891*0Sstevel@tonic-gate * and ire_delete() which decrements the nce_refcnt, when an ire is deleted. 892*0Sstevel@tonic-gate */ 893*0Sstevel@tonic-gate int 894*0Sstevel@tonic-gate ndp_resolver(ill_t *ill, const in6_addr_t *dst, mblk_t *mp, zoneid_t zoneid) 895*0Sstevel@tonic-gate { 896*0Sstevel@tonic-gate nce_t *nce; 897*0Sstevel@tonic-gate int err = 0; 898*0Sstevel@tonic-gate uint32_t ms; 899*0Sstevel@tonic-gate mblk_t *mp_nce = NULL; 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate ASSERT(ill != NULL); 902*0Sstevel@tonic-gate if (IN6_IS_ADDR_MULTICAST(dst)) { 903*0Sstevel@tonic-gate err = nce_set_multicast(ill, dst); 904*0Sstevel@tonic-gate return (err); 905*0Sstevel@tonic-gate } 906*0Sstevel@tonic-gate err = ndp_lookup_then_add(ill, 907*0Sstevel@tonic-gate NULL, /* No hardware address */ 908*0Sstevel@tonic-gate dst, 909*0Sstevel@tonic-gate &ipv6_all_ones, 910*0Sstevel@tonic-gate &ipv6_all_zeros, 911*0Sstevel@tonic-gate 0, 912*0Sstevel@tonic-gate (ill->ill_flags & ILLF_NONUD) ? NCE_F_NONUD : 0, 913*0Sstevel@tonic-gate ND_INCOMPLETE, 914*0Sstevel@tonic-gate &nce); 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate switch (err) { 917*0Sstevel@tonic-gate case 0: 918*0Sstevel@tonic-gate /* 919*0Sstevel@tonic-gate * New cache entry was created. Make sure that the state 920*0Sstevel@tonic-gate * is not ND_INCOMPLETE. It can be in some other state 921*0Sstevel@tonic-gate * even before we send out the solicitation as we could 922*0Sstevel@tonic-gate * get un-solicited advertisements. 923*0Sstevel@tonic-gate * 924*0Sstevel@tonic-gate * If this is an XRESOLV interface, simply return 0, 925*0Sstevel@tonic-gate * since we don't want to solicit just yet. 926*0Sstevel@tonic-gate */ 927*0Sstevel@tonic-gate if (ill->ill_flags & ILLF_XRESOLV) { 928*0Sstevel@tonic-gate NCE_REFRELE(nce); 929*0Sstevel@tonic-gate return (0); 930*0Sstevel@tonic-gate } 931*0Sstevel@tonic-gate rw_enter(&ill_g_lock, RW_READER); 932*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 933*0Sstevel@tonic-gate if (nce->nce_state != ND_INCOMPLETE) { 934*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 935*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 936*0Sstevel@tonic-gate NCE_REFRELE(nce); 937*0Sstevel@tonic-gate return (0); 938*0Sstevel@tonic-gate } 939*0Sstevel@tonic-gate mp_nce = ndp_prepend_zone(mp, zoneid); 940*0Sstevel@tonic-gate if (mp_nce == NULL) { 941*0Sstevel@tonic-gate /* The caller will free mp */ 942*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 943*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 944*0Sstevel@tonic-gate ndp_delete(nce); 945*0Sstevel@tonic-gate NCE_REFRELE(nce); 946*0Sstevel@tonic-gate return (ENOMEM); 947*0Sstevel@tonic-gate } 948*0Sstevel@tonic-gate ms = nce_solicit(nce, mp_nce); 949*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 950*0Sstevel@tonic-gate if (ms == 0) { 951*0Sstevel@tonic-gate /* The caller will free mp */ 952*0Sstevel@tonic-gate if (mp_nce != mp) 953*0Sstevel@tonic-gate freeb(mp_nce); 954*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 955*0Sstevel@tonic-gate ndp_delete(nce); 956*0Sstevel@tonic-gate NCE_REFRELE(nce); 957*0Sstevel@tonic-gate return (EBUSY); 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 960*0Sstevel@tonic-gate NDP_RESTART_TIMER(nce, (clock_t)ms); 961*0Sstevel@tonic-gate NCE_REFRELE(nce); 962*0Sstevel@tonic-gate return (EINPROGRESS); 963*0Sstevel@tonic-gate case EEXIST: 964*0Sstevel@tonic-gate /* Resolution in progress just queue the packet */ 965*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 966*0Sstevel@tonic-gate if (nce->nce_state == ND_INCOMPLETE) { 967*0Sstevel@tonic-gate mp_nce = ndp_prepend_zone(mp, zoneid); 968*0Sstevel@tonic-gate if (mp_nce == NULL) { 969*0Sstevel@tonic-gate err = ENOMEM; 970*0Sstevel@tonic-gate } else { 971*0Sstevel@tonic-gate nce_queue_mp(nce, mp_nce); 972*0Sstevel@tonic-gate err = EINPROGRESS; 973*0Sstevel@tonic-gate } 974*0Sstevel@tonic-gate } else { 975*0Sstevel@tonic-gate /* 976*0Sstevel@tonic-gate * Any other state implies we have 977*0Sstevel@tonic-gate * a nce but IRE needs to be added ... 978*0Sstevel@tonic-gate * ire_add_v6() will take care of the 979*0Sstevel@tonic-gate * the case when the nce becomes CONDEMNED 980*0Sstevel@tonic-gate * before the ire is added to the table. 981*0Sstevel@tonic-gate */ 982*0Sstevel@tonic-gate err = 0; 983*0Sstevel@tonic-gate } 984*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 985*0Sstevel@tonic-gate NCE_REFRELE(nce); 986*0Sstevel@tonic-gate break; 987*0Sstevel@tonic-gate default: 988*0Sstevel@tonic-gate ip1dbg(("ndp_resolver: Can't create NCE %d\n", err)); 989*0Sstevel@tonic-gate break; 990*0Sstevel@tonic-gate } 991*0Sstevel@tonic-gate return (err); 992*0Sstevel@tonic-gate } 993*0Sstevel@tonic-gate 994*0Sstevel@tonic-gate /* 995*0Sstevel@tonic-gate * When there is no resolver, the link layer template is passed in 996*0Sstevel@tonic-gate * the IRE. 997*0Sstevel@tonic-gate * Lookup a NCE for a given IRE. Regardless of whether one exists 998*0Sstevel@tonic-gate * or one is created, we defer making ire point to nce until the 999*0Sstevel@tonic-gate * ire is actually added at which point the nce_refcnt on the nce is 1000*0Sstevel@tonic-gate * incremented. This is done primarily to have symmetry between ire_add() 1001*0Sstevel@tonic-gate * and ire_delete() which decrements the nce_refcnt, when an ire is deleted. 1002*0Sstevel@tonic-gate */ 1003*0Sstevel@tonic-gate int 1004*0Sstevel@tonic-gate ndp_noresolver(ill_t *ill, const in6_addr_t *dst) 1005*0Sstevel@tonic-gate { 1006*0Sstevel@tonic-gate nce_t *nce; 1007*0Sstevel@tonic-gate int err = 0; 1008*0Sstevel@tonic-gate 1009*0Sstevel@tonic-gate ASSERT(ill != NULL); 1010*0Sstevel@tonic-gate if (IN6_IS_ADDR_MULTICAST(dst)) { 1011*0Sstevel@tonic-gate err = nce_set_multicast(ill, dst); 1012*0Sstevel@tonic-gate return (err); 1013*0Sstevel@tonic-gate } 1014*0Sstevel@tonic-gate 1015*0Sstevel@tonic-gate err = ndp_lookup_then_add(ill, 1016*0Sstevel@tonic-gate NULL, /* hardware address */ 1017*0Sstevel@tonic-gate dst, 1018*0Sstevel@tonic-gate &ipv6_all_ones, 1019*0Sstevel@tonic-gate &ipv6_all_zeros, 1020*0Sstevel@tonic-gate 0, 1021*0Sstevel@tonic-gate (ill->ill_flags & ILLF_NONUD) ? NCE_F_NONUD : 0, 1022*0Sstevel@tonic-gate ND_REACHABLE, 1023*0Sstevel@tonic-gate &nce); 1024*0Sstevel@tonic-gate 1025*0Sstevel@tonic-gate switch (err) { 1026*0Sstevel@tonic-gate case 0: 1027*0Sstevel@tonic-gate /* 1028*0Sstevel@tonic-gate * Cache entry with a proper resolver cookie was 1029*0Sstevel@tonic-gate * created. 1030*0Sstevel@tonic-gate */ 1031*0Sstevel@tonic-gate nce_fastpath(nce); 1032*0Sstevel@tonic-gate NCE_REFRELE(nce); 1033*0Sstevel@tonic-gate break; 1034*0Sstevel@tonic-gate case EEXIST: 1035*0Sstevel@tonic-gate err = 0; 1036*0Sstevel@tonic-gate NCE_REFRELE(nce); 1037*0Sstevel@tonic-gate break; 1038*0Sstevel@tonic-gate default: 1039*0Sstevel@tonic-gate ip1dbg(("ndp_noresolver: Can't create NCE %d\n", err)); 1040*0Sstevel@tonic-gate break; 1041*0Sstevel@tonic-gate } 1042*0Sstevel@tonic-gate return (err); 1043*0Sstevel@tonic-gate } 1044*0Sstevel@tonic-gate 1045*0Sstevel@tonic-gate /* 1046*0Sstevel@tonic-gate * For each interface an entry is added for the unspecified multicast group. 1047*0Sstevel@tonic-gate * Here that mapping is used to form the multicast cache entry for a particular 1048*0Sstevel@tonic-gate * multicast destination. 1049*0Sstevel@tonic-gate */ 1050*0Sstevel@tonic-gate static int 1051*0Sstevel@tonic-gate nce_set_multicast(ill_t *ill, const in6_addr_t *dst) 1052*0Sstevel@tonic-gate { 1053*0Sstevel@tonic-gate nce_t *mnce; /* Multicast mapping entry */ 1054*0Sstevel@tonic-gate nce_t *nce; 1055*0Sstevel@tonic-gate uchar_t *hw_addr = NULL; 1056*0Sstevel@tonic-gate int err = 0; 1057*0Sstevel@tonic-gate 1058*0Sstevel@tonic-gate ASSERT(ill != NULL); 1059*0Sstevel@tonic-gate ASSERT(!(IN6_IS_ADDR_UNSPECIFIED(dst))); 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate mutex_enter(&ndp_g_lock); 1062*0Sstevel@tonic-gate nce = nce_lookup_addr(ill, dst); 1063*0Sstevel@tonic-gate if (nce != NULL) { 1064*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 1065*0Sstevel@tonic-gate NCE_REFRELE(nce); 1066*0Sstevel@tonic-gate return (0); 1067*0Sstevel@tonic-gate } 1068*0Sstevel@tonic-gate /* No entry, now lookup for a mapping this should never fail */ 1069*0Sstevel@tonic-gate mnce = nce_lookup_mapping(ill, dst); 1070*0Sstevel@tonic-gate if (mnce == NULL) { 1071*0Sstevel@tonic-gate /* Something broken for the interface. */ 1072*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 1073*0Sstevel@tonic-gate return (ESRCH); 1074*0Sstevel@tonic-gate } 1075*0Sstevel@tonic-gate ASSERT(mnce->nce_flags & NCE_F_MAPPING); 1076*0Sstevel@tonic-gate if (ill->ill_net_type == IRE_IF_RESOLVER) { 1077*0Sstevel@tonic-gate /* 1078*0Sstevel@tonic-gate * For IRE_IF_RESOLVER a hardware mapping can be 1079*0Sstevel@tonic-gate * generated, for IRE_IF_NORESOLVER, resolution cookie 1080*0Sstevel@tonic-gate * in the ill is copied in ndp_add(). 1081*0Sstevel@tonic-gate */ 1082*0Sstevel@tonic-gate hw_addr = kmem_alloc(ill->ill_nd_lla_len, KM_NOSLEEP); 1083*0Sstevel@tonic-gate if (hw_addr == NULL) { 1084*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 1085*0Sstevel@tonic-gate NCE_REFRELE(mnce); 1086*0Sstevel@tonic-gate return (ENOMEM); 1087*0Sstevel@tonic-gate } 1088*0Sstevel@tonic-gate nce_make_mapping(mnce, hw_addr, (uchar_t *)dst); 1089*0Sstevel@tonic-gate } 1090*0Sstevel@tonic-gate NCE_REFRELE(mnce); 1091*0Sstevel@tonic-gate /* 1092*0Sstevel@tonic-gate * IRE_IF_NORESOLVER type simply copies the resolution 1093*0Sstevel@tonic-gate * cookie passed in. So no hw_addr is needed. 1094*0Sstevel@tonic-gate */ 1095*0Sstevel@tonic-gate err = ndp_add(ill, 1096*0Sstevel@tonic-gate hw_addr, 1097*0Sstevel@tonic-gate dst, 1098*0Sstevel@tonic-gate &ipv6_all_ones, 1099*0Sstevel@tonic-gate &ipv6_all_zeros, 1100*0Sstevel@tonic-gate 0, 1101*0Sstevel@tonic-gate NCE_F_NONUD, 1102*0Sstevel@tonic-gate ND_REACHABLE, 1103*0Sstevel@tonic-gate &nce); 1104*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 1105*0Sstevel@tonic-gate if (hw_addr != NULL) 1106*0Sstevel@tonic-gate kmem_free(hw_addr, ill->ill_nd_lla_len); 1107*0Sstevel@tonic-gate if (err != 0) { 1108*0Sstevel@tonic-gate ip1dbg(("nce_set_multicast: create failed" "%d\n", err)); 1109*0Sstevel@tonic-gate return (err); 1110*0Sstevel@tonic-gate } 1111*0Sstevel@tonic-gate nce_fastpath(nce); 1112*0Sstevel@tonic-gate NCE_REFRELE(nce); 1113*0Sstevel@tonic-gate return (0); 1114*0Sstevel@tonic-gate } 1115*0Sstevel@tonic-gate 1116*0Sstevel@tonic-gate /* 1117*0Sstevel@tonic-gate * Return the link layer address, and any flags of a nce. 1118*0Sstevel@tonic-gate */ 1119*0Sstevel@tonic-gate int 1120*0Sstevel@tonic-gate ndp_query(ill_t *ill, struct lif_nd_req *lnr) 1121*0Sstevel@tonic-gate { 1122*0Sstevel@tonic-gate nce_t *nce; 1123*0Sstevel@tonic-gate in6_addr_t *addr; 1124*0Sstevel@tonic-gate sin6_t *sin6; 1125*0Sstevel@tonic-gate dl_unitdata_req_t *dl; 1126*0Sstevel@tonic-gate 1127*0Sstevel@tonic-gate ASSERT(ill != NULL); 1128*0Sstevel@tonic-gate sin6 = (sin6_t *)&lnr->lnr_addr; 1129*0Sstevel@tonic-gate addr = &sin6->sin6_addr; 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate nce = ndp_lookup(ill, addr, B_FALSE); 1132*0Sstevel@tonic-gate if (nce == NULL) 1133*0Sstevel@tonic-gate return (ESRCH); 1134*0Sstevel@tonic-gate /* If in INCOMPLETE state, no link layer address is available yet */ 1135*0Sstevel@tonic-gate if (nce->nce_state == ND_INCOMPLETE) 1136*0Sstevel@tonic-gate goto done; 1137*0Sstevel@tonic-gate dl = (dl_unitdata_req_t *)nce->nce_res_mp->b_rptr; 1138*0Sstevel@tonic-gate if (ill->ill_flags & ILLF_XRESOLV) 1139*0Sstevel@tonic-gate lnr->lnr_hdw_len = dl->dl_dest_addr_length; 1140*0Sstevel@tonic-gate else 1141*0Sstevel@tonic-gate lnr->lnr_hdw_len = ill->ill_nd_lla_len; 1142*0Sstevel@tonic-gate ASSERT(NCE_LL_ADDR_OFFSET(ill) + lnr->lnr_hdw_len <= 1143*0Sstevel@tonic-gate sizeof (lnr->lnr_hdw_addr)); 1144*0Sstevel@tonic-gate bcopy(nce->nce_res_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill), 1145*0Sstevel@tonic-gate (uchar_t *)&lnr->lnr_hdw_addr, lnr->lnr_hdw_len); 1146*0Sstevel@tonic-gate if (nce->nce_flags & NCE_F_ISROUTER) 1147*0Sstevel@tonic-gate lnr->lnr_flags = NDF_ISROUTER_ON; 1148*0Sstevel@tonic-gate if (nce->nce_flags & NCE_F_PROXY) 1149*0Sstevel@tonic-gate lnr->lnr_flags |= NDF_PROXY_ON; 1150*0Sstevel@tonic-gate if (nce->nce_flags & NCE_F_ANYCAST) 1151*0Sstevel@tonic-gate lnr->lnr_flags |= NDF_ANYCAST_ON; 1152*0Sstevel@tonic-gate done: 1153*0Sstevel@tonic-gate NCE_REFRELE(nce); 1154*0Sstevel@tonic-gate return (0); 1155*0Sstevel@tonic-gate } 1156*0Sstevel@tonic-gate 1157*0Sstevel@tonic-gate /* 1158*0Sstevel@tonic-gate * Send Enable/Disable multicast reqs to driver. 1159*0Sstevel@tonic-gate */ 1160*0Sstevel@tonic-gate int 1161*0Sstevel@tonic-gate ndp_mcastreq(ill_t *ill, const in6_addr_t *addr, uint32_t hw_addr_len, 1162*0Sstevel@tonic-gate uint32_t hw_addr_offset, mblk_t *mp) 1163*0Sstevel@tonic-gate { 1164*0Sstevel@tonic-gate nce_t *nce; 1165*0Sstevel@tonic-gate uchar_t *hw_addr; 1166*0Sstevel@tonic-gate 1167*0Sstevel@tonic-gate ASSERT(ill != NULL); 1168*0Sstevel@tonic-gate ASSERT(ill->ill_net_type == IRE_IF_RESOLVER); 1169*0Sstevel@tonic-gate hw_addr = mi_offset_paramc(mp, hw_addr_offset, hw_addr_len); 1170*0Sstevel@tonic-gate if (hw_addr == NULL || !IN6_IS_ADDR_MULTICAST(addr)) { 1171*0Sstevel@tonic-gate freemsg(mp); 1172*0Sstevel@tonic-gate return (EINVAL); 1173*0Sstevel@tonic-gate } 1174*0Sstevel@tonic-gate mutex_enter(&ndp_g_lock); 1175*0Sstevel@tonic-gate nce = nce_lookup_mapping(ill, addr); 1176*0Sstevel@tonic-gate if (nce == NULL) { 1177*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 1178*0Sstevel@tonic-gate freemsg(mp); 1179*0Sstevel@tonic-gate return (ESRCH); 1180*0Sstevel@tonic-gate } 1181*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 1182*0Sstevel@tonic-gate /* 1183*0Sstevel@tonic-gate * Update dl_addr_length and dl_addr_offset for primitives that 1184*0Sstevel@tonic-gate * have physical addresses as opposed to full saps 1185*0Sstevel@tonic-gate */ 1186*0Sstevel@tonic-gate switch (((union DL_primitives *)mp->b_rptr)->dl_primitive) { 1187*0Sstevel@tonic-gate case DL_ENABMULTI_REQ: 1188*0Sstevel@tonic-gate /* Track the state if this is the first enabmulti */ 1189*0Sstevel@tonic-gate if (ill->ill_dlpi_multicast_state == IDMS_UNKNOWN) 1190*0Sstevel@tonic-gate ill->ill_dlpi_multicast_state = IDMS_INPROGRESS; 1191*0Sstevel@tonic-gate ip1dbg(("ndp_mcastreq: ENABMULTI\n")); 1192*0Sstevel@tonic-gate break; 1193*0Sstevel@tonic-gate case DL_DISABMULTI_REQ: 1194*0Sstevel@tonic-gate ip1dbg(("ndp_mcastreq: DISABMULTI\n")); 1195*0Sstevel@tonic-gate break; 1196*0Sstevel@tonic-gate default: 1197*0Sstevel@tonic-gate NCE_REFRELE(nce); 1198*0Sstevel@tonic-gate ip1dbg(("ndp_mcastreq: default\n")); 1199*0Sstevel@tonic-gate return (EINVAL); 1200*0Sstevel@tonic-gate } 1201*0Sstevel@tonic-gate nce_make_mapping(nce, hw_addr, (uchar_t *)addr); 1202*0Sstevel@tonic-gate NCE_REFRELE(nce); 1203*0Sstevel@tonic-gate putnext(ill->ill_wq, mp); 1204*0Sstevel@tonic-gate return (0); 1205*0Sstevel@tonic-gate } 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate /* 1208*0Sstevel@tonic-gate * Send a neighbor solicitation. 1209*0Sstevel@tonic-gate * Returns number of milliseconds after which we should either rexmit or abort. 1210*0Sstevel@tonic-gate * Return of zero means we should abort. 1211*0Sstevel@tonic-gate * The caller holds the nce_lock to protect nce_qd_mp and nce_rcnt. 1212*0Sstevel@tonic-gate * 1213*0Sstevel@tonic-gate * NOTE: This routine drops nce_lock (and later reacquires it) when sending 1214*0Sstevel@tonic-gate * the packet. 1215*0Sstevel@tonic-gate * NOTE: This routine does not consume mp. 1216*0Sstevel@tonic-gate */ 1217*0Sstevel@tonic-gate uint32_t 1218*0Sstevel@tonic-gate nce_solicit(nce_t *nce, mblk_t *mp) 1219*0Sstevel@tonic-gate { 1220*0Sstevel@tonic-gate ill_t *ill; 1221*0Sstevel@tonic-gate ill_t *src_ill; 1222*0Sstevel@tonic-gate ip6_t *ip6h; 1223*0Sstevel@tonic-gate in6_addr_t src; 1224*0Sstevel@tonic-gate in6_addr_t dst; 1225*0Sstevel@tonic-gate ipif_t *ipif; 1226*0Sstevel@tonic-gate ip6i_t *ip6i; 1227*0Sstevel@tonic-gate boolean_t dropped = B_FALSE; 1228*0Sstevel@tonic-gate 1229*0Sstevel@tonic-gate ASSERT(RW_READ_HELD(&ill_g_lock)); 1230*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nce->nce_lock)); 1231*0Sstevel@tonic-gate ill = nce->nce_ill; 1232*0Sstevel@tonic-gate ASSERT(ill != NULL); 1233*0Sstevel@tonic-gate 1234*0Sstevel@tonic-gate if (nce->nce_rcnt == 0) { 1235*0Sstevel@tonic-gate return (0); 1236*0Sstevel@tonic-gate } 1237*0Sstevel@tonic-gate 1238*0Sstevel@tonic-gate if (mp == NULL) { 1239*0Sstevel@tonic-gate ASSERT(nce->nce_qd_mp != NULL); 1240*0Sstevel@tonic-gate mp = nce->nce_qd_mp; 1241*0Sstevel@tonic-gate } else { 1242*0Sstevel@tonic-gate nce_queue_mp(nce, mp); 1243*0Sstevel@tonic-gate } 1244*0Sstevel@tonic-gate 1245*0Sstevel@tonic-gate /* Handle ip_newroute_v6 giving us IPSEC packets */ 1246*0Sstevel@tonic-gate if (mp->b_datap->db_type == M_CTL) 1247*0Sstevel@tonic-gate mp = mp->b_cont; 1248*0Sstevel@tonic-gate 1249*0Sstevel@tonic-gate ip6h = (ip6_t *)mp->b_rptr; 1250*0Sstevel@tonic-gate if (ip6h->ip6_nxt == IPPROTO_RAW) { 1251*0Sstevel@tonic-gate /* 1252*0Sstevel@tonic-gate * This message should have been pulled up already in 1253*0Sstevel@tonic-gate * ip_wput_v6. We can't do pullups here because the message 1254*0Sstevel@tonic-gate * could be from the nce_qd_mp which could have b_next/b_prev 1255*0Sstevel@tonic-gate * non-NULL. 1256*0Sstevel@tonic-gate */ 1257*0Sstevel@tonic-gate ip6i = (ip6i_t *)ip6h; 1258*0Sstevel@tonic-gate ASSERT((mp->b_wptr - (uchar_t *)ip6i) >= 1259*0Sstevel@tonic-gate sizeof (ip6i_t) + IPV6_HDR_LEN); 1260*0Sstevel@tonic-gate ip6h = (ip6_t *)(mp->b_rptr + sizeof (ip6i_t)); 1261*0Sstevel@tonic-gate } 1262*0Sstevel@tonic-gate src = ip6h->ip6_src; 1263*0Sstevel@tonic-gate /* 1264*0Sstevel@tonic-gate * If the src of outgoing packet is one of the assigned interface 1265*0Sstevel@tonic-gate * addresses use it, otherwise we will pick the source address below. 1266*0Sstevel@tonic-gate */ 1267*0Sstevel@tonic-gate src_ill = ill; 1268*0Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&src)) { 1269*0Sstevel@tonic-gate if (ill->ill_group != NULL) 1270*0Sstevel@tonic-gate src_ill = ill->ill_group->illgrp_ill; 1271*0Sstevel@tonic-gate for (; src_ill != NULL; src_ill = src_ill->ill_group_next) { 1272*0Sstevel@tonic-gate for (ipif = src_ill->ill_ipif; ipif != NULL; 1273*0Sstevel@tonic-gate ipif = ipif->ipif_next) { 1274*0Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&src, 1275*0Sstevel@tonic-gate &ipif->ipif_v6lcl_addr)) { 1276*0Sstevel@tonic-gate break; 1277*0Sstevel@tonic-gate } 1278*0Sstevel@tonic-gate } 1279*0Sstevel@tonic-gate if (ipif != NULL) 1280*0Sstevel@tonic-gate break; 1281*0Sstevel@tonic-gate } 1282*0Sstevel@tonic-gate if (src_ill == NULL) { 1283*0Sstevel@tonic-gate /* May be a forwarding packet */ 1284*0Sstevel@tonic-gate src_ill = ill; 1285*0Sstevel@tonic-gate src = ipv6_all_zeros; 1286*0Sstevel@tonic-gate } 1287*0Sstevel@tonic-gate } 1288*0Sstevel@tonic-gate dst = nce->nce_addr; 1289*0Sstevel@tonic-gate /* 1290*0Sstevel@tonic-gate * If source address is unspecified, nce_xmit will choose 1291*0Sstevel@tonic-gate * one for us and initialize the hardware address also 1292*0Sstevel@tonic-gate * appropriately. 1293*0Sstevel@tonic-gate */ 1294*0Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&src)) 1295*0Sstevel@tonic-gate src_ill = NULL; 1296*0Sstevel@tonic-gate nce->nce_rcnt--; 1297*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 1298*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 1299*0Sstevel@tonic-gate dropped = nce_xmit(ill, ND_NEIGHBOR_SOLICIT, src_ill, B_TRUE, &src, 1300*0Sstevel@tonic-gate &dst, 0); 1301*0Sstevel@tonic-gate rw_enter(&ill_g_lock, RW_READER); 1302*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 1303*0Sstevel@tonic-gate if (dropped) 1304*0Sstevel@tonic-gate nce->nce_rcnt++; 1305*0Sstevel@tonic-gate return (ill->ill_reachable_retrans_time); 1306*0Sstevel@tonic-gate } 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate void 1309*0Sstevel@tonic-gate ndp_input_solicit(ill_t *ill, mblk_t *mp) 1310*0Sstevel@tonic-gate { 1311*0Sstevel@tonic-gate nd_neighbor_solicit_t *ns; 1312*0Sstevel@tonic-gate uint32_t hlen = ill->ill_nd_lla_len; 1313*0Sstevel@tonic-gate uchar_t *haddr = NULL; 1314*0Sstevel@tonic-gate icmp6_t *icmp_nd; 1315*0Sstevel@tonic-gate ip6_t *ip6h; 1316*0Sstevel@tonic-gate nce_t *our_nce = NULL; 1317*0Sstevel@tonic-gate in6_addr_t target; 1318*0Sstevel@tonic-gate in6_addr_t src; 1319*0Sstevel@tonic-gate int len; 1320*0Sstevel@tonic-gate int flag = 0; 1321*0Sstevel@tonic-gate nd_opt_hdr_t *opt = NULL; 1322*0Sstevel@tonic-gate boolean_t bad_solicit = B_FALSE; 1323*0Sstevel@tonic-gate mib2_ipv6IfIcmpEntry_t *mib = ill->ill_icmp6_mib; 1324*0Sstevel@tonic-gate 1325*0Sstevel@tonic-gate ip6h = (ip6_t *)mp->b_rptr; 1326*0Sstevel@tonic-gate icmp_nd = (icmp6_t *)(mp->b_rptr + IPV6_HDR_LEN); 1327*0Sstevel@tonic-gate len = mp->b_wptr - mp->b_rptr - IPV6_HDR_LEN; 1328*0Sstevel@tonic-gate src = ip6h->ip6_src; 1329*0Sstevel@tonic-gate ns = (nd_neighbor_solicit_t *)icmp_nd; 1330*0Sstevel@tonic-gate target = ns->nd_ns_target; 1331*0Sstevel@tonic-gate if (IN6_IS_ADDR_MULTICAST(&target)) { 1332*0Sstevel@tonic-gate if (ip_debug > 2) { 1333*0Sstevel@tonic-gate /* ip1dbg */ 1334*0Sstevel@tonic-gate pr_addr_dbg("ndp_input_solicit: Target is" 1335*0Sstevel@tonic-gate " multicast! %s\n", AF_INET6, &target); 1336*0Sstevel@tonic-gate } 1337*0Sstevel@tonic-gate bad_solicit = B_TRUE; 1338*0Sstevel@tonic-gate goto done; 1339*0Sstevel@tonic-gate } 1340*0Sstevel@tonic-gate if (len > sizeof (nd_neighbor_solicit_t)) { 1341*0Sstevel@tonic-gate /* Options present */ 1342*0Sstevel@tonic-gate opt = (nd_opt_hdr_t *)&ns[1]; 1343*0Sstevel@tonic-gate len -= sizeof (nd_neighbor_solicit_t); 1344*0Sstevel@tonic-gate if (!ndp_verify_optlen(opt, len)) { 1345*0Sstevel@tonic-gate ip1dbg(("ndp_input_solicit: Bad opt len\n")); 1346*0Sstevel@tonic-gate bad_solicit = B_TRUE; 1347*0Sstevel@tonic-gate goto done; 1348*0Sstevel@tonic-gate } 1349*0Sstevel@tonic-gate } 1350*0Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&src)) { 1351*0Sstevel@tonic-gate /* Check to see if this is a valid DAD solicitation */ 1352*0Sstevel@tonic-gate if (!IN6_IS_ADDR_MC_SOLICITEDNODE(&ip6h->ip6_dst)) { 1353*0Sstevel@tonic-gate if (ip_debug > 2) { 1354*0Sstevel@tonic-gate /* ip1dbg */ 1355*0Sstevel@tonic-gate pr_addr_dbg("ndp_input_solicit: IPv6 " 1356*0Sstevel@tonic-gate "Destination is not solicited node " 1357*0Sstevel@tonic-gate "multicast %s\n", AF_INET6, 1358*0Sstevel@tonic-gate &ip6h->ip6_dst); 1359*0Sstevel@tonic-gate } 1360*0Sstevel@tonic-gate bad_solicit = B_TRUE; 1361*0Sstevel@tonic-gate goto done; 1362*0Sstevel@tonic-gate } 1363*0Sstevel@tonic-gate } 1364*0Sstevel@tonic-gate 1365*0Sstevel@tonic-gate our_nce = ndp_lookup(ill, &target, B_FALSE); 1366*0Sstevel@tonic-gate /* 1367*0Sstevel@tonic-gate * If this is a valid Solicitation, a permanent 1368*0Sstevel@tonic-gate * entry should exist in the cache 1369*0Sstevel@tonic-gate */ 1370*0Sstevel@tonic-gate if (our_nce == NULL || 1371*0Sstevel@tonic-gate !(our_nce->nce_flags & NCE_F_PERMANENT)) { 1372*0Sstevel@tonic-gate ip1dbg(("ndp_input_solicit: Wrong target in NS?!" 1373*0Sstevel@tonic-gate "ifname=%s ", ill->ill_name)); 1374*0Sstevel@tonic-gate if (ip_debug > 2) { 1375*0Sstevel@tonic-gate /* ip1dbg */ 1376*0Sstevel@tonic-gate pr_addr_dbg(" dst %s\n", AF_INET6, &target); 1377*0Sstevel@tonic-gate } 1378*0Sstevel@tonic-gate bad_solicit = B_TRUE; 1379*0Sstevel@tonic-gate goto done; 1380*0Sstevel@tonic-gate } 1381*0Sstevel@tonic-gate 1382*0Sstevel@tonic-gate /* At this point we should have a verified NS per spec */ 1383*0Sstevel@tonic-gate if (opt != NULL) { 1384*0Sstevel@tonic-gate opt = ndp_get_option(opt, len, ND_OPT_SOURCE_LINKADDR); 1385*0Sstevel@tonic-gate if (opt != NULL) { 1386*0Sstevel@tonic-gate /* 1387*0Sstevel@tonic-gate * No source link layer address option should 1388*0Sstevel@tonic-gate * be present in a valid DAD request. 1389*0Sstevel@tonic-gate */ 1390*0Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&src)) { 1391*0Sstevel@tonic-gate ip1dbg(("ndp_input_solicit: source link-layer " 1392*0Sstevel@tonic-gate "address option present with an " 1393*0Sstevel@tonic-gate "unspecified source. \n")); 1394*0Sstevel@tonic-gate bad_solicit = B_TRUE; 1395*0Sstevel@tonic-gate goto done; 1396*0Sstevel@tonic-gate } 1397*0Sstevel@tonic-gate haddr = (uchar_t *)&opt[1]; 1398*0Sstevel@tonic-gate if (hlen > opt->nd_opt_len * 8 || 1399*0Sstevel@tonic-gate hlen == 0) { 1400*0Sstevel@tonic-gate bad_solicit = B_TRUE; 1401*0Sstevel@tonic-gate goto done; 1402*0Sstevel@tonic-gate } 1403*0Sstevel@tonic-gate } 1404*0Sstevel@tonic-gate } 1405*0Sstevel@tonic-gate /* Set override flag, it will be reset later if need be. */ 1406*0Sstevel@tonic-gate flag |= NDP_ORIDE; 1407*0Sstevel@tonic-gate if (!IN6_IS_ADDR_MULTICAST(&ip6h->ip6_dst)) { 1408*0Sstevel@tonic-gate flag |= NDP_UNICAST; 1409*0Sstevel@tonic-gate } 1410*0Sstevel@tonic-gate 1411*0Sstevel@tonic-gate /* 1412*0Sstevel@tonic-gate * Create/update the entry for the soliciting node. 1413*0Sstevel@tonic-gate * or respond to outstanding queries, don't if 1414*0Sstevel@tonic-gate * the source is unspecified address. 1415*0Sstevel@tonic-gate */ 1416*0Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&src)) { 1417*0Sstevel@tonic-gate int err = 0; 1418*0Sstevel@tonic-gate nce_t *nnce; 1419*0Sstevel@tonic-gate 1420*0Sstevel@tonic-gate err = ndp_lookup_then_add(ill, 1421*0Sstevel@tonic-gate haddr, 1422*0Sstevel@tonic-gate &src, /* Soliciting nodes address */ 1423*0Sstevel@tonic-gate &ipv6_all_ones, 1424*0Sstevel@tonic-gate &ipv6_all_zeros, 1425*0Sstevel@tonic-gate 0, 1426*0Sstevel@tonic-gate 0, 1427*0Sstevel@tonic-gate ND_STALE, 1428*0Sstevel@tonic-gate &nnce); 1429*0Sstevel@tonic-gate switch (err) { 1430*0Sstevel@tonic-gate case 0: 1431*0Sstevel@tonic-gate /* done with this entry */ 1432*0Sstevel@tonic-gate NCE_REFRELE(nnce); 1433*0Sstevel@tonic-gate break; 1434*0Sstevel@tonic-gate case EEXIST: 1435*0Sstevel@tonic-gate /* 1436*0Sstevel@tonic-gate * B_FALSE indicates this is not an 1437*0Sstevel@tonic-gate * an advertisement. 1438*0Sstevel@tonic-gate */ 1439*0Sstevel@tonic-gate ndp_process(nnce, haddr, 0, B_FALSE); 1440*0Sstevel@tonic-gate NCE_REFRELE(nnce); 1441*0Sstevel@tonic-gate break; 1442*0Sstevel@tonic-gate default: 1443*0Sstevel@tonic-gate ip1dbg(("ndp_input_solicit: Can't create NCE %d\n", 1444*0Sstevel@tonic-gate err)); 1445*0Sstevel@tonic-gate goto done; 1446*0Sstevel@tonic-gate } 1447*0Sstevel@tonic-gate flag |= NDP_SOLICITED; 1448*0Sstevel@tonic-gate } else { 1449*0Sstevel@tonic-gate /* 1450*0Sstevel@tonic-gate * This is a DAD req, multicast the advertisement 1451*0Sstevel@tonic-gate * to the all-nodes address. 1452*0Sstevel@tonic-gate */ 1453*0Sstevel@tonic-gate src = ipv6_all_hosts_mcast; 1454*0Sstevel@tonic-gate } 1455*0Sstevel@tonic-gate if (our_nce->nce_flags & NCE_F_ISROUTER) 1456*0Sstevel@tonic-gate flag |= NDP_ISROUTER; 1457*0Sstevel@tonic-gate if (our_nce->nce_flags & NCE_F_PROXY) 1458*0Sstevel@tonic-gate flag &= ~NDP_ORIDE; 1459*0Sstevel@tonic-gate /* Response to a solicitation */ 1460*0Sstevel@tonic-gate (void) nce_xmit(ill, 1461*0Sstevel@tonic-gate ND_NEIGHBOR_ADVERT, 1462*0Sstevel@tonic-gate ill, /* ill to be used for extracting ill_nd_lla */ 1463*0Sstevel@tonic-gate B_TRUE, /* use ill_nd_lla */ 1464*0Sstevel@tonic-gate &target, /* Source and target of the advertisement pkt */ 1465*0Sstevel@tonic-gate &src, /* IP Destination (source of original pkt) */ 1466*0Sstevel@tonic-gate flag); 1467*0Sstevel@tonic-gate done: 1468*0Sstevel@tonic-gate if (bad_solicit) 1469*0Sstevel@tonic-gate BUMP_MIB(mib, ipv6IfIcmpInBadNeighborSolicitations); 1470*0Sstevel@tonic-gate if (our_nce != NULL) 1471*0Sstevel@tonic-gate NCE_REFRELE(our_nce); 1472*0Sstevel@tonic-gate } 1473*0Sstevel@tonic-gate 1474*0Sstevel@tonic-gate void 1475*0Sstevel@tonic-gate ndp_input_advert(ill_t *ill, mblk_t *mp) 1476*0Sstevel@tonic-gate { 1477*0Sstevel@tonic-gate nd_neighbor_advert_t *na; 1478*0Sstevel@tonic-gate uint32_t hlen = ill->ill_nd_lla_len; 1479*0Sstevel@tonic-gate uchar_t *haddr = NULL; 1480*0Sstevel@tonic-gate icmp6_t *icmp_nd; 1481*0Sstevel@tonic-gate ip6_t *ip6h; 1482*0Sstevel@tonic-gate nce_t *dst_nce = NULL; 1483*0Sstevel@tonic-gate in6_addr_t target; 1484*0Sstevel@tonic-gate nd_opt_hdr_t *opt = NULL; 1485*0Sstevel@tonic-gate int len; 1486*0Sstevel@tonic-gate mib2_ipv6IfIcmpEntry_t *mib = ill->ill_icmp6_mib; 1487*0Sstevel@tonic-gate 1488*0Sstevel@tonic-gate ip6h = (ip6_t *)mp->b_rptr; 1489*0Sstevel@tonic-gate icmp_nd = (icmp6_t *)(mp->b_rptr + IPV6_HDR_LEN); 1490*0Sstevel@tonic-gate len = mp->b_wptr - mp->b_rptr - IPV6_HDR_LEN; 1491*0Sstevel@tonic-gate na = (nd_neighbor_advert_t *)icmp_nd; 1492*0Sstevel@tonic-gate if (IN6_IS_ADDR_MULTICAST(&ip6h->ip6_dst) && 1493*0Sstevel@tonic-gate (na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED)) { 1494*0Sstevel@tonic-gate ip1dbg(("ndp_input_advert: Target is multicast but the " 1495*0Sstevel@tonic-gate "solicited flag is not zero\n")); 1496*0Sstevel@tonic-gate BUMP_MIB(mib, ipv6IfIcmpInBadNeighborAdvertisements); 1497*0Sstevel@tonic-gate return; 1498*0Sstevel@tonic-gate } 1499*0Sstevel@tonic-gate target = na->nd_na_target; 1500*0Sstevel@tonic-gate if (IN6_IS_ADDR_MULTICAST(&target)) { 1501*0Sstevel@tonic-gate ip1dbg(("ndp_input_advert: Target is multicast!\n")); 1502*0Sstevel@tonic-gate BUMP_MIB(mib, ipv6IfIcmpInBadNeighborAdvertisements); 1503*0Sstevel@tonic-gate return; 1504*0Sstevel@tonic-gate } 1505*0Sstevel@tonic-gate if (len > sizeof (nd_neighbor_advert_t)) { 1506*0Sstevel@tonic-gate opt = (nd_opt_hdr_t *)&na[1]; 1507*0Sstevel@tonic-gate if (!ndp_verify_optlen(opt, 1508*0Sstevel@tonic-gate len - sizeof (nd_neighbor_advert_t))) { 1509*0Sstevel@tonic-gate BUMP_MIB(mib, ipv6IfIcmpInBadNeighborAdvertisements); 1510*0Sstevel@tonic-gate return; 1511*0Sstevel@tonic-gate } 1512*0Sstevel@tonic-gate /* At this point we have a verified NA per spec */ 1513*0Sstevel@tonic-gate len -= sizeof (nd_neighbor_advert_t); 1514*0Sstevel@tonic-gate opt = ndp_get_option(opt, len, ND_OPT_TARGET_LINKADDR); 1515*0Sstevel@tonic-gate if (opt != NULL) { 1516*0Sstevel@tonic-gate haddr = (uchar_t *)&opt[1]; 1517*0Sstevel@tonic-gate if (hlen > opt->nd_opt_len * 8 || 1518*0Sstevel@tonic-gate hlen == 0) { 1519*0Sstevel@tonic-gate BUMP_MIB(mib, 1520*0Sstevel@tonic-gate ipv6IfIcmpInBadNeighborAdvertisements); 1521*0Sstevel@tonic-gate return; 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate } 1524*0Sstevel@tonic-gate } 1525*0Sstevel@tonic-gate 1526*0Sstevel@tonic-gate /* 1527*0Sstevel@tonic-gate * If this interface is part of the group look at all the 1528*0Sstevel@tonic-gate * ills in the group. 1529*0Sstevel@tonic-gate */ 1530*0Sstevel@tonic-gate rw_enter(&ill_g_lock, RW_READER); 1531*0Sstevel@tonic-gate if (ill->ill_group != NULL) 1532*0Sstevel@tonic-gate ill = ill->ill_group->illgrp_ill; 1533*0Sstevel@tonic-gate 1534*0Sstevel@tonic-gate for (; ill != NULL; ill = ill->ill_group_next) { 1535*0Sstevel@tonic-gate mutex_enter(&ill->ill_lock); 1536*0Sstevel@tonic-gate if (!ILL_CAN_LOOKUP(ill)) { 1537*0Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 1538*0Sstevel@tonic-gate continue; 1539*0Sstevel@tonic-gate } 1540*0Sstevel@tonic-gate ill_refhold_locked(ill); 1541*0Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 1542*0Sstevel@tonic-gate dst_nce = ndp_lookup(ill, &target, B_FALSE); 1543*0Sstevel@tonic-gate /* We have to drop the lock since ndp_process calls put* */ 1544*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 1545*0Sstevel@tonic-gate if (dst_nce != NULL) { 1546*0Sstevel@tonic-gate if (na->nd_na_flags_reserved & 1547*0Sstevel@tonic-gate ND_NA_FLAG_ROUTER) { 1548*0Sstevel@tonic-gate dst_nce->nce_flags |= NCE_F_ISROUTER; 1549*0Sstevel@tonic-gate } 1550*0Sstevel@tonic-gate /* B_TRUE indicates this an advertisement */ 1551*0Sstevel@tonic-gate ndp_process(dst_nce, haddr, 1552*0Sstevel@tonic-gate na->nd_na_flags_reserved, B_TRUE); 1553*0Sstevel@tonic-gate NCE_REFRELE(dst_nce); 1554*0Sstevel@tonic-gate } 1555*0Sstevel@tonic-gate rw_enter(&ill_g_lock, RW_READER); 1556*0Sstevel@tonic-gate ill_refrele(ill); 1557*0Sstevel@tonic-gate } 1558*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 1559*0Sstevel@tonic-gate } 1560*0Sstevel@tonic-gate 1561*0Sstevel@tonic-gate /* 1562*0Sstevel@tonic-gate * Process NDP neighbor solicitation/advertisement messages. 1563*0Sstevel@tonic-gate * The checksum has already checked o.k before reaching here. 1564*0Sstevel@tonic-gate */ 1565*0Sstevel@tonic-gate void 1566*0Sstevel@tonic-gate ndp_input(ill_t *ill, mblk_t *mp) 1567*0Sstevel@tonic-gate { 1568*0Sstevel@tonic-gate icmp6_t *icmp_nd; 1569*0Sstevel@tonic-gate ip6_t *ip6h; 1570*0Sstevel@tonic-gate int len; 1571*0Sstevel@tonic-gate mib2_ipv6IfIcmpEntry_t *mib = ill->ill_icmp6_mib; 1572*0Sstevel@tonic-gate 1573*0Sstevel@tonic-gate 1574*0Sstevel@tonic-gate if (!pullupmsg(mp, -1)) { 1575*0Sstevel@tonic-gate ip1dbg(("ndp_input: pullupmsg failed\n")); 1576*0Sstevel@tonic-gate BUMP_MIB(ill->ill_ip6_mib, ipv6InDiscards); 1577*0Sstevel@tonic-gate goto done; 1578*0Sstevel@tonic-gate } 1579*0Sstevel@tonic-gate ip6h = (ip6_t *)mp->b_rptr; 1580*0Sstevel@tonic-gate if (ip6h->ip6_hops != IPV6_MAX_HOPS) { 1581*0Sstevel@tonic-gate ip1dbg(("ndp_input: hoplimit != IPV6_MAX_HOPS\n")); 1582*0Sstevel@tonic-gate BUMP_MIB(mib, ipv6IfIcmpBadHoplimit); 1583*0Sstevel@tonic-gate goto done; 1584*0Sstevel@tonic-gate } 1585*0Sstevel@tonic-gate /* 1586*0Sstevel@tonic-gate * NDP does not accept any extension headers between the 1587*0Sstevel@tonic-gate * IP header and the ICMP header since e.g. a routing 1588*0Sstevel@tonic-gate * header could be dangerous. 1589*0Sstevel@tonic-gate * This assumes that any AH or ESP headers are removed 1590*0Sstevel@tonic-gate * by ip prior to passing the packet to ndp_input. 1591*0Sstevel@tonic-gate */ 1592*0Sstevel@tonic-gate if (ip6h->ip6_nxt != IPPROTO_ICMPV6) { 1593*0Sstevel@tonic-gate ip1dbg(("ndp_input: Wrong next header 0x%x\n", 1594*0Sstevel@tonic-gate ip6h->ip6_nxt)); 1595*0Sstevel@tonic-gate BUMP_MIB(mib, ipv6IfIcmpInErrors); 1596*0Sstevel@tonic-gate goto done; 1597*0Sstevel@tonic-gate } 1598*0Sstevel@tonic-gate icmp_nd = (icmp6_t *)(mp->b_rptr + IPV6_HDR_LEN); 1599*0Sstevel@tonic-gate ASSERT(icmp_nd->icmp6_type == ND_NEIGHBOR_SOLICIT || 1600*0Sstevel@tonic-gate icmp_nd->icmp6_type == ND_NEIGHBOR_ADVERT); 1601*0Sstevel@tonic-gate if (icmp_nd->icmp6_code != 0) { 1602*0Sstevel@tonic-gate ip1dbg(("ndp_input: icmp6 code != 0 \n")); 1603*0Sstevel@tonic-gate BUMP_MIB(mib, ipv6IfIcmpInErrors); 1604*0Sstevel@tonic-gate goto done; 1605*0Sstevel@tonic-gate } 1606*0Sstevel@tonic-gate len = mp->b_wptr - mp->b_rptr - IPV6_HDR_LEN; 1607*0Sstevel@tonic-gate /* 1608*0Sstevel@tonic-gate * Make sure packet length is large enough for either 1609*0Sstevel@tonic-gate * a NS or a NA icmp packet. 1610*0Sstevel@tonic-gate */ 1611*0Sstevel@tonic-gate if (len < sizeof (struct icmp6_hdr) + sizeof (struct in6_addr)) { 1612*0Sstevel@tonic-gate ip1dbg(("ndp_input: packet too short\n")); 1613*0Sstevel@tonic-gate BUMP_MIB(mib, ipv6IfIcmpInErrors); 1614*0Sstevel@tonic-gate goto done; 1615*0Sstevel@tonic-gate } 1616*0Sstevel@tonic-gate if (icmp_nd->icmp6_type == ND_NEIGHBOR_SOLICIT) { 1617*0Sstevel@tonic-gate ndp_input_solicit(ill, mp); 1618*0Sstevel@tonic-gate } else { 1619*0Sstevel@tonic-gate ndp_input_advert(ill, mp); 1620*0Sstevel@tonic-gate } 1621*0Sstevel@tonic-gate done: 1622*0Sstevel@tonic-gate freemsg(mp); 1623*0Sstevel@tonic-gate } 1624*0Sstevel@tonic-gate 1625*0Sstevel@tonic-gate /* 1626*0Sstevel@tonic-gate * nce_xmit is called to form and transmit a ND solicitation or 1627*0Sstevel@tonic-gate * advertisement ICMP packet. 1628*0Sstevel@tonic-gate * If source address is unspecified, appropriate source address 1629*0Sstevel@tonic-gate * and link layer address will be chosen here. This function 1630*0Sstevel@tonic-gate * *always* sends the link layer option. 1631*0Sstevel@tonic-gate * It returns B_FALSE only if it does a successful put() to the 1632*0Sstevel@tonic-gate * corresponding ill's ill_wq otherwise returns B_TRUE. 1633*0Sstevel@tonic-gate */ 1634*0Sstevel@tonic-gate static boolean_t 1635*0Sstevel@tonic-gate nce_xmit(ill_t *ill, uint32_t operation, ill_t *hwaddr_ill, 1636*0Sstevel@tonic-gate boolean_t use_nd_lla, const in6_addr_t *sender, const in6_addr_t *target, 1637*0Sstevel@tonic-gate int flag) 1638*0Sstevel@tonic-gate { 1639*0Sstevel@tonic-gate uint32_t len; 1640*0Sstevel@tonic-gate icmp6_t *icmp6; 1641*0Sstevel@tonic-gate mblk_t *mp; 1642*0Sstevel@tonic-gate ip6_t *ip6h; 1643*0Sstevel@tonic-gate nd_opt_hdr_t *opt; 1644*0Sstevel@tonic-gate uint_t plen; 1645*0Sstevel@tonic-gate ip6i_t *ip6i; 1646*0Sstevel@tonic-gate ipif_t *src_ipif = NULL; 1647*0Sstevel@tonic-gate 1648*0Sstevel@tonic-gate /* 1649*0Sstevel@tonic-gate * If we have a unspecified source(sender) address, select a 1650*0Sstevel@tonic-gate * proper source address for the solicitation here itself so 1651*0Sstevel@tonic-gate * that we can initialize the h/w address correctly. This is 1652*0Sstevel@tonic-gate * needed for interface groups as source address can come from 1653*0Sstevel@tonic-gate * the whole group and the h/w address initialized from ill will 1654*0Sstevel@tonic-gate * be wrong if the source address comes from a different ill. 1655*0Sstevel@tonic-gate * 1656*0Sstevel@tonic-gate * Note that the NA never comes here with the unspecified source 1657*0Sstevel@tonic-gate * address. The following asserts that whenever the source 1658*0Sstevel@tonic-gate * address is specified, the haddr also should be specified. 1659*0Sstevel@tonic-gate */ 1660*0Sstevel@tonic-gate ASSERT(IN6_IS_ADDR_UNSPECIFIED(sender) || (hwaddr_ill != NULL)); 1661*0Sstevel@tonic-gate 1662*0Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(sender)) { 1663*0Sstevel@tonic-gate ASSERT(operation != ND_NEIGHBOR_ADVERT); 1664*0Sstevel@tonic-gate /* 1665*0Sstevel@tonic-gate * Pick a source address for this solicitation, but 1666*0Sstevel@tonic-gate * restrict the selection to addresses assigned to the 1667*0Sstevel@tonic-gate * output interface (or interface group). We do this 1668*0Sstevel@tonic-gate * because the destination will create a neighbor cache 1669*0Sstevel@tonic-gate * entry for the source address of this packet, so the 1670*0Sstevel@tonic-gate * source address had better be a valid neighbor. 1671*0Sstevel@tonic-gate */ 1672*0Sstevel@tonic-gate src_ipif = ipif_select_source_v6(ill, target, B_TRUE, 1673*0Sstevel@tonic-gate IPV6_PREFER_SRC_DEFAULT, GLOBAL_ZONEID); 1674*0Sstevel@tonic-gate if (src_ipif == NULL) { 1675*0Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 1676*0Sstevel@tonic-gate 1677*0Sstevel@tonic-gate ip0dbg(("nce_xmit: No source ipif for dst %s\n", 1678*0Sstevel@tonic-gate inet_ntop(AF_INET6, (char *)target, buf, 1679*0Sstevel@tonic-gate sizeof (buf)))); 1680*0Sstevel@tonic-gate return (B_TRUE); 1681*0Sstevel@tonic-gate } 1682*0Sstevel@tonic-gate sender = &src_ipif->ipif_v6src_addr; 1683*0Sstevel@tonic-gate hwaddr_ill = src_ipif->ipif_ill; 1684*0Sstevel@tonic-gate } 1685*0Sstevel@tonic-gate 1686*0Sstevel@tonic-gate plen = (sizeof (nd_opt_hdr_t) + ill->ill_nd_lla_len + 7)/8; 1687*0Sstevel@tonic-gate /* 1688*0Sstevel@tonic-gate * Always make sure that the NS/NA packets don't get load 1689*0Sstevel@tonic-gate * spread. This is needed so that the probe packets sent 1690*0Sstevel@tonic-gate * by the in.mpathd daemon can really go out on the desired 1691*0Sstevel@tonic-gate * interface. Probe packets are made to go out on a desired 1692*0Sstevel@tonic-gate * interface by including a ip6i with ATTACH_IF flag. As these 1693*0Sstevel@tonic-gate * packets indirectly end up sending/receiving NS/NA packets 1694*0Sstevel@tonic-gate * (neighbor doing NUD), we have to make sure that NA 1695*0Sstevel@tonic-gate * also go out on the same interface. 1696*0Sstevel@tonic-gate */ 1697*0Sstevel@tonic-gate len = IPV6_HDR_LEN + sizeof (ip6i_t) + sizeof (nd_neighbor_advert_t) + 1698*0Sstevel@tonic-gate plen * 8; 1699*0Sstevel@tonic-gate mp = allocb(len, BPRI_LO); 1700*0Sstevel@tonic-gate if (mp == NULL) { 1701*0Sstevel@tonic-gate if (src_ipif != NULL) 1702*0Sstevel@tonic-gate ipif_refrele(src_ipif); 1703*0Sstevel@tonic-gate return (B_TRUE); 1704*0Sstevel@tonic-gate } 1705*0Sstevel@tonic-gate bzero((char *)mp->b_rptr, len); 1706*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + len; 1707*0Sstevel@tonic-gate 1708*0Sstevel@tonic-gate ip6i = (ip6i_t *)mp->b_rptr; 1709*0Sstevel@tonic-gate ip6i->ip6i_vcf = IPV6_DEFAULT_VERS_AND_FLOW; 1710*0Sstevel@tonic-gate ip6i->ip6i_nxt = IPPROTO_RAW; 1711*0Sstevel@tonic-gate ip6i->ip6i_flags = IP6I_ATTACH_IF | IP6I_HOPLIMIT; 1712*0Sstevel@tonic-gate ip6i->ip6i_ifindex = ill->ill_phyint->phyint_ifindex; 1713*0Sstevel@tonic-gate 1714*0Sstevel@tonic-gate ip6h = (ip6_t *)(mp->b_rptr + sizeof (ip6i_t)); 1715*0Sstevel@tonic-gate ip6h->ip6_vcf = IPV6_DEFAULT_VERS_AND_FLOW; 1716*0Sstevel@tonic-gate ip6h->ip6_plen = htons(len - IPV6_HDR_LEN - sizeof (ip6i_t)); 1717*0Sstevel@tonic-gate ip6h->ip6_nxt = IPPROTO_ICMPV6; 1718*0Sstevel@tonic-gate ip6h->ip6_hops = IPV6_MAX_HOPS; 1719*0Sstevel@tonic-gate ip6h->ip6_dst = *target; 1720*0Sstevel@tonic-gate icmp6 = (icmp6_t *)&ip6h[1]; 1721*0Sstevel@tonic-gate 1722*0Sstevel@tonic-gate opt = (nd_opt_hdr_t *)((uint8_t *)ip6h + IPV6_HDR_LEN + 1723*0Sstevel@tonic-gate sizeof (nd_neighbor_advert_t)); 1724*0Sstevel@tonic-gate 1725*0Sstevel@tonic-gate if (operation == ND_NEIGHBOR_SOLICIT) { 1726*0Sstevel@tonic-gate nd_neighbor_solicit_t *ns = (nd_neighbor_solicit_t *)icmp6; 1727*0Sstevel@tonic-gate 1728*0Sstevel@tonic-gate opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; 1729*0Sstevel@tonic-gate ip6h->ip6_src = *sender; 1730*0Sstevel@tonic-gate ns->nd_ns_target = *target; 1731*0Sstevel@tonic-gate if (!(flag & NDP_UNICAST)) { 1732*0Sstevel@tonic-gate /* Form multicast address of the target */ 1733*0Sstevel@tonic-gate ip6h->ip6_dst = ipv6_solicited_node_mcast; 1734*0Sstevel@tonic-gate ip6h->ip6_dst.s6_addr32[3] |= 1735*0Sstevel@tonic-gate ns->nd_ns_target.s6_addr32[3]; 1736*0Sstevel@tonic-gate } 1737*0Sstevel@tonic-gate } else { 1738*0Sstevel@tonic-gate nd_neighbor_advert_t *na = (nd_neighbor_advert_t *)icmp6; 1739*0Sstevel@tonic-gate 1740*0Sstevel@tonic-gate opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; 1741*0Sstevel@tonic-gate ip6h->ip6_src = *sender; 1742*0Sstevel@tonic-gate na->nd_na_target = *sender; 1743*0Sstevel@tonic-gate if (flag & NDP_ISROUTER) 1744*0Sstevel@tonic-gate na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER; 1745*0Sstevel@tonic-gate if (flag & NDP_SOLICITED) 1746*0Sstevel@tonic-gate na->nd_na_flags_reserved |= ND_NA_FLAG_SOLICITED; 1747*0Sstevel@tonic-gate if (flag & NDP_ORIDE) 1748*0Sstevel@tonic-gate na->nd_na_flags_reserved |= ND_NA_FLAG_OVERRIDE; 1749*0Sstevel@tonic-gate 1750*0Sstevel@tonic-gate } 1751*0Sstevel@tonic-gate /* Fill in link layer address and option len */ 1752*0Sstevel@tonic-gate opt->nd_opt_len = (uint8_t)plen; 1753*0Sstevel@tonic-gate mutex_enter(&hwaddr_ill->ill_lock); 1754*0Sstevel@tonic-gate bcopy(use_nd_lla ? hwaddr_ill->ill_nd_lla : hwaddr_ill->ill_phys_addr, 1755*0Sstevel@tonic-gate &opt[1], hwaddr_ill->ill_nd_lla_len); 1756*0Sstevel@tonic-gate mutex_exit(&hwaddr_ill->ill_lock); 1757*0Sstevel@tonic-gate icmp6->icmp6_type = (uint8_t)operation; 1758*0Sstevel@tonic-gate icmp6->icmp6_code = 0; 1759*0Sstevel@tonic-gate /* 1760*0Sstevel@tonic-gate * Prepare for checksum by putting icmp length in the icmp 1761*0Sstevel@tonic-gate * checksum field. The checksum is calculated in ip_wput_v6. 1762*0Sstevel@tonic-gate */ 1763*0Sstevel@tonic-gate icmp6->icmp6_cksum = ip6h->ip6_plen; 1764*0Sstevel@tonic-gate 1765*0Sstevel@tonic-gate if (src_ipif != NULL) 1766*0Sstevel@tonic-gate ipif_refrele(src_ipif); 1767*0Sstevel@tonic-gate if (canput(ill->ill_wq)) { 1768*0Sstevel@tonic-gate put(ill->ill_wq, mp); 1769*0Sstevel@tonic-gate return (B_FALSE); 1770*0Sstevel@tonic-gate } 1771*0Sstevel@tonic-gate freemsg(mp); 1772*0Sstevel@tonic-gate return (B_TRUE); 1773*0Sstevel@tonic-gate } 1774*0Sstevel@tonic-gate 1775*0Sstevel@tonic-gate /* 1776*0Sstevel@tonic-gate * Make a link layer address (does not include the SAP) from an nce. 1777*0Sstevel@tonic-gate * To form the link layer address, use the last four bytes of ipv6 1778*0Sstevel@tonic-gate * address passed in and the fixed offset stored in nce. 1779*0Sstevel@tonic-gate */ 1780*0Sstevel@tonic-gate static void 1781*0Sstevel@tonic-gate nce_make_mapping(nce_t *nce, uchar_t *addrpos, uchar_t *addr) 1782*0Sstevel@tonic-gate { 1783*0Sstevel@tonic-gate uchar_t *mask, *to; 1784*0Sstevel@tonic-gate ill_t *ill = nce->nce_ill; 1785*0Sstevel@tonic-gate int len; 1786*0Sstevel@tonic-gate 1787*0Sstevel@tonic-gate if (ill->ill_net_type == IRE_IF_NORESOLVER) 1788*0Sstevel@tonic-gate return; 1789*0Sstevel@tonic-gate ASSERT(nce->nce_res_mp != NULL); 1790*0Sstevel@tonic-gate ASSERT(ill->ill_net_type == IRE_IF_RESOLVER); 1791*0Sstevel@tonic-gate ASSERT(nce->nce_flags & NCE_F_MAPPING); 1792*0Sstevel@tonic-gate ASSERT(!IN6_IS_ADDR_UNSPECIFIED(&nce->nce_extract_mask)); 1793*0Sstevel@tonic-gate ASSERT(addr != NULL); 1794*0Sstevel@tonic-gate bcopy(nce->nce_res_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill), 1795*0Sstevel@tonic-gate addrpos, ill->ill_nd_lla_len); 1796*0Sstevel@tonic-gate len = MIN((int)ill->ill_nd_lla_len - nce->nce_ll_extract_start, 1797*0Sstevel@tonic-gate IPV6_ADDR_LEN); 1798*0Sstevel@tonic-gate mask = (uchar_t *)&nce->nce_extract_mask; 1799*0Sstevel@tonic-gate mask += (IPV6_ADDR_LEN - len); 1800*0Sstevel@tonic-gate addr += (IPV6_ADDR_LEN - len); 1801*0Sstevel@tonic-gate to = addrpos + nce->nce_ll_extract_start; 1802*0Sstevel@tonic-gate while (len-- > 0) 1803*0Sstevel@tonic-gate *to++ |= *mask++ & *addr++; 1804*0Sstevel@tonic-gate } 1805*0Sstevel@tonic-gate 1806*0Sstevel@tonic-gate /* 1807*0Sstevel@tonic-gate * Pass a cache report back out via NDD. 1808*0Sstevel@tonic-gate */ 1809*0Sstevel@tonic-gate /* ARGSUSED */ 1810*0Sstevel@tonic-gate int 1811*0Sstevel@tonic-gate ndp_report(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *ioc_cr) 1812*0Sstevel@tonic-gate { 1813*0Sstevel@tonic-gate (void) mi_mpprintf(mp, "ifname hardware addr flags" 1814*0Sstevel@tonic-gate " proto addr/mask"); 1815*0Sstevel@tonic-gate ndp_walk(NULL, (pfi_t)nce_report1, (uchar_t *)mp); 1816*0Sstevel@tonic-gate return (0); 1817*0Sstevel@tonic-gate } 1818*0Sstevel@tonic-gate 1819*0Sstevel@tonic-gate /* 1820*0Sstevel@tonic-gate * convert a link level address of arbitrary length 1821*0Sstevel@tonic-gate * to an ascii string. 1822*0Sstevel@tonic-gate * The caller *must* have already verified that the string buffer 1823*0Sstevel@tonic-gate * is large enough to hold the entire string, including trailing NULL. 1824*0Sstevel@tonic-gate */ 1825*0Sstevel@tonic-gate static void 1826*0Sstevel@tonic-gate lla2ascii(uint8_t *lla, int addrlen, uchar_t *buf) 1827*0Sstevel@tonic-gate { 1828*0Sstevel@tonic-gate uchar_t addrbyte[8]; /* needs to hold ascii for a byte plus a NULL */ 1829*0Sstevel@tonic-gate int i; 1830*0Sstevel@tonic-gate size_t len; 1831*0Sstevel@tonic-gate 1832*0Sstevel@tonic-gate buf[0] = '\0'; 1833*0Sstevel@tonic-gate for (i = 0; i < addrlen; i++) { 1834*0Sstevel@tonic-gate addrbyte[0] = '\0'; 1835*0Sstevel@tonic-gate (void) sprintf((char *)addrbyte, "%02x:", (lla[i] & 0xff)); 1836*0Sstevel@tonic-gate len = strlen((const char *)addrbyte); 1837*0Sstevel@tonic-gate bcopy(addrbyte, buf, len); 1838*0Sstevel@tonic-gate buf = buf + len; 1839*0Sstevel@tonic-gate } 1840*0Sstevel@tonic-gate *--buf = '\0'; 1841*0Sstevel@tonic-gate } 1842*0Sstevel@tonic-gate 1843*0Sstevel@tonic-gate /* 1844*0Sstevel@tonic-gate * Add a single line to the NDP Cache Entry Report. 1845*0Sstevel@tonic-gate */ 1846*0Sstevel@tonic-gate static void 1847*0Sstevel@tonic-gate nce_report1(nce_t *nce, uchar_t *mp_arg) 1848*0Sstevel@tonic-gate { 1849*0Sstevel@tonic-gate ill_t *ill = nce->nce_ill; 1850*0Sstevel@tonic-gate char local_buf[INET6_ADDRSTRLEN]; 1851*0Sstevel@tonic-gate uchar_t flags_buf[10]; 1852*0Sstevel@tonic-gate uint32_t flags = nce->nce_flags; 1853*0Sstevel@tonic-gate mblk_t *mp = (mblk_t *)mp_arg; 1854*0Sstevel@tonic-gate uchar_t *h; 1855*0Sstevel@tonic-gate uchar_t *m = flags_buf; 1856*0Sstevel@tonic-gate in6_addr_t v6addr; 1857*0Sstevel@tonic-gate 1858*0Sstevel@tonic-gate /* 1859*0Sstevel@tonic-gate * Lock the nce to protect nce_res_mp from being changed 1860*0Sstevel@tonic-gate * if an external resolver address resolution completes 1861*0Sstevel@tonic-gate * while nce_res_mp is being accessed here. 1862*0Sstevel@tonic-gate * 1863*0Sstevel@tonic-gate * Deal with all address formats, not just Ethernet-specific 1864*0Sstevel@tonic-gate * In addition, make sure that the mblk has enough space 1865*0Sstevel@tonic-gate * before writing to it. If is doesn't, allocate a new one. 1866*0Sstevel@tonic-gate */ 1867*0Sstevel@tonic-gate ASSERT(ill != NULL); 1868*0Sstevel@tonic-gate v6addr = nce->nce_mask; 1869*0Sstevel@tonic-gate if (flags & NCE_F_PERMANENT) 1870*0Sstevel@tonic-gate *m++ = 'P'; 1871*0Sstevel@tonic-gate if (flags & NCE_F_ISROUTER) 1872*0Sstevel@tonic-gate *m++ = 'R'; 1873*0Sstevel@tonic-gate if (flags & NCE_F_MAPPING) 1874*0Sstevel@tonic-gate *m++ = 'M'; 1875*0Sstevel@tonic-gate *m = '\0'; 1876*0Sstevel@tonic-gate 1877*0Sstevel@tonic-gate if (ill->ill_net_type == IRE_IF_RESOLVER) { 1878*0Sstevel@tonic-gate size_t addrlen; 1879*0Sstevel@tonic-gate uchar_t *addr_buf; 1880*0Sstevel@tonic-gate dl_unitdata_req_t *dl; 1881*0Sstevel@tonic-gate 1882*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 1883*0Sstevel@tonic-gate h = nce->nce_res_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill); 1884*0Sstevel@tonic-gate dl = (dl_unitdata_req_t *)nce->nce_res_mp->b_rptr; 1885*0Sstevel@tonic-gate if (ill->ill_flags & ILLF_XRESOLV) 1886*0Sstevel@tonic-gate addrlen = (3 * (dl->dl_dest_addr_length)); 1887*0Sstevel@tonic-gate else 1888*0Sstevel@tonic-gate addrlen = (3 * (ill->ill_nd_lla_len)); 1889*0Sstevel@tonic-gate if (addrlen <= 0) { 1890*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 1891*0Sstevel@tonic-gate (void) mi_mpprintf(mp, 1892*0Sstevel@tonic-gate "%8s %9s %5s %s/%d", 1893*0Sstevel@tonic-gate ill->ill_name, 1894*0Sstevel@tonic-gate "None", 1895*0Sstevel@tonic-gate (uchar_t *)&flags_buf, 1896*0Sstevel@tonic-gate inet_ntop(AF_INET6, (char *)&nce->nce_addr, 1897*0Sstevel@tonic-gate (char *)local_buf, sizeof (local_buf)), 1898*0Sstevel@tonic-gate ip_mask_to_plen_v6(&v6addr)); 1899*0Sstevel@tonic-gate } else { 1900*0Sstevel@tonic-gate /* 1901*0Sstevel@tonic-gate * Convert the hardware/lla address to ascii 1902*0Sstevel@tonic-gate */ 1903*0Sstevel@tonic-gate addr_buf = kmem_zalloc(addrlen, KM_NOSLEEP); 1904*0Sstevel@tonic-gate if (addr_buf == NULL) { 1905*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 1906*0Sstevel@tonic-gate return; 1907*0Sstevel@tonic-gate } 1908*0Sstevel@tonic-gate if (ill->ill_flags & ILLF_XRESOLV) 1909*0Sstevel@tonic-gate lla2ascii((uint8_t *)h, dl->dl_dest_addr_length, 1910*0Sstevel@tonic-gate addr_buf); 1911*0Sstevel@tonic-gate else 1912*0Sstevel@tonic-gate lla2ascii((uint8_t *)h, ill->ill_nd_lla_len, 1913*0Sstevel@tonic-gate addr_buf); 1914*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 1915*0Sstevel@tonic-gate (void) mi_mpprintf(mp, "%8s %17s %5s %s/%d", 1916*0Sstevel@tonic-gate ill->ill_name, addr_buf, (uchar_t *)&flags_buf, 1917*0Sstevel@tonic-gate inet_ntop(AF_INET6, (char *)&nce->nce_addr, 1918*0Sstevel@tonic-gate (char *)local_buf, sizeof (local_buf)), 1919*0Sstevel@tonic-gate ip_mask_to_plen_v6(&v6addr)); 1920*0Sstevel@tonic-gate kmem_free(addr_buf, addrlen); 1921*0Sstevel@tonic-gate } 1922*0Sstevel@tonic-gate } else { 1923*0Sstevel@tonic-gate (void) mi_mpprintf(mp, 1924*0Sstevel@tonic-gate "%8s %9s %5s %s/%d", 1925*0Sstevel@tonic-gate ill->ill_name, 1926*0Sstevel@tonic-gate "None", 1927*0Sstevel@tonic-gate (uchar_t *)&flags_buf, 1928*0Sstevel@tonic-gate inet_ntop(AF_INET6, (char *)&nce->nce_addr, 1929*0Sstevel@tonic-gate (char *)local_buf, sizeof (local_buf)), 1930*0Sstevel@tonic-gate ip_mask_to_plen_v6(&v6addr)); 1931*0Sstevel@tonic-gate } 1932*0Sstevel@tonic-gate } 1933*0Sstevel@tonic-gate 1934*0Sstevel@tonic-gate mblk_t * 1935*0Sstevel@tonic-gate nce_udreq_alloc(ill_t *ill) 1936*0Sstevel@tonic-gate { 1937*0Sstevel@tonic-gate mblk_t *template_mp = NULL; 1938*0Sstevel@tonic-gate dl_unitdata_req_t *dlur; 1939*0Sstevel@tonic-gate int sap_length; 1940*0Sstevel@tonic-gate 1941*0Sstevel@tonic-gate sap_length = ill->ill_sap_length; 1942*0Sstevel@tonic-gate template_mp = ip_dlpi_alloc(sizeof (dl_unitdata_req_t) + 1943*0Sstevel@tonic-gate ill->ill_nd_lla_len + ABS(sap_length), DL_UNITDATA_REQ); 1944*0Sstevel@tonic-gate if (template_mp == NULL) 1945*0Sstevel@tonic-gate return (NULL); 1946*0Sstevel@tonic-gate 1947*0Sstevel@tonic-gate dlur = (dl_unitdata_req_t *)template_mp->b_rptr; 1948*0Sstevel@tonic-gate dlur->dl_priority.dl_min = 0; 1949*0Sstevel@tonic-gate dlur->dl_priority.dl_max = 0; 1950*0Sstevel@tonic-gate dlur->dl_dest_addr_length = ABS(sap_length) + ill->ill_nd_lla_len; 1951*0Sstevel@tonic-gate dlur->dl_dest_addr_offset = sizeof (dl_unitdata_req_t); 1952*0Sstevel@tonic-gate 1953*0Sstevel@tonic-gate /* Copy in the SAP value. */ 1954*0Sstevel@tonic-gate NCE_LL_SAP_COPY(ill, template_mp); 1955*0Sstevel@tonic-gate 1956*0Sstevel@tonic-gate return (template_mp); 1957*0Sstevel@tonic-gate } 1958*0Sstevel@tonic-gate 1959*0Sstevel@tonic-gate /* 1960*0Sstevel@tonic-gate * NDP retransmit timer. 1961*0Sstevel@tonic-gate * This timer goes off when: 1962*0Sstevel@tonic-gate * a. It is time to retransmit NS for resolver. 1963*0Sstevel@tonic-gate * b. It is time to send reachability probes. 1964*0Sstevel@tonic-gate */ 1965*0Sstevel@tonic-gate void 1966*0Sstevel@tonic-gate ndp_timer(void *arg) 1967*0Sstevel@tonic-gate { 1968*0Sstevel@tonic-gate nce_t *nce = arg; 1969*0Sstevel@tonic-gate ill_t *ill = nce->nce_ill; 1970*0Sstevel@tonic-gate uint32_t ms; 1971*0Sstevel@tonic-gate char addrbuf[INET6_ADDRSTRLEN]; 1972*0Sstevel@tonic-gate mblk_t *mp; 1973*0Sstevel@tonic-gate boolean_t dropped = B_FALSE; 1974*0Sstevel@tonic-gate 1975*0Sstevel@tonic-gate /* 1976*0Sstevel@tonic-gate * The timer has to be cancelled by ndp_delete before doing the final 1977*0Sstevel@tonic-gate * refrele. So the NCE is guaranteed to exist when the timer runs 1978*0Sstevel@tonic-gate * until it clears the timeout_id. Before clearing the timeout_id 1979*0Sstevel@tonic-gate * bump up the refcnt so that we can continue to use the nce 1980*0Sstevel@tonic-gate */ 1981*0Sstevel@tonic-gate ASSERT(nce != NULL); 1982*0Sstevel@tonic-gate 1983*0Sstevel@tonic-gate /* 1984*0Sstevel@tonic-gate * Grab the ill_g_lock now itself to avoid lock order problems. 1985*0Sstevel@tonic-gate * nce_solicit needs ill_g_lock to be able to traverse ills 1986*0Sstevel@tonic-gate */ 1987*0Sstevel@tonic-gate rw_enter(&ill_g_lock, RW_READER); 1988*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 1989*0Sstevel@tonic-gate NCE_REFHOLD_LOCKED(nce); 1990*0Sstevel@tonic-gate nce->nce_timeout_id = 0; 1991*0Sstevel@tonic-gate 1992*0Sstevel@tonic-gate /* 1993*0Sstevel@tonic-gate * Check the reachability state first. 1994*0Sstevel@tonic-gate */ 1995*0Sstevel@tonic-gate switch (nce->nce_state) { 1996*0Sstevel@tonic-gate case ND_DELAY: 1997*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 1998*0Sstevel@tonic-gate nce->nce_state = ND_PROBE; 1999*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2000*0Sstevel@tonic-gate (void) nce_xmit(ill, ND_NEIGHBOR_SOLICIT, NULL, B_FALSE, 2001*0Sstevel@tonic-gate &ipv6_all_zeros, &nce->nce_addr, NDP_UNICAST); 2002*0Sstevel@tonic-gate if (ip_debug > 3) { 2003*0Sstevel@tonic-gate /* ip2dbg */ 2004*0Sstevel@tonic-gate pr_addr_dbg("ndp_timer: state for %s changed " 2005*0Sstevel@tonic-gate "to PROBE\n", AF_INET6, &nce->nce_addr); 2006*0Sstevel@tonic-gate } 2007*0Sstevel@tonic-gate NDP_RESTART_TIMER(nce, ill->ill_reachable_retrans_time); 2008*0Sstevel@tonic-gate NCE_REFRELE(nce); 2009*0Sstevel@tonic-gate return; 2010*0Sstevel@tonic-gate case ND_PROBE: 2011*0Sstevel@tonic-gate /* must be retransmit timer */ 2012*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 2013*0Sstevel@tonic-gate nce->nce_pcnt--; 2014*0Sstevel@tonic-gate ASSERT(nce->nce_pcnt < ND_MAX_UNICAST_SOLICIT && 2015*0Sstevel@tonic-gate nce->nce_pcnt >= -1); 2016*0Sstevel@tonic-gate if (nce->nce_pcnt == 0) { 2017*0Sstevel@tonic-gate /* Wait RetransTimer, before deleting the entry */ 2018*0Sstevel@tonic-gate ip2dbg(("ndp_timer: pcount=%x dst %s\n", 2019*0Sstevel@tonic-gate nce->nce_pcnt, inet_ntop(AF_INET6, 2020*0Sstevel@tonic-gate &nce->nce_addr, addrbuf, sizeof (addrbuf)))); 2021*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2022*0Sstevel@tonic-gate NDP_RESTART_TIMER(nce, ill->ill_reachable_retrans_time); 2023*0Sstevel@tonic-gate } else { 2024*0Sstevel@tonic-gate /* 2025*0Sstevel@tonic-gate * As per RFC2461, the nce gets deleted after 2026*0Sstevel@tonic-gate * MAX_UNICAST_SOLICIT unsuccessful re-transmissions. 2027*0Sstevel@tonic-gate * Note that the first unicast solicitation is sent 2028*0Sstevel@tonic-gate * during the DELAY state. 2029*0Sstevel@tonic-gate */ 2030*0Sstevel@tonic-gate if (nce->nce_pcnt > 0) { 2031*0Sstevel@tonic-gate ip2dbg(("ndp_timer: pcount=%x dst %s\n", 2032*0Sstevel@tonic-gate nce->nce_pcnt, inet_ntop(AF_INET6, 2033*0Sstevel@tonic-gate &nce->nce_addr, 2034*0Sstevel@tonic-gate addrbuf, sizeof (addrbuf)))); 2035*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2036*0Sstevel@tonic-gate dropped = nce_xmit(ill, ND_NEIGHBOR_SOLICIT, 2037*0Sstevel@tonic-gate NULL, B_FALSE, &ipv6_all_zeros, 2038*0Sstevel@tonic-gate &nce->nce_addr, NDP_UNICAST); 2039*0Sstevel@tonic-gate if (dropped) { 2040*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 2041*0Sstevel@tonic-gate nce->nce_pcnt++; 2042*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2043*0Sstevel@tonic-gate } 2044*0Sstevel@tonic-gate NDP_RESTART_TIMER(nce, 2045*0Sstevel@tonic-gate ill->ill_reachable_retrans_time); 2046*0Sstevel@tonic-gate } else { 2047*0Sstevel@tonic-gate /* No hope, delete the nce */ 2048*0Sstevel@tonic-gate nce->nce_state = ND_UNREACHABLE; 2049*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2050*0Sstevel@tonic-gate if (ip_debug > 2) { 2051*0Sstevel@tonic-gate /* ip1dbg */ 2052*0Sstevel@tonic-gate pr_addr_dbg("ndp_timer: Delete IRE for" 2053*0Sstevel@tonic-gate " dst %s\n", AF_INET6, 2054*0Sstevel@tonic-gate &nce->nce_addr); 2055*0Sstevel@tonic-gate } 2056*0Sstevel@tonic-gate ndp_delete(nce); 2057*0Sstevel@tonic-gate } 2058*0Sstevel@tonic-gate } 2059*0Sstevel@tonic-gate NCE_REFRELE(nce); 2060*0Sstevel@tonic-gate return; 2061*0Sstevel@tonic-gate case ND_INCOMPLETE: 2062*0Sstevel@tonic-gate /* 2063*0Sstevel@tonic-gate * Must be resolvers retransmit timer. 2064*0Sstevel@tonic-gate */ 2065*0Sstevel@tonic-gate for (mp = nce->nce_qd_mp; mp != NULL; mp = mp->b_next) { 2066*0Sstevel@tonic-gate ip6i_t *ip6i; 2067*0Sstevel@tonic-gate ip6_t *ip6h; 2068*0Sstevel@tonic-gate mblk_t *data_mp; 2069*0Sstevel@tonic-gate 2070*0Sstevel@tonic-gate /* 2071*0Sstevel@tonic-gate * Walk the list of packets queued, and see if there 2072*0Sstevel@tonic-gate * are any multipathing probe packets. Such packets 2073*0Sstevel@tonic-gate * are always queued at the head. Since this is a 2074*0Sstevel@tonic-gate * retransmit timer firing, mark such packets as 2075*0Sstevel@tonic-gate * delayed in ND resolution. This info will be used 2076*0Sstevel@tonic-gate * in ip_wput_v6(). Multipathing probe packets will 2077*0Sstevel@tonic-gate * always have an ip6i_t. Once we hit a packet without 2078*0Sstevel@tonic-gate * it, we can break out of this loop. 2079*0Sstevel@tonic-gate */ 2080*0Sstevel@tonic-gate if (mp->b_datap->db_type == M_CTL) 2081*0Sstevel@tonic-gate data_mp = mp->b_cont; 2082*0Sstevel@tonic-gate else 2083*0Sstevel@tonic-gate data_mp = mp; 2084*0Sstevel@tonic-gate 2085*0Sstevel@tonic-gate ip6h = (ip6_t *)data_mp->b_rptr; 2086*0Sstevel@tonic-gate if (ip6h->ip6_nxt != IPPROTO_RAW) 2087*0Sstevel@tonic-gate break; 2088*0Sstevel@tonic-gate 2089*0Sstevel@tonic-gate /* 2090*0Sstevel@tonic-gate * This message should have been pulled up already in 2091*0Sstevel@tonic-gate * ip_wput_v6. We can't do pullups here because the 2092*0Sstevel@tonic-gate * b_next/b_prev is non-NULL. 2093*0Sstevel@tonic-gate */ 2094*0Sstevel@tonic-gate ip6i = (ip6i_t *)ip6h; 2095*0Sstevel@tonic-gate ASSERT((data_mp->b_wptr - (uchar_t *)ip6i) >= 2096*0Sstevel@tonic-gate sizeof (ip6i_t) + IPV6_HDR_LEN); 2097*0Sstevel@tonic-gate 2098*0Sstevel@tonic-gate /* Mark this packet as delayed due to ND resolution */ 2099*0Sstevel@tonic-gate if (ip6i->ip6i_flags & IP6I_DROP_IFDELAYED) 2100*0Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_ND_DELAYED; 2101*0Sstevel@tonic-gate } 2102*0Sstevel@tonic-gate if (nce->nce_qd_mp != NULL) { 2103*0Sstevel@tonic-gate ms = nce_solicit(nce, NULL); 2104*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 2105*0Sstevel@tonic-gate if (ms == 0) { 2106*0Sstevel@tonic-gate if (nce->nce_state != ND_REACHABLE) { 2107*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2108*0Sstevel@tonic-gate nce_resolv_failed(nce); 2109*0Sstevel@tonic-gate ndp_delete(nce); 2110*0Sstevel@tonic-gate } else { 2111*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2112*0Sstevel@tonic-gate } 2113*0Sstevel@tonic-gate } else { 2114*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2115*0Sstevel@tonic-gate NDP_RESTART_TIMER(nce, (clock_t)ms); 2116*0Sstevel@tonic-gate } 2117*0Sstevel@tonic-gate NCE_REFRELE(nce); 2118*0Sstevel@tonic-gate return; 2119*0Sstevel@tonic-gate } 2120*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2121*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 2122*0Sstevel@tonic-gate NCE_REFRELE(nce); 2123*0Sstevel@tonic-gate break; 2124*0Sstevel@tonic-gate case ND_REACHABLE : 2125*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 2126*0Sstevel@tonic-gate if (nce->nce_flags & NCE_F_UNSOL_ADV && 2127*0Sstevel@tonic-gate nce->nce_unsolicit_count != 0) { 2128*0Sstevel@tonic-gate nce->nce_unsolicit_count--; 2129*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2130*0Sstevel@tonic-gate dropped = nce_xmit(ill, 2131*0Sstevel@tonic-gate ND_NEIGHBOR_ADVERT, 2132*0Sstevel@tonic-gate ill, /* ill to be used for hw addr */ 2133*0Sstevel@tonic-gate B_FALSE, /* use ill_phys_addr */ 2134*0Sstevel@tonic-gate &nce->nce_addr, 2135*0Sstevel@tonic-gate &ipv6_all_hosts_mcast, 2136*0Sstevel@tonic-gate nce->nce_flags | NDP_ORIDE); 2137*0Sstevel@tonic-gate if (dropped) { 2138*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 2139*0Sstevel@tonic-gate nce->nce_unsolicit_count++; 2140*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2141*0Sstevel@tonic-gate } 2142*0Sstevel@tonic-gate if (nce->nce_unsolicit_count != 0) { 2143*0Sstevel@tonic-gate NDP_RESTART_TIMER(nce, 2144*0Sstevel@tonic-gate ip_ndp_unsolicit_interval); 2145*0Sstevel@tonic-gate } 2146*0Sstevel@tonic-gate } else { 2147*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2148*0Sstevel@tonic-gate } 2149*0Sstevel@tonic-gate NCE_REFRELE(nce); 2150*0Sstevel@tonic-gate break; 2151*0Sstevel@tonic-gate default: 2152*0Sstevel@tonic-gate rw_exit(&ill_g_lock); 2153*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2154*0Sstevel@tonic-gate NCE_REFRELE(nce); 2155*0Sstevel@tonic-gate break; 2156*0Sstevel@tonic-gate } 2157*0Sstevel@tonic-gate } 2158*0Sstevel@tonic-gate 2159*0Sstevel@tonic-gate /* 2160*0Sstevel@tonic-gate * Set a link layer address from the ll_addr passed in. 2161*0Sstevel@tonic-gate * Copy SAP from ill. 2162*0Sstevel@tonic-gate */ 2163*0Sstevel@tonic-gate static void 2164*0Sstevel@tonic-gate nce_set_ll(nce_t *nce, uchar_t *ll_addr) 2165*0Sstevel@tonic-gate { 2166*0Sstevel@tonic-gate ill_t *ill = nce->nce_ill; 2167*0Sstevel@tonic-gate uchar_t *woffset; 2168*0Sstevel@tonic-gate 2169*0Sstevel@tonic-gate ASSERT(ll_addr != NULL); 2170*0Sstevel@tonic-gate /* Always called before fast_path_probe */ 2171*0Sstevel@tonic-gate if (nce->nce_fp_mp != NULL) 2172*0Sstevel@tonic-gate return; 2173*0Sstevel@tonic-gate if (ill->ill_sap_length != 0) { 2174*0Sstevel@tonic-gate /* 2175*0Sstevel@tonic-gate * Copy the SAP type specified in the 2176*0Sstevel@tonic-gate * request into the xmit template. 2177*0Sstevel@tonic-gate */ 2178*0Sstevel@tonic-gate NCE_LL_SAP_COPY(ill, nce->nce_res_mp); 2179*0Sstevel@tonic-gate } 2180*0Sstevel@tonic-gate if (ill->ill_phys_addr_length > 0) { 2181*0Sstevel@tonic-gate /* 2182*0Sstevel@tonic-gate * The bcopy() below used to be called for the physical address 2183*0Sstevel@tonic-gate * length rather than the link layer address length. For 2184*0Sstevel@tonic-gate * ethernet and many other media, the phys_addr and lla are 2185*0Sstevel@tonic-gate * identical. 2186*0Sstevel@tonic-gate * However, with xresolv interfaces being introduced, the 2187*0Sstevel@tonic-gate * phys_addr and lla are no longer the same, and the physical 2188*0Sstevel@tonic-gate * address may not have any useful meaning, so we use the lla 2189*0Sstevel@tonic-gate * for IPv6 address resolution and destination addressing. 2190*0Sstevel@tonic-gate * 2191*0Sstevel@tonic-gate * For PPP or other interfaces with a zero length 2192*0Sstevel@tonic-gate * physical address, don't do anything here. 2193*0Sstevel@tonic-gate * The bcopy() with a zero phys_addr length was previously 2194*0Sstevel@tonic-gate * a no-op for interfaces with a zero-length physical address. 2195*0Sstevel@tonic-gate * Using the lla for them would change the way they operate. 2196*0Sstevel@tonic-gate * Doing nothing in such cases preserves expected behavior. 2197*0Sstevel@tonic-gate */ 2198*0Sstevel@tonic-gate woffset = nce->nce_res_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill); 2199*0Sstevel@tonic-gate bcopy(ll_addr, woffset, ill->ill_nd_lla_len); 2200*0Sstevel@tonic-gate } 2201*0Sstevel@tonic-gate } 2202*0Sstevel@tonic-gate 2203*0Sstevel@tonic-gate static boolean_t 2204*0Sstevel@tonic-gate nce_cmp_ll_addr(nce_t *nce, char *ll_addr, uint32_t ll_addr_len) 2205*0Sstevel@tonic-gate { 2206*0Sstevel@tonic-gate ill_t *ill = nce->nce_ill; 2207*0Sstevel@tonic-gate uchar_t *ll_offset; 2208*0Sstevel@tonic-gate 2209*0Sstevel@tonic-gate ASSERT(nce->nce_res_mp != NULL); 2210*0Sstevel@tonic-gate if (ll_addr == NULL) 2211*0Sstevel@tonic-gate return (B_FALSE); 2212*0Sstevel@tonic-gate ll_offset = nce->nce_res_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill); 2213*0Sstevel@tonic-gate if (bcmp(ll_addr, (char *)ll_offset, ll_addr_len) != 0) 2214*0Sstevel@tonic-gate return (B_TRUE); 2215*0Sstevel@tonic-gate return (B_FALSE); 2216*0Sstevel@tonic-gate } 2217*0Sstevel@tonic-gate 2218*0Sstevel@tonic-gate /* 2219*0Sstevel@tonic-gate * Updates the link layer address or the reachability state of 2220*0Sstevel@tonic-gate * a cache entry. Reset probe counter if needed. 2221*0Sstevel@tonic-gate */ 2222*0Sstevel@tonic-gate static void 2223*0Sstevel@tonic-gate nce_update(nce_t *nce, uint16_t new_state, uchar_t *new_ll_addr) 2224*0Sstevel@tonic-gate { 2225*0Sstevel@tonic-gate ill_t *ill = nce->nce_ill; 2226*0Sstevel@tonic-gate boolean_t need_stop_timer = B_FALSE; 2227*0Sstevel@tonic-gate boolean_t need_fastpath_update = B_FALSE; 2228*0Sstevel@tonic-gate 2229*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nce->nce_lock)); 2230*0Sstevel@tonic-gate /* 2231*0Sstevel@tonic-gate * If this interface does not do NUD, there is no point 2232*0Sstevel@tonic-gate * in allowing an update to the cache entry. Although 2233*0Sstevel@tonic-gate * we will respond to NS. 2234*0Sstevel@tonic-gate * The only time we accept an update for a resolver when 2235*0Sstevel@tonic-gate * NUD is turned off is when it has just been created. 2236*0Sstevel@tonic-gate * Non-Resolvers will always be created as REACHABLE. 2237*0Sstevel@tonic-gate */ 2238*0Sstevel@tonic-gate if (new_state != ND_UNCHANGED) { 2239*0Sstevel@tonic-gate if ((nce->nce_flags & NCE_F_NONUD) && 2240*0Sstevel@tonic-gate (nce->nce_state != ND_INCOMPLETE)) 2241*0Sstevel@tonic-gate return; 2242*0Sstevel@tonic-gate ASSERT((int16_t)new_state >= ND_STATE_VALID_MIN); 2243*0Sstevel@tonic-gate ASSERT((int16_t)new_state <= ND_STATE_VALID_MAX); 2244*0Sstevel@tonic-gate need_stop_timer = B_TRUE; 2245*0Sstevel@tonic-gate if (new_state == ND_REACHABLE) 2246*0Sstevel@tonic-gate nce->nce_last = TICK_TO_MSEC(lbolt64); 2247*0Sstevel@tonic-gate else { 2248*0Sstevel@tonic-gate /* We force NUD in this case */ 2249*0Sstevel@tonic-gate nce->nce_last = 0; 2250*0Sstevel@tonic-gate } 2251*0Sstevel@tonic-gate nce->nce_state = new_state; 2252*0Sstevel@tonic-gate nce->nce_pcnt = ND_MAX_UNICAST_SOLICIT; 2253*0Sstevel@tonic-gate } 2254*0Sstevel@tonic-gate /* 2255*0Sstevel@tonic-gate * In case of fast path we need to free the the fastpath 2256*0Sstevel@tonic-gate * M_DATA and do another probe. Otherwise we can just 2257*0Sstevel@tonic-gate * overwrite the DL_UNITDATA_REQ data, noting we'll lose 2258*0Sstevel@tonic-gate * whatever packets that happens to be transmitting at the time. 2259*0Sstevel@tonic-gate */ 2260*0Sstevel@tonic-gate if (new_ll_addr != NULL) { 2261*0Sstevel@tonic-gate ASSERT(nce->nce_res_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill) + 2262*0Sstevel@tonic-gate ill->ill_nd_lla_len <= nce->nce_res_mp->b_wptr); 2263*0Sstevel@tonic-gate bcopy(new_ll_addr, nce->nce_res_mp->b_rptr + 2264*0Sstevel@tonic-gate NCE_LL_ADDR_OFFSET(ill), ill->ill_nd_lla_len); 2265*0Sstevel@tonic-gate if (nce->nce_fp_mp != NULL) { 2266*0Sstevel@tonic-gate freemsg(nce->nce_fp_mp); 2267*0Sstevel@tonic-gate nce->nce_fp_mp = NULL; 2268*0Sstevel@tonic-gate need_fastpath_update = B_TRUE; 2269*0Sstevel@tonic-gate } 2270*0Sstevel@tonic-gate } 2271*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2272*0Sstevel@tonic-gate if (need_stop_timer) { 2273*0Sstevel@tonic-gate (void) untimeout(nce->nce_timeout_id); 2274*0Sstevel@tonic-gate nce->nce_timeout_id = 0; 2275*0Sstevel@tonic-gate } 2276*0Sstevel@tonic-gate if (need_fastpath_update) 2277*0Sstevel@tonic-gate nce_fastpath(nce); 2278*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 2279*0Sstevel@tonic-gate } 2280*0Sstevel@tonic-gate 2281*0Sstevel@tonic-gate static void 2282*0Sstevel@tonic-gate nce_queue_mp(nce_t *nce, mblk_t *mp) 2283*0Sstevel@tonic-gate { 2284*0Sstevel@tonic-gate uint_t count = 0; 2285*0Sstevel@tonic-gate mblk_t **mpp; 2286*0Sstevel@tonic-gate boolean_t head_insert = B_FALSE; 2287*0Sstevel@tonic-gate ip6_t *ip6h; 2288*0Sstevel@tonic-gate ip6i_t *ip6i; 2289*0Sstevel@tonic-gate mblk_t *data_mp; 2290*0Sstevel@tonic-gate 2291*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nce->nce_lock)); 2292*0Sstevel@tonic-gate 2293*0Sstevel@tonic-gate if (mp->b_datap->db_type == M_CTL) 2294*0Sstevel@tonic-gate data_mp = mp->b_cont; 2295*0Sstevel@tonic-gate else 2296*0Sstevel@tonic-gate data_mp = mp; 2297*0Sstevel@tonic-gate ip6h = (ip6_t *)data_mp->b_rptr; 2298*0Sstevel@tonic-gate if (ip6h->ip6_nxt == IPPROTO_RAW) { 2299*0Sstevel@tonic-gate /* 2300*0Sstevel@tonic-gate * This message should have been pulled up already in 2301*0Sstevel@tonic-gate * ip_wput_v6. We can't do pullups here because the message 2302*0Sstevel@tonic-gate * could be from the nce_qd_mp which could have b_next/b_prev 2303*0Sstevel@tonic-gate * non-NULL. 2304*0Sstevel@tonic-gate */ 2305*0Sstevel@tonic-gate ip6i = (ip6i_t *)ip6h; 2306*0Sstevel@tonic-gate ASSERT((data_mp->b_wptr - (uchar_t *)ip6i) >= 2307*0Sstevel@tonic-gate sizeof (ip6i_t) + IPV6_HDR_LEN); 2308*0Sstevel@tonic-gate /* 2309*0Sstevel@tonic-gate * Multipathing probe packets have IP6I_DROP_IFDELAYED set. 2310*0Sstevel@tonic-gate * This has 2 aspects mentioned below. 2311*0Sstevel@tonic-gate * 1. Perform head insertion in the nce_qd_mp for these packets. 2312*0Sstevel@tonic-gate * This ensures that next retransmit of ND solicitation 2313*0Sstevel@tonic-gate * will use the interface specified by the probe packet, 2314*0Sstevel@tonic-gate * for both NS and NA. This corresponds to the src address 2315*0Sstevel@tonic-gate * in the IPv6 packet. If we insert at tail, we will be 2316*0Sstevel@tonic-gate * depending on the packet at the head for successful 2317*0Sstevel@tonic-gate * ND resolution. This is not reliable, because the interface 2318*0Sstevel@tonic-gate * on which the NA arrives could be different from the interface 2319*0Sstevel@tonic-gate * on which the NS was sent, and if the receiving interface is 2320*0Sstevel@tonic-gate * failed, it will appear that the sending interface is also 2321*0Sstevel@tonic-gate * failed, causing in.mpathd to misdiagnose this as link 2322*0Sstevel@tonic-gate * failure. 2323*0Sstevel@tonic-gate * 2. Drop the original packet, if the ND resolution did not 2324*0Sstevel@tonic-gate * succeed in the first attempt. However we will create the 2325*0Sstevel@tonic-gate * nce and the ire, as soon as the ND resolution succeeds. 2326*0Sstevel@tonic-gate * We don't gain anything by queueing multiple probe packets 2327*0Sstevel@tonic-gate * and sending them back-to-back once resolution succeeds. 2328*0Sstevel@tonic-gate * It is sufficient to send just 1 packet after ND resolution 2329*0Sstevel@tonic-gate * succeeds. Since mpathd is sending down probe packets at a 2330*0Sstevel@tonic-gate * constant rate, we don't need to send the queued packet. We 2331*0Sstevel@tonic-gate * need to queue it only for NDP resolution. The benefit of 2332*0Sstevel@tonic-gate * dropping the probe packets that were delayed in ND 2333*0Sstevel@tonic-gate * resolution, is that in.mpathd will not see inflated 2334*0Sstevel@tonic-gate * RTT. If the ND resolution does not succeed within 2335*0Sstevel@tonic-gate * in.mpathd's failure detection time, mpathd may detect 2336*0Sstevel@tonic-gate * a failure, and it does not matter whether the packet 2337*0Sstevel@tonic-gate * was queued or dropped. 2338*0Sstevel@tonic-gate */ 2339*0Sstevel@tonic-gate if (ip6i->ip6i_flags & IP6I_DROP_IFDELAYED) 2340*0Sstevel@tonic-gate head_insert = B_TRUE; 2341*0Sstevel@tonic-gate } 2342*0Sstevel@tonic-gate 2343*0Sstevel@tonic-gate for (mpp = &nce->nce_qd_mp; *mpp != NULL; 2344*0Sstevel@tonic-gate mpp = &(*mpp)->b_next) { 2345*0Sstevel@tonic-gate if (++count > 2346*0Sstevel@tonic-gate nce->nce_ill->ill_max_buf) { 2347*0Sstevel@tonic-gate mblk_t *tmp = nce->nce_qd_mp->b_next; 2348*0Sstevel@tonic-gate 2349*0Sstevel@tonic-gate nce->nce_qd_mp->b_next = NULL; 2350*0Sstevel@tonic-gate nce->nce_qd_mp->b_prev = NULL; 2351*0Sstevel@tonic-gate freemsg(nce->nce_qd_mp); 2352*0Sstevel@tonic-gate ip1dbg(("nce_queue_mp: pkt dropped\n")); 2353*0Sstevel@tonic-gate nce->nce_qd_mp = tmp; 2354*0Sstevel@tonic-gate } 2355*0Sstevel@tonic-gate } 2356*0Sstevel@tonic-gate /* put this on the list */ 2357*0Sstevel@tonic-gate if (head_insert) { 2358*0Sstevel@tonic-gate mp->b_next = nce->nce_qd_mp; 2359*0Sstevel@tonic-gate nce->nce_qd_mp = mp; 2360*0Sstevel@tonic-gate } else { 2361*0Sstevel@tonic-gate *mpp = mp; 2362*0Sstevel@tonic-gate } 2363*0Sstevel@tonic-gate } 2364*0Sstevel@tonic-gate 2365*0Sstevel@tonic-gate /* 2366*0Sstevel@tonic-gate * Called when address resolution failed due to a timeout. 2367*0Sstevel@tonic-gate * Send an ICMP unreachable in response to all queued packets. 2368*0Sstevel@tonic-gate */ 2369*0Sstevel@tonic-gate void 2370*0Sstevel@tonic-gate nce_resolv_failed(nce_t *nce) 2371*0Sstevel@tonic-gate { 2372*0Sstevel@tonic-gate mblk_t *mp, *nxt_mp, *first_mp; 2373*0Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 2374*0Sstevel@tonic-gate ip6_t *ip6h; 2375*0Sstevel@tonic-gate zoneid_t zoneid = GLOBAL_ZONEID; 2376*0Sstevel@tonic-gate 2377*0Sstevel@tonic-gate ip1dbg(("nce_resolv_failed: dst %s\n", 2378*0Sstevel@tonic-gate inet_ntop(AF_INET6, (char *)&nce->nce_addr, buf, sizeof (buf)))); 2379*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 2380*0Sstevel@tonic-gate mp = nce->nce_qd_mp; 2381*0Sstevel@tonic-gate nce->nce_qd_mp = NULL; 2382*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2383*0Sstevel@tonic-gate while (mp != NULL) { 2384*0Sstevel@tonic-gate nxt_mp = mp->b_next; 2385*0Sstevel@tonic-gate mp->b_next = NULL; 2386*0Sstevel@tonic-gate mp->b_prev = NULL; 2387*0Sstevel@tonic-gate 2388*0Sstevel@tonic-gate first_mp = mp; 2389*0Sstevel@tonic-gate if (mp->b_datap->db_type == M_CTL) { 2390*0Sstevel@tonic-gate ipsec_out_t *io = (ipsec_out_t *)mp->b_rptr; 2391*0Sstevel@tonic-gate ASSERT(io->ipsec_out_type == IPSEC_OUT); 2392*0Sstevel@tonic-gate zoneid = io->ipsec_out_zoneid; 2393*0Sstevel@tonic-gate ASSERT(zoneid != ALL_ZONES); 2394*0Sstevel@tonic-gate mp = mp->b_cont; 2395*0Sstevel@tonic-gate } 2396*0Sstevel@tonic-gate 2397*0Sstevel@tonic-gate ip6h = (ip6_t *)mp->b_rptr; 2398*0Sstevel@tonic-gate if (ip6h->ip6_nxt == IPPROTO_RAW) { 2399*0Sstevel@tonic-gate ip6i_t *ip6i; 2400*0Sstevel@tonic-gate /* 2401*0Sstevel@tonic-gate * This message should have been pulled up already 2402*0Sstevel@tonic-gate * in ip_wput_v6. ip_hdr_complete_v6 assumes that 2403*0Sstevel@tonic-gate * the header is pulled up. 2404*0Sstevel@tonic-gate */ 2405*0Sstevel@tonic-gate ip6i = (ip6i_t *)ip6h; 2406*0Sstevel@tonic-gate ASSERT((mp->b_wptr - (uchar_t *)ip6i) >= 2407*0Sstevel@tonic-gate sizeof (ip6i_t) + IPV6_HDR_LEN); 2408*0Sstevel@tonic-gate mp->b_rptr += sizeof (ip6i_t); 2409*0Sstevel@tonic-gate } 2410*0Sstevel@tonic-gate /* 2411*0Sstevel@tonic-gate * Ignore failure since icmp_unreachable_v6 will silently 2412*0Sstevel@tonic-gate * drop packets with an unspecified source address. 2413*0Sstevel@tonic-gate */ 2414*0Sstevel@tonic-gate (void) ip_hdr_complete_v6((ip6_t *)mp->b_rptr, zoneid); 2415*0Sstevel@tonic-gate icmp_unreachable_v6(nce->nce_ill->ill_wq, first_mp, 2416*0Sstevel@tonic-gate ICMP6_DST_UNREACH_ADDR, B_FALSE, B_FALSE); 2417*0Sstevel@tonic-gate mp = nxt_mp; 2418*0Sstevel@tonic-gate } 2419*0Sstevel@tonic-gate } 2420*0Sstevel@tonic-gate 2421*0Sstevel@tonic-gate /* 2422*0Sstevel@tonic-gate * Called by SIOCSNDP* ioctl to add/change an nce entry 2423*0Sstevel@tonic-gate * and the corresponding attributes. 2424*0Sstevel@tonic-gate * Disallow states other than ND_REACHABLE or ND_STALE. 2425*0Sstevel@tonic-gate */ 2426*0Sstevel@tonic-gate int 2427*0Sstevel@tonic-gate ndp_sioc_update(ill_t *ill, lif_nd_req_t *lnr) 2428*0Sstevel@tonic-gate { 2429*0Sstevel@tonic-gate sin6_t *sin6; 2430*0Sstevel@tonic-gate in6_addr_t *addr; 2431*0Sstevel@tonic-gate nce_t *nce; 2432*0Sstevel@tonic-gate int err; 2433*0Sstevel@tonic-gate uint16_t new_flags = 0; 2434*0Sstevel@tonic-gate uint16_t old_flags = 0; 2435*0Sstevel@tonic-gate int inflags = lnr->lnr_flags; 2436*0Sstevel@tonic-gate 2437*0Sstevel@tonic-gate if ((lnr->lnr_state_create != ND_REACHABLE) && 2438*0Sstevel@tonic-gate (lnr->lnr_state_create != ND_STALE)) 2439*0Sstevel@tonic-gate return (EINVAL); 2440*0Sstevel@tonic-gate 2441*0Sstevel@tonic-gate sin6 = (sin6_t *)&lnr->lnr_addr; 2442*0Sstevel@tonic-gate addr = &sin6->sin6_addr; 2443*0Sstevel@tonic-gate 2444*0Sstevel@tonic-gate mutex_enter(&ndp_g_lock); 2445*0Sstevel@tonic-gate /* We know it can not be mapping so just look in the hash table */ 2446*0Sstevel@tonic-gate nce = nce_lookup_addr(ill, addr); 2447*0Sstevel@tonic-gate if (nce != NULL) 2448*0Sstevel@tonic-gate new_flags = nce->nce_flags; 2449*0Sstevel@tonic-gate 2450*0Sstevel@tonic-gate switch (inflags & (NDF_ISROUTER_ON|NDF_ISROUTER_OFF)) { 2451*0Sstevel@tonic-gate case NDF_ISROUTER_ON: 2452*0Sstevel@tonic-gate new_flags |= NCE_F_ISROUTER; 2453*0Sstevel@tonic-gate break; 2454*0Sstevel@tonic-gate case NDF_ISROUTER_OFF: 2455*0Sstevel@tonic-gate new_flags &= ~NCE_F_ISROUTER; 2456*0Sstevel@tonic-gate break; 2457*0Sstevel@tonic-gate case (NDF_ISROUTER_OFF|NDF_ISROUTER_ON): 2458*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 2459*0Sstevel@tonic-gate if (nce != NULL) 2460*0Sstevel@tonic-gate NCE_REFRELE(nce); 2461*0Sstevel@tonic-gate return (EINVAL); 2462*0Sstevel@tonic-gate } 2463*0Sstevel@tonic-gate 2464*0Sstevel@tonic-gate switch (inflags & (NDF_ANYCAST_ON|NDF_ANYCAST_OFF)) { 2465*0Sstevel@tonic-gate case NDF_ANYCAST_ON: 2466*0Sstevel@tonic-gate new_flags |= NCE_F_ANYCAST; 2467*0Sstevel@tonic-gate break; 2468*0Sstevel@tonic-gate case NDF_ANYCAST_OFF: 2469*0Sstevel@tonic-gate new_flags &= ~NCE_F_ANYCAST; 2470*0Sstevel@tonic-gate break; 2471*0Sstevel@tonic-gate case (NDF_ANYCAST_OFF|NDF_ANYCAST_ON): 2472*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 2473*0Sstevel@tonic-gate if (nce != NULL) 2474*0Sstevel@tonic-gate NCE_REFRELE(nce); 2475*0Sstevel@tonic-gate return (EINVAL); 2476*0Sstevel@tonic-gate } 2477*0Sstevel@tonic-gate 2478*0Sstevel@tonic-gate switch (inflags & (NDF_PROXY_ON|NDF_PROXY_OFF)) { 2479*0Sstevel@tonic-gate case NDF_PROXY_ON: 2480*0Sstevel@tonic-gate new_flags |= NCE_F_PROXY; 2481*0Sstevel@tonic-gate break; 2482*0Sstevel@tonic-gate case NDF_PROXY_OFF: 2483*0Sstevel@tonic-gate new_flags &= ~NCE_F_PROXY; 2484*0Sstevel@tonic-gate break; 2485*0Sstevel@tonic-gate case (NDF_PROXY_OFF|NDF_PROXY_ON): 2486*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 2487*0Sstevel@tonic-gate if (nce != NULL) 2488*0Sstevel@tonic-gate NCE_REFRELE(nce); 2489*0Sstevel@tonic-gate return (EINVAL); 2490*0Sstevel@tonic-gate } 2491*0Sstevel@tonic-gate 2492*0Sstevel@tonic-gate if (nce == NULL) { 2493*0Sstevel@tonic-gate err = ndp_add(ill, 2494*0Sstevel@tonic-gate (uchar_t *)lnr->lnr_hdw_addr, 2495*0Sstevel@tonic-gate addr, 2496*0Sstevel@tonic-gate &ipv6_all_ones, 2497*0Sstevel@tonic-gate &ipv6_all_zeros, 2498*0Sstevel@tonic-gate 0, 2499*0Sstevel@tonic-gate new_flags, 2500*0Sstevel@tonic-gate lnr->lnr_state_create, 2501*0Sstevel@tonic-gate &nce); 2502*0Sstevel@tonic-gate if (err != 0) { 2503*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 2504*0Sstevel@tonic-gate ip1dbg(("ndp_sioc_update: Can't create NCE %d\n", err)); 2505*0Sstevel@tonic-gate return (err); 2506*0Sstevel@tonic-gate } 2507*0Sstevel@tonic-gate } 2508*0Sstevel@tonic-gate old_flags = nce->nce_flags; 2509*0Sstevel@tonic-gate if (old_flags & NCE_F_ISROUTER && !(new_flags & NCE_F_ISROUTER)) { 2510*0Sstevel@tonic-gate /* 2511*0Sstevel@tonic-gate * Router turned to host, delete all ires. 2512*0Sstevel@tonic-gate * XXX Just delete the entry, but we need to add too. 2513*0Sstevel@tonic-gate */ 2514*0Sstevel@tonic-gate nce->nce_flags &= ~NCE_F_ISROUTER; 2515*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 2516*0Sstevel@tonic-gate ndp_delete(nce); 2517*0Sstevel@tonic-gate NCE_REFRELE(nce); 2518*0Sstevel@tonic-gate return (0); 2519*0Sstevel@tonic-gate } 2520*0Sstevel@tonic-gate mutex_exit(&ndp_g_lock); 2521*0Sstevel@tonic-gate 2522*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 2523*0Sstevel@tonic-gate nce->nce_flags = new_flags; 2524*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2525*0Sstevel@tonic-gate /* 2526*0Sstevel@tonic-gate * Note that we ignore the state at this point, which 2527*0Sstevel@tonic-gate * should be either STALE or REACHABLE. Instead we let 2528*0Sstevel@tonic-gate * the link layer address passed in to determine the state 2529*0Sstevel@tonic-gate * much like incoming packets. 2530*0Sstevel@tonic-gate */ 2531*0Sstevel@tonic-gate ndp_process(nce, (uchar_t *)lnr->lnr_hdw_addr, 0, B_FALSE); 2532*0Sstevel@tonic-gate NCE_REFRELE(nce); 2533*0Sstevel@tonic-gate return (0); 2534*0Sstevel@tonic-gate } 2535*0Sstevel@tonic-gate 2536*0Sstevel@tonic-gate /* 2537*0Sstevel@tonic-gate * If the device driver supports it, we make nce_fp_mp to have 2538*0Sstevel@tonic-gate * an M_DATA prepend. Otherwise nce_fp_mp will be null. 2539*0Sstevel@tonic-gate * The caller insures there is hold on nce for this function. 2540*0Sstevel@tonic-gate * Note that since ill_fastpath_probe() copies the mblk there is 2541*0Sstevel@tonic-gate * no need for the hold beyond this function. 2542*0Sstevel@tonic-gate */ 2543*0Sstevel@tonic-gate static void 2544*0Sstevel@tonic-gate nce_fastpath(nce_t *nce) 2545*0Sstevel@tonic-gate { 2546*0Sstevel@tonic-gate ill_t *ill = nce->nce_ill; 2547*0Sstevel@tonic-gate int res; 2548*0Sstevel@tonic-gate 2549*0Sstevel@tonic-gate ASSERT(ill != NULL); 2550*0Sstevel@tonic-gate if (nce->nce_fp_mp != NULL) { 2551*0Sstevel@tonic-gate /* Already contains fastpath info */ 2552*0Sstevel@tonic-gate return; 2553*0Sstevel@tonic-gate } 2554*0Sstevel@tonic-gate if (nce->nce_res_mp != NULL) { 2555*0Sstevel@tonic-gate nce_fastpath_list_add(nce); 2556*0Sstevel@tonic-gate res = ill_fastpath_probe(ill, nce->nce_res_mp); 2557*0Sstevel@tonic-gate /* 2558*0Sstevel@tonic-gate * EAGAIN is an indication of a transient error 2559*0Sstevel@tonic-gate * i.e. allocation failure etc. leave the nce in the list it 2560*0Sstevel@tonic-gate * will be updated when another probe happens for another ire 2561*0Sstevel@tonic-gate * if not it will be taken out of the list when the ire is 2562*0Sstevel@tonic-gate * deleted. 2563*0Sstevel@tonic-gate */ 2564*0Sstevel@tonic-gate 2565*0Sstevel@tonic-gate if (res != 0 && res != EAGAIN) 2566*0Sstevel@tonic-gate nce_fastpath_list_delete(nce); 2567*0Sstevel@tonic-gate } 2568*0Sstevel@tonic-gate } 2569*0Sstevel@tonic-gate 2570*0Sstevel@tonic-gate /* 2571*0Sstevel@tonic-gate * Drain the list of nce's waiting for fastpath response. 2572*0Sstevel@tonic-gate */ 2573*0Sstevel@tonic-gate void 2574*0Sstevel@tonic-gate nce_fastpath_list_dispatch(ill_t *ill, boolean_t (*func)(nce_t *, void *), 2575*0Sstevel@tonic-gate void *arg) 2576*0Sstevel@tonic-gate { 2577*0Sstevel@tonic-gate 2578*0Sstevel@tonic-gate nce_t *next_nce; 2579*0Sstevel@tonic-gate nce_t *current_nce; 2580*0Sstevel@tonic-gate nce_t *first_nce; 2581*0Sstevel@tonic-gate nce_t *prev_nce = NULL; 2582*0Sstevel@tonic-gate 2583*0Sstevel@tonic-gate ASSERT(ill != NULL); 2584*0Sstevel@tonic-gate 2585*0Sstevel@tonic-gate mutex_enter(&ill->ill_lock); 2586*0Sstevel@tonic-gate first_nce = current_nce = (nce_t *)ill->ill_fastpath_list; 2587*0Sstevel@tonic-gate while (current_nce != (nce_t *)&ill->ill_fastpath_list) { 2588*0Sstevel@tonic-gate next_nce = current_nce->nce_fastpath; 2589*0Sstevel@tonic-gate /* 2590*0Sstevel@tonic-gate * Take it off the list if we're flushing, or if the callback 2591*0Sstevel@tonic-gate * routine tells us to do so. Otherwise, leave the nce in the 2592*0Sstevel@tonic-gate * fastpath list to handle any pending response from the lower 2593*0Sstevel@tonic-gate * layer. We can't drain the list when the callback routine 2594*0Sstevel@tonic-gate * comparison failed, because the response is asynchronous in 2595*0Sstevel@tonic-gate * nature, and may not arrive in the same order as the list 2596*0Sstevel@tonic-gate * insertion. 2597*0Sstevel@tonic-gate */ 2598*0Sstevel@tonic-gate if (func == NULL || func(current_nce, arg)) { 2599*0Sstevel@tonic-gate current_nce->nce_fastpath = NULL; 2600*0Sstevel@tonic-gate if (current_nce == first_nce) 2601*0Sstevel@tonic-gate ill->ill_fastpath_list = first_nce = next_nce; 2602*0Sstevel@tonic-gate else 2603*0Sstevel@tonic-gate prev_nce->nce_fastpath = next_nce; 2604*0Sstevel@tonic-gate } else { 2605*0Sstevel@tonic-gate /* previous element that is still in the list */ 2606*0Sstevel@tonic-gate prev_nce = current_nce; 2607*0Sstevel@tonic-gate } 2608*0Sstevel@tonic-gate current_nce = next_nce; 2609*0Sstevel@tonic-gate } 2610*0Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 2611*0Sstevel@tonic-gate } 2612*0Sstevel@tonic-gate 2613*0Sstevel@tonic-gate /* 2614*0Sstevel@tonic-gate * Add nce to the nce fastpath list. 2615*0Sstevel@tonic-gate */ 2616*0Sstevel@tonic-gate void 2617*0Sstevel@tonic-gate nce_fastpath_list_add(nce_t *nce) 2618*0Sstevel@tonic-gate { 2619*0Sstevel@tonic-gate ill_t *ill; 2620*0Sstevel@tonic-gate 2621*0Sstevel@tonic-gate ill = nce->nce_ill; 2622*0Sstevel@tonic-gate ASSERT(ill != NULL); 2623*0Sstevel@tonic-gate 2624*0Sstevel@tonic-gate mutex_enter(&ill->ill_lock); 2625*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 2626*0Sstevel@tonic-gate 2627*0Sstevel@tonic-gate /* 2628*0Sstevel@tonic-gate * if nce has not been deleted and 2629*0Sstevel@tonic-gate * is not already in the list add it. 2630*0Sstevel@tonic-gate */ 2631*0Sstevel@tonic-gate if (!(nce->nce_flags & NCE_F_CONDEMNED) && 2632*0Sstevel@tonic-gate (nce->nce_fastpath == NULL)) { 2633*0Sstevel@tonic-gate nce->nce_fastpath = (nce_t *)ill->ill_fastpath_list; 2634*0Sstevel@tonic-gate ill->ill_fastpath_list = nce; 2635*0Sstevel@tonic-gate } 2636*0Sstevel@tonic-gate 2637*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2638*0Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 2639*0Sstevel@tonic-gate } 2640*0Sstevel@tonic-gate 2641*0Sstevel@tonic-gate /* 2642*0Sstevel@tonic-gate * remove nce from the nce fastpath list. 2643*0Sstevel@tonic-gate */ 2644*0Sstevel@tonic-gate void 2645*0Sstevel@tonic-gate nce_fastpath_list_delete(nce_t *nce) 2646*0Sstevel@tonic-gate { 2647*0Sstevel@tonic-gate nce_t *nce_ptr; 2648*0Sstevel@tonic-gate 2649*0Sstevel@tonic-gate ill_t *ill; 2650*0Sstevel@tonic-gate 2651*0Sstevel@tonic-gate ill = nce->nce_ill; 2652*0Sstevel@tonic-gate ASSERT(ill != NULL); 2653*0Sstevel@tonic-gate 2654*0Sstevel@tonic-gate mutex_enter(&ill->ill_lock); 2655*0Sstevel@tonic-gate if (nce->nce_fastpath == NULL) 2656*0Sstevel@tonic-gate goto done; 2657*0Sstevel@tonic-gate 2658*0Sstevel@tonic-gate ASSERT(ill->ill_fastpath_list != &ill->ill_fastpath_list); 2659*0Sstevel@tonic-gate 2660*0Sstevel@tonic-gate if (ill->ill_fastpath_list == nce) { 2661*0Sstevel@tonic-gate ill->ill_fastpath_list = nce->nce_fastpath; 2662*0Sstevel@tonic-gate } else { 2663*0Sstevel@tonic-gate nce_ptr = ill->ill_fastpath_list; 2664*0Sstevel@tonic-gate while (nce_ptr != (nce_t *)&ill->ill_fastpath_list) { 2665*0Sstevel@tonic-gate if (nce_ptr->nce_fastpath == nce) { 2666*0Sstevel@tonic-gate nce_ptr->nce_fastpath = nce->nce_fastpath; 2667*0Sstevel@tonic-gate break; 2668*0Sstevel@tonic-gate } 2669*0Sstevel@tonic-gate nce_ptr = nce_ptr->nce_fastpath; 2670*0Sstevel@tonic-gate } 2671*0Sstevel@tonic-gate } 2672*0Sstevel@tonic-gate 2673*0Sstevel@tonic-gate nce->nce_fastpath = NULL; 2674*0Sstevel@tonic-gate done: 2675*0Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 2676*0Sstevel@tonic-gate } 2677*0Sstevel@tonic-gate 2678*0Sstevel@tonic-gate /* 2679*0Sstevel@tonic-gate * Update all NCE's that are not in fastpath mode and 2680*0Sstevel@tonic-gate * have an nce_fp_mp that matches mp. mp->b_cont contains 2681*0Sstevel@tonic-gate * the fastpath header. 2682*0Sstevel@tonic-gate * 2683*0Sstevel@tonic-gate * Returns TRUE if entry should be dequeued, or FALSE otherwise. 2684*0Sstevel@tonic-gate */ 2685*0Sstevel@tonic-gate boolean_t 2686*0Sstevel@tonic-gate ndp_fastpath_update(nce_t *nce, void *arg) 2687*0Sstevel@tonic-gate { 2688*0Sstevel@tonic-gate mblk_t *mp, *fp_mp; 2689*0Sstevel@tonic-gate uchar_t *mp_rptr, *ud_mp_rptr; 2690*0Sstevel@tonic-gate mblk_t *ud_mp = nce->nce_res_mp; 2691*0Sstevel@tonic-gate ptrdiff_t cmplen; 2692*0Sstevel@tonic-gate 2693*0Sstevel@tonic-gate if (nce->nce_flags & NCE_F_MAPPING) 2694*0Sstevel@tonic-gate return (B_TRUE); 2695*0Sstevel@tonic-gate if ((nce->nce_fp_mp != NULL) || (ud_mp == NULL)) 2696*0Sstevel@tonic-gate return (B_TRUE); 2697*0Sstevel@tonic-gate 2698*0Sstevel@tonic-gate ip2dbg(("ndp_fastpath_update: trying\n")); 2699*0Sstevel@tonic-gate mp = (mblk_t *)arg; 2700*0Sstevel@tonic-gate mp_rptr = mp->b_rptr; 2701*0Sstevel@tonic-gate cmplen = mp->b_wptr - mp_rptr; 2702*0Sstevel@tonic-gate ASSERT(cmplen >= 0); 2703*0Sstevel@tonic-gate ud_mp_rptr = ud_mp->b_rptr; 2704*0Sstevel@tonic-gate /* 2705*0Sstevel@tonic-gate * The nce is locked here to prevent any other threads 2706*0Sstevel@tonic-gate * from accessing and changing nce_res_mp when the IPv6 address 2707*0Sstevel@tonic-gate * becomes resolved to an lla while we're in the middle 2708*0Sstevel@tonic-gate * of looking at and comparing the hardware address (lla). 2709*0Sstevel@tonic-gate * It is also locked to prevent multiple threads in nce_fastpath_update 2710*0Sstevel@tonic-gate * from examining nce_res_mp atthe same time. 2711*0Sstevel@tonic-gate */ 2712*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 2713*0Sstevel@tonic-gate if (ud_mp->b_wptr - ud_mp_rptr != cmplen || 2714*0Sstevel@tonic-gate bcmp((char *)mp_rptr, (char *)ud_mp_rptr, cmplen) != 0) { 2715*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2716*0Sstevel@tonic-gate /* 2717*0Sstevel@tonic-gate * Don't take the ire off the fastpath list yet, 2718*0Sstevel@tonic-gate * since the response may come later. 2719*0Sstevel@tonic-gate */ 2720*0Sstevel@tonic-gate return (B_FALSE); 2721*0Sstevel@tonic-gate } 2722*0Sstevel@tonic-gate /* Matched - install mp as the fastpath mp */ 2723*0Sstevel@tonic-gate ip1dbg(("ndp_fastpath_update: match\n")); 2724*0Sstevel@tonic-gate fp_mp = dupb(mp->b_cont); 2725*0Sstevel@tonic-gate if (fp_mp != NULL) { 2726*0Sstevel@tonic-gate nce->nce_fp_mp = fp_mp; 2727*0Sstevel@tonic-gate } 2728*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2729*0Sstevel@tonic-gate return (B_TRUE); 2730*0Sstevel@tonic-gate } 2731*0Sstevel@tonic-gate 2732*0Sstevel@tonic-gate /* 2733*0Sstevel@tonic-gate * This function handles the DL_NOTE_FASTPATH_FLUSH notification from 2734*0Sstevel@tonic-gate * driver. Note that it assumes IP is exclusive... 2735*0Sstevel@tonic-gate */ 2736*0Sstevel@tonic-gate /* ARGSUSED */ 2737*0Sstevel@tonic-gate void 2738*0Sstevel@tonic-gate ndp_fastpath_flush(nce_t *nce, char *arg) 2739*0Sstevel@tonic-gate { 2740*0Sstevel@tonic-gate if (nce->nce_flags & NCE_F_MAPPING) 2741*0Sstevel@tonic-gate return; 2742*0Sstevel@tonic-gate /* No fastpath info? */ 2743*0Sstevel@tonic-gate if (nce->nce_fp_mp == NULL || nce->nce_res_mp == NULL) 2744*0Sstevel@tonic-gate return; 2745*0Sstevel@tonic-gate 2746*0Sstevel@tonic-gate /* Just delete the NCE... */ 2747*0Sstevel@tonic-gate ndp_delete(nce); 2748*0Sstevel@tonic-gate } 2749*0Sstevel@tonic-gate 2750*0Sstevel@tonic-gate /* 2751*0Sstevel@tonic-gate * Return a pointer to a given option in the packet. 2752*0Sstevel@tonic-gate * Assumes that option part of the packet have already been validated. 2753*0Sstevel@tonic-gate */ 2754*0Sstevel@tonic-gate nd_opt_hdr_t * 2755*0Sstevel@tonic-gate ndp_get_option(nd_opt_hdr_t *opt, int optlen, int opt_type) 2756*0Sstevel@tonic-gate { 2757*0Sstevel@tonic-gate while (optlen > 0) { 2758*0Sstevel@tonic-gate if (opt->nd_opt_type == opt_type) 2759*0Sstevel@tonic-gate return (opt); 2760*0Sstevel@tonic-gate optlen -= 8 * opt->nd_opt_len; 2761*0Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + 8 * opt->nd_opt_len); 2762*0Sstevel@tonic-gate } 2763*0Sstevel@tonic-gate return (NULL); 2764*0Sstevel@tonic-gate } 2765*0Sstevel@tonic-gate 2766*0Sstevel@tonic-gate /* 2767*0Sstevel@tonic-gate * Verify all option lengths present are > 0, also check to see 2768*0Sstevel@tonic-gate * if the option lengths and packet length are consistent. 2769*0Sstevel@tonic-gate */ 2770*0Sstevel@tonic-gate boolean_t 2771*0Sstevel@tonic-gate ndp_verify_optlen(nd_opt_hdr_t *opt, int optlen) 2772*0Sstevel@tonic-gate { 2773*0Sstevel@tonic-gate ASSERT(opt != NULL); 2774*0Sstevel@tonic-gate while (optlen > 0) { 2775*0Sstevel@tonic-gate if (opt->nd_opt_len == 0) 2776*0Sstevel@tonic-gate return (B_FALSE); 2777*0Sstevel@tonic-gate optlen -= 8 * opt->nd_opt_len; 2778*0Sstevel@tonic-gate if (optlen < 0) 2779*0Sstevel@tonic-gate return (B_FALSE); 2780*0Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + 8 * opt->nd_opt_len); 2781*0Sstevel@tonic-gate } 2782*0Sstevel@tonic-gate return (B_TRUE); 2783*0Sstevel@tonic-gate } 2784*0Sstevel@tonic-gate 2785*0Sstevel@tonic-gate /* 2786*0Sstevel@tonic-gate * ndp_walk function. 2787*0Sstevel@tonic-gate * Free a fraction of the NCE cache entries. 2788*0Sstevel@tonic-gate * A fraction of zero means to not free any in that category. 2789*0Sstevel@tonic-gate */ 2790*0Sstevel@tonic-gate void 2791*0Sstevel@tonic-gate ndp_cache_reclaim(nce_t *nce, char *arg) 2792*0Sstevel@tonic-gate { 2793*0Sstevel@tonic-gate nce_cache_reclaim_t *ncr = (nce_cache_reclaim_t *)arg; 2794*0Sstevel@tonic-gate uint_t rand; 2795*0Sstevel@tonic-gate 2796*0Sstevel@tonic-gate if (nce->nce_flags & NCE_F_PERMANENT) 2797*0Sstevel@tonic-gate return; 2798*0Sstevel@tonic-gate 2799*0Sstevel@tonic-gate rand = (uint_t)lbolt + 2800*0Sstevel@tonic-gate NCE_ADDR_HASH_V6(nce->nce_addr, NCE_TABLE_SIZE); 2801*0Sstevel@tonic-gate if (ncr->ncr_host != 0 && 2802*0Sstevel@tonic-gate (rand/ncr->ncr_host)*ncr->ncr_host == rand) { 2803*0Sstevel@tonic-gate ndp_delete(nce); 2804*0Sstevel@tonic-gate return; 2805*0Sstevel@tonic-gate } 2806*0Sstevel@tonic-gate } 2807*0Sstevel@tonic-gate 2808*0Sstevel@tonic-gate /* 2809*0Sstevel@tonic-gate * ndp_walk function. 2810*0Sstevel@tonic-gate * Count the number of NCEs that can be deleted. 2811*0Sstevel@tonic-gate * These would be hosts but not routers. 2812*0Sstevel@tonic-gate */ 2813*0Sstevel@tonic-gate void 2814*0Sstevel@tonic-gate ndp_cache_count(nce_t *nce, char *arg) 2815*0Sstevel@tonic-gate { 2816*0Sstevel@tonic-gate ncc_cache_count_t *ncc = (ncc_cache_count_t *)arg; 2817*0Sstevel@tonic-gate 2818*0Sstevel@tonic-gate if (nce->nce_flags & NCE_F_PERMANENT) 2819*0Sstevel@tonic-gate return; 2820*0Sstevel@tonic-gate 2821*0Sstevel@tonic-gate ncc->ncc_total++; 2822*0Sstevel@tonic-gate if (!(nce->nce_flags & NCE_F_ISROUTER)) 2823*0Sstevel@tonic-gate ncc->ncc_host++; 2824*0Sstevel@tonic-gate } 2825*0Sstevel@tonic-gate 2826*0Sstevel@tonic-gate #ifdef NCE_DEBUG 2827*0Sstevel@tonic-gate th_trace_t * 2828*0Sstevel@tonic-gate th_trace_nce_lookup(nce_t *nce) 2829*0Sstevel@tonic-gate { 2830*0Sstevel@tonic-gate int bucket_id; 2831*0Sstevel@tonic-gate th_trace_t *th_trace; 2832*0Sstevel@tonic-gate 2833*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nce->nce_lock)); 2834*0Sstevel@tonic-gate 2835*0Sstevel@tonic-gate bucket_id = IP_TR_HASH(curthread); 2836*0Sstevel@tonic-gate ASSERT(bucket_id < IP_TR_HASH_MAX); 2837*0Sstevel@tonic-gate 2838*0Sstevel@tonic-gate for (th_trace = nce->nce_trace[bucket_id]; th_trace != NULL; 2839*0Sstevel@tonic-gate th_trace = th_trace->th_next) { 2840*0Sstevel@tonic-gate if (th_trace->th_id == curthread) 2841*0Sstevel@tonic-gate return (th_trace); 2842*0Sstevel@tonic-gate } 2843*0Sstevel@tonic-gate return (NULL); 2844*0Sstevel@tonic-gate } 2845*0Sstevel@tonic-gate 2846*0Sstevel@tonic-gate void 2847*0Sstevel@tonic-gate nce_trace_ref(nce_t *nce) 2848*0Sstevel@tonic-gate { 2849*0Sstevel@tonic-gate int bucket_id; 2850*0Sstevel@tonic-gate th_trace_t *th_trace; 2851*0Sstevel@tonic-gate 2852*0Sstevel@tonic-gate /* 2853*0Sstevel@tonic-gate * Attempt to locate the trace buffer for the curthread. 2854*0Sstevel@tonic-gate * If it does not exist, then allocate a new trace buffer 2855*0Sstevel@tonic-gate * and link it in list of trace bufs for this ipif, at the head 2856*0Sstevel@tonic-gate */ 2857*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nce->nce_lock)); 2858*0Sstevel@tonic-gate 2859*0Sstevel@tonic-gate if (nce->nce_trace_disable == B_TRUE) 2860*0Sstevel@tonic-gate return; 2861*0Sstevel@tonic-gate 2862*0Sstevel@tonic-gate th_trace = th_trace_nce_lookup(nce); 2863*0Sstevel@tonic-gate if (th_trace == NULL) { 2864*0Sstevel@tonic-gate bucket_id = IP_TR_HASH(curthread); 2865*0Sstevel@tonic-gate th_trace = (th_trace_t *)kmem_zalloc(sizeof (th_trace_t), 2866*0Sstevel@tonic-gate KM_NOSLEEP); 2867*0Sstevel@tonic-gate if (th_trace == NULL) { 2868*0Sstevel@tonic-gate nce->nce_trace_disable = B_TRUE; 2869*0Sstevel@tonic-gate nce_trace_inactive(nce); 2870*0Sstevel@tonic-gate return; 2871*0Sstevel@tonic-gate } 2872*0Sstevel@tonic-gate th_trace->th_id = curthread; 2873*0Sstevel@tonic-gate th_trace->th_next = nce->nce_trace[bucket_id]; 2874*0Sstevel@tonic-gate th_trace->th_prev = &nce->nce_trace[bucket_id]; 2875*0Sstevel@tonic-gate if (th_trace->th_next != NULL) 2876*0Sstevel@tonic-gate th_trace->th_next->th_prev = &th_trace->th_next; 2877*0Sstevel@tonic-gate nce->nce_trace[bucket_id] = th_trace; 2878*0Sstevel@tonic-gate } 2879*0Sstevel@tonic-gate ASSERT(th_trace->th_refcnt < TR_BUF_MAX - 1); 2880*0Sstevel@tonic-gate th_trace->th_refcnt++; 2881*0Sstevel@tonic-gate th_trace_rrecord(th_trace); 2882*0Sstevel@tonic-gate } 2883*0Sstevel@tonic-gate 2884*0Sstevel@tonic-gate void 2885*0Sstevel@tonic-gate nce_untrace_ref(nce_t *nce) 2886*0Sstevel@tonic-gate { 2887*0Sstevel@tonic-gate th_trace_t *th_trace; 2888*0Sstevel@tonic-gate 2889*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nce->nce_lock)); 2890*0Sstevel@tonic-gate 2891*0Sstevel@tonic-gate if (nce->nce_trace_disable == B_TRUE) 2892*0Sstevel@tonic-gate return; 2893*0Sstevel@tonic-gate 2894*0Sstevel@tonic-gate th_trace = th_trace_nce_lookup(nce); 2895*0Sstevel@tonic-gate ASSERT(th_trace != NULL && th_trace->th_refcnt > 0); 2896*0Sstevel@tonic-gate 2897*0Sstevel@tonic-gate th_trace_rrecord(th_trace); 2898*0Sstevel@tonic-gate th_trace->th_refcnt--; 2899*0Sstevel@tonic-gate } 2900*0Sstevel@tonic-gate 2901*0Sstevel@tonic-gate void 2902*0Sstevel@tonic-gate nce_trace_inactive(nce_t *nce) 2903*0Sstevel@tonic-gate { 2904*0Sstevel@tonic-gate th_trace_t *th_trace; 2905*0Sstevel@tonic-gate int i; 2906*0Sstevel@tonic-gate 2907*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nce->nce_lock)); 2908*0Sstevel@tonic-gate 2909*0Sstevel@tonic-gate for (i = 0; i < IP_TR_HASH_MAX; i++) { 2910*0Sstevel@tonic-gate while (nce->nce_trace[i] != NULL) { 2911*0Sstevel@tonic-gate th_trace = nce->nce_trace[i]; 2912*0Sstevel@tonic-gate 2913*0Sstevel@tonic-gate /* unlink th_trace and free it */ 2914*0Sstevel@tonic-gate nce->nce_trace[i] = th_trace->th_next; 2915*0Sstevel@tonic-gate if (th_trace->th_next != NULL) 2916*0Sstevel@tonic-gate th_trace->th_next->th_prev = 2917*0Sstevel@tonic-gate &nce->nce_trace[i]; 2918*0Sstevel@tonic-gate 2919*0Sstevel@tonic-gate th_trace->th_next = NULL; 2920*0Sstevel@tonic-gate th_trace->th_prev = NULL; 2921*0Sstevel@tonic-gate kmem_free(th_trace, sizeof (th_trace_t)); 2922*0Sstevel@tonic-gate } 2923*0Sstevel@tonic-gate } 2924*0Sstevel@tonic-gate 2925*0Sstevel@tonic-gate } 2926*0Sstevel@tonic-gate 2927*0Sstevel@tonic-gate /* ARGSUSED */ 2928*0Sstevel@tonic-gate int 2929*0Sstevel@tonic-gate nce_thread_exit(nce_t *nce, caddr_t arg) 2930*0Sstevel@tonic-gate { 2931*0Sstevel@tonic-gate th_trace_t *th_trace; 2932*0Sstevel@tonic-gate 2933*0Sstevel@tonic-gate mutex_enter(&nce->nce_lock); 2934*0Sstevel@tonic-gate th_trace = th_trace_nce_lookup(nce); 2935*0Sstevel@tonic-gate 2936*0Sstevel@tonic-gate if (th_trace == NULL) { 2937*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2938*0Sstevel@tonic-gate return (0); 2939*0Sstevel@tonic-gate } 2940*0Sstevel@tonic-gate 2941*0Sstevel@tonic-gate ASSERT(th_trace->th_refcnt == 0); 2942*0Sstevel@tonic-gate 2943*0Sstevel@tonic-gate /* unlink th_trace and free it */ 2944*0Sstevel@tonic-gate *th_trace->th_prev = th_trace->th_next; 2945*0Sstevel@tonic-gate if (th_trace->th_next != NULL) 2946*0Sstevel@tonic-gate th_trace->th_next->th_prev = th_trace->th_prev; 2947*0Sstevel@tonic-gate th_trace->th_next = NULL; 2948*0Sstevel@tonic-gate th_trace->th_prev = NULL; 2949*0Sstevel@tonic-gate kmem_free(th_trace, sizeof (th_trace_t)); 2950*0Sstevel@tonic-gate mutex_exit(&nce->nce_lock); 2951*0Sstevel@tonic-gate return (0); 2952*0Sstevel@tonic-gate } 2953*0Sstevel@tonic-gate #endif 2954