1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #ifndef _INET_IP_NDP_H 28 #define _INET_IP_NDP_H 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* 33 * Internal definitions for the kernel implementation of the IPv6 34 * Neighbor Discovery Protocol (NDP). 35 */ 36 37 #ifdef __cplusplus 38 extern "C" { 39 #endif 40 41 #ifdef _KERNEL 42 /* 43 * ndp_g_lock protects neighbor cache tables access and 44 * insertion/removal of cache entries into/from these tables. 45 * nce_lock protects nce_pcnt, nce_rcnt, nce_qd_mp nce_state, 46 * nce_res_mp, nce_refcnt and nce_last. 47 * nce_refcnt is incremented for every ire pointing to this nce and 48 * every time ndp_lookup() finds an nce. 49 * Should there be a need to obtain nce_lock and ndp_g_lock, ndp_g_lock is 50 * acquired first. 51 * To avoid becoming exclusive when deleting NCEs, ndp_walk() routine holds 52 * the ndp_g_lock (i.e global lock) and marks NCEs to be deleted with 53 * NCE_F_CONDEMNED. When all active users of such NCEs are gone the walk 54 * routine passes a list for deletion to nce_ire_delete_list(). 55 */ 56 kmutex_t ndp_g_lock; /* Lock protecting nighbor cache hash table */ 57 /* NDP Cache Entry */ 58 typedef struct nce_s { 59 struct nce_s *nce_next; /* Hash chain next pointer */ 60 struct nce_s **nce_ptpn; /* Pointer to previous next */ 61 struct ill_s *nce_ill; /* Associated ill */ 62 uint16_t nce_flags; /* See below */ 63 uint16_t nce_state; /* See reachability states in if.h */ 64 int16_t nce_pcnt; /* Probe counter */ 65 uint16_t nce_rcnt; /* Retransmit counter */ 66 in6_addr_t nce_addr; /* address of the nighbor */ 67 in6_addr_t nce_mask; /* If not all ones, mask allows an */ 68 /* entry to respond to requests for a group of addresses, for */ 69 /* instantance multicast addresses */ 70 in6_addr_t nce_extract_mask; /* For mappings */ 71 uint32_t nce_ll_extract_start; /* For mappings */ 72 #define nce_first_mp_to_free nce_fp_mp 73 mblk_t *nce_fp_mp; /* link layer fast path mp */ 74 mblk_t *nce_res_mp; /* DL_UNITDATA_REQ or link layer mp */ 75 mblk_t *nce_qd_mp; /* Head outgoing queued packets */ 76 #define nce_last_mp_to_free nce_qd_mp 77 mblk_t *nce_timer_mp; /* NDP timer mblk */ 78 mblk_t *nce_mp; /* mblk we are in, last to be freed */ 79 uint64_t nce_last; /* Time last reachable in msec */ 80 uint32_t nce_refcnt; /* nce active usage count */ 81 kmutex_t nce_lock; /* See comments on top for what */ 82 /* this field protects */ 83 int nce_unsolicit_count; /* Unsolicited Adv count */ 84 struct nce_s *nce_fastpath; /* for fastpath list */ 85 timeout_id_t nce_timeout_id; 86 #ifdef NCE_DEBUG 87 th_trace_t *nce_trace[IP_TR_HASH_MAX]; 88 boolean_t nce_trace_disable; /* True when alloc fails */ 89 #endif 90 } nce_t; 91 92 /* nce_flags */ 93 #define NCE_F_PERMANENT 0x1 94 #define NCE_F_MAPPING 0x2 95 #define NCE_F_ISROUTER 0x4 96 #define NCE_F_PROXY 0x8 97 #define NCE_F_NONUD 0x10 98 #define NCE_F_ANYCAST 0x20 99 #define NCE_F_CONDEMNED 0x40 100 #define NCE_F_UNSOL_ADV 0x80 101 102 #define NCE_EXTERNAL_FLAGS_MASK \ 103 (NCE_F_PERMANENT | NCE_F_MAPPING | NCE_F_ISROUTER | NCE_F_NONUD | \ 104 NCE_F_ANYCAST | NCE_F_UNSOL_ADV) 105 106 /* State REACHABLE, STALE, DELAY or PROBE */ 107 #define NCE_ISREACHABLE(nce) \ 108 (((((nce)->nce_state) >= ND_REACHABLE) && \ 109 ((nce)->nce_state) <= ND_PROBE)) 110 111 /* NDP flags set in SOL/ADV requests */ 112 #define NDP_UNICAST 0x1 113 #define NDP_ISROUTER 0x2 114 #define NDP_SOLICITED 0x4 115 #define NDP_ORIDE 0x8 116 117 /* Number of packets queued in NDP for a neighbor */ 118 #define ND_MAX_Q 4 119 120 121 #ifdef NCE_DEBUG 122 #define NCE_TRACE_REF(nce) nce_trace_ref(nce) 123 #define NCE_UNTRACE_REF(nce) nce_untrace_ref(nce) 124 #else 125 #define NCE_TRACE_REF(nce) 126 #define NCE_UNTRACE_REF(nce) 127 #endif 128 129 #define NCE_REFHOLD(nce) { \ 130 mutex_enter(&(nce)->nce_lock); \ 131 (nce)->nce_refcnt++; \ 132 ASSERT((nce)->nce_refcnt != 0); \ 133 NCE_TRACE_REF(nce); \ 134 mutex_exit(&(nce)->nce_lock); \ 135 } 136 137 #define NCE_REFHOLD_NOTR(nce) { \ 138 mutex_enter(&(nce)->nce_lock); \ 139 (nce)->nce_refcnt++; \ 140 ASSERT((nce)->nce_refcnt != 0); \ 141 mutex_exit(&(nce)->nce_lock); \ 142 } 143 144 #define NCE_REFHOLD_LOCKED(nce) { \ 145 ASSERT(MUTEX_HELD(&(nce)->nce_lock)); \ 146 (nce)->nce_refcnt++; \ 147 NCE_TRACE_REF(nce); \ 148 } 149 150 /* nce_inactive destroys the mutex thus no mutex_exit is needed */ 151 #define NCE_REFRELE(nce) { \ 152 mutex_enter(&(nce)->nce_lock); \ 153 NCE_UNTRACE_REF(nce); \ 154 ASSERT((nce)->nce_refcnt != 0); \ 155 if (--(nce)->nce_refcnt == 0) \ 156 ndp_inactive(nce); \ 157 else { \ 158 mutex_exit(&(nce)->nce_lock);\ 159 } \ 160 } 161 162 #define NCE_REFRELE_NOTR(nce) { \ 163 mutex_enter(&(nce)->nce_lock); \ 164 ASSERT((nce)->nce_refcnt != 0); \ 165 if (--(nce)->nce_refcnt == 0) \ 166 ndp_inactive(nce); \ 167 else { \ 168 mutex_exit(&(nce)->nce_lock);\ 169 } \ 170 } 171 172 #define NDP_RESTART_TIMER(nce, ms) { \ 173 ASSERT(!MUTEX_HELD(&(nce)->nce_lock)); \ 174 if ((nce)->nce_timeout_id != 0) { \ 175 /* Ok to untimeout bad id. we don't hold a lock. */ \ 176 (void) untimeout((nce)->nce_timeout_id); \ 177 } \ 178 mutex_enter(&(nce)->nce_lock); \ 179 /* Don't start the timer if the nce has been deleted */ \ 180 if (!((nce)->nce_flags & NCE_F_CONDEMNED)) \ 181 nce->nce_timeout_id = timeout(ndp_timer, nce, \ 182 MSEC_TO_TICK(ms) == 0 ? 1 : MSEC_TO_TICK(ms)); \ 183 mutex_exit(&(nce)->nce_lock); \ 184 } 185 186 /* Structure for ndp_cache_count() */ 187 typedef struct { 188 int ncc_total; /* Total number of NCEs */ 189 int ncc_host; /* NCE entries without R bit set */ 190 } ncc_cache_count_t; 191 192 /* 193 * Structure of ndp_cache_reclaim(). Each field is a fraction i.e. 1 means 194 * reclaim all, N means reclaim 1/Nth of all entries, 0 means reclaim none. 195 */ 196 typedef struct { 197 int ncr_host; /* Fraction for host entries */ 198 } nce_cache_reclaim_t; 199 200 /* When SAP is greater than zero address appears before SAP */ 201 #define NCE_LL_ADDR_OFFSET(ill) (((ill)->ill_sap_length) < 0 ? \ 202 (sizeof (dl_unitdata_req_t)) : \ 203 ((sizeof (dl_unitdata_req_t)) + (ABS((ill)->ill_sap_length)))) 204 205 #define NCE_LL_SAP_OFFSET(ill) (((ill)->ill_sap_length) < 0 ? \ 206 ((sizeof (dl_unitdata_req_t)) + ((ill)->ill_phys_addr_length)) : \ 207 (sizeof (dl_unitdata_req_t))) 208 209 #ifdef _BIG_ENDIAN 210 #define NCE_LL_SAP_COPY(ill, mp) \ 211 { \ 212 size_t abs_sap_len = ABS((ill)->ill_sap_length); \ 213 if (abs_sap_len > 0) { \ 214 ASSERT(abs_sap_len <= sizeof (uint32_t)); \ 215 ASSERT((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill) + \ 216 abs_sap_len <= ((mp)->b_wptr)); \ 217 bcopy((uint8_t *)&(ill)->ill_sap + sizeof (ill->ill_sap) - \ 218 abs_sap_len, \ 219 ((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill)), \ 220 abs_sap_len); \ 221 } \ 222 } 223 #else 224 #define NCE_LL_SAP_COPY(ill, mp) \ 225 { \ 226 size_t abs_sap_len = ABS((ill)->ill_sap_length); \ 227 if (abs_sap_len > 0) { \ 228 uint32_t abs_sap_len = ABS((ill)->ill_sap_length); \ 229 ASSERT(abs_sap_len <= sizeof (uint32_t)); \ 230 ASSERT((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill) + \ 231 abs_sap_len <= ((mp)->b_wptr)); \ 232 bcopy(&((ill)->ill_sap), \ 233 ((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill)), \ 234 abs_sap_len); \ 235 } \ 236 } 237 #endif 238 239 /* 240 * Exclusive-or the 6 bytes that are likely to contain the MAC 241 * address. Assumes table_size does not exceed 256. 242 * Assumes EUI-64 format for good hashing. 243 */ 244 #define NCE_ADDR_HASH_V6(addr, table_size) \ 245 (((addr).s6_addr8[8] ^ (addr).s6_addr8[9] ^ \ 246 (addr).s6_addr8[10] ^ (addr).s6_addr8[13] ^ \ 247 (addr).s6_addr8[14] ^ (addr).s6_addr8[15]) % (table_size)) 248 249 extern void ndp_cache_count(nce_t *, char *); 250 extern void ndp_cache_reclaim(nce_t *, char *); 251 extern void ndp_delete(nce_t *); 252 extern void ndp_delete_per_ill(nce_t *, uchar_t *); 253 extern void ndp_fastpath_flush(nce_t *, char *); 254 extern boolean_t ndp_fastpath_update(nce_t *, void *); 255 extern nd_opt_hdr_t *ndp_get_option(nd_opt_hdr_t *, int, int); 256 extern void ndp_inactive(nce_t *); 257 extern void ndp_input(ill_t *, mblk_t *); 258 extern nce_t *ndp_lookup(ill_t *, const in6_addr_t *, boolean_t); 259 extern int ndp_lookup_then_add(ill_t *, uchar_t *, const in6_addr_t *, 260 const in6_addr_t *, const in6_addr_t *, uint32_t, uint16_t, 261 uint16_t, nce_t **); 262 extern int ndp_mcastreq(ill_t *, const in6_addr_t *, uint32_t, uint32_t, 263 mblk_t *); 264 extern int ndp_noresolver(ill_t *, const in6_addr_t *); 265 extern void ndp_process(nce_t *, uchar_t *, uint32_t, boolean_t); 266 extern int ndp_query(ill_t *, lif_nd_req_t *); 267 extern int ndp_report(queue_t *, mblk_t *, caddr_t, cred_t *); 268 extern int ndp_resolver(ill_t *, const in6_addr_t *, mblk_t *, zoneid_t); 269 extern int ndp_sioc_update(ill_t *, lif_nd_req_t *); 270 extern boolean_t ndp_verify_optlen(nd_opt_hdr_t *, int); 271 extern void ndp_timer(void *); 272 extern void ndp_walk(ill_t *, pfi_t, uchar_t *); 273 extern void ndp_walk_impl(ill_t *, pfi_t, uchar_t *, boolean_t); 274 extern int ndp_add(ill_t *, uchar_t *, const in6_addr_t *, 275 const in6_addr_t *, const in6_addr_t *, 276 uint32_t, uint16_t, uint16_t, nce_t **); 277 extern void nce_resolv_failed(nce_t *); 278 extern void nce_fastpath_list_add(nce_t *); 279 extern void nce_fastpath_list_delete(nce_t *); 280 extern void nce_fastpath_list_dispatch(ill_t *, 281 boolean_t (*)(nce_t *, void *), void *); 282 #ifdef NCE_DEBUG 283 extern void nce_trace_inactive(nce_t *); 284 extern void nce_trace_ref(nce_t *); 285 extern void nce_untrace_ref(nce_t *); 286 extern int nce_thread_exit(nce_t *, caddr_t); 287 #endif 288 289 #endif /* _KERNEL */ 290 291 #ifdef __cplusplus 292 } 293 #endif 294 295 #endif /* _INET_IP_NDP_H */ 296