1bd670b35SErik Nordmark /* 2bd670b35SErik Nordmark * CDDL HEADER START 3bd670b35SErik Nordmark * 4bd670b35SErik Nordmark * The contents of this file are subject to the terms of the 5bd670b35SErik Nordmark * Common Development and Distribution License (the "License"). 6bd670b35SErik Nordmark * You may not use this file except in compliance with the License. 7bd670b35SErik Nordmark * 8bd670b35SErik Nordmark * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9bd670b35SErik Nordmark * or http://www.opensolaris.org/os/licensing. 10bd670b35SErik Nordmark * See the License for the specific language governing permissions 11bd670b35SErik Nordmark * and limitations under the License. 12bd670b35SErik Nordmark * 13bd670b35SErik Nordmark * When distributing Covered Code, include this CDDL HEADER in each 14bd670b35SErik Nordmark * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15bd670b35SErik Nordmark * If applicable, add the following below this CDDL HEADER, with the 16bd670b35SErik Nordmark * fields enclosed by brackets "[]" replaced with your own identifying 17bd670b35SErik Nordmark * information: Portions Copyright [yyyy] [name of copyright owner] 18bd670b35SErik Nordmark * 19bd670b35SErik Nordmark * CDDL HEADER END 20bd670b35SErik Nordmark */ 21bd670b35SErik Nordmark 22bd670b35SErik Nordmark /* 231f19738eSmeem * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24bd670b35SErik Nordmark */ 25bd670b35SErik Nordmark 26bd670b35SErik Nordmark #include <inet/ip_arp.h> 27bd670b35SErik Nordmark #include <inet/ip_ndp.h> 28bd670b35SErik Nordmark #include <net/if_arp.h> 29bd670b35SErik Nordmark #include <netinet/if_ether.h> 30bd670b35SErik Nordmark #include <sys/strsubr.h> 31bd670b35SErik Nordmark #include <inet/ip6.h> 32bd670b35SErik Nordmark #include <inet/ip.h> 33bd670b35SErik Nordmark #include <inet/ip_ire.h> 34bd670b35SErik Nordmark #include <inet/ip_if.h> 35bd670b35SErik Nordmark #include <sys/dlpi.h> 36bd670b35SErik Nordmark #include <sys/sunddi.h> 37bd670b35SErik Nordmark #include <sys/strsun.h> 38bd670b35SErik Nordmark #include <sys/sdt.h> 39bd670b35SErik Nordmark #include <inet/mi.h> 40bd670b35SErik Nordmark #include <inet/arp.h> 41bd670b35SErik Nordmark #include <inet/ipdrop.h> 42bd670b35SErik Nordmark #include <sys/sockio.h> 43bd670b35SErik Nordmark #include <inet/ip_impl.h> 44bd670b35SErik Nordmark #include <sys/policy.h> 45bd670b35SErik Nordmark 46bd670b35SErik Nordmark #define ARL_LL_ADDR_OFFSET(arl) (((arl)->arl_sap_length) < 0 ? \ 47bd670b35SErik Nordmark (sizeof (dl_unitdata_req_t)) : \ 48bd670b35SErik Nordmark ((sizeof (dl_unitdata_req_t)) + (ABS((arl)->arl_sap_length)))) 49bd670b35SErik Nordmark 50bd670b35SErik Nordmark /* 51bd670b35SErik Nordmark * MAC-specific intelligence. Shouldn't be needed, but the DL_INFO_ACK 52bd670b35SErik Nordmark * doesn't quite do it for us. 53bd670b35SErik Nordmark */ 54bd670b35SErik Nordmark typedef struct arp_m_s { 55bd670b35SErik Nordmark t_uscalar_t arp_mac_type; 56bd670b35SErik Nordmark uint32_t arp_mac_arp_hw_type; 57bd670b35SErik Nordmark t_scalar_t arp_mac_sap_length; 58bd670b35SErik Nordmark uint32_t arp_mac_hw_addr_length; 59bd670b35SErik Nordmark } arp_m_t; 60bd670b35SErik Nordmark 61bd670b35SErik Nordmark static int arp_close(queue_t *, int); 62bd670b35SErik Nordmark static void arp_rput(queue_t *, mblk_t *); 63bd670b35SErik Nordmark static void arp_wput(queue_t *, mblk_t *); 64bd670b35SErik Nordmark static arp_m_t *arp_m_lookup(t_uscalar_t mac_type); 65bd670b35SErik Nordmark static void arp_notify(ipaddr_t, mblk_t *, uint32_t, ip_recv_attr_t *, 66bd670b35SErik Nordmark ncec_t *); 67bd670b35SErik Nordmark static int arp_output(ill_t *, uint32_t, const uchar_t *, const uchar_t *, 68bd670b35SErik Nordmark const uchar_t *, const uchar_t *, uchar_t *); 69bd670b35SErik Nordmark static int arp_modclose(arl_t *); 70bd670b35SErik Nordmark static void arp_mod_close_tail(arl_t *); 71bd670b35SErik Nordmark static mblk_t *arl_unbind(arl_t *); 72bd670b35SErik Nordmark static void arp_process_packet(ill_t *, mblk_t *); 73bd670b35SErik Nordmark static void arp_excl(ipsq_t *, queue_t *, mblk_t *, void *); 74bd670b35SErik Nordmark static void arp_drop_packet(const char *str, mblk_t *, ill_t *); 75bd670b35SErik Nordmark static int arp_open(queue_t *, dev_t *, int, int, cred_t *); 76bd670b35SErik Nordmark static int ip_sioctl_ifunitsel_arp(queue_t *, int *); 77bd670b35SErik Nordmark static int ip_sioctl_slifname_arp(queue_t *, void *); 78bd670b35SErik Nordmark static void arp_dlpi_send(arl_t *, mblk_t *); 79bd670b35SErik Nordmark static void arl_defaults_common(arl_t *, mblk_t *); 80bd670b35SErik Nordmark static int arp_modopen(queue_t *, dev_t *, int, int, cred_t *); 81bd670b35SErik Nordmark static void arp_ifname_notify(arl_t *); 82bd670b35SErik Nordmark static void arp_rput_dlpi_writer(ipsq_t *, queue_t *, mblk_t *, void *); 83bd670b35SErik Nordmark static arl_t *ill_to_arl(ill_t *); 84bd670b35SErik Nordmark 85bd670b35SErik Nordmark #define DL_PRIM(mp) (((union DL_primitives *)(mp)->b_rptr)->dl_primitive) 86bd670b35SErik Nordmark #define IS_DLPI_DATA(mp) \ 87bd670b35SErik Nordmark ((DB_TYPE(mp) == M_PROTO) && \ 88bd670b35SErik Nordmark MBLKL(mp) >= sizeof (dl_unitdata_ind_t) && \ 89bd670b35SErik Nordmark (DL_PRIM(mp) == DL_UNITDATA_IND)) 90bd670b35SErik Nordmark 91bd670b35SErik Nordmark #define AR_NOTFOUND 1 /* No matching ace found in cache */ 92bd670b35SErik Nordmark #define AR_MERGED 2 /* Matching ace updated (RFC 826 Merge_flag) */ 93bd670b35SErik Nordmark #define AR_LOOPBACK 3 /* Our own arp packet was received */ 94bd670b35SErik Nordmark #define AR_BOGON 4 /* Another host has our IP addr. */ 95bd670b35SErik Nordmark #define AR_FAILED 5 /* Duplicate Address Detection has failed */ 96bd670b35SErik Nordmark #define AR_CHANGED 6 /* Address has changed; tell IP (and merged) */ 97bd670b35SErik Nordmark 98bd670b35SErik Nordmark boolean_t arp_no_defense; 99bd670b35SErik Nordmark 100bd670b35SErik Nordmark struct module_info arp_mod_info = { 101937e6fcdSNitin Hande IP_MOD_ID, "arp", 1, INFPSZ, 65536, 1024 102bd670b35SErik Nordmark }; 103bd670b35SErik Nordmark static struct qinit rinit_arp = { 104bd670b35SErik Nordmark (pfi_t)arp_rput, NULL, arp_open, arp_close, NULL, &arp_mod_info 105bd670b35SErik Nordmark }; 106bd670b35SErik Nordmark static struct qinit winit_arp = { 107bd670b35SErik Nordmark (pfi_t)arp_wput, NULL, arp_open, arp_close, NULL, 108bd670b35SErik Nordmark &arp_mod_info 109bd670b35SErik Nordmark }; 110bd670b35SErik Nordmark struct streamtab arpinfo = { 111bd670b35SErik Nordmark &rinit_arp, &winit_arp 112bd670b35SErik Nordmark }; 113bd670b35SErik Nordmark #define ARH_FIXED_LEN 8 114bd670b35SErik Nordmark #define AR_LL_HDR_SLACK 32 115bd670b35SErik Nordmark 116bd670b35SErik Nordmark /* 117bd670b35SErik Nordmark * pfhooks for ARP. 118bd670b35SErik Nordmark */ 119bd670b35SErik Nordmark #define ARP_HOOK_IN(_hook, _event, _ilp, _hdr, _fm, _m, ipst) \ 120bd670b35SErik Nordmark \ 121bd670b35SErik Nordmark if ((_hook).he_interested) { \ 122bd670b35SErik Nordmark hook_pkt_event_t info; \ 123bd670b35SErik Nordmark \ 124bd670b35SErik Nordmark info.hpe_protocol = ipst->ips_arp_net_data; \ 125bd670b35SErik Nordmark info.hpe_ifp = _ilp; \ 126bd670b35SErik Nordmark info.hpe_ofp = 0; \ 127bd670b35SErik Nordmark info.hpe_hdr = _hdr; \ 128bd670b35SErik Nordmark info.hpe_mp = &(_fm); \ 129bd670b35SErik Nordmark info.hpe_mb = _m; \ 130bd670b35SErik Nordmark if (hook_run(ipst->ips_arp_net_data->netd_hooks, \ 131bd670b35SErik Nordmark _event, (hook_data_t)&info) != 0) { \ 132bd670b35SErik Nordmark if (_fm != NULL) { \ 133bd670b35SErik Nordmark freemsg(_fm); \ 134bd670b35SErik Nordmark _fm = NULL; \ 135bd670b35SErik Nordmark } \ 136bd670b35SErik Nordmark _hdr = NULL; \ 137bd670b35SErik Nordmark _m = NULL; \ 138bd670b35SErik Nordmark } else { \ 139bd670b35SErik Nordmark _hdr = info.hpe_hdr; \ 140bd670b35SErik Nordmark _m = info.hpe_mb; \ 141bd670b35SErik Nordmark } \ 142bd670b35SErik Nordmark } 143bd670b35SErik Nordmark 144bd670b35SErik Nordmark #define ARP_HOOK_OUT(_hook, _event, _olp, _hdr, _fm, _m, ipst) \ 145bd670b35SErik Nordmark \ 146bd670b35SErik Nordmark if ((_hook).he_interested) { \ 147bd670b35SErik Nordmark hook_pkt_event_t info; \ 148bd670b35SErik Nordmark \ 149bd670b35SErik Nordmark info.hpe_protocol = ipst->ips_arp_net_data; \ 150bd670b35SErik Nordmark info.hpe_ifp = 0; \ 151bd670b35SErik Nordmark info.hpe_ofp = _olp; \ 152bd670b35SErik Nordmark info.hpe_hdr = _hdr; \ 153bd670b35SErik Nordmark info.hpe_mp = &(_fm); \ 154bd670b35SErik Nordmark info.hpe_mb = _m; \ 155bd670b35SErik Nordmark if (hook_run(ipst->ips_arp_net_data->netd_hooks, \ 156bd670b35SErik Nordmark _event, (hook_data_t)&info) != 0) { \ 157bd670b35SErik Nordmark if (_fm != NULL) { \ 158bd670b35SErik Nordmark freemsg(_fm); \ 159bd670b35SErik Nordmark _fm = NULL; \ 160bd670b35SErik Nordmark } \ 161bd670b35SErik Nordmark _hdr = NULL; \ 162bd670b35SErik Nordmark _m = NULL; \ 163bd670b35SErik Nordmark } else { \ 164bd670b35SErik Nordmark _hdr = info.hpe_hdr; \ 165bd670b35SErik Nordmark _m = info.hpe_mb; \ 166bd670b35SErik Nordmark } \ 167bd670b35SErik Nordmark } 168bd670b35SErik Nordmark 169bd670b35SErik Nordmark static arp_m_t arp_m_tbl[] = { 170bd670b35SErik Nordmark { DL_CSMACD, ARPHRD_ETHER, -2, 6}, /* 802.3 */ 171bd670b35SErik Nordmark { DL_TPB, ARPHRD_IEEE802, -2, 6}, /* 802.4 */ 172bd670b35SErik Nordmark { DL_TPR, ARPHRD_IEEE802, -2, 6}, /* 802.5 */ 173bd670b35SErik Nordmark { DL_METRO, ARPHRD_IEEE802, -2, 6}, /* 802.6 */ 174bd670b35SErik Nordmark { DL_ETHER, ARPHRD_ETHER, -2, 6}, /* Ethernet */ 175bd670b35SErik Nordmark { DL_FDDI, ARPHRD_ETHER, -2, 6}, /* FDDI */ 176bd670b35SErik Nordmark { DL_IB, ARPHRD_IB, -2, 20}, /* Infiniband */ 177bd670b35SErik Nordmark { DL_OTHER, ARPHRD_ETHER, -2, 6} /* unknown */ 178bd670b35SErik Nordmark }; 179bd670b35SErik Nordmark 180bd670b35SErik Nordmark static void 181bd670b35SErik Nordmark arl_refhold_locked(arl_t *arl) 182bd670b35SErik Nordmark { 183bd670b35SErik Nordmark ASSERT(MUTEX_HELD(&arl->arl_lock)); 184bd670b35SErik Nordmark arl->arl_refcnt++; 185bd670b35SErik Nordmark ASSERT(arl->arl_refcnt != 0); 186bd670b35SErik Nordmark } 187bd670b35SErik Nordmark 188bd670b35SErik Nordmark static void 189bd670b35SErik Nordmark arl_refrele(arl_t *arl) 190bd670b35SErik Nordmark { 191bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 192bd670b35SErik Nordmark ASSERT(arl->arl_refcnt != 0); 193bd670b35SErik Nordmark arl->arl_refcnt--; 194bd670b35SErik Nordmark if (arl->arl_refcnt > 1) { 195bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 196bd670b35SErik Nordmark return; 197bd670b35SErik Nordmark } 198bd670b35SErik Nordmark 199bd670b35SErik Nordmark /* ill_close or arp_unbind_complete may be waiting */ 200bd670b35SErik Nordmark cv_broadcast(&arl->arl_cv); 201bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 202bd670b35SErik Nordmark } 203bd670b35SErik Nordmark 204bd670b35SErik Nordmark /* 205bd670b35SErik Nordmark * wake up any pending ip ioctls. 206bd670b35SErik Nordmark */ 207bd670b35SErik Nordmark static void 208bd670b35SErik Nordmark arp_cmd_done(ill_t *ill, int err, t_uscalar_t lastprim) 209bd670b35SErik Nordmark { 210bd670b35SErik Nordmark if (lastprim == DL_UNBIND_REQ && ill->ill_replumbing) 211bd670b35SErik Nordmark arp_replumb_done(ill, 0); 212bd670b35SErik Nordmark else 213bd670b35SErik Nordmark arp_bringup_done(ill, err); 214bd670b35SErik Nordmark } 215bd670b35SErik Nordmark 216bd670b35SErik Nordmark static int 217bd670b35SErik Nordmark ip_nce_resolve_all(ill_t *ill, uchar_t *src_haddr, uint32_t hlen, 218bd670b35SErik Nordmark const in_addr_t *src_paddr, ncec_t **sncec, int op) 219bd670b35SErik Nordmark { 220bd670b35SErik Nordmark int retv; 221bd670b35SErik Nordmark ncec_t *ncec; 222bd670b35SErik Nordmark boolean_t ll_changed; 223bd670b35SErik Nordmark uchar_t *lladdr = NULL; 224bd670b35SErik Nordmark int new_state; 225bd670b35SErik Nordmark 226bd670b35SErik Nordmark ASSERT(ill != NULL); 227bd670b35SErik Nordmark 228bd670b35SErik Nordmark ncec = ncec_lookup_illgrp_v4(ill, src_paddr); 229bd670b35SErik Nordmark *sncec = ncec; 230bd670b35SErik Nordmark 231bd670b35SErik Nordmark if (ncec == NULL) { 232bd670b35SErik Nordmark retv = AR_NOTFOUND; 233bd670b35SErik Nordmark goto done; 234bd670b35SErik Nordmark } 235bd670b35SErik Nordmark 236bd670b35SErik Nordmark mutex_enter(&ncec->ncec_lock); 237bd670b35SErik Nordmark /* 238bd670b35SErik Nordmark * IP addr and hardware address match what we already 239bd670b35SErik Nordmark * have, then this is a broadcast packet emitted by one of our 240bd670b35SErik Nordmark * interfaces, reflected by the switch and received on another 241bd670b35SErik Nordmark * interface. We return AR_LOOPBACK. 242bd670b35SErik Nordmark */ 243bd670b35SErik Nordmark lladdr = ncec->ncec_lladdr; 244bd670b35SErik Nordmark if (NCE_MYADDR(ncec) && hlen == ncec->ncec_ill->ill_phys_addr_length && 245bd670b35SErik Nordmark bcmp(lladdr, src_haddr, hlen) == 0) { 246bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 247bd670b35SErik Nordmark retv = AR_LOOPBACK; 248bd670b35SErik Nordmark goto done; 249bd670b35SErik Nordmark } 250bd670b35SErik Nordmark /* 251bd670b35SErik Nordmark * If the entry is unverified, then we've just verified that 252bd670b35SErik Nordmark * someone else already owns this address, because this is a 253bd670b35SErik Nordmark * message with the same protocol address but different 254bd670b35SErik Nordmark * hardware address. 255bd670b35SErik Nordmark */ 256bd670b35SErik Nordmark if (ncec->ncec_flags & NCE_F_UNVERIFIED) { 257bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 258bd670b35SErik Nordmark ncec_delete(ncec); 259bd670b35SErik Nordmark ncec_refrele(ncec); 260bd670b35SErik Nordmark *sncec = NULL; 261bd670b35SErik Nordmark retv = AR_FAILED; 262bd670b35SErik Nordmark goto done; 263bd670b35SErik Nordmark } 264bd670b35SErik Nordmark 265bd670b35SErik Nordmark /* 266bd670b35SErik Nordmark * If the IP address matches ours and we're authoritative for 267bd670b35SErik Nordmark * this entry, then some other node is using our IP addr, so 268bd670b35SErik Nordmark * return AR_BOGON. Also reset the transmit count to zero so 269bd670b35SErik Nordmark * that, if we're currently in initial announcement mode, we 270bd670b35SErik Nordmark * switch back to the lazier defense mode. Knowing that 271bd670b35SErik Nordmark * there's at least one duplicate out there, we ought not 272bd670b35SErik Nordmark * blindly announce. 273bd670b35SErik Nordmark * 274bd670b35SErik Nordmark * NCE_F_AUTHORITY is set in one of two ways: 275bd670b35SErik Nordmark * 1. /sbin/arp told us so, via the "permanent" flag. 276bd670b35SErik Nordmark * 2. This is one of my addresses. 277bd670b35SErik Nordmark */ 278bd670b35SErik Nordmark if (ncec->ncec_flags & NCE_F_AUTHORITY) { 279bd670b35SErik Nordmark ncec->ncec_unsolicit_count = 0; 280bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 281bd670b35SErik Nordmark retv = AR_BOGON; 282bd670b35SErik Nordmark goto done; 283bd670b35SErik Nordmark } 284bd670b35SErik Nordmark 285bd670b35SErik Nordmark /* 286bd670b35SErik Nordmark * No address conflict was detected, and we are getting 287bd670b35SErik Nordmark * ready to update the ncec's hwaddr. The nce MUST NOT be on an 288bd670b35SErik Nordmark * under interface, because all dynamic nce's are created on the 289bd670b35SErik Nordmark * native interface (in the non-IPMP case) or on the IPMP 290bd670b35SErik Nordmark * meta-interface (in the IPMP case) 291bd670b35SErik Nordmark */ 292bd670b35SErik Nordmark ASSERT(!IS_UNDER_IPMP(ncec->ncec_ill)); 293bd670b35SErik Nordmark 294bd670b35SErik Nordmark /* 295bd670b35SErik Nordmark * update ncec with src_haddr, hlen. 296bd670b35SErik Nordmark * 297bd670b35SErik Nordmark * We are trying to resolve this ncec_addr/src_paddr and we 298bd670b35SErik Nordmark * got a REQUEST/RESPONSE from the ncec_addr/src_paddr. 299bd670b35SErik Nordmark * So the new_state is at least "STALE". If, in addition, 300bd670b35SErik Nordmark * this a solicited, unicast ARP_RESPONSE, we can transition 301bd670b35SErik Nordmark * to REACHABLE. 302bd670b35SErik Nordmark */ 303bd670b35SErik Nordmark new_state = ND_STALE; 304bd670b35SErik Nordmark ip1dbg(("got info for ncec %p from addr %x\n", 305bd670b35SErik Nordmark (void *)ncec, *src_paddr)); 306bd670b35SErik Nordmark retv = AR_MERGED; 307bd670b35SErik Nordmark if (ncec->ncec_state == ND_INCOMPLETE || 308bd670b35SErik Nordmark ncec->ncec_state == ND_INITIAL) { 309bd670b35SErik Nordmark ll_changed = B_TRUE; 310bd670b35SErik Nordmark } else { 311bd670b35SErik Nordmark ll_changed = nce_cmp_ll_addr(ncec, src_haddr, hlen); 312bd670b35SErik Nordmark if (!ll_changed) 313bd670b35SErik Nordmark new_state = ND_UNCHANGED; 314bd670b35SErik Nordmark else 315bd670b35SErik Nordmark retv = AR_CHANGED; 316bd670b35SErik Nordmark } 317bd670b35SErik Nordmark /* 318bd670b35SErik Nordmark * We don't have the equivalent of the IPv6 'S' flag indicating 319bd670b35SErik Nordmark * a solicited response, so we assume that if we are in 320bd670b35SErik Nordmark * INCOMPLETE, or got back an unchanged lladdr in PROBE state, 321bd670b35SErik Nordmark * and this is an ARP_RESPONSE, it must be a 322bd670b35SErik Nordmark * solicited response allowing us to transtion to REACHABLE. 323bd670b35SErik Nordmark */ 324bd670b35SErik Nordmark if (op == ARP_RESPONSE) { 325bd670b35SErik Nordmark switch (ncec->ncec_state) { 326bd670b35SErik Nordmark case ND_PROBE: 327bd670b35SErik Nordmark new_state = (ll_changed ? ND_STALE : ND_REACHABLE); 328bd670b35SErik Nordmark break; 329bd670b35SErik Nordmark case ND_INCOMPLETE: 330bd670b35SErik Nordmark new_state = ND_REACHABLE; 331bd670b35SErik Nordmark break; 332bd670b35SErik Nordmark } 333bd670b35SErik Nordmark } 334bd670b35SErik Nordmark /* 335bd670b35SErik Nordmark * Call nce_update() to refresh fastpath information on any 336bd670b35SErik Nordmark * dependent nce_t entries. 337bd670b35SErik Nordmark */ 338bd670b35SErik Nordmark nce_update(ncec, new_state, (ll_changed ? src_haddr : NULL)); 339bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 340bd670b35SErik Nordmark nce_resolv_ok(ncec); 341bd670b35SErik Nordmark done: 342bd670b35SErik Nordmark return (retv); 343bd670b35SErik Nordmark } 344bd670b35SErik Nordmark 345bd670b35SErik Nordmark /* Find an entry for a particular MAC type in the arp_m_tbl. */ 346bd670b35SErik Nordmark static arp_m_t * 347bd670b35SErik Nordmark arp_m_lookup(t_uscalar_t mac_type) 348bd670b35SErik Nordmark { 349bd670b35SErik Nordmark arp_m_t *arm; 350bd670b35SErik Nordmark 351bd670b35SErik Nordmark for (arm = arp_m_tbl; arm < A_END(arp_m_tbl); arm++) { 352bd670b35SErik Nordmark if (arm->arp_mac_type == mac_type) 353bd670b35SErik Nordmark return (arm); 354bd670b35SErik Nordmark } 355bd670b35SErik Nordmark return (NULL); 356bd670b35SErik Nordmark } 357bd670b35SErik Nordmark 358*a6911619SDarren Reed uint32_t 359bd670b35SErik Nordmark arp_hw_type(t_uscalar_t mactype) 360bd670b35SErik Nordmark { 361bd670b35SErik Nordmark arp_m_t *arm; 362bd670b35SErik Nordmark 363bd670b35SErik Nordmark if ((arm = arp_m_lookup(mactype)) == NULL) 364bd670b35SErik Nordmark arm = arp_m_lookup(DL_OTHER); 365bd670b35SErik Nordmark return (arm->arp_mac_arp_hw_type); 366bd670b35SErik Nordmark } 367bd670b35SErik Nordmark 368bd670b35SErik Nordmark /* 369bd670b35SErik Nordmark * Called when an DLPI control message has been acked; send down the next 370bd670b35SErik Nordmark * queued message (if any). 371bd670b35SErik Nordmark * The DLPI messages of interest being bind, attach and unbind since 372bd670b35SErik Nordmark * these are the only ones sent by ARP via arp_dlpi_send. 373bd670b35SErik Nordmark */ 374bd670b35SErik Nordmark static void 375bd670b35SErik Nordmark arp_dlpi_done(arl_t *arl, ill_t *ill) 376bd670b35SErik Nordmark { 377bd670b35SErik Nordmark mblk_t *mp; 378bd670b35SErik Nordmark int err; 379bd670b35SErik Nordmark t_uscalar_t prim; 380bd670b35SErik Nordmark 381bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 382bd670b35SErik Nordmark prim = arl->arl_dlpi_pending; 383bd670b35SErik Nordmark 384bd670b35SErik Nordmark if ((mp = arl->arl_dlpi_deferred) == NULL) { 385bd670b35SErik Nordmark arl->arl_dlpi_pending = DL_PRIM_INVAL; 386bd670b35SErik Nordmark if (arl->arl_state_flags & ARL_LL_DOWN) 387bd670b35SErik Nordmark err = ENETDOWN; 388bd670b35SErik Nordmark else 389bd670b35SErik Nordmark err = 0; 390bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 391bd670b35SErik Nordmark 392bd670b35SErik Nordmark mutex_enter(&ill->ill_lock); 393bd670b35SErik Nordmark ill->ill_arl_dlpi_pending = 0; 394bd670b35SErik Nordmark mutex_exit(&ill->ill_lock); 395bd670b35SErik Nordmark arp_cmd_done(ill, err, prim); 396bd670b35SErik Nordmark return; 397bd670b35SErik Nordmark } 398bd670b35SErik Nordmark 399bd670b35SErik Nordmark arl->arl_dlpi_deferred = mp->b_next; 400bd670b35SErik Nordmark mp->b_next = NULL; 401bd670b35SErik Nordmark 402bd670b35SErik Nordmark ASSERT(DB_TYPE(mp) == M_PROTO || DB_TYPE(mp) == M_PCPROTO); 403bd670b35SErik Nordmark 404bd670b35SErik Nordmark arl->arl_dlpi_pending = DL_PRIM(mp); 405bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 406bd670b35SErik Nordmark 407bd670b35SErik Nordmark mutex_enter(&ill->ill_lock); 408bd670b35SErik Nordmark ill->ill_arl_dlpi_pending = 1; 409bd670b35SErik Nordmark mutex_exit(&ill->ill_lock); 410bd670b35SErik Nordmark 411bd670b35SErik Nordmark putnext(arl->arl_wq, mp); 412bd670b35SErik Nordmark } 413bd670b35SErik Nordmark 414bd670b35SErik Nordmark /* 415bd670b35SErik Nordmark * This routine is called during module initialization when the DL_INFO_ACK 416bd670b35SErik Nordmark * comes back from the device. We set up defaults for all the device dependent 417bd670b35SErik Nordmark * doo-dads we are going to need. This will leave us ready to roll if we are 418bd670b35SErik Nordmark * attempting auto-configuration. Alternatively, these defaults can be 419bd670b35SErik Nordmark * overridden by initialization procedures possessing higher intelligence. 420bd670b35SErik Nordmark * 421bd670b35SErik Nordmark * Caller will free the mp. 422bd670b35SErik Nordmark */ 423bd670b35SErik Nordmark static void 424bd670b35SErik Nordmark arp_ll_set_defaults(arl_t *arl, mblk_t *mp) 425bd670b35SErik Nordmark { 426bd670b35SErik Nordmark arp_m_t *arm; 427bd670b35SErik Nordmark dl_info_ack_t *dlia = (dl_info_ack_t *)mp->b_rptr; 428bd670b35SErik Nordmark 429bd670b35SErik Nordmark if ((arm = arp_m_lookup(dlia->dl_mac_type)) == NULL) 430bd670b35SErik Nordmark arm = arp_m_lookup(DL_OTHER); 431bd670b35SErik Nordmark ASSERT(arm != NULL); 432bd670b35SErik Nordmark 433bd670b35SErik Nordmark /* 434bd670b35SErik Nordmark * We initialize based on parameters in the (currently) not too 435bd670b35SErik Nordmark * exhaustive arp_m_tbl. 436bd670b35SErik Nordmark */ 437bd670b35SErik Nordmark if (dlia->dl_version == DL_VERSION_2) { 438bd670b35SErik Nordmark arl->arl_sap_length = dlia->dl_sap_length; 439bd670b35SErik Nordmark arl->arl_phys_addr_length = dlia->dl_brdcst_addr_length; 440bd670b35SErik Nordmark if (dlia->dl_provider_style == DL_STYLE2) 441bd670b35SErik Nordmark arl->arl_needs_attach = 1; 442bd670b35SErik Nordmark } else { 443bd670b35SErik Nordmark arl->arl_sap_length = arm->arp_mac_sap_length; 444bd670b35SErik Nordmark arl->arl_phys_addr_length = arm->arp_mac_hw_addr_length; 445bd670b35SErik Nordmark } 446bd670b35SErik Nordmark /* 447bd670b35SErik Nordmark * Note: the arp_hw_type in the arp header may be derived from 448bd670b35SErik Nordmark * the ill_mac_type and arp_m_lookup(). 449bd670b35SErik Nordmark */ 450bd670b35SErik Nordmark arl->arl_sap = ETHERTYPE_ARP; 451bd670b35SErik Nordmark arl_defaults_common(arl, mp); 452bd670b35SErik Nordmark } 453bd670b35SErik Nordmark 454bd670b35SErik Nordmark static void 455bd670b35SErik Nordmark arp_wput(queue_t *q, mblk_t *mp) 456bd670b35SErik Nordmark { 457bd670b35SErik Nordmark int err = EINVAL; 458bd670b35SErik Nordmark struct iocblk *ioc; 459bd670b35SErik Nordmark mblk_t *mp1; 460bd670b35SErik Nordmark 461bd670b35SErik Nordmark switch (DB_TYPE(mp)) { 462bd670b35SErik Nordmark case M_IOCTL: 463bd670b35SErik Nordmark ASSERT(q->q_next != NULL); 464bd670b35SErik Nordmark ioc = (struct iocblk *)mp->b_rptr; 465bd670b35SErik Nordmark if (ioc->ioc_cmd != SIOCSLIFNAME && 466bd670b35SErik Nordmark ioc->ioc_cmd != IF_UNITSEL) { 467bd670b35SErik Nordmark DTRACE_PROBE4(arl__dlpi, char *, "arp_wput", 468bd670b35SErik Nordmark char *, "<some ioctl>", char *, "-", 469bd670b35SErik Nordmark arl_t *, (arl_t *)q->q_ptr); 470bd670b35SErik Nordmark putnext(q, mp); 471bd670b35SErik Nordmark return; 472bd670b35SErik Nordmark } 473bd670b35SErik Nordmark if ((mp1 = mp->b_cont) == 0) 474bd670b35SErik Nordmark err = EINVAL; 475bd670b35SErik Nordmark else if (ioc->ioc_cmd == SIOCSLIFNAME) 476bd670b35SErik Nordmark err = ip_sioctl_slifname_arp(q, mp1->b_rptr); 477bd670b35SErik Nordmark else if (ioc->ioc_cmd == IF_UNITSEL) 478bd670b35SErik Nordmark err = ip_sioctl_ifunitsel_arp(q, (int *)mp1->b_rptr); 479bd670b35SErik Nordmark if (err == 0) 480bd670b35SErik Nordmark miocack(q, mp, 0, 0); 481bd670b35SErik Nordmark else 482bd670b35SErik Nordmark miocnak(q, mp, 0, err); 483bd670b35SErik Nordmark return; 484bd670b35SErik Nordmark default: 485bd670b35SErik Nordmark DTRACE_PROBE4(arl__dlpi, char *, "arp_wput default", 486bd670b35SErik Nordmark char *, "default mblk", char *, "-", 487bd670b35SErik Nordmark arl_t *, (arl_t *)q->q_ptr); 488bd670b35SErik Nordmark putnext(q, mp); 489bd670b35SErik Nordmark return; 490bd670b35SErik Nordmark } 491bd670b35SErik Nordmark } 492bd670b35SErik Nordmark 493bd670b35SErik Nordmark /* 494bd670b35SErik Nordmark * similar to ill_dlpi_pending(): verify that the received DLPI response 495bd670b35SErik Nordmark * matches the one that is pending for the arl. 496bd670b35SErik Nordmark */ 497bd670b35SErik Nordmark static boolean_t 498bd670b35SErik Nordmark arl_dlpi_pending(arl_t *arl, t_uscalar_t prim) 499bd670b35SErik Nordmark { 500bd670b35SErik Nordmark t_uscalar_t pending; 501bd670b35SErik Nordmark 502bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 503bd670b35SErik Nordmark if (arl->arl_dlpi_pending == prim) { 504bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 505bd670b35SErik Nordmark return (B_TRUE); 506bd670b35SErik Nordmark } 507bd670b35SErik Nordmark 508bd670b35SErik Nordmark if (arl->arl_state_flags & ARL_CONDEMNED) { 509bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 510bd670b35SErik Nordmark return (B_FALSE); 511bd670b35SErik Nordmark } 512bd670b35SErik Nordmark pending = arl->arl_dlpi_pending; 513bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 514bd670b35SErik Nordmark 515bd670b35SErik Nordmark if (pending == DL_PRIM_INVAL) { 516bd670b35SErik Nordmark ip0dbg(("arl_dlpi_pending unsolicited ack for %s on %s", 517bd670b35SErik Nordmark dl_primstr(prim), arl->arl_name)); 518bd670b35SErik Nordmark } else { 519bd670b35SErik Nordmark ip0dbg(("arl_dlpi_pending ack for %s on %s expect %s", 520bd670b35SErik Nordmark dl_primstr(prim), arl->arl_name, dl_primstr(pending))); 521bd670b35SErik Nordmark } 522bd670b35SErik Nordmark return (B_FALSE); 523bd670b35SErik Nordmark } 524bd670b35SErik Nordmark 525bd670b35SErik Nordmark /* DLPI messages, other than DL_UNITDATA_IND are handled here. */ 526bd670b35SErik Nordmark static void 527bd670b35SErik Nordmark arp_rput_dlpi(queue_t *q, mblk_t *mp) 528bd670b35SErik Nordmark { 529bd670b35SErik Nordmark arl_t *arl = (arl_t *)q->q_ptr; 530bd670b35SErik Nordmark union DL_primitives *dlp; 531bd670b35SErik Nordmark t_uscalar_t prim; 532bd670b35SErik Nordmark t_uscalar_t reqprim = DL_PRIM_INVAL; 533bd670b35SErik Nordmark ill_t *ill; 534bd670b35SErik Nordmark 535bd670b35SErik Nordmark if ((mp->b_wptr - mp->b_rptr) < sizeof (dlp->dl_primitive)) { 536bd670b35SErik Nordmark putnext(q, mp); 537bd670b35SErik Nordmark return; 538bd670b35SErik Nordmark } 539bd670b35SErik Nordmark dlp = (union DL_primitives *)mp->b_rptr; 540bd670b35SErik Nordmark prim = dlp->dl_primitive; 541bd670b35SErik Nordmark 542bd670b35SErik Nordmark /* 543bd670b35SErik Nordmark * If we received an ACK but didn't send a request for it, then it 544bd670b35SErik Nordmark * can't be part of any pending operation; discard up-front. 545bd670b35SErik Nordmark */ 546bd670b35SErik Nordmark switch (prim) { 547bd670b35SErik Nordmark case DL_ERROR_ACK: 548bd670b35SErik Nordmark /* 549bd670b35SErik Nordmark * ce is confused about how DLPI works, so we have to interpret 550bd670b35SErik Nordmark * an "error" on DL_NOTIFY_ACK (which we never could have sent) 551bd670b35SErik Nordmark * as really meaning an error on DL_NOTIFY_REQ. 552bd670b35SErik Nordmark * 553bd670b35SErik Nordmark * Note that supporting DL_NOTIFY_REQ is optional, so printing 554bd670b35SErik Nordmark * out an error message on the console isn't warranted except 555bd670b35SErik Nordmark * for debug. 556bd670b35SErik Nordmark */ 557bd670b35SErik Nordmark if (dlp->error_ack.dl_error_primitive == DL_NOTIFY_ACK || 558bd670b35SErik Nordmark dlp->error_ack.dl_error_primitive == DL_NOTIFY_REQ) { 559bd670b35SErik Nordmark reqprim = DL_NOTIFY_REQ; 560bd670b35SErik Nordmark } else { 561bd670b35SErik Nordmark reqprim = dlp->error_ack.dl_error_primitive; 562bd670b35SErik Nordmark } 563bd670b35SErik Nordmark break; 564bd670b35SErik Nordmark case DL_INFO_ACK: 565bd670b35SErik Nordmark reqprim = DL_INFO_REQ; 566bd670b35SErik Nordmark break; 567bd670b35SErik Nordmark case DL_OK_ACK: 568bd670b35SErik Nordmark reqprim = dlp->ok_ack.dl_correct_primitive; 569bd670b35SErik Nordmark break; 570bd670b35SErik Nordmark case DL_BIND_ACK: 571bd670b35SErik Nordmark reqprim = DL_BIND_REQ; 572bd670b35SErik Nordmark break; 573bd670b35SErik Nordmark default: 574bd670b35SErik Nordmark DTRACE_PROBE2(rput_dl_badprim, arl_t *, arl, 575bd670b35SErik Nordmark union DL_primitives *, dlp); 576bd670b35SErik Nordmark putnext(q, mp); 577bd670b35SErik Nordmark return; 578bd670b35SErik Nordmark } 579bd670b35SErik Nordmark if (reqprim == DL_PRIM_INVAL || !arl_dlpi_pending(arl, reqprim)) { 580bd670b35SErik Nordmark freemsg(mp); 581bd670b35SErik Nordmark return; 582bd670b35SErik Nordmark } 583bd670b35SErik Nordmark DTRACE_PROBE4(arl__dlpi, char *, "arp_rput_dlpi received", 584bd670b35SErik Nordmark char *, dl_primstr(prim), char *, dl_primstr(reqprim), 585bd670b35SErik Nordmark arl_t *, arl); 586bd670b35SErik Nordmark 587bd670b35SErik Nordmark ASSERT(prim != DL_NOTIFY_IND); 588bd670b35SErik Nordmark 589bd670b35SErik Nordmark ill = arl_to_ill(arl); 590bd670b35SErik Nordmark 591bd670b35SErik Nordmark switch (reqprim) { 592bd670b35SErik Nordmark case DL_INFO_REQ: 593bd670b35SErik Nordmark /* 594bd670b35SErik Nordmark * ill has not been set up yet for this case. This is the 595bd670b35SErik Nordmark * DL_INFO_ACK for the first DL_INFO_REQ sent from 596bd670b35SErik Nordmark * arp_modopen(). There should be no other arl_dlpi_deferred 597bd670b35SErik Nordmark * messages pending. We initialize the arl here. 598bd670b35SErik Nordmark */ 599bd670b35SErik Nordmark ASSERT(!arl->arl_dlpi_style_set); 600bd670b35SErik Nordmark ASSERT(arl->arl_dlpi_pending == DL_INFO_REQ); 601bd670b35SErik Nordmark ASSERT(arl->arl_dlpi_deferred == NULL); 602bd670b35SErik Nordmark arl->arl_dlpi_pending = DL_PRIM_INVAL; 603bd670b35SErik Nordmark arp_ll_set_defaults(arl, mp); 604bd670b35SErik Nordmark freemsg(mp); 605bd670b35SErik Nordmark return; 606bd670b35SErik Nordmark case DL_UNBIND_REQ: 607bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 608bd670b35SErik Nordmark arl->arl_state_flags &= ~ARL_DL_UNBIND_IN_PROGRESS; 609bd670b35SErik Nordmark /* 610bd670b35SErik Nordmark * This is not an error, so we don't set ARL_LL_DOWN 611bd670b35SErik Nordmark */ 612bd670b35SErik Nordmark arl->arl_state_flags &= ~ARL_LL_UP; 613bd670b35SErik Nordmark arl->arl_state_flags |= ARL_LL_UNBOUND; 614bd670b35SErik Nordmark if (arl->arl_state_flags & ARL_CONDEMNED) { 615bd670b35SErik Nordmark /* 616bd670b35SErik Nordmark * if this is part of the unplumb the arl may 617bd670b35SErik Nordmark * vaporize any moment after we cv_signal the 618bd670b35SErik Nordmark * arl_cv so we reset arl_dlpi_pending here. 619bd670b35SErik Nordmark * All other cases (including replumb) will 620bd670b35SErik Nordmark * have the arl_dlpi_pending reset in 621bd670b35SErik Nordmark * arp_dlpi_done. 622bd670b35SErik Nordmark */ 623bd670b35SErik Nordmark arl->arl_dlpi_pending = DL_PRIM_INVAL; 624bd670b35SErik Nordmark } 625bd670b35SErik Nordmark cv_signal(&arl->arl_cv); 626bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 627bd670b35SErik Nordmark break; 628bd670b35SErik Nordmark } 629bd670b35SErik Nordmark if (ill != NULL) { 630bd670b35SErik Nordmark /* 631bd670b35SErik Nordmark * ill ref obtained by arl_to_ill() will be released 632bd670b35SErik Nordmark * by qwriter_ip() 633bd670b35SErik Nordmark */ 634bd670b35SErik Nordmark qwriter_ip(ill, ill->ill_wq, mp, arp_rput_dlpi_writer, 635bd670b35SErik Nordmark CUR_OP, B_TRUE); 636bd670b35SErik Nordmark return; 637bd670b35SErik Nordmark } 638bd670b35SErik Nordmark freemsg(mp); 639bd670b35SErik Nordmark } 640bd670b35SErik Nordmark 641bd670b35SErik Nordmark /* 642bd670b35SErik Nordmark * Handling of DLPI messages that require exclusive access to the ipsq. 643bd670b35SErik Nordmark */ 644bd670b35SErik Nordmark /* ARGSUSED */ 645bd670b35SErik Nordmark static void 646bd670b35SErik Nordmark arp_rput_dlpi_writer(ipsq_t *ipsq, queue_t *q, mblk_t *mp, void *dummy_arg) 647bd670b35SErik Nordmark { 648bd670b35SErik Nordmark union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr; 649bd670b35SErik Nordmark ill_t *ill = (ill_t *)q->q_ptr; 650bd670b35SErik Nordmark arl_t *arl = ill_to_arl(ill); 651bd670b35SErik Nordmark 652bd670b35SErik Nordmark if (arl == NULL) { 653bd670b35SErik Nordmark /* 654bd670b35SErik Nordmark * happens as a result arp_modclose triggering unbind. 655bd670b35SErik Nordmark * arp_rput_dlpi will cv_signal the arl_cv and the modclose 656bd670b35SErik Nordmark * will complete, but when it does ipsq_exit, the waiting 657bd670b35SErik Nordmark * qwriter_ip gets into the ipsq but will find the arl null. 658bd670b35SErik Nordmark * There should be no deferred messages in this case, so 659bd670b35SErik Nordmark * just complete and exit. 660bd670b35SErik Nordmark */ 661bd670b35SErik Nordmark arp_cmd_done(ill, 0, DL_UNBIND_REQ); 662bd670b35SErik Nordmark freemsg(mp); 663bd670b35SErik Nordmark return; 664bd670b35SErik Nordmark } 665bd670b35SErik Nordmark switch (dlp->dl_primitive) { 666bd670b35SErik Nordmark case DL_ERROR_ACK: 667bd670b35SErik Nordmark switch (dlp->error_ack.dl_error_primitive) { 668bd670b35SErik Nordmark case DL_UNBIND_REQ: 669bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 670bd670b35SErik Nordmark arl->arl_state_flags &= ~ARL_DL_UNBIND_IN_PROGRESS; 671bd670b35SErik Nordmark arl->arl_state_flags &= ~ARL_LL_UP; 672bd670b35SErik Nordmark arl->arl_state_flags |= ARL_LL_UNBOUND; 673bd670b35SErik Nordmark arl->arl_state_flags |= ARL_LL_DOWN; 674bd670b35SErik Nordmark cv_signal(&arl->arl_cv); 675bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 676bd670b35SErik Nordmark break; 677bd670b35SErik Nordmark case DL_BIND_REQ: 678bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 679bd670b35SErik Nordmark arl->arl_state_flags &= ~ARL_LL_UP; 680bd670b35SErik Nordmark arl->arl_state_flags |= ARL_LL_DOWN; 681bd670b35SErik Nordmark arl->arl_state_flags |= ARL_LL_UNBOUND; 682bd670b35SErik Nordmark cv_signal(&arl->arl_cv); 683bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 684bd670b35SErik Nordmark break; 685bd670b35SErik Nordmark case DL_ATTACH_REQ: 686bd670b35SErik Nordmark break; 687bd670b35SErik Nordmark default: 688bd670b35SErik Nordmark /* If it's anything else, we didn't send it. */ 689bd670b35SErik Nordmark arl_refrele(arl); 690bd670b35SErik Nordmark putnext(q, mp); 691bd670b35SErik Nordmark return; 692bd670b35SErik Nordmark } 693bd670b35SErik Nordmark break; 694bd670b35SErik Nordmark case DL_OK_ACK: 695bd670b35SErik Nordmark DTRACE_PROBE4(arl__dlpi, char *, "arp_rput_dlpi_writer ok", 696bd670b35SErik Nordmark char *, dl_primstr(dlp->ok_ack.dl_correct_primitive), 697bd670b35SErik Nordmark char *, dl_primstr(dlp->ok_ack.dl_correct_primitive), 698bd670b35SErik Nordmark arl_t *, arl); 699bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 700bd670b35SErik Nordmark switch (dlp->ok_ack.dl_correct_primitive) { 701bd670b35SErik Nordmark case DL_UNBIND_REQ: 702bd670b35SErik Nordmark case DL_ATTACH_REQ: 703bd670b35SErik Nordmark break; 704bd670b35SErik Nordmark default: 705bd670b35SErik Nordmark ip0dbg(("Dropping unrecognized DL_OK_ACK for %s", 706bd670b35SErik Nordmark dl_primstr(dlp->ok_ack.dl_correct_primitive))); 707bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 708bd670b35SErik Nordmark arl_refrele(arl); 709bd670b35SErik Nordmark freemsg(mp); 710bd670b35SErik Nordmark return; 711bd670b35SErik Nordmark } 712bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 713bd670b35SErik Nordmark break; 714bd670b35SErik Nordmark case DL_BIND_ACK: 715bd670b35SErik Nordmark DTRACE_PROBE2(rput_dl_bind, arl_t *, arl, 716bd670b35SErik Nordmark dl_bind_ack_t *, &dlp->bind_ack); 717bd670b35SErik Nordmark 718bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 719bd670b35SErik Nordmark ASSERT(arl->arl_state_flags & ARL_LL_BIND_PENDING); 720bd670b35SErik Nordmark arl->arl_state_flags &= 721bd670b35SErik Nordmark ~(ARL_LL_BIND_PENDING|ARL_LL_DOWN|ARL_LL_UNBOUND); 722bd670b35SErik Nordmark arl->arl_state_flags |= ARL_LL_UP; 723bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 724bd670b35SErik Nordmark break; 725bd670b35SErik Nordmark case DL_UDERROR_IND: 726bd670b35SErik Nordmark DTRACE_PROBE2(rput_dl_uderror, arl_t *, arl, 727bd670b35SErik Nordmark dl_uderror_ind_t *, &dlp->uderror_ind); 728bd670b35SErik Nordmark arl_refrele(arl); 729bd670b35SErik Nordmark putnext(q, mp); 730bd670b35SErik Nordmark return; 731bd670b35SErik Nordmark default: 732bd670b35SErik Nordmark DTRACE_PROBE2(rput_dl_badprim, arl_t *, arl, 733bd670b35SErik Nordmark union DL_primitives *, dlp); 734bd670b35SErik Nordmark arl_refrele(arl); 735bd670b35SErik Nordmark putnext(q, mp); 736bd670b35SErik Nordmark return; 737bd670b35SErik Nordmark } 738bd670b35SErik Nordmark arp_dlpi_done(arl, ill); 739bd670b35SErik Nordmark arl_refrele(arl); 740bd670b35SErik Nordmark freemsg(mp); 741bd670b35SErik Nordmark } 742bd670b35SErik Nordmark 743bd670b35SErik Nordmark void 744bd670b35SErik Nordmark arp_rput(queue_t *q, mblk_t *mp) 745bd670b35SErik Nordmark { 746bd670b35SErik Nordmark arl_t *arl = q->q_ptr; 747bd670b35SErik Nordmark boolean_t need_refrele = B_FALSE; 748bd670b35SErik Nordmark 749bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 750bd670b35SErik Nordmark if (((arl->arl_state_flags & 751bd670b35SErik Nordmark (ARL_CONDEMNED | ARL_LL_REPLUMBING)) != 0)) { 752bd670b35SErik Nordmark /* 753bd670b35SErik Nordmark * Only allow high priority DLPI messages during unplumb or 754bd670b35SErik Nordmark * replumb, and we don't take an arl_refcnt for that case. 755bd670b35SErik Nordmark */ 756bd670b35SErik Nordmark if (DB_TYPE(mp) != M_PCPROTO) { 757bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 758bd670b35SErik Nordmark freemsg(mp); 759bd670b35SErik Nordmark return; 760bd670b35SErik Nordmark } 761bd670b35SErik Nordmark } else { 762bd670b35SErik Nordmark arl_refhold_locked(arl); 763bd670b35SErik Nordmark need_refrele = B_TRUE; 764bd670b35SErik Nordmark } 765bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 766bd670b35SErik Nordmark 767bd670b35SErik Nordmark switch (DB_TYPE(mp)) { 768bd670b35SErik Nordmark case M_PCPROTO: 769bd670b35SErik Nordmark case M_PROTO: { 770bd670b35SErik Nordmark ill_t *ill; 771bd670b35SErik Nordmark 772bd670b35SErik Nordmark /* 773bd670b35SErik Nordmark * could be one of 774bd670b35SErik Nordmark * (i) real message from the wire, (DLPI_DATA) 775bd670b35SErik Nordmark * (ii) DLPI message 776bd670b35SErik Nordmark * Take a ref on the ill associated with this arl to 777bd670b35SErik Nordmark * prevent the ill from being unplumbed until this thread 778bd670b35SErik Nordmark * is done. 779bd670b35SErik Nordmark */ 780bd670b35SErik Nordmark if (IS_DLPI_DATA(mp)) { 781bd670b35SErik Nordmark ill = arl_to_ill(arl); 782bd670b35SErik Nordmark if (ill == NULL) { 783bd670b35SErik Nordmark arp_drop_packet("No ill", mp, ill); 784bd670b35SErik Nordmark break; 785bd670b35SErik Nordmark } 786bd670b35SErik Nordmark arp_process_packet(ill, mp); 787bd670b35SErik Nordmark ill_refrele(ill); 788bd670b35SErik Nordmark break; 789bd670b35SErik Nordmark } 790bd670b35SErik Nordmark /* Miscellaneous DLPI messages get shuffled off. */ 791bd670b35SErik Nordmark arp_rput_dlpi(q, mp); 792bd670b35SErik Nordmark break; 793bd670b35SErik Nordmark } 794bd670b35SErik Nordmark case M_ERROR: 795bd670b35SErik Nordmark case M_HANGUP: 796bd670b35SErik Nordmark if (mp->b_rptr < mp->b_wptr) 797bd670b35SErik Nordmark arl->arl_error = (int)(*mp->b_rptr & 0xFF); 798bd670b35SErik Nordmark if (arl->arl_error == 0) 799bd670b35SErik Nordmark arl->arl_error = ENXIO; 800bd670b35SErik Nordmark freemsg(mp); 801bd670b35SErik Nordmark break; 802bd670b35SErik Nordmark default: 803bd670b35SErik Nordmark ip1dbg(("arp_rput other db type %x\n", DB_TYPE(mp))); 804bd670b35SErik Nordmark putnext(q, mp); 805bd670b35SErik Nordmark break; 806bd670b35SErik Nordmark } 807bd670b35SErik Nordmark if (need_refrele) 808bd670b35SErik Nordmark arl_refrele(arl); 809bd670b35SErik Nordmark } 810bd670b35SErik Nordmark 811bd670b35SErik Nordmark static void 812bd670b35SErik Nordmark arp_process_packet(ill_t *ill, mblk_t *mp) 813bd670b35SErik Nordmark { 814bd670b35SErik Nordmark mblk_t *mp1; 815bd670b35SErik Nordmark arh_t *arh; 816bd670b35SErik Nordmark in_addr_t src_paddr, dst_paddr; 817bd670b35SErik Nordmark uint32_t hlen, plen; 818bd670b35SErik Nordmark boolean_t is_probe; 819bd670b35SErik Nordmark int op; 820bd670b35SErik Nordmark ncec_t *dst_ncec, *src_ncec = NULL; 821bd670b35SErik Nordmark uchar_t *src_haddr, *arhp, *dst_haddr, *dp, *sp; 822bd670b35SErik Nordmark int err; 823bd670b35SErik Nordmark ip_stack_t *ipst; 824bd670b35SErik Nordmark boolean_t need_ill_refrele = B_FALSE; 825bd670b35SErik Nordmark nce_t *nce; 826bd670b35SErik Nordmark uchar_t *src_lladdr; 827bd670b35SErik Nordmark dl_unitdata_ind_t *dlui; 828bd670b35SErik Nordmark ip_recv_attr_t iras; 829bd670b35SErik Nordmark 830bd670b35SErik Nordmark ASSERT(ill != NULL); 831bd670b35SErik Nordmark if (ill->ill_flags & ILLF_NOARP) { 832bd670b35SErik Nordmark arp_drop_packet("Interface does not support ARP", mp, ill); 833bd670b35SErik Nordmark return; 834bd670b35SErik Nordmark } 835bd670b35SErik Nordmark ipst = ill->ill_ipst; 836bd670b35SErik Nordmark /* 837bd670b35SErik Nordmark * What we should have at this point is a DL_UNITDATA_IND message 838bd670b35SErik Nordmark * followed by an ARP packet. We do some initial checks and then 839bd670b35SErik Nordmark * get to work. 840bd670b35SErik Nordmark */ 841bd670b35SErik Nordmark dlui = (dl_unitdata_ind_t *)mp->b_rptr; 842bd670b35SErik Nordmark if (dlui->dl_group_address == 1) { 843bd670b35SErik Nordmark /* 844bd670b35SErik Nordmark * multicast or broadcast packet. Only accept on the ipmp 845bd670b35SErik Nordmark * nominated interface for multicasts ('cast_ill'). 846bd670b35SErik Nordmark * If we have no cast_ill we are liberal and accept everything. 847bd670b35SErik Nordmark */ 848bd670b35SErik Nordmark if (IS_UNDER_IPMP(ill)) { 849bd670b35SErik Nordmark /* For an under ill_grp can change under lock */ 850bd670b35SErik Nordmark rw_enter(&ipst->ips_ill_g_lock, RW_READER); 851bd670b35SErik Nordmark if (!ill->ill_nom_cast && ill->ill_grp != NULL && 852bd670b35SErik Nordmark ill->ill_grp->ig_cast_ill != NULL) { 853bd670b35SErik Nordmark rw_exit(&ipst->ips_ill_g_lock); 854bd670b35SErik Nordmark arp_drop_packet("Interface is not nominated " 855bd670b35SErik Nordmark "for multicast sends and receives", 856bd670b35SErik Nordmark mp, ill); 857bd670b35SErik Nordmark return; 858bd670b35SErik Nordmark } 859bd670b35SErik Nordmark rw_exit(&ipst->ips_ill_g_lock); 860bd670b35SErik Nordmark } 861bd670b35SErik Nordmark } 862bd670b35SErik Nordmark mp1 = mp->b_cont; 863bd670b35SErik Nordmark if (mp1 == NULL) { 864bd670b35SErik Nordmark arp_drop_packet("Missing ARP packet", mp, ill); 865bd670b35SErik Nordmark return; 866bd670b35SErik Nordmark } 867bd670b35SErik Nordmark if (mp1->b_cont != NULL) { 868bd670b35SErik Nordmark /* No fooling around with funny messages. */ 869bd670b35SErik Nordmark if (!pullupmsg(mp1, -1)) { 870bd670b35SErik Nordmark arp_drop_packet("Funny message: pullup failed", 871bd670b35SErik Nordmark mp, ill); 872bd670b35SErik Nordmark return; 873bd670b35SErik Nordmark } 874bd670b35SErik Nordmark } 875bd670b35SErik Nordmark arh = (arh_t *)mp1->b_rptr; 876bd670b35SErik Nordmark hlen = arh->arh_hlen; 877bd670b35SErik Nordmark plen = arh->arh_plen; 878bd670b35SErik Nordmark if (MBLKL(mp1) < ARH_FIXED_LEN + 2 * hlen + 2 * plen) { 879bd670b35SErik Nordmark arp_drop_packet("mblk len too small", mp, ill); 880bd670b35SErik Nordmark return; 881bd670b35SErik Nordmark } 882bd670b35SErik Nordmark /* 883bd670b35SErik Nordmark * hlen 0 is used for RFC 1868 UnARP. 884bd670b35SErik Nordmark * 885bd670b35SErik Nordmark * Note that the rest of the code checks that hlen is what we expect 886bd670b35SErik Nordmark * for this hardware address type, so might as well discard packets 887bd670b35SErik Nordmark * here that don't match. 888bd670b35SErik Nordmark */ 889bd670b35SErik Nordmark if ((hlen > 0 && hlen != ill->ill_phys_addr_length) || plen == 0) { 890bd670b35SErik Nordmark DTRACE_PROBE2(rput_bogus, ill_t *, ill, mblk_t *, mp1); 891bd670b35SErik Nordmark arp_drop_packet("Bogus hlen or plen", mp, ill); 892bd670b35SErik Nordmark return; 893bd670b35SErik Nordmark } 894bd670b35SErik Nordmark /* 895bd670b35SErik Nordmark * Historically, Solaris has been lenient about hardware type numbers. 896bd670b35SErik Nordmark * We should check here, but don't. 897bd670b35SErik Nordmark */ 898bd670b35SErik Nordmark DTRACE_PROBE3(arp__physical__in__start, ill_t *, ill, arh_t *, arh, 899bd670b35SErik Nordmark mblk_t *, mp); 900bd670b35SErik Nordmark /* 901bd670b35SErik Nordmark * If ill is in an ipmp group, it will be the under ill. If we want 902bd670b35SErik Nordmark * to report the packet as coming up the IPMP interface, we should 903bd670b35SErik Nordmark * convert it to the ipmp ill. 904bd670b35SErik Nordmark */ 905bd670b35SErik Nordmark ARP_HOOK_IN(ipst->ips_arp_physical_in_event, ipst->ips_arp_physical_in, 906bd670b35SErik Nordmark ill->ill_phyint->phyint_ifindex, arh, mp, mp1, ipst); 907bd670b35SErik Nordmark DTRACE_PROBE1(arp__physical__in__end, mblk_t *, mp); 908bd670b35SErik Nordmark if (mp == NULL) 909bd670b35SErik Nordmark return; 910bd670b35SErik Nordmark arhp = (uchar_t *)arh + ARH_FIXED_LEN; 911bd670b35SErik Nordmark src_haddr = arhp; /* ar$sha */ 912bd670b35SErik Nordmark arhp += hlen; 913bd670b35SErik Nordmark bcopy(arhp, &src_paddr, IP_ADDR_LEN); /* ar$spa */ 914bd670b35SErik Nordmark sp = arhp; 915bd670b35SErik Nordmark arhp += IP_ADDR_LEN; 916bd670b35SErik Nordmark dst_haddr = arhp; /* ar$dha */ 917bd670b35SErik Nordmark arhp += hlen; 918bd670b35SErik Nordmark bcopy(arhp, &dst_paddr, IP_ADDR_LEN); /* ar$tpa */ 919bd670b35SErik Nordmark dp = arhp; 920bd670b35SErik Nordmark op = BE16_TO_U16(arh->arh_operation); 921bd670b35SErik Nordmark 922bd670b35SErik Nordmark DTRACE_PROBE2(ip__arp__input, (in_addr_t), src_paddr, 923bd670b35SErik Nordmark (in_addr_t), dst_paddr); 924bd670b35SErik Nordmark 925bd670b35SErik Nordmark /* Determine if this is just a probe */ 926bd670b35SErik Nordmark is_probe = (src_paddr == INADDR_ANY); 927bd670b35SErik Nordmark 928bd670b35SErik Nordmark /* 92901685f97SSowmini Varadhan * The following test for loopback is faster than 93001685f97SSowmini Varadhan * IP_LOOPBACK_ADDR(), because it avoids any bitwise 93101685f97SSowmini Varadhan * operations. 93201685f97SSowmini Varadhan * Note that these addresses are always in network byte order 93301685f97SSowmini Varadhan */ 93401685f97SSowmini Varadhan if ((*(uint8_t *)&src_paddr) == IN_LOOPBACKNET || 93501685f97SSowmini Varadhan (*(uint8_t *)&dst_paddr) == IN_LOOPBACKNET || 936c13c3653SSowmini Varadhan CLASSD(src_paddr) || CLASSD(dst_paddr)) { 93701685f97SSowmini Varadhan arp_drop_packet("Martian IP addr", mp, ill); 93801685f97SSowmini Varadhan return; 93901685f97SSowmini Varadhan } 94001685f97SSowmini Varadhan 94101685f97SSowmini Varadhan /* 942bd670b35SErik Nordmark * ira_ill is the only field used down the arp_notify path. 943bd670b35SErik Nordmark */ 944bd670b35SErik Nordmark bzero(&iras, sizeof (iras)); 945bd670b35SErik Nordmark iras.ira_ill = iras.ira_rill = ill; 946bd670b35SErik Nordmark /* 947bd670b35SErik Nordmark * RFC 826: first check if the <protocol, sender protocol address> is 948bd670b35SErik Nordmark * in the cache, if there is a sender protocol address. Note that this 949bd670b35SErik Nordmark * step also handles resolutions based on source. 950bd670b35SErik Nordmark */ 951bd670b35SErik Nordmark /* Note: after here we need to freeb(mp) and freemsg(mp1) separately */ 952bd670b35SErik Nordmark mp->b_cont = NULL; 953bd670b35SErik Nordmark if (is_probe) { 954bd670b35SErik Nordmark err = AR_NOTFOUND; 955bd670b35SErik Nordmark } else { 956bd670b35SErik Nordmark if (plen != 4) { 957bd670b35SErik Nordmark arp_drop_packet("bad protocol len", mp, ill); 958bd670b35SErik Nordmark return; 959bd670b35SErik Nordmark } 960bd670b35SErik Nordmark err = ip_nce_resolve_all(ill, src_haddr, hlen, &src_paddr, 961bd670b35SErik Nordmark &src_ncec, op); 962bd670b35SErik Nordmark switch (err) { 963bd670b35SErik Nordmark case AR_BOGON: 964bd670b35SErik Nordmark ASSERT(src_ncec != NULL); 965bd670b35SErik Nordmark arp_notify(src_paddr, mp1, AR_CN_BOGON, 966bd670b35SErik Nordmark &iras, src_ncec); 967bd670b35SErik Nordmark break; 968bd670b35SErik Nordmark case AR_FAILED: 969bd670b35SErik Nordmark arp_notify(src_paddr, mp1, AR_CN_FAILED, &iras, 970bd670b35SErik Nordmark src_ncec); 971bd670b35SErik Nordmark break; 972bd670b35SErik Nordmark case AR_LOOPBACK: 973bd670b35SErik Nordmark DTRACE_PROBE2(rput_loopback, ill_t *, ill, arh_t *, 974bd670b35SErik Nordmark arh); 975bd670b35SErik Nordmark freemsg(mp1); 976bd670b35SErik Nordmark break; 977bd670b35SErik Nordmark default: 978bd670b35SErik Nordmark goto update; 979bd670b35SErik Nordmark } 980bd670b35SErik Nordmark freemsg(mp); 981bd670b35SErik Nordmark if (src_ncec != NULL) 982bd670b35SErik Nordmark ncec_refrele(src_ncec); 983bd670b35SErik Nordmark return; 984bd670b35SErik Nordmark } 985bd670b35SErik Nordmark update: 986bd670b35SErik Nordmark /* 987bd670b35SErik Nordmark * Now look up the destination address. By RFC 826, we ignore the 988bd670b35SErik Nordmark * packet at this step if the target isn't one of our addresses (i.e., 989bd670b35SErik Nordmark * one we have been asked to PUBLISH). This is true even if the 990bd670b35SErik Nordmark * target is something we're trying to resolve and the packet 991bd670b35SErik Nordmark * is a response. 992bd670b35SErik Nordmark */ 993bd670b35SErik Nordmark dst_ncec = ncec_lookup_illgrp_v4(ill, &dst_paddr); 994bd670b35SErik Nordmark if (dst_ncec == NULL || !NCE_PUBLISH(dst_ncec)) { 995bd670b35SErik Nordmark /* 996bd670b35SErik Nordmark * Let the client know if the source mapping has changed, even 997bd670b35SErik Nordmark * if the destination provides no useful information for the 998bd670b35SErik Nordmark * client. 999bd670b35SErik Nordmark */ 1000bd670b35SErik Nordmark if (err == AR_CHANGED) { 1001bd670b35SErik Nordmark arp_notify(src_paddr, mp1, AR_CN_ANNOUNCE, &iras, 1002bd670b35SErik Nordmark NULL); 1003bd670b35SErik Nordmark freemsg(mp); 1004bd670b35SErik Nordmark } else { 1005bd670b35SErik Nordmark freemsg(mp); 1006bd670b35SErik Nordmark arp_drop_packet("Target is not interesting", mp1, ill); 1007bd670b35SErik Nordmark } 1008bd670b35SErik Nordmark if (dst_ncec != NULL) 1009bd670b35SErik Nordmark ncec_refrele(dst_ncec); 1010bd670b35SErik Nordmark if (src_ncec != NULL) 1011bd670b35SErik Nordmark ncec_refrele(src_ncec); 1012bd670b35SErik Nordmark return; 1013bd670b35SErik Nordmark } 1014bd670b35SErik Nordmark 1015bd670b35SErik Nordmark if (dst_ncec->ncec_flags & NCE_F_UNVERIFIED) { 1016bd670b35SErik Nordmark /* 1017bd670b35SErik Nordmark * Check for a reflection. Some misbehaving bridges will 1018bd670b35SErik Nordmark * reflect our own transmitted packets back to us. 1019bd670b35SErik Nordmark */ 1020bd670b35SErik Nordmark ASSERT(NCE_PUBLISH(dst_ncec)); 1021bd670b35SErik Nordmark if (hlen != dst_ncec->ncec_ill->ill_phys_addr_length) { 1022bd670b35SErik Nordmark ncec_refrele(dst_ncec); 1023bd670b35SErik Nordmark if (src_ncec != NULL) 1024bd670b35SErik Nordmark ncec_refrele(src_ncec); 1025bd670b35SErik Nordmark freemsg(mp); 1026bd670b35SErik Nordmark arp_drop_packet("bad arh_len", mp1, ill); 1027bd670b35SErik Nordmark return; 1028bd670b35SErik Nordmark } 1029bd670b35SErik Nordmark if (!nce_cmp_ll_addr(dst_ncec, src_haddr, hlen)) { 1030bd670b35SErik Nordmark DTRACE_PROBE3(rput_probe_reflected, ill_t *, ill, 1031bd670b35SErik Nordmark arh_t *, arh, ncec_t *, dst_ncec); 1032bd670b35SErik Nordmark ncec_refrele(dst_ncec); 1033bd670b35SErik Nordmark if (src_ncec != NULL) 1034bd670b35SErik Nordmark ncec_refrele(src_ncec); 1035bd670b35SErik Nordmark freemsg(mp); 1036bd670b35SErik Nordmark arp_drop_packet("Reflected probe", mp1, ill); 1037bd670b35SErik Nordmark return; 1038bd670b35SErik Nordmark } 1039bd670b35SErik Nordmark /* 1040bd670b35SErik Nordmark * Responses targeting our HW address that are not responses to 1041bd670b35SErik Nordmark * our DAD probe must be ignored as they are related to requests 1042bd670b35SErik Nordmark * sent before DAD was restarted. 1043bd670b35SErik Nordmark */ 1044bd670b35SErik Nordmark if (op == ARP_RESPONSE && 1045bd670b35SErik Nordmark (nce_cmp_ll_addr(dst_ncec, dst_haddr, hlen) == 0)) { 1046bd670b35SErik Nordmark ncec_refrele(dst_ncec); 1047bd670b35SErik Nordmark if (src_ncec != NULL) 1048bd670b35SErik Nordmark ncec_refrele(src_ncec); 1049bd670b35SErik Nordmark freemsg(mp); 1050bd670b35SErik Nordmark arp_drop_packet( 1051bd670b35SErik Nordmark "Response to request that was sent before DAD", 1052bd670b35SErik Nordmark mp1, ill); 1053bd670b35SErik Nordmark return; 1054bd670b35SErik Nordmark } 1055bd670b35SErik Nordmark /* 1056bd670b35SErik Nordmark * Responses targeted to HW addresses which are not ours but 1057bd670b35SErik Nordmark * sent to our unverified proto address are also conflicts. 1058bd670b35SErik Nordmark * These may be reported by a proxy rather than the interface 1059bd670b35SErik Nordmark * with the conflicting address, dst_paddr is in conflict 1060bd670b35SErik Nordmark * rather than src_paddr. To ensure IP can locate the correct 1061bd670b35SErik Nordmark * ipif to take down, it is necessary to copy dst_paddr to 1062bd670b35SErik Nordmark * the src_paddr field before sending it to IP. The same is 1063bd670b35SErik Nordmark * required for probes, where src_paddr will be INADDR_ANY. 1064bd670b35SErik Nordmark */ 1065bd670b35SErik Nordmark if (is_probe || op == ARP_RESPONSE) { 1066bd670b35SErik Nordmark bcopy(dp, sp, plen); 1067bd670b35SErik Nordmark arp_notify(src_paddr, mp1, AR_CN_FAILED, &iras, 1068bd670b35SErik Nordmark NULL); 1069bd670b35SErik Nordmark ncec_delete(dst_ncec); 1070bd670b35SErik Nordmark } else if (err == AR_CHANGED) { 1071bd670b35SErik Nordmark arp_notify(src_paddr, mp1, AR_CN_ANNOUNCE, &iras, 1072bd670b35SErik Nordmark NULL); 1073bd670b35SErik Nordmark } else { 1074bd670b35SErik Nordmark DTRACE_PROBE3(rput_request_unverified, 1075bd670b35SErik Nordmark ill_t *, ill, arh_t *, arh, ncec_t *, dst_ncec); 1076bd670b35SErik Nordmark arp_drop_packet("Unverified request", mp1, ill); 1077bd670b35SErik Nordmark } 1078bd670b35SErik Nordmark freemsg(mp); 1079bd670b35SErik Nordmark ncec_refrele(dst_ncec); 1080bd670b35SErik Nordmark if (src_ncec != NULL) 1081bd670b35SErik Nordmark ncec_refrele(src_ncec); 1082bd670b35SErik Nordmark return; 1083bd670b35SErik Nordmark } 1084bd670b35SErik Nordmark /* 1085bd670b35SErik Nordmark * If it's a request, then we reply to this, and if we think the 1086bd670b35SErik Nordmark * sender's unknown, then we create an entry to avoid unnecessary ARPs. 1087bd670b35SErik Nordmark * The design assumption is that someone ARPing us is likely to send us 1088bd670b35SErik Nordmark * a packet soon, and that we'll want to reply to it. 1089bd670b35SErik Nordmark */ 1090bd670b35SErik Nordmark if (op == ARP_REQUEST) { 1091bd670b35SErik Nordmark const uchar_t *nce_hwaddr; 1092bd670b35SErik Nordmark struct in_addr nce_paddr; 1093bd670b35SErik Nordmark clock_t now; 1094bd670b35SErik Nordmark ill_t *under_ill = ill; 1095bd670b35SErik Nordmark boolean_t send_unicast = B_TRUE; 1096bd670b35SErik Nordmark 1097bd670b35SErik Nordmark ASSERT(NCE_PUBLISH(dst_ncec)); 1098bd670b35SErik Nordmark 1099bd670b35SErik Nordmark if ((dst_ncec->ncec_flags & (NCE_F_BCAST|NCE_F_MCAST)) != 0) { 1100bd670b35SErik Nordmark /* 1101bd670b35SErik Nordmark * Ignore senders who are deliberately or accidentally 1102bd670b35SErik Nordmark * confused. 1103bd670b35SErik Nordmark */ 1104bd670b35SErik Nordmark goto bail; 1105bd670b35SErik Nordmark } 1106bd670b35SErik Nordmark 1107bd670b35SErik Nordmark if (!is_probe && err == AR_NOTFOUND) { 1108bd670b35SErik Nordmark ASSERT(src_ncec == NULL); 1109bd670b35SErik Nordmark 1110bd670b35SErik Nordmark if (IS_UNDER_IPMP(under_ill)) { 1111bd670b35SErik Nordmark /* 1112bd670b35SErik Nordmark * create the ncec for the sender on ipmp_ill. 1113bd670b35SErik Nordmark * We pass in the ipmp_ill itself to avoid 1114bd670b35SErik Nordmark * creating an nce_t on the under_ill. 1115bd670b35SErik Nordmark */ 1116bd670b35SErik Nordmark ill = ipmp_ill_hold_ipmp_ill(under_ill); 1117bd670b35SErik Nordmark if (ill == NULL) 1118bd670b35SErik Nordmark ill = under_ill; 1119bd670b35SErik Nordmark else 1120bd670b35SErik Nordmark need_ill_refrele = B_TRUE; 1121bd670b35SErik Nordmark } 1122bd670b35SErik Nordmark 1123bd670b35SErik Nordmark err = nce_lookup_then_add_v4(ill, src_haddr, hlen, 1124bd670b35SErik Nordmark &src_paddr, 0, ND_STALE, &nce); 1125bd670b35SErik Nordmark 1126bd670b35SErik Nordmark switch (err) { 1127bd670b35SErik Nordmark case 0: 1128bd670b35SErik Nordmark case EEXIST: 1129bd670b35SErik Nordmark ip1dbg(("added ncec %p in state %d ill %s\n", 1130bd670b35SErik Nordmark (void *)src_ncec, src_ncec->ncec_state, 1131bd670b35SErik Nordmark ill->ill_name)); 1132bd670b35SErik Nordmark src_ncec = nce->nce_common; 1133bd670b35SErik Nordmark break; 1134bd670b35SErik Nordmark default: 1135bd670b35SErik Nordmark /* 1136bd670b35SErik Nordmark * Either no memory, or the outgoing interface 1137bd670b35SErik Nordmark * is in the process of down/unplumb. In the 1138bd670b35SErik Nordmark * latter case, we will fail the send anyway, 1139bd670b35SErik Nordmark * and in the former case, we should try to send 1140bd670b35SErik Nordmark * the ARP response. 1141bd670b35SErik Nordmark */ 1142bd670b35SErik Nordmark src_lladdr = src_haddr; 1143bd670b35SErik Nordmark goto send_response; 1144bd670b35SErik Nordmark } 1145bd670b35SErik Nordmark ncec_refhold(src_ncec); 1146bd670b35SErik Nordmark nce_refrele(nce); 1147bd670b35SErik Nordmark /* set up cleanup interval on ncec */ 1148bd670b35SErik Nordmark } 1149bd670b35SErik Nordmark 1150bd670b35SErik Nordmark /* 1151bd670b35SErik Nordmark * This implements periodic address defense based on a modified 1152bd670b35SErik Nordmark * version of the RFC 3927 requirements. Instead of sending a 1153bd670b35SErik Nordmark * broadcasted reply every time, as demanded by the RFC, we 1154bd670b35SErik Nordmark * send at most one broadcast reply per arp_broadcast_interval. 1155bd670b35SErik Nordmark */ 1156bd670b35SErik Nordmark now = ddi_get_lbolt(); 1157bd670b35SErik Nordmark if ((now - dst_ncec->ncec_last_time_defended) > 1158bd670b35SErik Nordmark MSEC_TO_TICK(ipst->ips_ipv4_dad_announce_interval)) { 1159bd670b35SErik Nordmark dst_ncec->ncec_last_time_defended = now; 1160bd670b35SErik Nordmark /* 1161bd670b35SErik Nordmark * If this is one of the long-suffering entries, 1162bd670b35SErik Nordmark * pull it out now. It no longer needs separate 1163bd670b35SErik Nordmark * defense, because we're now doing that with this 1164bd670b35SErik Nordmark * broadcasted reply. 1165bd670b35SErik Nordmark */ 1166bd670b35SErik Nordmark dst_ncec->ncec_flags &= ~NCE_F_DELAYED; 1167bd670b35SErik Nordmark send_unicast = B_FALSE; 1168bd670b35SErik Nordmark } 1169bd670b35SErik Nordmark if (src_ncec != NULL && send_unicast) { 1170bd670b35SErik Nordmark src_lladdr = src_ncec->ncec_lladdr; 1171bd670b35SErik Nordmark } else { 1172bd670b35SErik Nordmark src_lladdr = under_ill->ill_bcast_mp->b_rptr + 1173bd670b35SErik Nordmark NCE_LL_ADDR_OFFSET(under_ill); 1174bd670b35SErik Nordmark } 1175bd670b35SErik Nordmark send_response: 1176bd670b35SErik Nordmark nce_hwaddr = dst_ncec->ncec_lladdr; 1177bd670b35SErik Nordmark IN6_V4MAPPED_TO_INADDR(&dst_ncec->ncec_addr, &nce_paddr); 1178bd670b35SErik Nordmark 1179bd670b35SErik Nordmark (void) arp_output(under_ill, ARP_RESPONSE, 1180bd670b35SErik Nordmark nce_hwaddr, (uchar_t *)&nce_paddr, src_haddr, 1181bd670b35SErik Nordmark (uchar_t *)&src_paddr, src_lladdr); 1182bd670b35SErik Nordmark } 1183bd670b35SErik Nordmark bail: 1184bd670b35SErik Nordmark if (dst_ncec != NULL) { 1185bd670b35SErik Nordmark ncec_refrele(dst_ncec); 1186bd670b35SErik Nordmark } 1187bd670b35SErik Nordmark if (src_ncec != NULL) { 1188bd670b35SErik Nordmark ncec_refrele(src_ncec); 1189bd670b35SErik Nordmark } 1190bd670b35SErik Nordmark if (err == AR_CHANGED) { 1191bd670b35SErik Nordmark mp->b_cont = NULL; 1192bd670b35SErik Nordmark arp_notify(src_paddr, mp1, AR_CN_ANNOUNCE, &iras, NULL); 1193bd670b35SErik Nordmark mp1 = NULL; 1194bd670b35SErik Nordmark } 1195bd670b35SErik Nordmark if (need_ill_refrele) 1196bd670b35SErik Nordmark ill_refrele(ill); 1197bd670b35SErik Nordmark done: 1198bd670b35SErik Nordmark freemsg(mp); 1199bd670b35SErik Nordmark freemsg(mp1); 1200bd670b35SErik Nordmark } 1201bd670b35SErik Nordmark 1202bd670b35SErik Nordmark /* 1203bd670b35SErik Nordmark * Basic initialization of the arl_t and the arl_common structure shared with 1204bd670b35SErik Nordmark * the ill_t that is done after SLIFNAME/IF_UNITSEL. 1205bd670b35SErik Nordmark */ 1206bd670b35SErik Nordmark static int 1207bd670b35SErik Nordmark arl_ill_init(arl_t *arl, char *ill_name) 1208bd670b35SErik Nordmark { 1209bd670b35SErik Nordmark ill_t *ill; 1210bd670b35SErik Nordmark arl_ill_common_t *ai; 1211bd670b35SErik Nordmark 1212bd670b35SErik Nordmark ill = ill_lookup_on_name(ill_name, B_FALSE, B_FALSE, B_FALSE, 1213bd670b35SErik Nordmark arl->arl_ipst); 1214bd670b35SErik Nordmark 1215bd670b35SErik Nordmark if (ill == NULL) 1216bd670b35SErik Nordmark return (ENXIO); 1217bd670b35SErik Nordmark 1218bd670b35SErik Nordmark /* 1219bd670b35SErik Nordmark * By the time we set up the arl, we expect the ETHERTYPE_IP 1220bd670b35SErik Nordmark * stream to be fully bound and attached. So we copy/verify 1221bd670b35SErik Nordmark * relevant information as possible from/against the ill. 1222bd670b35SErik Nordmark * 1223bd670b35SErik Nordmark * The following should have been set up in arp_ll_set_defaults() 1224bd670b35SErik Nordmark * after the first DL_INFO_ACK was received. 1225bd670b35SErik Nordmark */ 1226bd670b35SErik Nordmark ASSERT(arl->arl_phys_addr_length == ill->ill_phys_addr_length); 1227bd670b35SErik Nordmark ASSERT(arl->arl_sap == ETHERTYPE_ARP); 1228bd670b35SErik Nordmark ASSERT(arl->arl_mactype == ill->ill_mactype); 1229bd670b35SErik Nordmark ASSERT(arl->arl_sap_length == ill->ill_sap_length); 1230bd670b35SErik Nordmark 1231bd670b35SErik Nordmark ai = kmem_zalloc(sizeof (*ai), KM_SLEEP); 1232bd670b35SErik Nordmark mutex_enter(&ill->ill_lock); 1233bd670b35SErik Nordmark /* First ensure that the ill is not CONDEMNED. */ 1234bd670b35SErik Nordmark if (ill->ill_state_flags & ILL_CONDEMNED) { 1235bd670b35SErik Nordmark mutex_exit(&ill->ill_lock); 1236bd670b35SErik Nordmark ill_refrele(ill); 1237bd670b35SErik Nordmark kmem_free(ai, sizeof (*ai)); 1238bd670b35SErik Nordmark return (ENXIO); 1239bd670b35SErik Nordmark } 1240bd670b35SErik Nordmark if (ill->ill_common != NULL || arl->arl_common != NULL) { 1241bd670b35SErik Nordmark mutex_exit(&ill->ill_lock); 1242bd670b35SErik Nordmark ip0dbg(("%s: PPA already exists", ill->ill_name)); 1243bd670b35SErik Nordmark ill_refrele(ill); 1244bd670b35SErik Nordmark kmem_free(ai, sizeof (*ai)); 1245bd670b35SErik Nordmark return (EEXIST); 1246bd670b35SErik Nordmark } 1247bd670b35SErik Nordmark mutex_init(&ai->ai_lock, NULL, MUTEX_DEFAULT, NULL); 1248bd670b35SErik Nordmark ai->ai_arl = arl; 1249bd670b35SErik Nordmark ai->ai_ill = ill; 1250bd670b35SErik Nordmark ill->ill_common = ai; 1251bd670b35SErik Nordmark arl->arl_common = ai; 1252bd670b35SErik Nordmark mutex_exit(&ill->ill_lock); 1253bd670b35SErik Nordmark (void) strlcpy(arl->arl_name, ill->ill_name, LIFNAMSIZ); 1254bd670b35SErik Nordmark arl->arl_name_length = ill->ill_name_length; 1255bd670b35SErik Nordmark ill_refrele(ill); 1256bd670b35SErik Nordmark arp_ifname_notify(arl); 1257bd670b35SErik Nordmark return (0); 1258bd670b35SErik Nordmark } 1259bd670b35SErik Nordmark 1260bd670b35SErik Nordmark /* Allocate and do common initializations for DLPI messages. */ 1261bd670b35SErik Nordmark static mblk_t * 1262bd670b35SErik Nordmark ip_ar_dlpi_comm(t_uscalar_t prim, size_t size) 1263bd670b35SErik Nordmark { 1264bd670b35SErik Nordmark mblk_t *mp; 1265bd670b35SErik Nordmark 1266bd670b35SErik Nordmark if ((mp = allocb(size, BPRI_HI)) == NULL) 1267bd670b35SErik Nordmark return (NULL); 1268bd670b35SErik Nordmark 1269bd670b35SErik Nordmark /* 1270bd670b35SErik Nordmark * DLPIv2 says that DL_INFO_REQ and DL_TOKEN_REQ (the latter 1271bd670b35SErik Nordmark * of which we don't seem to use) are sent with M_PCPROTO, and 1272bd670b35SErik Nordmark * that other DLPI are M_PROTO. 1273bd670b35SErik Nordmark */ 1274bd670b35SErik Nordmark DB_TYPE(mp) = (prim == DL_INFO_REQ) ? M_PCPROTO : M_PROTO; 1275bd670b35SErik Nordmark 1276bd670b35SErik Nordmark mp->b_wptr = mp->b_rptr + size; 1277bd670b35SErik Nordmark bzero(mp->b_rptr, size); 1278bd670b35SErik Nordmark DL_PRIM(mp) = prim; 1279bd670b35SErik Nordmark return (mp); 1280bd670b35SErik Nordmark } 1281bd670b35SErik Nordmark 1282bd670b35SErik Nordmark 1283bd670b35SErik Nordmark int 1284bd670b35SErik Nordmark ip_sioctl_ifunitsel_arp(queue_t *q, int *ppa) 1285bd670b35SErik Nordmark { 1286bd670b35SErik Nordmark arl_t *arl; 1287bd670b35SErik Nordmark char *cp, ill_name[LIFNAMSIZ]; 1288bd670b35SErik Nordmark 1289bd670b35SErik Nordmark if (q->q_next == NULL) 1290bd670b35SErik Nordmark return (EINVAL); 1291bd670b35SErik Nordmark 1292bd670b35SErik Nordmark do { 1293bd670b35SErik Nordmark q = q->q_next; 1294bd670b35SErik Nordmark } while (q->q_next != NULL); 1295bd670b35SErik Nordmark cp = q->q_qinfo->qi_minfo->mi_idname; 1296bd670b35SErik Nordmark 1297bd670b35SErik Nordmark arl = (arl_t *)q->q_ptr; 1298bd670b35SErik Nordmark (void) snprintf(ill_name, sizeof (ill_name), "%s%d", cp, *ppa); 1299bd670b35SErik Nordmark arl->arl_ppa = *ppa; 1300bd670b35SErik Nordmark return (arl_ill_init(arl, ill_name)); 1301bd670b35SErik Nordmark } 1302bd670b35SErik Nordmark 1303bd670b35SErik Nordmark int 1304bd670b35SErik Nordmark ip_sioctl_slifname_arp(queue_t *q, void *lifreq) 1305bd670b35SErik Nordmark { 1306bd670b35SErik Nordmark arl_t *arl; 1307bd670b35SErik Nordmark struct lifreq *lifr = lifreq; 1308bd670b35SErik Nordmark 1309bd670b35SErik Nordmark /* ioctl not valid when IP opened as a device */ 1310bd670b35SErik Nordmark if (q->q_next == NULL) 1311bd670b35SErik Nordmark return (EINVAL); 1312bd670b35SErik Nordmark 1313bd670b35SErik Nordmark arl = (arl_t *)q->q_ptr; 1314bd670b35SErik Nordmark arl->arl_ppa = lifr->lifr_ppa; 1315bd670b35SErik Nordmark return (arl_ill_init(arl, lifr->lifr_name)); 1316bd670b35SErik Nordmark } 1317bd670b35SErik Nordmark 1318bd670b35SErik Nordmark arl_t * 1319bd670b35SErik Nordmark ill_to_arl(ill_t *ill) 1320bd670b35SErik Nordmark { 1321bd670b35SErik Nordmark arl_ill_common_t *ai = ill->ill_common; 1322bd670b35SErik Nordmark arl_t *arl = NULL; 1323bd670b35SErik Nordmark 1324bd670b35SErik Nordmark if (ai == NULL) 1325bd670b35SErik Nordmark return (NULL); 1326bd670b35SErik Nordmark /* 1327bd670b35SErik Nordmark * Find the arl_t that corresponds to this ill_t from the shared 1328bd670b35SErik Nordmark * ill_common structure. We can safely access the ai here as it 1329bd670b35SErik Nordmark * will only be freed in arp_modclose() after we have become 1330bd670b35SErik Nordmark * single-threaded. 1331bd670b35SErik Nordmark */ 1332bd670b35SErik Nordmark mutex_enter(&ai->ai_lock); 1333bd670b35SErik Nordmark if ((arl = ai->ai_arl) != NULL) { 1334bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 1335bd670b35SErik Nordmark if (!(arl->arl_state_flags & ARL_CONDEMNED)) { 1336bd670b35SErik Nordmark arl_refhold_locked(arl); 1337bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 1338bd670b35SErik Nordmark } else { 1339bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 1340bd670b35SErik Nordmark arl = NULL; 1341bd670b35SErik Nordmark } 1342bd670b35SErik Nordmark } 1343bd670b35SErik Nordmark mutex_exit(&ai->ai_lock); 1344bd670b35SErik Nordmark return (arl); 1345bd670b35SErik Nordmark } 1346bd670b35SErik Nordmark 1347bd670b35SErik Nordmark ill_t * 1348bd670b35SErik Nordmark arl_to_ill(arl_t *arl) 1349bd670b35SErik Nordmark { 1350bd670b35SErik Nordmark arl_ill_common_t *ai = arl->arl_common; 1351bd670b35SErik Nordmark ill_t *ill = NULL; 1352bd670b35SErik Nordmark 1353bd670b35SErik Nordmark if (ai == NULL) { 1354bd670b35SErik Nordmark /* 1355bd670b35SErik Nordmark * happens when the arp stream is just being opened, and 1356bd670b35SErik Nordmark * arl_ill_init has not been executed yet. 1357bd670b35SErik Nordmark */ 1358bd670b35SErik Nordmark return (NULL); 1359bd670b35SErik Nordmark } 1360bd670b35SErik Nordmark /* 1361bd670b35SErik Nordmark * Find the ill_t that corresponds to this arl_t from the shared 1362bd670b35SErik Nordmark * arl_common structure. We can safely access the ai here as it 1363bd670b35SErik Nordmark * will only be freed in arp_modclose() after we have become 1364bd670b35SErik Nordmark * single-threaded. 1365bd670b35SErik Nordmark */ 1366bd670b35SErik Nordmark mutex_enter(&ai->ai_lock); 1367bd670b35SErik Nordmark if ((ill = ai->ai_ill) != NULL) { 1368bd670b35SErik Nordmark mutex_enter(&ill->ill_lock); 1369bd670b35SErik Nordmark if (!ILL_IS_CONDEMNED(ill)) { 1370bd670b35SErik Nordmark ill_refhold_locked(ill); 1371bd670b35SErik Nordmark mutex_exit(&ill->ill_lock); 1372bd670b35SErik Nordmark } else { 1373bd670b35SErik Nordmark mutex_exit(&ill->ill_lock); 1374bd670b35SErik Nordmark ill = NULL; 1375bd670b35SErik Nordmark } 1376bd670b35SErik Nordmark } 1377bd670b35SErik Nordmark mutex_exit(&ai->ai_lock); 1378bd670b35SErik Nordmark return (ill); 1379bd670b35SErik Nordmark } 1380bd670b35SErik Nordmark 1381bd670b35SErik Nordmark int 1382bd670b35SErik Nordmark arp_ll_up(ill_t *ill) 1383bd670b35SErik Nordmark { 1384bd670b35SErik Nordmark mblk_t *attach_mp = NULL; 1385bd670b35SErik Nordmark mblk_t *bind_mp = NULL; 1386bd670b35SErik Nordmark mblk_t *unbind_mp = NULL; 1387bd670b35SErik Nordmark arl_t *arl; 1388bd670b35SErik Nordmark 1389bd670b35SErik Nordmark ASSERT(IAM_WRITER_ILL(ill)); 1390bd670b35SErik Nordmark arl = ill_to_arl(ill); 1391bd670b35SErik Nordmark 1392bd670b35SErik Nordmark DTRACE_PROBE2(ill__downup, char *, "arp_ll_up", ill_t *, ill); 1393bd670b35SErik Nordmark if (arl == NULL) 1394bd670b35SErik Nordmark return (ENXIO); 1395bd670b35SErik Nordmark DTRACE_PROBE2(arl__downup, char *, "arp_ll_up", arl_t *, arl); 1396bd670b35SErik Nordmark if ((arl->arl_state_flags & ARL_LL_UP) != 0) { 1397bd670b35SErik Nordmark arl_refrele(arl); 1398bd670b35SErik Nordmark return (0); 1399bd670b35SErik Nordmark } 1400bd670b35SErik Nordmark if (arl->arl_needs_attach) { /* DL_STYLE2 */ 1401bd670b35SErik Nordmark attach_mp = 1402bd670b35SErik Nordmark ip_ar_dlpi_comm(DL_ATTACH_REQ, sizeof (dl_attach_req_t)); 1403bd670b35SErik Nordmark if (attach_mp == NULL) 1404bd670b35SErik Nordmark goto bad; 1405bd670b35SErik Nordmark ((dl_attach_req_t *)attach_mp->b_rptr)->dl_ppa = arl->arl_ppa; 1406bd670b35SErik Nordmark } 1407bd670b35SErik Nordmark 1408bd670b35SErik Nordmark /* Allocate and initialize a bind message. */ 1409bd670b35SErik Nordmark bind_mp = ip_ar_dlpi_comm(DL_BIND_REQ, sizeof (dl_bind_req_t)); 1410bd670b35SErik Nordmark if (bind_mp == NULL) 1411bd670b35SErik Nordmark goto bad; 1412bd670b35SErik Nordmark ((dl_bind_req_t *)bind_mp->b_rptr)->dl_sap = ETHERTYPE_ARP; 1413bd670b35SErik Nordmark ((dl_bind_req_t *)bind_mp->b_rptr)->dl_service_mode = DL_CLDLS; 1414bd670b35SErik Nordmark 1415bd670b35SErik Nordmark unbind_mp = ip_ar_dlpi_comm(DL_UNBIND_REQ, sizeof (dl_unbind_req_t)); 1416bd670b35SErik Nordmark if (unbind_mp == NULL) 1417bd670b35SErik Nordmark goto bad; 1418bd670b35SErik Nordmark if (arl->arl_needs_attach) { 1419bd670b35SErik Nordmark arp_dlpi_send(arl, attach_mp); 1420bd670b35SErik Nordmark } 1421bd670b35SErik Nordmark arl->arl_unbind_mp = unbind_mp; 1422bd670b35SErik Nordmark 1423bd670b35SErik Nordmark arl->arl_state_flags |= ARL_LL_BIND_PENDING; 1424bd670b35SErik Nordmark arp_dlpi_send(arl, bind_mp); 1425bd670b35SErik Nordmark arl_refrele(arl); 1426bd670b35SErik Nordmark return (EINPROGRESS); 1427bd670b35SErik Nordmark 1428bd670b35SErik Nordmark bad: 1429bd670b35SErik Nordmark freemsg(attach_mp); 1430bd670b35SErik Nordmark freemsg(bind_mp); 1431bd670b35SErik Nordmark freemsg(unbind_mp); 1432bd670b35SErik Nordmark arl_refrele(arl); 1433bd670b35SErik Nordmark return (ENOMEM); 1434bd670b35SErik Nordmark } 1435bd670b35SErik Nordmark 1436bd670b35SErik Nordmark /* 1437bd670b35SErik Nordmark * consumes/frees mp 1438bd670b35SErik Nordmark */ 1439bd670b35SErik Nordmark static void 1440bd670b35SErik Nordmark arp_notify(in_addr_t src, mblk_t *mp, uint32_t arcn_code, 1441bd670b35SErik Nordmark ip_recv_attr_t *ira, ncec_t *ncec) 1442bd670b35SErik Nordmark { 1443bd670b35SErik Nordmark char hbuf[MAC_STR_LEN]; 1444bd670b35SErik Nordmark char sbuf[INET_ADDRSTRLEN]; 1445bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 1446bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 1447bd670b35SErik Nordmark arh_t *arh = (arh_t *)mp->b_rptr; 1448bd670b35SErik Nordmark 1449bd670b35SErik Nordmark switch (arcn_code) { 1450bd670b35SErik Nordmark case AR_CN_BOGON: 1451bd670b35SErik Nordmark /* 1452bd670b35SErik Nordmark * Someone is sending ARP packets with a source protocol 1453bd670b35SErik Nordmark * address that we have published and for which we believe our 1454bd670b35SErik Nordmark * entry is authoritative and verified to be unique on 1455bd670b35SErik Nordmark * the network. 1456bd670b35SErik Nordmark * 1457bd670b35SErik Nordmark * arp_process_packet() sends AR_CN_FAILED for the case when 1458bd670b35SErik Nordmark * a DAD probe is received and the hardware address of a 1459bd670b35SErik Nordmark * non-authoritative entry has changed. Thus, AR_CN_BOGON 1460bd670b35SErik Nordmark * indicates a real conflict, and we have to do resolution. 1461bd670b35SErik Nordmark * 1462bd670b35SErik Nordmark * We back away quickly from the address if it's from DHCP or 1463bd670b35SErik Nordmark * otherwise temporary and hasn't been used recently (or at 1464bd670b35SErik Nordmark * all). We'd like to include "deprecated" addresses here as 1465bd670b35SErik Nordmark * well (as there's no real reason to defend something we're 1466bd670b35SErik Nordmark * discarding), but IPMP "reuses" this flag to mean something 1467bd670b35SErik Nordmark * other than the standard meaning. 1468bd670b35SErik Nordmark */ 1469bd670b35SErik Nordmark if (ip_nce_conflict(mp, ira, ncec)) { 1470bd670b35SErik Nordmark (void) mac_colon_addr((uint8_t *)(arh + 1), 1471bd670b35SErik Nordmark arh->arh_hlen, hbuf, sizeof (hbuf)); 1472bd670b35SErik Nordmark (void) ip_dot_addr(src, sbuf); 1473bd670b35SErik Nordmark cmn_err(CE_WARN, 1474bd670b35SErik Nordmark "proxy ARP problem? Node '%s' is using %s on %s", 1475bd670b35SErik Nordmark hbuf, sbuf, ill->ill_name); 1476bd670b35SErik Nordmark if (!arp_no_defense) 1477bd670b35SErik Nordmark (void) arp_announce(ncec); 1478bd670b35SErik Nordmark /* 1479bd670b35SErik Nordmark * ncec_last_time_defended has been adjusted in 1480bd670b35SErik Nordmark * ip_nce_conflict. 1481bd670b35SErik Nordmark */ 1482bd670b35SErik Nordmark } else { 1483bd670b35SErik Nordmark ncec_delete(ncec); 1484bd670b35SErik Nordmark } 1485bd670b35SErik Nordmark freemsg(mp); 1486bd670b35SErik Nordmark break; 1487bd670b35SErik Nordmark case AR_CN_ANNOUNCE: { 1488bd670b35SErik Nordmark nce_hw_map_t hwm; 1489bd670b35SErik Nordmark /* 1490bd670b35SErik Nordmark * ARP gives us a copy of any packet where it thinks 1491bd670b35SErik Nordmark * the address has changed, so that we can update our 1492bd670b35SErik Nordmark * caches. We're responsible for caching known answers 1493bd670b35SErik Nordmark * in the current design. We check whether the 1494bd670b35SErik Nordmark * hardware address really has changed in all of our 1495bd670b35SErik Nordmark * entries that have cached this mapping, and if so, we 1496bd670b35SErik Nordmark * blow them away. This way we will immediately pick 1497bd670b35SErik Nordmark * up the rare case of a host changing hardware 1498bd670b35SErik Nordmark * address. 1499bd670b35SErik Nordmark */ 1500bd670b35SErik Nordmark if (src == 0) { 1501bd670b35SErik Nordmark freemsg(mp); 1502bd670b35SErik Nordmark break; 1503bd670b35SErik Nordmark } 1504bd670b35SErik Nordmark hwm.hwm_addr = src; 1505bd670b35SErik Nordmark hwm.hwm_hwlen = arh->arh_hlen; 1506bd670b35SErik Nordmark hwm.hwm_hwaddr = (uchar_t *)(arh + 1); 1507bd670b35SErik Nordmark hwm.hwm_flags = 0; 1508bd670b35SErik Nordmark ncec_walk_common(ipst->ips_ndp4, NULL, 1509bd670b35SErik Nordmark (pfi_t)nce_update_hw_changed, &hwm, B_TRUE); 1510bd670b35SErik Nordmark freemsg(mp); 1511bd670b35SErik Nordmark break; 1512bd670b35SErik Nordmark } 1513bd670b35SErik Nordmark case AR_CN_FAILED: 1514bd670b35SErik Nordmark if (arp_no_defense) { 1515bd670b35SErik Nordmark (void) mac_colon_addr((uint8_t *)(arh + 1), 1516bd670b35SErik Nordmark arh->arh_hlen, hbuf, sizeof (hbuf)); 1517bd670b35SErik Nordmark (void) ip_dot_addr(src, sbuf); 1518bd670b35SErik Nordmark 1519bd670b35SErik Nordmark cmn_err(CE_WARN, 1520bd670b35SErik Nordmark "node %s is using our IP address %s on %s", 1521bd670b35SErik Nordmark hbuf, sbuf, ill->ill_name); 1522bd670b35SErik Nordmark freemsg(mp); 1523bd670b35SErik Nordmark break; 1524bd670b35SErik Nordmark } 1525bd670b35SErik Nordmark /* 1526bd670b35SErik Nordmark * mp will be freed by arp_excl. 1527bd670b35SErik Nordmark */ 1528bd670b35SErik Nordmark ill_refhold(ill); 1529bd670b35SErik Nordmark qwriter_ip(ill, ill->ill_rq, mp, arp_excl, NEW_OP, B_FALSE); 1530bd670b35SErik Nordmark return; 1531bd670b35SErik Nordmark default: 1532bd670b35SErik Nordmark ASSERT(0); 1533bd670b35SErik Nordmark freemsg(mp); 1534bd670b35SErik Nordmark break; 1535bd670b35SErik Nordmark } 1536bd670b35SErik Nordmark } 1537bd670b35SErik Nordmark 1538bd670b35SErik Nordmark /* 1539bd670b35SErik Nordmark * arp_output is called to transmit an ARP Request or Response. The mapping 1540bd670b35SErik Nordmark * to RFC 826 variables is: 1541bd670b35SErik Nordmark * haddr1 == ar$sha 1542bd670b35SErik Nordmark * paddr1 == ar$spa 1543bd670b35SErik Nordmark * haddr2 == ar$tha 1544bd670b35SErik Nordmark * paddr2 == ar$tpa 1545bd670b35SErik Nordmark * The ARP frame is sent to the ether_dst in dst_lladdr. 1546bd670b35SErik Nordmark */ 1547bd670b35SErik Nordmark static int 1548bd670b35SErik Nordmark arp_output(ill_t *ill, uint32_t operation, 1549bd670b35SErik Nordmark const uchar_t *haddr1, const uchar_t *paddr1, const uchar_t *haddr2, 1550bd670b35SErik Nordmark const uchar_t *paddr2, uchar_t *dst_lladdr) 1551bd670b35SErik Nordmark { 1552bd670b35SErik Nordmark arh_t *arh; 1553bd670b35SErik Nordmark uint8_t *cp; 1554bd670b35SErik Nordmark uint_t hlen; 1555bd670b35SErik Nordmark uint32_t plen = IPV4_ADDR_LEN; /* ar$pln from RFC 826 */ 1556bd670b35SErik Nordmark uint32_t proto = IP_ARP_PROTO_TYPE; 1557bd670b35SErik Nordmark mblk_t *mp; 1558bd670b35SErik Nordmark arl_t *arl; 1559bd670b35SErik Nordmark 1560bd670b35SErik Nordmark ASSERT(dst_lladdr != NULL); 1561bd670b35SErik Nordmark hlen = ill->ill_phys_addr_length; /* ar$hln from RFC 826 */ 1562bd670b35SErik Nordmark mp = ill_dlur_gen(dst_lladdr, hlen, ETHERTYPE_ARP, ill->ill_sap_length); 1563bd670b35SErik Nordmark 1564bd670b35SErik Nordmark if (mp == NULL) 1565bd670b35SErik Nordmark return (ENOMEM); 1566bd670b35SErik Nordmark 1567bd670b35SErik Nordmark /* IFF_NOARP flag is set or link down: do not send arp messages */ 1568bd670b35SErik Nordmark if ((ill->ill_flags & ILLF_NOARP) || !ill->ill_dl_up) { 1569bd670b35SErik Nordmark freemsg(mp); 1570bd670b35SErik Nordmark return (ENXIO); 1571bd670b35SErik Nordmark } 1572bd670b35SErik Nordmark 1573bd670b35SErik Nordmark mp->b_cont = allocb(AR_LL_HDR_SLACK + ARH_FIXED_LEN + (hlen * 4) + 1574bd670b35SErik Nordmark plen + plen, BPRI_MED); 1575bd670b35SErik Nordmark if (mp->b_cont == NULL) { 1576bd670b35SErik Nordmark freeb(mp); 1577bd670b35SErik Nordmark return (ENOMEM); 1578bd670b35SErik Nordmark } 1579bd670b35SErik Nordmark 1580bd670b35SErik Nordmark /* Fill in the ARP header. */ 1581bd670b35SErik Nordmark cp = mp->b_cont->b_rptr + (AR_LL_HDR_SLACK + hlen + hlen); 1582bd670b35SErik Nordmark mp->b_cont->b_rptr = cp; 1583bd670b35SErik Nordmark arh = (arh_t *)cp; 1584bd670b35SErik Nordmark U16_TO_BE16(arp_hw_type(ill->ill_mactype), arh->arh_hardware); 1585bd670b35SErik Nordmark U16_TO_BE16(proto, arh->arh_proto); 1586bd670b35SErik Nordmark arh->arh_hlen = (uint8_t)hlen; 1587bd670b35SErik Nordmark arh->arh_plen = (uint8_t)plen; 1588bd670b35SErik Nordmark U16_TO_BE16(operation, arh->arh_operation); 1589bd670b35SErik Nordmark cp += ARH_FIXED_LEN; 1590bd670b35SErik Nordmark bcopy(haddr1, cp, hlen); 1591bd670b35SErik Nordmark cp += hlen; 1592bd670b35SErik Nordmark if (paddr1 == NULL) 1593bd670b35SErik Nordmark bzero(cp, plen); 1594bd670b35SErik Nordmark else 1595bd670b35SErik Nordmark bcopy(paddr1, cp, plen); 1596bd670b35SErik Nordmark cp += plen; 1597bd670b35SErik Nordmark if (haddr2 == NULL) 1598bd670b35SErik Nordmark bzero(cp, hlen); 1599bd670b35SErik Nordmark else 1600bd670b35SErik Nordmark bcopy(haddr2, cp, hlen); 1601bd670b35SErik Nordmark cp += hlen; 1602bd670b35SErik Nordmark bcopy(paddr2, cp, plen); 1603bd670b35SErik Nordmark cp += plen; 1604bd670b35SErik Nordmark mp->b_cont->b_wptr = cp; 1605bd670b35SErik Nordmark 1606bd670b35SErik Nordmark DTRACE_PROBE3(arp__physical__out__start, 1607bd670b35SErik Nordmark ill_t *, ill, arh_t *, arh, mblk_t *, mp); 1608bd670b35SErik Nordmark ARP_HOOK_OUT(ill->ill_ipst->ips_arp_physical_out_event, 1609bd670b35SErik Nordmark ill->ill_ipst->ips_arp_physical_out, 1610bd670b35SErik Nordmark ill->ill_phyint->phyint_ifindex, arh, mp, mp->b_cont, 1611bd670b35SErik Nordmark ill->ill_ipst); 1612bd670b35SErik Nordmark DTRACE_PROBE1(arp__physical__out__end, mblk_t *, mp); 1613bd670b35SErik Nordmark if (mp == NULL) 1614bd670b35SErik Nordmark return (0); 1615bd670b35SErik Nordmark 1616bd670b35SErik Nordmark /* Ship it out. */ 1617bd670b35SErik Nordmark arl = ill_to_arl(ill); 1618bd670b35SErik Nordmark if (arl == NULL) { 1619bd670b35SErik Nordmark freemsg(mp); 1620bd670b35SErik Nordmark return (0); 1621bd670b35SErik Nordmark } 1622bd670b35SErik Nordmark if (canputnext(arl->arl_wq)) 1623bd670b35SErik Nordmark putnext(arl->arl_wq, mp); 1624bd670b35SErik Nordmark else 1625bd670b35SErik Nordmark freemsg(mp); 1626bd670b35SErik Nordmark arl_refrele(arl); 1627bd670b35SErik Nordmark return (0); 1628bd670b35SErik Nordmark } 1629bd670b35SErik Nordmark 1630bd670b35SErik Nordmark /* 1631bd670b35SErik Nordmark * Process resolve requests. 1632bd670b35SErik Nordmark * If we are not yet reachable then we check and decrease ncec_rcnt; otherwise 1633bd670b35SErik Nordmark * we leave it alone (the caller will check and manage ncec_pcnt in those 1634bd670b35SErik Nordmark * cases.) 1635bd670b35SErik Nordmark */ 1636bd670b35SErik Nordmark int 1637bd670b35SErik Nordmark arp_request(ncec_t *ncec, in_addr_t sender, ill_t *ill) 1638bd670b35SErik Nordmark { 1639bd670b35SErik Nordmark int err; 1640bd670b35SErik Nordmark const uchar_t *target_hwaddr; 1641bd670b35SErik Nordmark struct in_addr nce_paddr; 1642bd670b35SErik Nordmark uchar_t *dst_lladdr; 1643bd670b35SErik Nordmark boolean_t use_rcnt = !NCE_ISREACHABLE(ncec); 1644bd670b35SErik Nordmark 1645bd670b35SErik Nordmark ASSERT(MUTEX_HELD(&ncec->ncec_lock)); 1646bd670b35SErik Nordmark ASSERT(!IS_IPMP(ill)); 1647bd670b35SErik Nordmark 1648bd670b35SErik Nordmark if (use_rcnt && ncec->ncec_rcnt == 0) { 1649bd670b35SErik Nordmark /* not allowed any more retransmits. */ 1650bd670b35SErik Nordmark return (0); 1651bd670b35SErik Nordmark } 1652bd670b35SErik Nordmark 1653bd670b35SErik Nordmark if ((ill->ill_flags & ILLF_NOARP) != 0) 1654bd670b35SErik Nordmark return (0); 1655bd670b35SErik Nordmark 1656bd670b35SErik Nordmark IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &nce_paddr); 1657bd670b35SErik Nordmark 1658bd670b35SErik Nordmark target_hwaddr = 1659bd670b35SErik Nordmark ill->ill_bcast_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill); 1660bd670b35SErik Nordmark 1661bd670b35SErik Nordmark if (NCE_ISREACHABLE(ncec)) { 1662bd670b35SErik Nordmark dst_lladdr = ncec->ncec_lladdr; 1663bd670b35SErik Nordmark } else { 1664bd670b35SErik Nordmark dst_lladdr = ill->ill_bcast_mp->b_rptr + 1665bd670b35SErik Nordmark NCE_LL_ADDR_OFFSET(ill); 1666bd670b35SErik Nordmark } 1667bd670b35SErik Nordmark 1668bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 1669bd670b35SErik Nordmark err = arp_output(ill, ARP_REQUEST, 1670bd670b35SErik Nordmark ill->ill_phys_addr, (uchar_t *)&sender, target_hwaddr, 1671bd670b35SErik Nordmark (uchar_t *)&nce_paddr, dst_lladdr); 1672bd670b35SErik Nordmark mutex_enter(&ncec->ncec_lock); 1673bd670b35SErik Nordmark 1674bd670b35SErik Nordmark if (err != 0) { 1675bd670b35SErik Nordmark /* 1676bd670b35SErik Nordmark * Some transient error such as ENOMEM or a down link was 1677bd670b35SErik Nordmark * encountered. If the link has been taken down permanently, 1678bd670b35SErik Nordmark * the ncec will eventually be cleaned up (ipif_down_tail() 1679bd670b35SErik Nordmark * will call ipif_nce_down() and flush the ncec), to terminate 1680bd670b35SErik Nordmark * recurring attempts to send ARP requests. In all other cases, 1681bd670b35SErik Nordmark * allow the caller another chance at success next time. 1682bd670b35SErik Nordmark */ 1683bd670b35SErik Nordmark return (ncec->ncec_ill->ill_reachable_retrans_time); 1684bd670b35SErik Nordmark } 1685bd670b35SErik Nordmark 1686bd670b35SErik Nordmark if (use_rcnt) 1687bd670b35SErik Nordmark ncec->ncec_rcnt--; 1688bd670b35SErik Nordmark 1689bd670b35SErik Nordmark return (ncec->ncec_ill->ill_reachable_retrans_time); 1690bd670b35SErik Nordmark } 1691bd670b35SErik Nordmark 1692bd670b35SErik Nordmark /* return B_TRUE if dropped */ 1693bd670b35SErik Nordmark boolean_t 1694bd670b35SErik Nordmark arp_announce(ncec_t *ncec) 1695bd670b35SErik Nordmark { 1696bd670b35SErik Nordmark ill_t *ill; 1697bd670b35SErik Nordmark int err; 1698bd670b35SErik Nordmark uchar_t *sphys_addr, *bcast_addr; 1699bd670b35SErik Nordmark struct in_addr ncec_addr; 1700bd670b35SErik Nordmark boolean_t need_refrele = B_FALSE; 1701bd670b35SErik Nordmark 1702bd670b35SErik Nordmark ASSERT((ncec->ncec_flags & NCE_F_BCAST) == 0); 1703bd670b35SErik Nordmark ASSERT((ncec->ncec_flags & NCE_F_MCAST) == 0); 1704bd670b35SErik Nordmark 1705bd670b35SErik Nordmark if (IS_IPMP(ncec->ncec_ill)) { 1706bd670b35SErik Nordmark /* sent on the cast_ill */ 17071f19738eSmeem ill = ipmp_ill_hold_xmit_ill(ncec->ncec_ill, B_FALSE); 1708bd670b35SErik Nordmark if (ill == NULL) 1709bd670b35SErik Nordmark return (B_TRUE); 1710bd670b35SErik Nordmark need_refrele = B_TRUE; 1711bd670b35SErik Nordmark } else { 1712bd670b35SErik Nordmark ill = ncec->ncec_ill; 1713bd670b35SErik Nordmark } 1714bd670b35SErik Nordmark 1715bd670b35SErik Nordmark /* 1716bd670b35SErik Nordmark * broadcast an announce to ill_bcast address. 1717bd670b35SErik Nordmark */ 1718bd670b35SErik Nordmark IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &ncec_addr); 1719bd670b35SErik Nordmark 1720bd670b35SErik Nordmark sphys_addr = ncec->ncec_lladdr; 1721bd670b35SErik Nordmark bcast_addr = ill->ill_bcast_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill); 1722bd670b35SErik Nordmark 1723bd670b35SErik Nordmark err = arp_output(ill, ARP_REQUEST, 1724bd670b35SErik Nordmark sphys_addr, (uchar_t *)&ncec_addr, bcast_addr, 1725bd670b35SErik Nordmark (uchar_t *)&ncec_addr, bcast_addr); 1726bd670b35SErik Nordmark 1727bd670b35SErik Nordmark if (need_refrele) 1728bd670b35SErik Nordmark ill_refrele(ill); 1729bd670b35SErik Nordmark return (err != 0); 1730bd670b35SErik Nordmark } 1731bd670b35SErik Nordmark 1732bd670b35SErik Nordmark /* return B_TRUE if dropped */ 1733bd670b35SErik Nordmark boolean_t 1734bd670b35SErik Nordmark arp_probe(ncec_t *ncec) 1735bd670b35SErik Nordmark { 1736bd670b35SErik Nordmark ill_t *ill; 1737bd670b35SErik Nordmark int err; 1738bd670b35SErik Nordmark struct in_addr ncec_addr; 1739bd670b35SErik Nordmark uchar_t *sphys_addr, *dst_lladdr; 1740bd670b35SErik Nordmark 1741bd670b35SErik Nordmark if (IS_IPMP(ncec->ncec_ill)) { 17421f19738eSmeem ill = ipmp_ill_hold_xmit_ill(ncec->ncec_ill, B_FALSE); 1743bd670b35SErik Nordmark if (ill == NULL) 1744bd670b35SErik Nordmark return (B_TRUE); 1745bd670b35SErik Nordmark } else { 1746bd670b35SErik Nordmark ill = ncec->ncec_ill; 1747bd670b35SErik Nordmark } 1748bd670b35SErik Nordmark 1749bd670b35SErik Nordmark IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &ncec_addr); 1750bd670b35SErik Nordmark 1751bd670b35SErik Nordmark sphys_addr = ncec->ncec_lladdr; 1752bd670b35SErik Nordmark dst_lladdr = ill->ill_bcast_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill); 1753bd670b35SErik Nordmark err = arp_output(ill, ARP_REQUEST, 1754bd670b35SErik Nordmark sphys_addr, NULL, NULL, (uchar_t *)&ncec_addr, dst_lladdr); 1755bd670b35SErik Nordmark 1756bd670b35SErik Nordmark if (IS_IPMP(ncec->ncec_ill)) 1757bd670b35SErik Nordmark ill_refrele(ill); 1758bd670b35SErik Nordmark return (err != 0); 1759bd670b35SErik Nordmark } 1760bd670b35SErik Nordmark 1761bd670b35SErik Nordmark static mblk_t * 1762bd670b35SErik Nordmark arl_unbind(arl_t *arl) 1763bd670b35SErik Nordmark { 1764bd670b35SErik Nordmark mblk_t *mp; 1765bd670b35SErik Nordmark 1766bd670b35SErik Nordmark if ((mp = arl->arl_unbind_mp) != NULL) { 1767bd670b35SErik Nordmark arl->arl_unbind_mp = NULL; 1768bd670b35SErik Nordmark arl->arl_state_flags |= ARL_DL_UNBIND_IN_PROGRESS; 1769bd670b35SErik Nordmark } 1770bd670b35SErik Nordmark return (mp); 1771bd670b35SErik Nordmark } 1772bd670b35SErik Nordmark 1773bd670b35SErik Nordmark int 1774bd670b35SErik Nordmark arp_ll_down(ill_t *ill) 1775bd670b35SErik Nordmark { 1776bd670b35SErik Nordmark arl_t *arl; 1777bd670b35SErik Nordmark mblk_t *unbind_mp; 1778bd670b35SErik Nordmark int err = 0; 1779bd670b35SErik Nordmark boolean_t replumb = (ill->ill_replumbing == 1); 1780bd670b35SErik Nordmark 1781bd670b35SErik Nordmark DTRACE_PROBE2(ill__downup, char *, "arp_ll_down", ill_t *, ill); 1782bd670b35SErik Nordmark if ((arl = ill_to_arl(ill)) == NULL) 1783bd670b35SErik Nordmark return (ENXIO); 1784bd670b35SErik Nordmark DTRACE_PROBE2(arl__downup, char *, "arp_ll_down", arl_t *, arl); 1785bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 1786bd670b35SErik Nordmark unbind_mp = arl_unbind(arl); 1787bd670b35SErik Nordmark if (unbind_mp != NULL) { 1788bd670b35SErik Nordmark ASSERT(arl->arl_state_flags & ARL_DL_UNBIND_IN_PROGRESS); 1789bd670b35SErik Nordmark DTRACE_PROBE2(arp__unbinding, mblk_t *, unbind_mp, 1790bd670b35SErik Nordmark arl_t *, arl); 1791bd670b35SErik Nordmark err = EINPROGRESS; 1792bd670b35SErik Nordmark if (replumb) 1793bd670b35SErik Nordmark arl->arl_state_flags |= ARL_LL_REPLUMBING; 1794bd670b35SErik Nordmark } 1795bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 1796bd670b35SErik Nordmark if (unbind_mp != NULL) 1797bd670b35SErik Nordmark arp_dlpi_send(arl, unbind_mp); 1798bd670b35SErik Nordmark arl_refrele(arl); 1799bd670b35SErik Nordmark return (err); 1800bd670b35SErik Nordmark } 1801bd670b35SErik Nordmark 1802bd670b35SErik Nordmark /* ARGSUSED */ 1803bd670b35SErik Nordmark int 1804bd670b35SErik Nordmark arp_close(queue_t *q, int flags) 1805bd670b35SErik Nordmark { 1806bd670b35SErik Nordmark if (WR(q)->q_next != NULL) { 1807bd670b35SErik Nordmark /* This is a module close */ 1808bd670b35SErik Nordmark return (arp_modclose(q->q_ptr)); 1809bd670b35SErik Nordmark } 1810bd670b35SErik Nordmark qprocsoff(q); 1811bd670b35SErik Nordmark q->q_ptr = WR(q)->q_ptr = NULL; 1812bd670b35SErik Nordmark return (0); 1813bd670b35SErik Nordmark } 1814bd670b35SErik Nordmark 1815bd670b35SErik Nordmark static int 1816bd670b35SErik Nordmark arp_modclose(arl_t *arl) 1817bd670b35SErik Nordmark { 1818bd670b35SErik Nordmark arl_ill_common_t *ai = arl->arl_common; 1819bd670b35SErik Nordmark ill_t *ill; 1820bd670b35SErik Nordmark queue_t *q = arl->arl_rq; 1821bd670b35SErik Nordmark mblk_t *mp, *nextmp; 1822bd670b35SErik Nordmark ipsq_t *ipsq = NULL; 1823bd670b35SErik Nordmark 1824bd670b35SErik Nordmark ill = arl_to_ill(arl); 1825bd670b35SErik Nordmark if (ill != NULL) { 1826bd670b35SErik Nordmark if (!ill_waiter_inc(ill)) { 1827bd670b35SErik Nordmark ill_refrele(ill); 1828bd670b35SErik Nordmark } else { 1829bd670b35SErik Nordmark ill_refrele(ill); 1830bd670b35SErik Nordmark if (ipsq_enter(ill, B_FALSE, NEW_OP)) 1831bd670b35SErik Nordmark ipsq = ill->ill_phyint->phyint_ipsq; 1832bd670b35SErik Nordmark ill_waiter_dcr(ill); 1833bd670b35SErik Nordmark } 1834bd670b35SErik Nordmark if (ipsq == NULL) { 1835bd670b35SErik Nordmark /* 1836bd670b35SErik Nordmark * could not enter the ipsq because ill is already 1837bd670b35SErik Nordmark * marked CONDEMNED. 1838bd670b35SErik Nordmark */ 1839bd670b35SErik Nordmark ill = NULL; 1840bd670b35SErik Nordmark } 1841bd670b35SErik Nordmark } 1842bd670b35SErik Nordmark if (ai != NULL && ipsq == NULL) { 1843bd670b35SErik Nordmark /* 1844bd670b35SErik Nordmark * Either we did not get an ill because it was marked CONDEMNED 1845bd670b35SErik Nordmark * or we could not enter the ipsq because it was unplumbing. 1846bd670b35SErik Nordmark * In both cases, wait for the ill to complete ip_modclose(). 1847bd670b35SErik Nordmark * 1848bd670b35SErik Nordmark * If the arp_modclose happened even before SLIFNAME, the ai 1849bd670b35SErik Nordmark * itself would be NULL, in which case we can complete the close 1850bd670b35SErik Nordmark * without waiting. 1851bd670b35SErik Nordmark */ 1852bd670b35SErik Nordmark mutex_enter(&ai->ai_lock); 1853bd670b35SErik Nordmark while (ai->ai_ill != NULL) 1854bd670b35SErik Nordmark cv_wait(&ai->ai_ill_unplumb_done, &ai->ai_lock); 1855bd670b35SErik Nordmark mutex_exit(&ai->ai_lock); 1856bd670b35SErik Nordmark } 1857bd670b35SErik Nordmark ASSERT(ill == NULL || IAM_WRITER_ILL(ill)); 1858bd670b35SErik Nordmark 1859bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 1860bd670b35SErik Nordmark /* 1861bd670b35SErik Nordmark * If the ill had completed unplumbing before arp_modclose(), there 1862bd670b35SErik Nordmark * would be no ill (and therefore, no ipsq) to serialize arp_modclose() 1863bd670b35SErik Nordmark * so that we need to explicitly check for ARL_CONDEMNED and back off 1864bd670b35SErik Nordmark * if it is set. 1865bd670b35SErik Nordmark */ 1866bd670b35SErik Nordmark if ((arl->arl_state_flags & ARL_CONDEMNED) != 0) { 1867bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 1868bd670b35SErik Nordmark ASSERT(ipsq == NULL); 1869bd670b35SErik Nordmark return (0); 1870bd670b35SErik Nordmark } 1871bd670b35SErik Nordmark arl->arl_state_flags |= ARL_CONDEMNED; 1872bd670b35SErik Nordmark 1873bd670b35SErik Nordmark /* 1874bd670b35SErik Nordmark * send out all pending dlpi messages, don't wait for the ack (which 1875bd670b35SErik Nordmark * will be ignored in arp_rput when CONDEMNED is set) 1876bd670b35SErik Nordmark * 1877bd670b35SErik Nordmark * We have to check for pending DL_UNBIND_REQ because, in the case 1878bd670b35SErik Nordmark * that ip_modclose() executed before arp_modclose(), the call to 1879bd670b35SErik Nordmark * ill_delete_tail->ipif_arp_down() would have triggered a 1880bd670b35SErik Nordmark * DL_UNBIND_REQ. When arp_modclose() executes ipsq_enter() will fail 1881bd670b35SErik Nordmark * (since ip_modclose() is in the ipsq) but the DL_UNBIND_ACK may not 1882bd670b35SErik Nordmark * have been processed yet. In this scenario, we cannot reset 1883bd670b35SErik Nordmark * arl_dlpi_pending, because the setting/clearing of arl_state_flags 1884bd670b35SErik Nordmark * related to unbind, and the associated cv_waits must be allowed to 1885bd670b35SErik Nordmark * continue. 1886bd670b35SErik Nordmark */ 1887bd670b35SErik Nordmark if (arl->arl_dlpi_pending != DL_UNBIND_REQ) 1888bd670b35SErik Nordmark arl->arl_dlpi_pending = DL_PRIM_INVAL; 1889bd670b35SErik Nordmark mp = arl->arl_dlpi_deferred; 1890bd670b35SErik Nordmark arl->arl_dlpi_deferred = NULL; 1891bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 1892bd670b35SErik Nordmark 1893bd670b35SErik Nordmark for (; mp != NULL; mp = nextmp) { 1894bd670b35SErik Nordmark nextmp = mp->b_next; 1895bd670b35SErik Nordmark mp->b_next = NULL; 1896bd670b35SErik Nordmark putnext(arl->arl_wq, mp); 1897bd670b35SErik Nordmark } 1898bd670b35SErik Nordmark 1899bd670b35SErik Nordmark /* Wait for data paths to quiesce */ 1900bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 1901bd670b35SErik Nordmark while (arl->arl_refcnt != 0) 1902bd670b35SErik Nordmark cv_wait(&arl->arl_cv, &arl->arl_lock); 1903bd670b35SErik Nordmark 1904bd670b35SErik Nordmark /* 1905bd670b35SErik Nordmark * unbind, so that nothing else can come up from driver. 1906bd670b35SErik Nordmark */ 1907bd670b35SErik Nordmark mp = arl_unbind(arl); 1908bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 1909bd670b35SErik Nordmark if (mp != NULL) 1910bd670b35SErik Nordmark arp_dlpi_send(arl, mp); 1911bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 1912bd670b35SErik Nordmark 1913bd670b35SErik Nordmark /* wait for unbind ack */ 1914bd670b35SErik Nordmark while (arl->arl_state_flags & ARL_DL_UNBIND_IN_PROGRESS) 1915bd670b35SErik Nordmark cv_wait(&arl->arl_cv, &arl->arl_lock); 1916bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 1917bd670b35SErik Nordmark 1918bd670b35SErik Nordmark qprocsoff(q); 1919bd670b35SErik Nordmark 1920bd670b35SErik Nordmark if (ill != NULL) { 1921bd670b35SErik Nordmark mutex_enter(&ill->ill_lock); 1922bd670b35SErik Nordmark ill->ill_arl_dlpi_pending = 0; 1923bd670b35SErik Nordmark mutex_exit(&ill->ill_lock); 1924bd670b35SErik Nordmark } 1925bd670b35SErik Nordmark 1926bd670b35SErik Nordmark if (ai != NULL) { 1927bd670b35SErik Nordmark mutex_enter(&ai->ai_lock); 1928bd670b35SErik Nordmark ai->ai_arl = NULL; 1929bd670b35SErik Nordmark if (ai->ai_ill == NULL) { 1930bd670b35SErik Nordmark mutex_destroy(&ai->ai_lock); 1931bd670b35SErik Nordmark kmem_free(ai, sizeof (*ai)); 1932bd670b35SErik Nordmark } else { 1933bd670b35SErik Nordmark mutex_exit(&ai->ai_lock); 1934bd670b35SErik Nordmark } 1935bd670b35SErik Nordmark } 1936bd670b35SErik Nordmark 1937bd670b35SErik Nordmark /* free up the rest */ 1938bd670b35SErik Nordmark arp_mod_close_tail(arl); 1939bd670b35SErik Nordmark 1940bd670b35SErik Nordmark q->q_ptr = WR(q)->q_ptr = NULL; 1941bd670b35SErik Nordmark 1942bd670b35SErik Nordmark if (ipsq != NULL) 1943bd670b35SErik Nordmark ipsq_exit(ipsq); 1944bd670b35SErik Nordmark 1945bd670b35SErik Nordmark return (0); 1946bd670b35SErik Nordmark } 1947bd670b35SErik Nordmark 1948bd670b35SErik Nordmark static void 1949bd670b35SErik Nordmark arp_mod_close_tail(arl_t *arl) 1950bd670b35SErik Nordmark { 1951bd670b35SErik Nordmark ip_stack_t *ipst = arl->arl_ipst; 1952bd670b35SErik Nordmark mblk_t **mpp; 1953bd670b35SErik Nordmark 1954bd670b35SErik Nordmark mutex_enter(&ipst->ips_ip_mi_lock); 1955bd670b35SErik Nordmark mi_close_unlink(&ipst->ips_arp_g_head, (IDP)arl); 1956bd670b35SErik Nordmark mutex_exit(&ipst->ips_ip_mi_lock); 1957bd670b35SErik Nordmark 1958bd670b35SErik Nordmark /* 1959bd670b35SErik Nordmark * credp could be null if the open didn't succeed and ip_modopen 1960bd670b35SErik Nordmark * itself calls ip_close. 1961bd670b35SErik Nordmark */ 1962bd670b35SErik Nordmark if (arl->arl_credp != NULL) 1963bd670b35SErik Nordmark crfree(arl->arl_credp); 1964bd670b35SErik Nordmark 1965bd670b35SErik Nordmark /* Free all retained control messages. */ 1966bd670b35SErik Nordmark mpp = &arl->arl_first_mp_to_free; 1967bd670b35SErik Nordmark do { 1968bd670b35SErik Nordmark while (mpp[0]) { 1969bd670b35SErik Nordmark mblk_t *mp; 1970bd670b35SErik Nordmark mblk_t *mp1; 1971bd670b35SErik Nordmark 1972bd670b35SErik Nordmark mp = mpp[0]; 1973bd670b35SErik Nordmark mpp[0] = mp->b_next; 1974bd670b35SErik Nordmark for (mp1 = mp; mp1 != NULL; mp1 = mp1->b_cont) { 1975bd670b35SErik Nordmark mp1->b_next = NULL; 1976bd670b35SErik Nordmark mp1->b_prev = NULL; 1977bd670b35SErik Nordmark } 1978bd670b35SErik Nordmark freemsg(mp); 1979bd670b35SErik Nordmark } 1980bd670b35SErik Nordmark } while (mpp++ != &arl->arl_last_mp_to_free); 1981bd670b35SErik Nordmark 1982bd670b35SErik Nordmark netstack_rele(ipst->ips_netstack); 1983bd670b35SErik Nordmark mi_free(arl->arl_name); 1984bd670b35SErik Nordmark mi_close_free((IDP)arl); 1985bd670b35SErik Nordmark } 1986bd670b35SErik Nordmark 1987bd670b35SErik Nordmark /* 1988bd670b35SErik Nordmark * DAD failed. Tear down ipifs with the specified srce address. Note that 1989bd670b35SErik Nordmark * tearing down the ipif also meas deleting the ncec through ipif_down, 1990bd670b35SErik Nordmark * so it is not possible to use nce_timer for recovery. Instead we start 1991bd670b35SErik Nordmark * a timer on the ipif. Caller has to free the mp. 1992bd670b35SErik Nordmark */ 1993bd670b35SErik Nordmark void 1994bd670b35SErik Nordmark arp_failure(mblk_t *mp, ip_recv_attr_t *ira) 1995bd670b35SErik Nordmark { 1996bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 1997bd670b35SErik Nordmark 1998bd670b35SErik Nordmark if ((mp = copymsg(mp)) != NULL) { 1999bd670b35SErik Nordmark ill_refhold(ill); 2000bd670b35SErik Nordmark qwriter_ip(ill, ill->ill_rq, mp, arp_excl, NEW_OP, B_FALSE); 2001bd670b35SErik Nordmark } 2002bd670b35SErik Nordmark } 2003bd670b35SErik Nordmark 2004bd670b35SErik Nordmark /* 2005bd670b35SErik Nordmark * This is for exclusive changes due to ARP. Tear down an interface due 2006bd670b35SErik Nordmark * to AR_CN_FAILED and AR_CN_BOGON. 2007bd670b35SErik Nordmark */ 2008bd670b35SErik Nordmark /* ARGSUSED */ 2009bd670b35SErik Nordmark static void 2010bd670b35SErik Nordmark arp_excl(ipsq_t *ipsq, queue_t *rq, mblk_t *mp, void *dummy_arg) 2011bd670b35SErik Nordmark { 2012bd670b35SErik Nordmark ill_t *ill = rq->q_ptr; 2013bd670b35SErik Nordmark arh_t *arh; 2014bd670b35SErik Nordmark ipaddr_t src; 2015bd670b35SErik Nordmark ipif_t *ipif; 2016bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 2017bd670b35SErik Nordmark uchar_t *haddr; 2018bd670b35SErik Nordmark uint_t haddrlen; 2019bd670b35SErik Nordmark 2020bd670b35SErik Nordmark /* first try src = ar$spa */ 2021bd670b35SErik Nordmark arh = (arh_t *)mp->b_rptr; 2022bd670b35SErik Nordmark bcopy((char *)&arh[1] + arh->arh_hlen, &src, IP_ADDR_LEN); 2023bd670b35SErik Nordmark 2024bd670b35SErik Nordmark haddrlen = arh->arh_hlen; 2025bd670b35SErik Nordmark haddr = (uint8_t *)(arh + 1); 2026bd670b35SErik Nordmark 2027bd670b35SErik Nordmark if (haddrlen == ill->ill_phys_addr_length) { 2028bd670b35SErik Nordmark /* 2029bd670b35SErik Nordmark * Ignore conflicts generated by misbehaving switches that 2030bd670b35SErik Nordmark * just reflect our own messages back to us. For IPMP, we may 2031bd670b35SErik Nordmark * see reflections across any ill in the illgrp. 2032bd670b35SErik Nordmark */ 2033bd670b35SErik Nordmark /* For an under ill_grp can change under lock */ 2034bd670b35SErik Nordmark rw_enter(&ipst->ips_ill_g_lock, RW_READER); 2035bd670b35SErik Nordmark if (bcmp(haddr, ill->ill_phys_addr, haddrlen) == 0 || 2036bd670b35SErik Nordmark IS_UNDER_IPMP(ill) && ill->ill_grp != NULL && 2037bd670b35SErik Nordmark ipmp_illgrp_find_ill(ill->ill_grp, haddr, 2038bd670b35SErik Nordmark haddrlen) != NULL) { 2039bd670b35SErik Nordmark rw_exit(&ipst->ips_ill_g_lock); 2040bd670b35SErik Nordmark goto ignore_conflict; 2041bd670b35SErik Nordmark } 2042bd670b35SErik Nordmark rw_exit(&ipst->ips_ill_g_lock); 2043bd670b35SErik Nordmark } 2044bd670b35SErik Nordmark 2045bd670b35SErik Nordmark /* 2046bd670b35SErik Nordmark * Look up the appropriate ipif. 2047bd670b35SErik Nordmark */ 2048bd670b35SErik Nordmark ipif = ipif_lookup_addr(src, ill, ALL_ZONES, ipst); 2049bd670b35SErik Nordmark if (ipif == NULL) 2050bd670b35SErik Nordmark goto ignore_conflict; 2051bd670b35SErik Nordmark 2052bd670b35SErik Nordmark /* Reload the ill to match the ipif */ 2053bd670b35SErik Nordmark ill = ipif->ipif_ill; 2054bd670b35SErik Nordmark 2055bd670b35SErik Nordmark /* If it's already duplicate or ineligible, then don't do anything. */ 2056bd670b35SErik Nordmark if (ipif->ipif_flags & (IPIF_POINTOPOINT|IPIF_DUPLICATE)) { 2057bd670b35SErik Nordmark ipif_refrele(ipif); 2058bd670b35SErik Nordmark goto ignore_conflict; 2059bd670b35SErik Nordmark } 2060bd670b35SErik Nordmark 2061bd670b35SErik Nordmark /* 2062bd670b35SErik Nordmark * If we failed on a recovery probe, then restart the timer to 2063bd670b35SErik Nordmark * try again later. 2064bd670b35SErik Nordmark */ 2065bd670b35SErik Nordmark if (!ipif->ipif_was_dup) { 2066bd670b35SErik Nordmark char hbuf[MAC_STR_LEN]; 2067bd670b35SErik Nordmark char sbuf[INET_ADDRSTRLEN]; 2068bd670b35SErik Nordmark char ibuf[LIFNAMSIZ]; 2069bd670b35SErik Nordmark 2070bd670b35SErik Nordmark (void) mac_colon_addr(haddr, haddrlen, hbuf, sizeof (hbuf)); 2071bd670b35SErik Nordmark (void) ip_dot_addr(src, sbuf); 2072bd670b35SErik Nordmark ipif_get_name(ipif, ibuf, sizeof (ibuf)); 2073bd670b35SErik Nordmark 2074bd670b35SErik Nordmark cmn_err(CE_WARN, "%s has duplicate address %s (in use by %s);" 2075bd670b35SErik Nordmark " disabled", ibuf, sbuf, hbuf); 2076bd670b35SErik Nordmark } 2077bd670b35SErik Nordmark mutex_enter(&ill->ill_lock); 2078bd670b35SErik Nordmark ASSERT(!(ipif->ipif_flags & IPIF_DUPLICATE)); 2079bd670b35SErik Nordmark ipif->ipif_flags |= IPIF_DUPLICATE; 2080bd670b35SErik Nordmark ill->ill_ipif_dup_count++; 2081bd670b35SErik Nordmark mutex_exit(&ill->ill_lock); 2082bd670b35SErik Nordmark (void) ipif_down(ipif, NULL, NULL); 2083bd670b35SErik Nordmark (void) ipif_down_tail(ipif); 2084bd670b35SErik Nordmark mutex_enter(&ill->ill_lock); 2085bd670b35SErik Nordmark if (!(ipif->ipif_flags & (IPIF_DHCPRUNNING|IPIF_TEMPORARY)) && 2086bd670b35SErik Nordmark ill->ill_net_type == IRE_IF_RESOLVER && 2087bd670b35SErik Nordmark !(ipif->ipif_state_flags & IPIF_CONDEMNED) && 2088bd670b35SErik Nordmark ipst->ips_ip_dup_recovery > 0) { 2089bd670b35SErik Nordmark ASSERT(ipif->ipif_recovery_id == 0); 2090bd670b35SErik Nordmark ipif->ipif_recovery_id = timeout(ipif_dup_recovery, 2091bd670b35SErik Nordmark ipif, MSEC_TO_TICK(ipst->ips_ip_dup_recovery)); 2092bd670b35SErik Nordmark } 2093bd670b35SErik Nordmark mutex_exit(&ill->ill_lock); 2094bd670b35SErik Nordmark ipif_refrele(ipif); 2095bd670b35SErik Nordmark 2096bd670b35SErik Nordmark ignore_conflict: 2097bd670b35SErik Nordmark freemsg(mp); 2098bd670b35SErik Nordmark } 2099bd670b35SErik Nordmark 2100bd670b35SErik Nordmark /* 2101bd670b35SErik Nordmark * This is a place for a dtrace hook. 2102bd670b35SErik Nordmark * Note that mp can be either the DL_UNITDATA_IND with a b_cont payload, 2103bd670b35SErik Nordmark * or just the ARP packet payload as an M_DATA. 2104bd670b35SErik Nordmark */ 2105bd670b35SErik Nordmark /* ARGSUSED */ 2106bd670b35SErik Nordmark static void 2107bd670b35SErik Nordmark arp_drop_packet(const char *str, mblk_t *mp, ill_t *ill) 2108bd670b35SErik Nordmark { 2109bd670b35SErik Nordmark freemsg(mp); 2110bd670b35SErik Nordmark } 2111bd670b35SErik Nordmark 2112bd670b35SErik Nordmark static boolean_t 2113bd670b35SErik Nordmark arp_over_driver(queue_t *q) 2114bd670b35SErik Nordmark { 2115bd670b35SErik Nordmark queue_t *qnext = STREAM(q)->sd_wrq->q_next; 2116bd670b35SErik Nordmark 2117bd670b35SErik Nordmark /* 2118bd670b35SErik Nordmark * check if first module below stream head is IP or UDP. 2119bd670b35SErik Nordmark */ 2120bd670b35SErik Nordmark ASSERT(qnext != NULL); 2121bd670b35SErik Nordmark if (strcmp(Q2NAME(qnext), "ip") != 0 && 2122bd670b35SErik Nordmark strcmp(Q2NAME(qnext), "udp") != 0) { 2123bd670b35SErik Nordmark /* 2124bd670b35SErik Nordmark * module below is not ip or udp, so arp has been pushed 2125bd670b35SErik Nordmark * on the driver. 2126bd670b35SErik Nordmark */ 2127bd670b35SErik Nordmark return (B_TRUE); 2128bd670b35SErik Nordmark } 2129bd670b35SErik Nordmark return (B_FALSE); 2130bd670b35SErik Nordmark } 2131bd670b35SErik Nordmark 2132bd670b35SErik Nordmark static int 2133bd670b35SErik Nordmark arp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 2134bd670b35SErik Nordmark { 2135bd670b35SErik Nordmark int err; 2136bd670b35SErik Nordmark 2137bd670b35SErik Nordmark ASSERT(sflag & MODOPEN); 2138bd670b35SErik Nordmark if (!arp_over_driver(q)) { 2139bd670b35SErik Nordmark q->q_qinfo = dummymodinfo.st_rdinit; 2140bd670b35SErik Nordmark WR(q)->q_qinfo = dummymodinfo.st_wrinit; 2141bd670b35SErik Nordmark return ((*dummymodinfo.st_rdinit->qi_qopen)(q, devp, flag, 2142bd670b35SErik Nordmark sflag, credp)); 2143bd670b35SErik Nordmark } 2144bd670b35SErik Nordmark err = arp_modopen(q, devp, flag, sflag, credp); 2145bd670b35SErik Nordmark return (err); 2146bd670b35SErik Nordmark } 2147bd670b35SErik Nordmark 2148bd670b35SErik Nordmark /* 2149bd670b35SErik Nordmark * In most cases we must be a writer on the IP stream before coming to 2150bd670b35SErik Nordmark * arp_dlpi_send(), to serialize DLPI sends to the driver. The exceptions 2151bd670b35SErik Nordmark * when we are not a writer are very early duing initialization (in 2152bd670b35SErik Nordmark * arl_init, before the arl has done a SLIFNAME, so that we don't yet know 2153bd670b35SErik Nordmark * the associated ill) or during arp_mod_close, when we could not enter the 2154bd670b35SErik Nordmark * ipsq because the ill has already unplumbed. 2155bd670b35SErik Nordmark */ 2156bd670b35SErik Nordmark static void 2157bd670b35SErik Nordmark arp_dlpi_send(arl_t *arl, mblk_t *mp) 2158bd670b35SErik Nordmark { 2159bd670b35SErik Nordmark mblk_t **mpp; 2160bd670b35SErik Nordmark t_uscalar_t prim; 2161bd670b35SErik Nordmark arl_ill_common_t *ai; 2162bd670b35SErik Nordmark 2163bd670b35SErik Nordmark ASSERT(DB_TYPE(mp) == M_PROTO || DB_TYPE(mp) == M_PCPROTO); 2164bd670b35SErik Nordmark 2165bd670b35SErik Nordmark #ifdef DEBUG 2166bd670b35SErik Nordmark ai = arl->arl_common; 2167bd670b35SErik Nordmark if (ai != NULL) { 2168bd670b35SErik Nordmark mutex_enter(&ai->ai_lock); 2169bd670b35SErik Nordmark if (ai->ai_ill != NULL) 2170bd670b35SErik Nordmark ASSERT(IAM_WRITER_ILL(ai->ai_ill)); 2171bd670b35SErik Nordmark mutex_exit(&ai->ai_lock); 2172bd670b35SErik Nordmark } 2173bd670b35SErik Nordmark #endif /* DEBUG */ 2174bd670b35SErik Nordmark 2175bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 2176bd670b35SErik Nordmark if (arl->arl_dlpi_pending != DL_PRIM_INVAL) { 2177bd670b35SErik Nordmark /* Must queue message. Tail insertion */ 2178bd670b35SErik Nordmark mpp = &arl->arl_dlpi_deferred; 2179bd670b35SErik Nordmark while (*mpp != NULL) 2180bd670b35SErik Nordmark mpp = &((*mpp)->b_next); 2181bd670b35SErik Nordmark 2182bd670b35SErik Nordmark *mpp = mp; 2183bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 2184bd670b35SErik Nordmark return; 2185bd670b35SErik Nordmark } 2186bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 2187bd670b35SErik Nordmark if ((prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive) 2188bd670b35SErik Nordmark == DL_BIND_REQ) { 2189bd670b35SErik Nordmark ASSERT((arl->arl_state_flags & ARL_DL_UNBIND_IN_PROGRESS) == 0); 2190bd670b35SErik Nordmark } 2191bd670b35SErik Nordmark /* 2192bd670b35SErik Nordmark * No need to take the arl_lock to examine ARL_CONDEMNED at this point 2193bd670b35SErik Nordmark * because the only thread that can see ARL_CONDEMNED here is the 2194bd670b35SErik Nordmark * closing arp_modclose() thread which sets the flag after becoming a 2195bd670b35SErik Nordmark * writer on the ipsq. Threads from IP must have finished and 2196bd670b35SErik Nordmark * cannot be active now. 2197bd670b35SErik Nordmark */ 2198bd670b35SErik Nordmark if (!(arl->arl_state_flags & ARL_CONDEMNED) || 2199bd670b35SErik Nordmark (prim == DL_UNBIND_REQ)) { 2200bd670b35SErik Nordmark if (prim != DL_NOTIFY_CONF) { 2201bd670b35SErik Nordmark ill_t *ill = arl_to_ill(arl); 2202bd670b35SErik Nordmark 2203bd670b35SErik Nordmark arl->arl_dlpi_pending = prim; 2204bd670b35SErik Nordmark if (ill != NULL) { 2205bd670b35SErik Nordmark mutex_enter(&ill->ill_lock); 2206bd670b35SErik Nordmark ill->ill_arl_dlpi_pending = 1; 2207bd670b35SErik Nordmark mutex_exit(&ill->ill_lock); 2208bd670b35SErik Nordmark ill_refrele(ill); 2209bd670b35SErik Nordmark } 2210bd670b35SErik Nordmark } 2211bd670b35SErik Nordmark } 2212bd670b35SErik Nordmark DTRACE_PROBE4(arl__dlpi, char *, "arp_dlpi_send", 2213bd670b35SErik Nordmark char *, dl_primstr(prim), char *, "-", arl_t *, arl); 2214bd670b35SErik Nordmark putnext(arl->arl_wq, mp); 2215bd670b35SErik Nordmark } 2216bd670b35SErik Nordmark 2217bd670b35SErik Nordmark static void 2218bd670b35SErik Nordmark arl_defaults_common(arl_t *arl, mblk_t *mp) 2219bd670b35SErik Nordmark { 2220bd670b35SErik Nordmark dl_info_ack_t *dlia = (dl_info_ack_t *)mp->b_rptr; 2221bd670b35SErik Nordmark /* 2222bd670b35SErik Nordmark * Till the ill is fully up the ill is not globally visible. 2223bd670b35SErik Nordmark * So no need for a lock. 2224bd670b35SErik Nordmark */ 2225bd670b35SErik Nordmark arl->arl_mactype = dlia->dl_mac_type; 2226bd670b35SErik Nordmark arl->arl_sap_length = dlia->dl_sap_length; 2227bd670b35SErik Nordmark 2228bd670b35SErik Nordmark if (!arl->arl_dlpi_style_set) { 2229bd670b35SErik Nordmark if (dlia->dl_provider_style == DL_STYLE2) 2230bd670b35SErik Nordmark arl->arl_needs_attach = 1; 2231bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 2232bd670b35SErik Nordmark ASSERT(arl->arl_dlpi_style_set == 0); 2233bd670b35SErik Nordmark arl->arl_dlpi_style_set = 1; 2234bd670b35SErik Nordmark arl->arl_state_flags &= ~ARL_LL_SUBNET_PENDING; 2235bd670b35SErik Nordmark cv_broadcast(&arl->arl_cv); 2236bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 2237bd670b35SErik Nordmark } 2238bd670b35SErik Nordmark } 2239bd670b35SErik Nordmark 2240bd670b35SErik Nordmark int 2241bd670b35SErik Nordmark arl_init(queue_t *q, arl_t *arl) 2242bd670b35SErik Nordmark { 2243bd670b35SErik Nordmark mblk_t *info_mp; 2244bd670b35SErik Nordmark dl_info_req_t *dlir; 2245bd670b35SErik Nordmark 2246bd670b35SErik Nordmark /* subset of ill_init */ 2247bd670b35SErik Nordmark mutex_init(&arl->arl_lock, NULL, MUTEX_DEFAULT, 0); 2248bd670b35SErik Nordmark 2249bd670b35SErik Nordmark arl->arl_rq = q; 2250bd670b35SErik Nordmark arl->arl_wq = WR(q); 2251bd670b35SErik Nordmark 2252bd670b35SErik Nordmark info_mp = allocb(MAX(sizeof (dl_info_req_t), sizeof (dl_info_ack_t)), 2253bd670b35SErik Nordmark BPRI_HI); 2254bd670b35SErik Nordmark if (info_mp == NULL) 2255bd670b35SErik Nordmark return (ENOMEM); 2256bd670b35SErik Nordmark /* 2257bd670b35SErik Nordmark * allocate sufficient space to contain device name. 2258bd670b35SErik Nordmark */ 2259bd670b35SErik Nordmark arl->arl_name = (char *)(mi_zalloc(2 * LIFNAMSIZ)); 2260bd670b35SErik Nordmark arl->arl_ppa = UINT_MAX; 2261bd670b35SErik Nordmark arl->arl_state_flags |= (ARL_LL_SUBNET_PENDING | ARL_LL_UNBOUND); 2262bd670b35SErik Nordmark 2263bd670b35SErik Nordmark /* Send down the Info Request to the driver. */ 2264bd670b35SErik Nordmark info_mp->b_datap->db_type = M_PCPROTO; 2265bd670b35SErik Nordmark dlir = (dl_info_req_t *)info_mp->b_rptr; 2266bd670b35SErik Nordmark info_mp->b_wptr = (uchar_t *)&dlir[1]; 2267bd670b35SErik Nordmark dlir->dl_primitive = DL_INFO_REQ; 2268bd670b35SErik Nordmark arl->arl_dlpi_pending = DL_PRIM_INVAL; 2269bd670b35SErik Nordmark qprocson(q); 2270bd670b35SErik Nordmark 2271bd670b35SErik Nordmark arp_dlpi_send(arl, info_mp); 2272bd670b35SErik Nordmark return (0); 2273bd670b35SErik Nordmark } 2274bd670b35SErik Nordmark 2275bd670b35SErik Nordmark int 2276bd670b35SErik Nordmark arl_wait_for_info_ack(arl_t *arl) 2277bd670b35SErik Nordmark { 2278bd670b35SErik Nordmark int err; 2279bd670b35SErik Nordmark 2280bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 2281bd670b35SErik Nordmark while (arl->arl_state_flags & ARL_LL_SUBNET_PENDING) { 2282bd670b35SErik Nordmark /* 2283bd670b35SErik Nordmark * Return value of 0 indicates a pending signal. 2284bd670b35SErik Nordmark */ 2285bd670b35SErik Nordmark err = cv_wait_sig(&arl->arl_cv, &arl->arl_lock); 2286bd670b35SErik Nordmark if (err == 0) { 2287bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 2288bd670b35SErik Nordmark return (EINTR); 2289bd670b35SErik Nordmark } 2290bd670b35SErik Nordmark } 2291bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 2292bd670b35SErik Nordmark /* 2293bd670b35SErik Nordmark * ip_rput_other could have set an error in ill_error on 2294bd670b35SErik Nordmark * receipt of M_ERROR. 2295bd670b35SErik Nordmark */ 2296bd670b35SErik Nordmark return (arl->arl_error); 2297bd670b35SErik Nordmark } 2298bd670b35SErik Nordmark 2299bd670b35SErik Nordmark void 2300bd670b35SErik Nordmark arl_set_muxid(ill_t *ill, int muxid) 2301bd670b35SErik Nordmark { 2302bd670b35SErik Nordmark arl_t *arl; 2303bd670b35SErik Nordmark 2304bd670b35SErik Nordmark arl = ill_to_arl(ill); 2305bd670b35SErik Nordmark if (arl != NULL) { 2306bd670b35SErik Nordmark arl->arl_muxid = muxid; 2307bd670b35SErik Nordmark arl_refrele(arl); 2308bd670b35SErik Nordmark } 2309bd670b35SErik Nordmark } 2310bd670b35SErik Nordmark 2311bd670b35SErik Nordmark int 2312bd670b35SErik Nordmark arl_get_muxid(ill_t *ill) 2313bd670b35SErik Nordmark { 2314bd670b35SErik Nordmark arl_t *arl; 2315bd670b35SErik Nordmark int muxid = 0; 2316bd670b35SErik Nordmark 2317bd670b35SErik Nordmark arl = ill_to_arl(ill); 2318bd670b35SErik Nordmark if (arl != NULL) { 2319bd670b35SErik Nordmark muxid = arl->arl_muxid; 2320bd670b35SErik Nordmark arl_refrele(arl); 2321bd670b35SErik Nordmark } 2322bd670b35SErik Nordmark return (muxid); 2323bd670b35SErik Nordmark } 2324bd670b35SErik Nordmark 2325bd670b35SErik Nordmark static int 2326bd670b35SErik Nordmark arp_modopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 2327bd670b35SErik Nordmark { 2328bd670b35SErik Nordmark int err; 2329bd670b35SErik Nordmark zoneid_t zoneid; 2330bd670b35SErik Nordmark netstack_t *ns; 2331bd670b35SErik Nordmark ip_stack_t *ipst; 2332bd670b35SErik Nordmark arl_t *arl = NULL; 2333bd670b35SErik Nordmark 2334bd670b35SErik Nordmark /* 2335bd670b35SErik Nordmark * Prevent unprivileged processes from pushing IP so that 2336bd670b35SErik Nordmark * they can't send raw IP. 2337bd670b35SErik Nordmark */ 2338bd670b35SErik Nordmark if (secpolicy_net_rawaccess(credp) != 0) 2339bd670b35SErik Nordmark return (EPERM); 2340bd670b35SErik Nordmark 2341bd670b35SErik Nordmark ns = netstack_find_by_cred(credp); 2342bd670b35SErik Nordmark ASSERT(ns != NULL); 2343bd670b35SErik Nordmark ipst = ns->netstack_ip; 2344bd670b35SErik Nordmark ASSERT(ipst != NULL); 2345bd670b35SErik Nordmark 2346bd670b35SErik Nordmark /* 2347bd670b35SErik Nordmark * For exclusive stacks we set the zoneid to zero 2348bd670b35SErik Nordmark * to make IP operate as if in the global zone. 2349bd670b35SErik Nordmark */ 2350bd670b35SErik Nordmark if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID) 2351bd670b35SErik Nordmark zoneid = GLOBAL_ZONEID; 2352bd670b35SErik Nordmark else 2353bd670b35SErik Nordmark zoneid = crgetzoneid(credp); 2354bd670b35SErik Nordmark 2355bd670b35SErik Nordmark arl = (arl_t *)mi_open_alloc_sleep(sizeof (arl_t)); 2356bd670b35SErik Nordmark q->q_ptr = WR(q)->q_ptr = arl; 2357bd670b35SErik Nordmark arl->arl_ipst = ipst; 2358bd670b35SErik Nordmark arl->arl_zoneid = zoneid; 2359bd670b35SErik Nordmark err = arl_init(q, arl); 2360bd670b35SErik Nordmark 2361bd670b35SErik Nordmark if (err != 0) { 2362bd670b35SErik Nordmark mi_free(arl->arl_name); 2363bd670b35SErik Nordmark mi_free(arl); 2364bd670b35SErik Nordmark netstack_rele(ipst->ips_netstack); 2365bd670b35SErik Nordmark q->q_ptr = NULL; 2366bd670b35SErik Nordmark WR(q)->q_ptr = NULL; 2367bd670b35SErik Nordmark return (err); 2368bd670b35SErik Nordmark } 2369bd670b35SErik Nordmark 2370bd670b35SErik Nordmark /* 2371bd670b35SErik Nordmark * Wait for the DL_INFO_ACK if a DL_INFO_REQ was sent. 2372bd670b35SErik Nordmark */ 2373bd670b35SErik Nordmark err = arl_wait_for_info_ack(arl); 2374bd670b35SErik Nordmark if (err == 0) 2375bd670b35SErik Nordmark arl->arl_credp = credp; 2376bd670b35SErik Nordmark else 2377bd670b35SErik Nordmark goto fail; 2378bd670b35SErik Nordmark 2379bd670b35SErik Nordmark crhold(credp); 2380bd670b35SErik Nordmark 2381bd670b35SErik Nordmark mutex_enter(&ipst->ips_ip_mi_lock); 2382bd670b35SErik Nordmark err = mi_open_link(&ipst->ips_arp_g_head, (IDP)q->q_ptr, devp, flag, 2383bd670b35SErik Nordmark sflag, credp); 2384bd670b35SErik Nordmark mutex_exit(&ipst->ips_ip_mi_lock); 2385bd670b35SErik Nordmark fail: 2386bd670b35SErik Nordmark if (err) { 2387bd670b35SErik Nordmark (void) arp_close(q, 0); 2388bd670b35SErik Nordmark return (err); 2389bd670b35SErik Nordmark } 2390bd670b35SErik Nordmark return (0); 2391bd670b35SErik Nordmark } 2392bd670b35SErik Nordmark 2393bd670b35SErik Nordmark /* 2394bd670b35SErik Nordmark * Notify any downstream modules (esp softmac and hitbox) of the name 2395bd670b35SErik Nordmark * of this interface using an M_CTL. 2396bd670b35SErik Nordmark */ 2397bd670b35SErik Nordmark static void 2398bd670b35SErik Nordmark arp_ifname_notify(arl_t *arl) 2399bd670b35SErik Nordmark { 2400bd670b35SErik Nordmark mblk_t *mp1, *mp2; 2401bd670b35SErik Nordmark struct iocblk *iocp; 2402bd670b35SErik Nordmark struct lifreq *lifr; 2403bd670b35SErik Nordmark 2404bd670b35SErik Nordmark if ((mp1 = mkiocb(SIOCSLIFNAME)) == NULL) 2405bd670b35SErik Nordmark return; 2406bd670b35SErik Nordmark if ((mp2 = allocb(sizeof (struct lifreq), BPRI_HI)) == NULL) { 2407bd670b35SErik Nordmark freemsg(mp1); 2408bd670b35SErik Nordmark return; 2409bd670b35SErik Nordmark } 2410bd670b35SErik Nordmark 2411bd670b35SErik Nordmark lifr = (struct lifreq *)mp2->b_rptr; 2412bd670b35SErik Nordmark mp2->b_wptr += sizeof (struct lifreq); 2413bd670b35SErik Nordmark bzero(lifr, sizeof (struct lifreq)); 2414bd670b35SErik Nordmark 2415bd670b35SErik Nordmark (void) strncpy(lifr->lifr_name, arl->arl_name, LIFNAMSIZ); 2416bd670b35SErik Nordmark lifr->lifr_ppa = arl->arl_ppa; 2417bd670b35SErik Nordmark lifr->lifr_flags = ILLF_IPV4; 2418bd670b35SErik Nordmark 2419bd670b35SErik Nordmark /* Use M_CTL to avoid confusing anyone else who might be listening. */ 2420bd670b35SErik Nordmark DB_TYPE(mp1) = M_CTL; 2421bd670b35SErik Nordmark mp1->b_cont = mp2; 2422bd670b35SErik Nordmark iocp = (struct iocblk *)mp1->b_rptr; 2423bd670b35SErik Nordmark iocp->ioc_count = msgsize(mp1->b_cont); 2424bd670b35SErik Nordmark DTRACE_PROBE4(arl__dlpi, char *, "arp_ifname_notify", 2425bd670b35SErik Nordmark char *, "SIOCSLIFNAME", char *, "-", arl_t *, arl); 2426bd670b35SErik Nordmark putnext(arl->arl_wq, mp1); 2427bd670b35SErik Nordmark } 2428bd670b35SErik Nordmark 2429bd670b35SErik Nordmark void 2430bd670b35SErik Nordmark arp_send_replumb_conf(ill_t *ill) 2431bd670b35SErik Nordmark { 2432bd670b35SErik Nordmark mblk_t *mp; 2433bd670b35SErik Nordmark arl_t *arl = ill_to_arl(ill); 2434bd670b35SErik Nordmark 2435bd670b35SErik Nordmark if (arl == NULL) 2436bd670b35SErik Nordmark return; 2437bd670b35SErik Nordmark /* 2438bd670b35SErik Nordmark * arl_got_replumb and arl_got_unbind to be cleared after we complete 2439bd670b35SErik Nordmark * arp_cmd_done. 2440bd670b35SErik Nordmark */ 2441bd670b35SErik Nordmark mp = mexchange(NULL, NULL, sizeof (dl_notify_conf_t), M_PROTO, 2442bd670b35SErik Nordmark DL_NOTIFY_CONF); 2443bd670b35SErik Nordmark ((dl_notify_conf_t *)(mp->b_rptr))->dl_notification = 2444bd670b35SErik Nordmark DL_NOTE_REPLUMB_DONE; 2445bd670b35SErik Nordmark arp_dlpi_send(arl, mp); 2446bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 2447bd670b35SErik Nordmark arl->arl_state_flags &= ~ARL_LL_REPLUMBING; 2448bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 2449bd670b35SErik Nordmark arl_refrele(arl); 2450bd670b35SErik Nordmark } 2451bd670b35SErik Nordmark 2452bd670b35SErik Nordmark /* 2453bd670b35SErik Nordmark * The unplumb code paths call arp_unbind_complete() to make sure that it is 2454bd670b35SErik Nordmark * safe to tear down the ill. We wait for DL_UNBIND_ACK to complete, and also 2455bd670b35SErik Nordmark * for the arl_refcnt to fall to one so that, when we return from 2456bd670b35SErik Nordmark * arp_unbind_complete(), we know for certain that there are no threads in 2457bd670b35SErik Nordmark * arp_rput() that might access the arl_ill. 2458bd670b35SErik Nordmark */ 2459bd670b35SErik Nordmark void 2460bd670b35SErik Nordmark arp_unbind_complete(ill_t *ill) 2461bd670b35SErik Nordmark { 2462bd670b35SErik Nordmark arl_t *arl = ill_to_arl(ill); 2463bd670b35SErik Nordmark 2464bd670b35SErik Nordmark if (arl == NULL) 2465bd670b35SErik Nordmark return; 2466bd670b35SErik Nordmark mutex_enter(&arl->arl_lock); 2467bd670b35SErik Nordmark /* 2468bd670b35SErik Nordmark * wait for unbind ack and arl_refcnt to drop to 1. Note that the 2469bd670b35SErik Nordmark * quiescent arl_refcnt for this function is 1 (and not 0) because 2470bd670b35SErik Nordmark * ill_to_arl() will itself return after taking a ref on the arl_t. 2471bd670b35SErik Nordmark */ 2472bd670b35SErik Nordmark while (arl->arl_state_flags & ARL_DL_UNBIND_IN_PROGRESS) 2473bd670b35SErik Nordmark cv_wait(&arl->arl_cv, &arl->arl_lock); 2474bd670b35SErik Nordmark while (arl->arl_refcnt != 1) 2475bd670b35SErik Nordmark cv_wait(&arl->arl_cv, &arl->arl_lock); 2476bd670b35SErik Nordmark mutex_exit(&arl->arl_lock); 2477bd670b35SErik Nordmark arl_refrele(arl); 2478bd670b35SErik Nordmark } 2479