14eaa4710SRishi Srivatsavai /* 24eaa4710SRishi Srivatsavai * CDDL HEADER START 34eaa4710SRishi Srivatsavai * 44eaa4710SRishi Srivatsavai * The contents of this file are subject to the terms of the 54eaa4710SRishi Srivatsavai * Common Development and Distribution License (the "License"). 64eaa4710SRishi Srivatsavai * You may not use this file except in compliance with the License. 74eaa4710SRishi Srivatsavai * 84eaa4710SRishi Srivatsavai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94eaa4710SRishi Srivatsavai * or http://www.opensolaris.org/os/licensing. 104eaa4710SRishi Srivatsavai * See the License for the specific language governing permissions 114eaa4710SRishi Srivatsavai * and limitations under the License. 124eaa4710SRishi Srivatsavai * 134eaa4710SRishi Srivatsavai * When distributing Covered Code, include this CDDL HEADER in each 144eaa4710SRishi Srivatsavai * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154eaa4710SRishi Srivatsavai * If applicable, add the following below this CDDL HEADER, with the 164eaa4710SRishi Srivatsavai * fields enclosed by brackets "[]" replaced with your own identifying 174eaa4710SRishi Srivatsavai * information: Portions Copyright [yyyy] [name of copyright owner] 184eaa4710SRishi Srivatsavai * 194eaa4710SRishi Srivatsavai * CDDL HEADER END 204eaa4710SRishi Srivatsavai */ 214eaa4710SRishi Srivatsavai 224eaa4710SRishi Srivatsavai /* 236f40bf67SRishi Srivatsavai * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 244eaa4710SRishi Srivatsavai * Use is subject to license terms. 254eaa4710SRishi Srivatsavai */ 264eaa4710SRishi Srivatsavai 274eaa4710SRishi Srivatsavai /* 284eaa4710SRishi Srivatsavai * This module supports AF_TRILL sockets and TRILL layer-2 forwarding. 294eaa4710SRishi Srivatsavai */ 304eaa4710SRishi Srivatsavai 314eaa4710SRishi Srivatsavai #include <sys/strsubr.h> 324eaa4710SRishi Srivatsavai #include <sys/socket.h> 334eaa4710SRishi Srivatsavai #include <sys/socketvar.h> 344eaa4710SRishi Srivatsavai #include <sys/modctl.h> 354eaa4710SRishi Srivatsavai #include <sys/cmn_err.h> 364eaa4710SRishi Srivatsavai #include <sys/tihdr.h> 374eaa4710SRishi Srivatsavai #include <sys/strsun.h> 384eaa4710SRishi Srivatsavai #include <sys/policy.h> 394eaa4710SRishi Srivatsavai #include <sys/ethernet.h> 404eaa4710SRishi Srivatsavai #include <sys/vlan.h> 414eaa4710SRishi Srivatsavai #include <net/trill.h> 424eaa4710SRishi Srivatsavai #include <net/if_dl.h> 434eaa4710SRishi Srivatsavai #include <sys/mac.h> 444eaa4710SRishi Srivatsavai #include <sys/mac_client.h> 454eaa4710SRishi Srivatsavai #include <sys/mac_provider.h> 464eaa4710SRishi Srivatsavai #include <sys/mac_client_priv.h> 474eaa4710SRishi Srivatsavai #include <sys/sdt.h> 484eaa4710SRishi Srivatsavai #include <sys/dls.h> 494eaa4710SRishi Srivatsavai #include <sys/sunddi.h> 504eaa4710SRishi Srivatsavai 514eaa4710SRishi Srivatsavai #include "trill_impl.h" 524eaa4710SRishi Srivatsavai 534eaa4710SRishi Srivatsavai static void trill_del_all(trill_inst_t *, boolean_t); 544eaa4710SRishi Srivatsavai static int trill_del_nick(trill_inst_t *, uint16_t, boolean_t); 554eaa4710SRishi Srivatsavai static void trill_stop_recv(trill_sock_t *); 564eaa4710SRishi Srivatsavai static void trill_ctrl_input(trill_sock_t *, mblk_t *, const uint8_t *, 574eaa4710SRishi Srivatsavai uint16_t); 584eaa4710SRishi Srivatsavai static trill_node_t *trill_node_lookup(trill_inst_t *, uint16_t); 594eaa4710SRishi Srivatsavai static void trill_node_unref(trill_inst_t *, trill_node_t *); 604eaa4710SRishi Srivatsavai static void trill_sock_unref(trill_sock_t *); 614eaa4710SRishi Srivatsavai static void trill_kstats_init(trill_sock_t *, const char *); 624eaa4710SRishi Srivatsavai 634eaa4710SRishi Srivatsavai static list_t trill_inst_list; 644eaa4710SRishi Srivatsavai static krwlock_t trill_inst_rwlock; 654eaa4710SRishi Srivatsavai 664eaa4710SRishi Srivatsavai static sock_lower_handle_t trill_create(int, int, int, sock_downcalls_t **, 674eaa4710SRishi Srivatsavai uint_t *, int *, int, cred_t *); 684eaa4710SRishi Srivatsavai 694eaa4710SRishi Srivatsavai static smod_reg_t sinfo = { 704eaa4710SRishi Srivatsavai SOCKMOD_VERSION, 714eaa4710SRishi Srivatsavai "trill", 724eaa4710SRishi Srivatsavai SOCK_UC_VERSION, 734eaa4710SRishi Srivatsavai SOCK_DC_VERSION, 744eaa4710SRishi Srivatsavai trill_create, 754eaa4710SRishi Srivatsavai NULL, 764eaa4710SRishi Srivatsavai }; 774eaa4710SRishi Srivatsavai 784eaa4710SRishi Srivatsavai /* modldrv structure */ 794eaa4710SRishi Srivatsavai static struct modlsockmod sockmod = { 804eaa4710SRishi Srivatsavai &mod_sockmodops, "AF_TRILL socket module", &sinfo 814eaa4710SRishi Srivatsavai }; 824eaa4710SRishi Srivatsavai 834eaa4710SRishi Srivatsavai /* modlinkage structure */ 844eaa4710SRishi Srivatsavai static struct modlinkage ml = { 854eaa4710SRishi Srivatsavai MODREV_1, 864eaa4710SRishi Srivatsavai &sockmod, 874eaa4710SRishi Srivatsavai NULL 884eaa4710SRishi Srivatsavai }; 894eaa4710SRishi Srivatsavai 904eaa4710SRishi Srivatsavai #define VALID_NICK(n) ((n) != RBRIDGE_NICKNAME_NONE && \ 914eaa4710SRishi Srivatsavai (n) != RBRIDGE_NICKNAME_UNUSED) 924eaa4710SRishi Srivatsavai 934eaa4710SRishi Srivatsavai static mblk_t * 944eaa4710SRishi Srivatsavai create_trill_header(trill_sock_t *tsock, mblk_t *mp, const uint8_t *daddr, 954eaa4710SRishi Srivatsavai boolean_t trill_hdr_ok, boolean_t multidest, uint16_t tci, 964eaa4710SRishi Srivatsavai size_t msglen) 974eaa4710SRishi Srivatsavai { 984eaa4710SRishi Srivatsavai int extra_hdr_len; 994eaa4710SRishi Srivatsavai struct ether_vlan_header *ethvlanhdr; 1004eaa4710SRishi Srivatsavai mblk_t *hdr_mp; 1014eaa4710SRishi Srivatsavai uint16_t etype; 1024eaa4710SRishi Srivatsavai 1034eaa4710SRishi Srivatsavai etype = msglen > 0 ? (uint16_t)msglen : ETHERTYPE_TRILL; 1044eaa4710SRishi Srivatsavai 1054eaa4710SRishi Srivatsavai /* When sending on the PVID, we must not give a VLAN ID */ 1064eaa4710SRishi Srivatsavai if (tci == tsock->ts_link->bl_pvid) 1074eaa4710SRishi Srivatsavai tci = TRILL_NO_TCI; 1084eaa4710SRishi Srivatsavai 1094eaa4710SRishi Srivatsavai /* 1104eaa4710SRishi Srivatsavai * Create new Ethernet header and include additional space 1114eaa4710SRishi Srivatsavai * for writing TRILL header and/or VLAN tag. 1124eaa4710SRishi Srivatsavai */ 1134eaa4710SRishi Srivatsavai extra_hdr_len = (trill_hdr_ok ? 0 : sizeof (trill_header_t)) + 1144eaa4710SRishi Srivatsavai (tci != TRILL_NO_TCI ? sizeof (struct ether_vlan_extinfo) : 0); 1154eaa4710SRishi Srivatsavai hdr_mp = mac_header(tsock->ts_link->bl_mh, daddr, 1164eaa4710SRishi Srivatsavai tci != TRILL_NO_TCI ? ETHERTYPE_VLAN : etype, mp, extra_hdr_len); 1174eaa4710SRishi Srivatsavai if (hdr_mp == NULL) { 1184eaa4710SRishi Srivatsavai freemsg(mp); 1194eaa4710SRishi Srivatsavai return (NULL); 1204eaa4710SRishi Srivatsavai } 1214eaa4710SRishi Srivatsavai 1224eaa4710SRishi Srivatsavai if (tci != TRILL_NO_TCI) { 1234eaa4710SRishi Srivatsavai /* LINTED: alignment */ 1244eaa4710SRishi Srivatsavai ethvlanhdr = (struct ether_vlan_header *)hdr_mp->b_rptr; 1254eaa4710SRishi Srivatsavai ethvlanhdr->ether_tci = htons(tci); 1264eaa4710SRishi Srivatsavai ethvlanhdr->ether_type = htons(etype); 1274eaa4710SRishi Srivatsavai hdr_mp->b_wptr += sizeof (struct ether_vlan_extinfo); 1284eaa4710SRishi Srivatsavai } 1294eaa4710SRishi Srivatsavai 1304eaa4710SRishi Srivatsavai if (!trill_hdr_ok) { 1314eaa4710SRishi Srivatsavai trill_header_t *thp; 1324eaa4710SRishi Srivatsavai /* LINTED: alignment */ 1334eaa4710SRishi Srivatsavai thp = (trill_header_t *)hdr_mp->b_wptr; 1344eaa4710SRishi Srivatsavai (void) memset(thp, 0, sizeof (trill_header_t)); 1354eaa4710SRishi Srivatsavai thp->th_hopcount = TRILL_DEFAULT_HOPS; 1364eaa4710SRishi Srivatsavai thp->th_multidest = (multidest ? 1:0); 1374eaa4710SRishi Srivatsavai hdr_mp->b_wptr += sizeof (trill_header_t); 1384eaa4710SRishi Srivatsavai } 1394eaa4710SRishi Srivatsavai 1404eaa4710SRishi Srivatsavai hdr_mp->b_cont = mp; 1414eaa4710SRishi Srivatsavai return (hdr_mp); 1424eaa4710SRishi Srivatsavai } 1434eaa4710SRishi Srivatsavai 1444eaa4710SRishi Srivatsavai /* 1454eaa4710SRishi Srivatsavai * TRILL local recv function. TRILL data frames that should be received 1464eaa4710SRishi Srivatsavai * by the local system are decapsulated here and passed to bridging for 1474eaa4710SRishi Srivatsavai * learning and local system receive. Only called when we are the forwarder 1484eaa4710SRishi Srivatsavai * on the link (multi-dest frames) or the frame was destined for us. 1494eaa4710SRishi Srivatsavai */ 1504eaa4710SRishi Srivatsavai static void 1514eaa4710SRishi Srivatsavai trill_recv_local(trill_sock_t *tsock, mblk_t *mp, uint16_t ingressnick) 1524eaa4710SRishi Srivatsavai { 1534eaa4710SRishi Srivatsavai struct ether_header *inner_ethhdr; 1544eaa4710SRishi Srivatsavai 1554eaa4710SRishi Srivatsavai /* LINTED: alignment */ 1564eaa4710SRishi Srivatsavai inner_ethhdr = (struct ether_header *)mp->b_rptr; 1574eaa4710SRishi Srivatsavai DTRACE_PROBE1(trill__recv__local, struct ether_header *, inner_ethhdr); 1584eaa4710SRishi Srivatsavai 1594eaa4710SRishi Srivatsavai DB_CKSUMFLAGS(mp) = 0; 1604eaa4710SRishi Srivatsavai /* 1614eaa4710SRishi Srivatsavai * Transmit the decapsulated frame on the link via Bridging. 1624eaa4710SRishi Srivatsavai * Bridging does source address learning and appropriate forwarding. 1634eaa4710SRishi Srivatsavai */ 1644eaa4710SRishi Srivatsavai bridge_trill_decaps(tsock->ts_link, mp, ingressnick); 1654eaa4710SRishi Srivatsavai KSPINCR(tks_decap); 1664eaa4710SRishi Srivatsavai } 1674eaa4710SRishi Srivatsavai 1684eaa4710SRishi Srivatsavai /* 1694eaa4710SRishi Srivatsavai * Determines the outgoing link to reach a RBridge having the given nick 1704eaa4710SRishi Srivatsavai * Assumes caller has acquired the trill instance rwlock. 1714eaa4710SRishi Srivatsavai */ 1724eaa4710SRishi Srivatsavai static trill_sock_t * 1734eaa4710SRishi Srivatsavai find_trill_link(trill_inst_t *tip, datalink_id_t linkid) 1744eaa4710SRishi Srivatsavai { 1754eaa4710SRishi Srivatsavai trill_sock_t *tsp = NULL; 1764eaa4710SRishi Srivatsavai 1774eaa4710SRishi Srivatsavai ASSERT(RW_LOCK_HELD(&tip->ti_rwlock)); 1784eaa4710SRishi Srivatsavai for (tsp = list_head(&tip->ti_socklist); tsp != NULL; 1794eaa4710SRishi Srivatsavai tsp = list_next(&tip->ti_socklist, tsp)) { 1804eaa4710SRishi Srivatsavai if (tsp->ts_link != NULL && tsp->ts_link->bl_linkid == linkid) { 1814eaa4710SRishi Srivatsavai ASSERT(tsp->ts_link->bl_mh != NULL); 1824eaa4710SRishi Srivatsavai ASSERT(!(tsp->ts_flags & TSF_SHUTDOWN)); 1834eaa4710SRishi Srivatsavai atomic_inc_uint(&tsp->ts_refs); 1844eaa4710SRishi Srivatsavai break; 1854eaa4710SRishi Srivatsavai } 1864eaa4710SRishi Srivatsavai } 1874eaa4710SRishi Srivatsavai return (tsp); 1884eaa4710SRishi Srivatsavai } 1894eaa4710SRishi Srivatsavai 1904eaa4710SRishi Srivatsavai /* 1914eaa4710SRishi Srivatsavai * TRILL destination forwarding function. Transmits the TRILL data packet 1924eaa4710SRishi Srivatsavai * to the next-hop, adjacent RBridge. Consumes passed mblk_t. 1934eaa4710SRishi Srivatsavai */ 1944eaa4710SRishi Srivatsavai static void 1954eaa4710SRishi Srivatsavai trill_dest_fwd(trill_inst_t *tip, mblk_t *fwd_mp, uint16_t adj_nick, 1964eaa4710SRishi Srivatsavai boolean_t has_trill_hdr, boolean_t multidest, uint16_t dtnick) 1974eaa4710SRishi Srivatsavai { 1984eaa4710SRishi Srivatsavai trill_node_t *adj; 1994eaa4710SRishi Srivatsavai trill_sock_t *tsock = NULL; 2004eaa4710SRishi Srivatsavai trill_header_t *trillhdr; 2014eaa4710SRishi Srivatsavai struct ether_header *ethhdr; 2024eaa4710SRishi Srivatsavai int ethtype; 2034eaa4710SRishi Srivatsavai int ethhdrlen; 2044eaa4710SRishi Srivatsavai 2054eaa4710SRishi Srivatsavai adj = trill_node_lookup(tip, adj_nick); 2064eaa4710SRishi Srivatsavai if (adj == NULL || ((tsock = adj->tn_tsp) == NULL)) 2074eaa4710SRishi Srivatsavai goto dest_fwd_fail; 2084eaa4710SRishi Srivatsavai 2094eaa4710SRishi Srivatsavai ASSERT(tsock->ts_link != NULL); 2104eaa4710SRishi Srivatsavai ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN)); 2114eaa4710SRishi Srivatsavai ASSERT(adj->tn_ni != NULL); 2124eaa4710SRishi Srivatsavai 2134eaa4710SRishi Srivatsavai DTRACE_PROBE3(trill__dest__fwd, uint16_t, adj_nick, trill_node_t, 2144eaa4710SRishi Srivatsavai adj, trill_sock_t, tsock); 2154eaa4710SRishi Srivatsavai 2164eaa4710SRishi Srivatsavai /* 2174eaa4710SRishi Srivatsavai * For broadcast links by using the dest address of 2184eaa4710SRishi Srivatsavai * the RBridge to forward the frame should result in 2194eaa4710SRishi Srivatsavai * savings. When the link is a bridged LAN or there are 2204eaa4710SRishi Srivatsavai * many end stations the frame will not always be flooded. 2214eaa4710SRishi Srivatsavai */ 2224eaa4710SRishi Srivatsavai fwd_mp = create_trill_header(tsock, fwd_mp, adj->tn_ni->tni_adjsnpa, 2234eaa4710SRishi Srivatsavai has_trill_hdr, multidest, tsock->ts_desigvlan, 0); 2244eaa4710SRishi Srivatsavai if (fwd_mp == NULL) 2254eaa4710SRishi Srivatsavai goto dest_fwd_fail; 2264eaa4710SRishi Srivatsavai 2274eaa4710SRishi Srivatsavai /* LINTED: alignment */ 2284eaa4710SRishi Srivatsavai ethhdr = (struct ether_header *)fwd_mp->b_rptr; 2294eaa4710SRishi Srivatsavai ethtype = ntohs(ethhdr->ether_type); 2304eaa4710SRishi Srivatsavai ASSERT(ethtype == ETHERTYPE_VLAN || ethtype == ETHERTYPE_TRILL); 2314eaa4710SRishi Srivatsavai 2324eaa4710SRishi Srivatsavai /* Pullup Ethernet and TRILL header (w/o TRILL options) */ 2334eaa4710SRishi Srivatsavai ethhdrlen = sizeof (struct ether_header) + 2344eaa4710SRishi Srivatsavai (ethtype == ETHERTYPE_VLAN ? sizeof (struct ether_vlan_extinfo):0); 2354eaa4710SRishi Srivatsavai if (!pullupmsg(fwd_mp, ethhdrlen + sizeof (trill_header_t))) 2364eaa4710SRishi Srivatsavai goto dest_fwd_fail; 2374eaa4710SRishi Srivatsavai /* LINTED: alignment */ 2384eaa4710SRishi Srivatsavai trillhdr = (struct trill_header *)(fwd_mp->b_rptr + ethhdrlen); 2394eaa4710SRishi Srivatsavai 2404eaa4710SRishi Srivatsavai /* Update TRILL header with ingress and egress nicks for new frames */ 2414eaa4710SRishi Srivatsavai if (!has_trill_hdr) { 2424eaa4710SRishi Srivatsavai /* We are creating a new TRILL frame */ 2434eaa4710SRishi Srivatsavai trillhdr->th_egressnick = (multidest ? dtnick:adj_nick); 2444eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_READER); 2454eaa4710SRishi Srivatsavai trillhdr->th_ingressnick = tip->ti_nick; 2464eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 2474eaa4710SRishi Srivatsavai if (!VALID_NICK(trillhdr->th_ingressnick)) 2484eaa4710SRishi Srivatsavai goto dest_fwd_fail; 2494eaa4710SRishi Srivatsavai } 2504eaa4710SRishi Srivatsavai 2514eaa4710SRishi Srivatsavai /* Set hop count and update header in packet */ 2524eaa4710SRishi Srivatsavai ASSERT(trillhdr->th_hopcount != 0); 2534eaa4710SRishi Srivatsavai trillhdr->th_hopcount--; 2544eaa4710SRishi Srivatsavai 2554eaa4710SRishi Srivatsavai /* Clear checksum flag and transmit frame on the link */ 2564eaa4710SRishi Srivatsavai DB_CKSUMFLAGS(fwd_mp) = 0; 2574eaa4710SRishi Srivatsavai DTRACE_PROBE1(trill__dest__fwd__tx, trill_header_t *, &trillhdr); 2584eaa4710SRishi Srivatsavai fwd_mp = bridge_trill_output(tsock->ts_link, fwd_mp); 2594eaa4710SRishi Srivatsavai if (fwd_mp == NULL) { 2604eaa4710SRishi Srivatsavai KSPINCR(tks_sent); 2614eaa4710SRishi Srivatsavai KSPINCR(tks_forward); 2624eaa4710SRishi Srivatsavai } else { 2634eaa4710SRishi Srivatsavai freemsg(fwd_mp); 2644eaa4710SRishi Srivatsavai KSPINCR(tks_drops); 2654eaa4710SRishi Srivatsavai } 2664eaa4710SRishi Srivatsavai trill_node_unref(tip, adj); 2674eaa4710SRishi Srivatsavai return; 2684eaa4710SRishi Srivatsavai 2694eaa4710SRishi Srivatsavai dest_fwd_fail: 2704eaa4710SRishi Srivatsavai if (adj != NULL) 2714eaa4710SRishi Srivatsavai trill_node_unref(tip, adj); 2724eaa4710SRishi Srivatsavai if (tsock != NULL) 2734eaa4710SRishi Srivatsavai KSPINCR(tks_drops); 2744eaa4710SRishi Srivatsavai freemsg(fwd_mp); 2754eaa4710SRishi Srivatsavai } 2764eaa4710SRishi Srivatsavai 2774eaa4710SRishi Srivatsavai /* 2784eaa4710SRishi Srivatsavai * TRILL multi-destination forwarding. Transmits the packet to the adjacencies 2794eaa4710SRishi Srivatsavai * on the distribution tree determined by the egress nick. Source addr (saddr) 2804eaa4710SRishi Srivatsavai * is NULL for new TRILL packets originating from us. 2814eaa4710SRishi Srivatsavai */ 2824eaa4710SRishi Srivatsavai static void 2834eaa4710SRishi Srivatsavai trill_multidest_fwd(trill_inst_t *tip, mblk_t *mp, uint16_t egressnick, 2844eaa4710SRishi Srivatsavai uint16_t ingressnick, boolean_t is_trill_pkt, const uint8_t *saddr, 2854eaa4710SRishi Srivatsavai int inner_vlan, boolean_t free_mblk) 2864eaa4710SRishi Srivatsavai { 2874eaa4710SRishi Srivatsavai int idx; 2884eaa4710SRishi Srivatsavai uint16_t adjnick; 2894eaa4710SRishi Srivatsavai trill_node_t *dest; 2904eaa4710SRishi Srivatsavai trill_node_t *adj; 2914eaa4710SRishi Srivatsavai mblk_t *fwd_mp; 2924eaa4710SRishi Srivatsavai boolean_t nicksaved = B_FALSE; 2934eaa4710SRishi Srivatsavai uint16_t adjnicksaved; 2944eaa4710SRishi Srivatsavai 2954eaa4710SRishi Srivatsavai /* Lookup the egress nick info, this is the DT root */ 2964eaa4710SRishi Srivatsavai if ((dest = trill_node_lookup(tip, egressnick)) == NULL) 2974eaa4710SRishi Srivatsavai goto fail_multidest_fwd; 2984eaa4710SRishi Srivatsavai 2994eaa4710SRishi Srivatsavai /* Send a copy to all our adjacencies on the DT root */ 3004eaa4710SRishi Srivatsavai ASSERT(dest->tn_ni); 3014eaa4710SRishi Srivatsavai for (idx = 0; idx < dest->tn_ni->tni_adjcount; idx++) { 3024eaa4710SRishi Srivatsavai 3034eaa4710SRishi Srivatsavai /* Check for a valid adjacency node */ 3044eaa4710SRishi Srivatsavai adjnick = TNI_ADJNICK(dest->tn_ni, idx); 3054eaa4710SRishi Srivatsavai if (!VALID_NICK(adjnick) || ingressnick == adjnick || 3064eaa4710SRishi Srivatsavai ((adj = trill_node_lookup(tip, adjnick)) == NULL)) 3074eaa4710SRishi Srivatsavai continue; 3084eaa4710SRishi Srivatsavai 3094eaa4710SRishi Srivatsavai /* Do not forward back to adjacency that sent the pkt to us */ 3104eaa4710SRishi Srivatsavai ASSERT(adj->tn_ni != NULL); 3114eaa4710SRishi Srivatsavai if ((saddr != NULL) && 3124eaa4710SRishi Srivatsavai (memcmp(adj->tn_ni->tni_adjsnpa, saddr, 3134eaa4710SRishi Srivatsavai ETHERADDRL) == 0)) { 3144eaa4710SRishi Srivatsavai trill_node_unref(tip, adj); 3154eaa4710SRishi Srivatsavai continue; 3164eaa4710SRishi Srivatsavai } 3174eaa4710SRishi Srivatsavai 3184eaa4710SRishi Srivatsavai /* Check if adj is marked as reaching inner VLAN downstream */ 3194eaa4710SRishi Srivatsavai if ((inner_vlan != VLAN_ID_NONE) && 3204eaa4710SRishi Srivatsavai !TRILL_VLANISSET(TNI_VLANFILTERMAP(dest->tn_ni, idx), 3214eaa4710SRishi Srivatsavai inner_vlan)) { 3224eaa4710SRishi Srivatsavai trill_node_unref(tip, adj); 3234eaa4710SRishi Srivatsavai DTRACE_PROBE4(trill__multi__dest__fwd__vlanfiltered, 3244eaa4710SRishi Srivatsavai uint16_t, adjnick, uint16_t, ingressnick, 3254eaa4710SRishi Srivatsavai uint16_t, egressnick, int, inner_vlan); 3264eaa4710SRishi Srivatsavai continue; 3274eaa4710SRishi Srivatsavai } 3284eaa4710SRishi Srivatsavai 3294eaa4710SRishi Srivatsavai trill_node_unref(tip, adj); 3304eaa4710SRishi Srivatsavai 3314eaa4710SRishi Srivatsavai /* 3324eaa4710SRishi Srivatsavai * Save the nick and look ahead to see if we should forward the 3334eaa4710SRishi Srivatsavai * frame to more adjacencies. We avoid doing a copy for this 3344eaa4710SRishi Srivatsavai * nick and use the passed mblk when we can consume the passed 3354eaa4710SRishi Srivatsavai * mblk. 3364eaa4710SRishi Srivatsavai */ 3374eaa4710SRishi Srivatsavai if (free_mblk && !nicksaved) { 3384eaa4710SRishi Srivatsavai adjnicksaved = adjnick; 3394eaa4710SRishi Srivatsavai nicksaved = B_TRUE; 3404eaa4710SRishi Srivatsavai continue; 3414eaa4710SRishi Srivatsavai } 3424eaa4710SRishi Srivatsavai 3434eaa4710SRishi Srivatsavai fwd_mp = copymsg(mp); 3444eaa4710SRishi Srivatsavai if (fwd_mp == NULL) 3454eaa4710SRishi Srivatsavai break; 3464eaa4710SRishi Srivatsavai DTRACE_PROBE2(trill__multi__dest__fwd, uint16_t, 3474eaa4710SRishi Srivatsavai adjnick, uint16_t, ingressnick); 3484eaa4710SRishi Srivatsavai trill_dest_fwd(tip, fwd_mp, adjnick, is_trill_pkt, 3494eaa4710SRishi Srivatsavai B_TRUE, egressnick); 3504eaa4710SRishi Srivatsavai } 3514eaa4710SRishi Srivatsavai trill_node_unref(tip, dest); 3524eaa4710SRishi Srivatsavai 3534eaa4710SRishi Srivatsavai if (nicksaved) { 3544eaa4710SRishi Srivatsavai ASSERT(free_mblk); 3554eaa4710SRishi Srivatsavai DTRACE_PROBE2(trill__multi__dest__fwd, uint16_t, 3564eaa4710SRishi Srivatsavai adjnicksaved, uint16_t, ingressnick); 3574eaa4710SRishi Srivatsavai trill_dest_fwd(tip, mp, adjnicksaved, is_trill_pkt, 3584eaa4710SRishi Srivatsavai B_TRUE, egressnick); 3594eaa4710SRishi Srivatsavai return; 3604eaa4710SRishi Srivatsavai } 3614eaa4710SRishi Srivatsavai 3624eaa4710SRishi Srivatsavai fail_multidest_fwd: 3634eaa4710SRishi Srivatsavai DTRACE_PROBE2(trill__multi__dest__fwd__fail, uint16_t, 3644eaa4710SRishi Srivatsavai egressnick, uint16_t, ingressnick); 3654eaa4710SRishi Srivatsavai if (free_mblk) { 3664eaa4710SRishi Srivatsavai freemsg(mp); 3674eaa4710SRishi Srivatsavai } 3684eaa4710SRishi Srivatsavai } 3694eaa4710SRishi Srivatsavai 3704eaa4710SRishi Srivatsavai /* 3714eaa4710SRishi Srivatsavai * TRILL data receive function. Forwards the received frame if necessary 3724eaa4710SRishi Srivatsavai * and also determines if the received frame should be consumed locally. 3734eaa4710SRishi Srivatsavai * Consumes passed mblk. 3744eaa4710SRishi Srivatsavai */ 3754eaa4710SRishi Srivatsavai static void 3764eaa4710SRishi Srivatsavai trill_recv(trill_sock_t *tsock, mblk_t *mp, const uint8_t *mpsaddr) 3774eaa4710SRishi Srivatsavai { 3784eaa4710SRishi Srivatsavai trill_header_t *trillhdr; 3794eaa4710SRishi Srivatsavai trill_node_t *dest = NULL; 3804eaa4710SRishi Srivatsavai trill_node_t *source = NULL; 3814eaa4710SRishi Srivatsavai trill_node_t *adj; 3824eaa4710SRishi Srivatsavai uint16_t ournick, adjnick, treeroot; 3834eaa4710SRishi Srivatsavai struct ether_header *ethhdr; 3844eaa4710SRishi Srivatsavai trill_inst_t *tip = tsock->ts_tip; 3854eaa4710SRishi Srivatsavai uint8_t srcaddr[ETHERADDRL]; 3864eaa4710SRishi Srivatsavai size_t trillhdrlen; 3874eaa4710SRishi Srivatsavai int inner_vlan = VLAN_ID_NONE; 3884eaa4710SRishi Srivatsavai int tci; 3894eaa4710SRishi Srivatsavai int idx; 3904eaa4710SRishi Srivatsavai size_t min_size; 3914eaa4710SRishi Srivatsavai 3924eaa4710SRishi Srivatsavai /* Copy Ethernet source address before modifying packet */ 3934eaa4710SRishi Srivatsavai (void) memcpy(srcaddr, mpsaddr, ETHERADDRL); 3944eaa4710SRishi Srivatsavai 3954eaa4710SRishi Srivatsavai /* Pull up TRILL header if necessary. */ 3964eaa4710SRishi Srivatsavai min_size = sizeof (trill_header_t); 3974eaa4710SRishi Srivatsavai if ((MBLKL(mp) < min_size || 3984eaa4710SRishi Srivatsavai !IS_P2ALIGNED(mp->b_rptr, TRILL_HDR_ALIGN)) && 3994eaa4710SRishi Srivatsavai !pullupmsg(mp, min_size)) 4004eaa4710SRishi Srivatsavai goto fail; 4014eaa4710SRishi Srivatsavai 4024eaa4710SRishi Srivatsavai /* LINTED: alignment */ 4034eaa4710SRishi Srivatsavai trillhdr = (trill_header_t *)mp->b_rptr; 4044eaa4710SRishi Srivatsavai if (trillhdr->th_version != TRILL_PROTOCOL_VERS) { 4054eaa4710SRishi Srivatsavai DTRACE_PROBE1(trill__recv__wrongversion, 4064eaa4710SRishi Srivatsavai trill_header_t *, trillhdr); 4074eaa4710SRishi Srivatsavai goto fail; 4084eaa4710SRishi Srivatsavai } 4094eaa4710SRishi Srivatsavai 4104eaa4710SRishi Srivatsavai /* Drop if unknown or invalid nickname */ 4114eaa4710SRishi Srivatsavai if (!VALID_NICK(trillhdr->th_egressnick) || 4124eaa4710SRishi Srivatsavai !VALID_NICK(trillhdr->th_ingressnick)) { 4134eaa4710SRishi Srivatsavai DTRACE_PROBE1(trill__recv__invalidnick, 4144eaa4710SRishi Srivatsavai trill_header_t *, trillhdr); 4154eaa4710SRishi Srivatsavai goto fail; 4164eaa4710SRishi Srivatsavai } 4174eaa4710SRishi Srivatsavai 4184eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_READER); 4194eaa4710SRishi Srivatsavai ournick = tip->ti_nick; 4204eaa4710SRishi Srivatsavai treeroot = tip->ti_treeroot; 4214eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 4224eaa4710SRishi Srivatsavai /* Drop if we received a packet with our nick as ingress */ 4234eaa4710SRishi Srivatsavai if (trillhdr->th_ingressnick == ournick) 4244eaa4710SRishi Srivatsavai goto fail; 4254eaa4710SRishi Srivatsavai 4264eaa4710SRishi Srivatsavai /* Re-pull any TRILL options and inner Ethernet header */ 4274eaa4710SRishi Srivatsavai min_size += GET_TRILL_OPTS_LEN(trillhdr) * sizeof (uint32_t) + 4284eaa4710SRishi Srivatsavai sizeof (struct ether_header); 4294eaa4710SRishi Srivatsavai if (MBLKL(mp) < min_size) { 4304eaa4710SRishi Srivatsavai if (!pullupmsg(mp, min_size)) 4314eaa4710SRishi Srivatsavai goto fail; 4324eaa4710SRishi Srivatsavai /* LINTED: alignment */ 4334eaa4710SRishi Srivatsavai trillhdr = (trill_header_t *)mp->b_rptr; 4344eaa4710SRishi Srivatsavai } 4354eaa4710SRishi Srivatsavai trillhdrlen = sizeof (trill_header_t) + 4364eaa4710SRishi Srivatsavai (GET_TRILL_OPTS_LEN(trillhdr) * sizeof (uint32_t)); 4374eaa4710SRishi Srivatsavai 4384eaa4710SRishi Srivatsavai /* 4394eaa4710SRishi Srivatsavai * Get the inner Ethernet header, plus the inner VLAN header if there 4404eaa4710SRishi Srivatsavai * is one. 4414eaa4710SRishi Srivatsavai */ 4424eaa4710SRishi Srivatsavai /* LINTED: alignment */ 4434eaa4710SRishi Srivatsavai ethhdr = (struct ether_header *)(mp->b_rptr + trillhdrlen); 4444eaa4710SRishi Srivatsavai if (ethhdr->ether_type == htons(ETHERTYPE_VLAN)) { 4454eaa4710SRishi Srivatsavai min_size += sizeof (struct ether_vlan_extinfo); 4464eaa4710SRishi Srivatsavai if (MBLKL(mp) < min_size) { 4474eaa4710SRishi Srivatsavai if (!pullupmsg(mp, min_size)) 4484eaa4710SRishi Srivatsavai goto fail; 4494eaa4710SRishi Srivatsavai /* LINTED: alignment */ 4504eaa4710SRishi Srivatsavai trillhdr = (trill_header_t *)mp->b_rptr; 4514eaa4710SRishi Srivatsavai /* LINTED: alignment */ 4524eaa4710SRishi Srivatsavai ethhdr = (struct ether_header *)(mp->b_rptr + 4534eaa4710SRishi Srivatsavai trillhdrlen); 4544eaa4710SRishi Srivatsavai } 4554eaa4710SRishi Srivatsavai 4564eaa4710SRishi Srivatsavai tci = ntohs(((struct ether_vlan_header *)ethhdr)->ether_tci); 4574eaa4710SRishi Srivatsavai inner_vlan = VLAN_ID(tci); 4584eaa4710SRishi Srivatsavai } 4594eaa4710SRishi Srivatsavai 4604eaa4710SRishi Srivatsavai /* Known/single destination forwarding. */ 4614eaa4710SRishi Srivatsavai if (!trillhdr->th_multidest) { 4624eaa4710SRishi Srivatsavai 4634eaa4710SRishi Srivatsavai /* Inner MacDA must be unicast */ 4644eaa4710SRishi Srivatsavai if (ethhdr->ether_dhost.ether_addr_octet[0] & 1) 4654eaa4710SRishi Srivatsavai goto fail; 4664eaa4710SRishi Srivatsavai 4674eaa4710SRishi Srivatsavai /* Ingress and Egress nicks must be different */ 4684eaa4710SRishi Srivatsavai if (trillhdr->th_egressnick == trillhdr->th_ingressnick) 4694eaa4710SRishi Srivatsavai goto fail; 4704eaa4710SRishi Srivatsavai 4714eaa4710SRishi Srivatsavai DTRACE_PROBE1(trill__recv__singledest, 4724eaa4710SRishi Srivatsavai trill_header_t *, trillhdr); 4734eaa4710SRishi Srivatsavai if (trillhdr->th_egressnick == ournick) { 4744eaa4710SRishi Srivatsavai mp->b_rptr += trillhdrlen; 4754eaa4710SRishi Srivatsavai trill_recv_local(tsock, mp, trillhdr->th_ingressnick); 4764eaa4710SRishi Srivatsavai } else if (trillhdr->th_hopcount > 0) { 4774eaa4710SRishi Srivatsavai trill_dest_fwd(tip, mp, trillhdr->th_egressnick, 4784eaa4710SRishi Srivatsavai B_TRUE, B_FALSE, RBRIDGE_NICKNAME_NONE); 4794eaa4710SRishi Srivatsavai } else { 4804eaa4710SRishi Srivatsavai goto fail; 4814eaa4710SRishi Srivatsavai } 4824eaa4710SRishi Srivatsavai return; 4834eaa4710SRishi Srivatsavai } 4844eaa4710SRishi Srivatsavai 4854eaa4710SRishi Srivatsavai /* 4864eaa4710SRishi Srivatsavai * Multi-destination frame: perform checks verifying we have 4874eaa4710SRishi Srivatsavai * received a valid multi-destination frame before receiving the 4884eaa4710SRishi Srivatsavai * frame locally and forwarding the frame to other RBridges. 4894eaa4710SRishi Srivatsavai * 4904eaa4710SRishi Srivatsavai * Check if we received this multi-destination frame on a 4914eaa4710SRishi Srivatsavai * adjacency in the distribution tree indicated by the frame's 4924eaa4710SRishi Srivatsavai * egress nickname. 4934eaa4710SRishi Srivatsavai */ 4944eaa4710SRishi Srivatsavai if ((dest = trill_node_lookup(tip, trillhdr->th_egressnick)) == NULL) 4954eaa4710SRishi Srivatsavai goto fail; 4964eaa4710SRishi Srivatsavai for (idx = 0; idx < dest->tn_ni->tni_adjcount; idx++) { 4974eaa4710SRishi Srivatsavai adjnick = TNI_ADJNICK(dest->tn_ni, idx); 4984eaa4710SRishi Srivatsavai if ((adj = trill_node_lookup(tip, adjnick)) == NULL) 4994eaa4710SRishi Srivatsavai continue; 5004eaa4710SRishi Srivatsavai if (memcmp(adj->tn_ni->tni_adjsnpa, srcaddr, ETHERADDRL) == 0) { 5014eaa4710SRishi Srivatsavai trill_node_unref(tip, adj); 5024eaa4710SRishi Srivatsavai break; 5034eaa4710SRishi Srivatsavai } 5044eaa4710SRishi Srivatsavai trill_node_unref(tip, adj); 5054eaa4710SRishi Srivatsavai } 5064eaa4710SRishi Srivatsavai 5074eaa4710SRishi Srivatsavai if (idx >= dest->tn_ni->tni_adjcount) { 5084eaa4710SRishi Srivatsavai DTRACE_PROBE2(trill__recv__multidest__adjcheckfail, 5094eaa4710SRishi Srivatsavai trill_header_t *, trillhdr, trill_node_t *, dest); 5104eaa4710SRishi Srivatsavai goto fail; 5114eaa4710SRishi Srivatsavai } 5124eaa4710SRishi Srivatsavai 5134eaa4710SRishi Srivatsavai /* 5144eaa4710SRishi Srivatsavai * Reverse path forwarding check. Check if the ingress RBridge 5154eaa4710SRishi Srivatsavai * that has forwarded the frame advertised the use of the 5164eaa4710SRishi Srivatsavai * distribution tree specified in the egress nick. 5174eaa4710SRishi Srivatsavai */ 5184eaa4710SRishi Srivatsavai if ((source = trill_node_lookup(tip, trillhdr->th_ingressnick)) == NULL) 5194eaa4710SRishi Srivatsavai goto fail; 5204eaa4710SRishi Srivatsavai for (idx = 0; idx < source->tn_ni->tni_dtrootcount; idx++) { 5214eaa4710SRishi Srivatsavai if (TNI_DTROOTNICK(source->tn_ni, idx) == 5224eaa4710SRishi Srivatsavai trillhdr->th_egressnick) 5234eaa4710SRishi Srivatsavai break; 5244eaa4710SRishi Srivatsavai } 5254eaa4710SRishi Srivatsavai 5264eaa4710SRishi Srivatsavai if (idx >= source->tn_ni->tni_dtrootcount) { 5274eaa4710SRishi Srivatsavai /* 5284eaa4710SRishi Srivatsavai * Allow receipt of forwarded frame with the highest 5294eaa4710SRishi Srivatsavai * tree root RBridge as the egress RBridge when the 5304eaa4710SRishi Srivatsavai * ingress RBridge has not advertised the use of any 5314eaa4710SRishi Srivatsavai * distribution trees. 5324eaa4710SRishi Srivatsavai */ 5334eaa4710SRishi Srivatsavai if (source->tn_ni->tni_dtrootcount != 0 || 5344eaa4710SRishi Srivatsavai trillhdr->th_egressnick != treeroot) { 5354eaa4710SRishi Srivatsavai DTRACE_PROBE3( 5364eaa4710SRishi Srivatsavai trill__recv__multidest__rpfcheckfail, 5374eaa4710SRishi Srivatsavai trill_header_t *, trillhdr, trill_node_t *, 5384eaa4710SRishi Srivatsavai source, trill_inst_t *, tip); 5394eaa4710SRishi Srivatsavai goto fail; 5404eaa4710SRishi Srivatsavai } 5414eaa4710SRishi Srivatsavai } 5424eaa4710SRishi Srivatsavai 5434eaa4710SRishi Srivatsavai /* Check hop count before doing any forwarding */ 5444eaa4710SRishi Srivatsavai if (trillhdr->th_hopcount == 0) 5454eaa4710SRishi Srivatsavai goto fail; 5464eaa4710SRishi Srivatsavai 5474eaa4710SRishi Srivatsavai /* Forward frame using the distribution tree specified by egress nick */ 5484eaa4710SRishi Srivatsavai DTRACE_PROBE2(trill__recv__multidest, trill_header_t *, 5494eaa4710SRishi Srivatsavai trillhdr, trill_node_t *, source); 5504eaa4710SRishi Srivatsavai trill_node_unref(tip, source); 5514eaa4710SRishi Srivatsavai trill_node_unref(tip, dest); 5524eaa4710SRishi Srivatsavai 5534eaa4710SRishi Srivatsavai /* Tell forwarding not to free if we're the link forwarder. */ 5544eaa4710SRishi Srivatsavai trill_multidest_fwd(tip, mp, trillhdr->th_egressnick, 5554eaa4710SRishi Srivatsavai trillhdr->th_ingressnick, B_TRUE, srcaddr, inner_vlan, 5564eaa4710SRishi Srivatsavai B_FALSE); 5574eaa4710SRishi Srivatsavai 5584eaa4710SRishi Srivatsavai /* 5594eaa4710SRishi Srivatsavai * Send de-capsulated frame locally if we are the link forwarder (also 5604eaa4710SRishi Srivatsavai * does bridge learning). 5614eaa4710SRishi Srivatsavai */ 5624eaa4710SRishi Srivatsavai mp->b_rptr += trillhdrlen; 5634eaa4710SRishi Srivatsavai trill_recv_local(tsock, mp, trillhdr->th_ingressnick); 5644eaa4710SRishi Srivatsavai KSPINCR(tks_recv); 5654eaa4710SRishi Srivatsavai return; 5664eaa4710SRishi Srivatsavai 5674eaa4710SRishi Srivatsavai fail: 5684eaa4710SRishi Srivatsavai DTRACE_PROBE2(trill__recv__multidest__fail, mblk_t *, mp, 5694eaa4710SRishi Srivatsavai trill_sock_t *, tsock); 5704eaa4710SRishi Srivatsavai if (dest != NULL) 5714eaa4710SRishi Srivatsavai trill_node_unref(tip, dest); 5724eaa4710SRishi Srivatsavai if (source != NULL) 5734eaa4710SRishi Srivatsavai trill_node_unref(tip, source); 5744eaa4710SRishi Srivatsavai freemsg(mp); 5754eaa4710SRishi Srivatsavai KSPINCR(tks_drops); 5764eaa4710SRishi Srivatsavai } 5774eaa4710SRishi Srivatsavai 5784eaa4710SRishi Srivatsavai static void 5794eaa4710SRishi Srivatsavai trill_stop_recv(trill_sock_t *tsock) 5804eaa4710SRishi Srivatsavai { 5814eaa4710SRishi Srivatsavai mutex_enter(&tsock->ts_socklock); 5824eaa4710SRishi Srivatsavai stop_retry: 5834eaa4710SRishi Srivatsavai if (tsock->ts_state == TS_UNBND || tsock->ts_link == NULL) { 5844eaa4710SRishi Srivatsavai mutex_exit(&tsock->ts_socklock); 5854eaa4710SRishi Srivatsavai return; 5864eaa4710SRishi Srivatsavai } 5874eaa4710SRishi Srivatsavai 5884eaa4710SRishi Srivatsavai /* 5894eaa4710SRishi Srivatsavai * If another thread is closing the socket then wait. Our callers 5904eaa4710SRishi Srivatsavai * expect us to return only after the socket is closed. 5914eaa4710SRishi Srivatsavai */ 5924eaa4710SRishi Srivatsavai if (tsock->ts_flags & TSF_CLOSEWAIT) { 5934eaa4710SRishi Srivatsavai cv_wait(&tsock->ts_sockclosewait, &tsock->ts_socklock); 5944eaa4710SRishi Srivatsavai goto stop_retry; 5954eaa4710SRishi Srivatsavai } 5964eaa4710SRishi Srivatsavai 5974eaa4710SRishi Srivatsavai /* 5984eaa4710SRishi Srivatsavai * Set state and flags to block new bind or close calls 5994eaa4710SRishi Srivatsavai * while we close the socket. 6004eaa4710SRishi Srivatsavai */ 6014eaa4710SRishi Srivatsavai tsock->ts_flags |= TSF_CLOSEWAIT; 6024eaa4710SRishi Srivatsavai 6034eaa4710SRishi Srivatsavai /* Wait until all AF_TRILL socket transmit operations are done */ 6044eaa4710SRishi Srivatsavai while (tsock->ts_sockthreadcount > 0) 6054eaa4710SRishi Srivatsavai cv_wait(&tsock->ts_sockthreadwait, &tsock->ts_socklock); 6064eaa4710SRishi Srivatsavai 6074eaa4710SRishi Srivatsavai /* 6084eaa4710SRishi Srivatsavai * We are guaranteed to be the only thread closing on the 6094eaa4710SRishi Srivatsavai * socket while the TSF_CLOSEWAIT flag is set, all others cv_wait 6104eaa4710SRishi Srivatsavai * for us to finish. 6114eaa4710SRishi Srivatsavai */ 6124eaa4710SRishi Srivatsavai ASSERT(tsock->ts_link != NULL); 6134eaa4710SRishi Srivatsavai if (tsock->ts_ksp != NULL) 6144eaa4710SRishi Srivatsavai kstat_delete(tsock->ts_ksp); 6154eaa4710SRishi Srivatsavai 6164eaa4710SRishi Srivatsavai /* 6174eaa4710SRishi Srivatsavai * Release lock before bridge_trill_lnunref to prevent deadlock 6184eaa4710SRishi Srivatsavai * between trill_ctrl_input thread waiting to acquire ts_socklock 6194eaa4710SRishi Srivatsavai * and bridge_trill_lnunref waiting for the trill thread to finish. 6204eaa4710SRishi Srivatsavai */ 6214eaa4710SRishi Srivatsavai mutex_exit(&tsock->ts_socklock); 6224eaa4710SRishi Srivatsavai 6234eaa4710SRishi Srivatsavai /* 6244eaa4710SRishi Srivatsavai * Release TRILL link reference from Bridging. On return from 6254eaa4710SRishi Srivatsavai * bridge_trill_lnunref we can be sure there are no active TRILL data 6264eaa4710SRishi Srivatsavai * threads for this link. 6274eaa4710SRishi Srivatsavai */ 6284eaa4710SRishi Srivatsavai bridge_trill_lnunref(tsock->ts_link); 6294eaa4710SRishi Srivatsavai 6304eaa4710SRishi Srivatsavai /* Set socket as unbound & wakeup threads waiting for socket to close */ 6314eaa4710SRishi Srivatsavai mutex_enter(&tsock->ts_socklock); 6324eaa4710SRishi Srivatsavai ASSERT(tsock->ts_link != NULL); 6334eaa4710SRishi Srivatsavai tsock->ts_link = NULL; 6344eaa4710SRishi Srivatsavai tsock->ts_state = TS_UNBND; 6354eaa4710SRishi Srivatsavai tsock->ts_flags &= ~TSF_CLOSEWAIT; 6364eaa4710SRishi Srivatsavai cv_broadcast(&tsock->ts_sockclosewait); 6374eaa4710SRishi Srivatsavai mutex_exit(&tsock->ts_socklock); 6384eaa4710SRishi Srivatsavai } 6394eaa4710SRishi Srivatsavai 6404eaa4710SRishi Srivatsavai static int 6414eaa4710SRishi Srivatsavai trill_start_recv(trill_sock_t *tsock, const struct sockaddr *sa, socklen_t len) 6424eaa4710SRishi Srivatsavai { 6434eaa4710SRishi Srivatsavai struct sockaddr_dl *lladdr = (struct sockaddr_dl *)sa; 6444eaa4710SRishi Srivatsavai datalink_id_t linkid; 6454eaa4710SRishi Srivatsavai int err = 0; 6464eaa4710SRishi Srivatsavai 6474eaa4710SRishi Srivatsavai if (len != sizeof (*lladdr)) 6484eaa4710SRishi Srivatsavai return (EINVAL); 6494eaa4710SRishi Srivatsavai 6504eaa4710SRishi Srivatsavai mutex_enter(&tsock->ts_socklock); 6514eaa4710SRishi Srivatsavai if (tsock->ts_tip == NULL || tsock->ts_state != TS_UNBND) { 6524eaa4710SRishi Srivatsavai err = EINVAL; 6534eaa4710SRishi Srivatsavai goto bind_error; 6544eaa4710SRishi Srivatsavai } 6554eaa4710SRishi Srivatsavai 6564eaa4710SRishi Srivatsavai if (tsock->ts_flags & TSF_CLOSEWAIT || tsock->ts_link != NULL) { 6574eaa4710SRishi Srivatsavai err = EBUSY; 6584eaa4710SRishi Srivatsavai goto bind_error; 6594eaa4710SRishi Srivatsavai } 6604eaa4710SRishi Srivatsavai 6614eaa4710SRishi Srivatsavai (void) memcpy(&(tsock->ts_lladdr), lladdr, 6624eaa4710SRishi Srivatsavai sizeof (struct sockaddr_dl)); 6634eaa4710SRishi Srivatsavai (void) memcpy(&linkid, tsock->ts_lladdr.sdl_data, 6644eaa4710SRishi Srivatsavai sizeof (datalink_id_t)); 6654eaa4710SRishi Srivatsavai 6664eaa4710SRishi Srivatsavai tsock->ts_link = bridge_trill_lnref(tsock->ts_tip->ti_binst, 6674eaa4710SRishi Srivatsavai linkid, tsock); 6684eaa4710SRishi Srivatsavai if (tsock->ts_link == NULL) { 6694eaa4710SRishi Srivatsavai err = EINVAL; 6704eaa4710SRishi Srivatsavai goto bind_error; 6714eaa4710SRishi Srivatsavai } 6724eaa4710SRishi Srivatsavai 6734eaa4710SRishi Srivatsavai trill_kstats_init(tsock, tsock->ts_tip->ti_bridgename); 6744eaa4710SRishi Srivatsavai tsock->ts_state = TS_IDLE; 6754eaa4710SRishi Srivatsavai 6764eaa4710SRishi Srivatsavai bind_error: 6774eaa4710SRishi Srivatsavai mutex_exit(&tsock->ts_socklock); 6784eaa4710SRishi Srivatsavai return (err); 6794eaa4710SRishi Srivatsavai } 6804eaa4710SRishi Srivatsavai 6814eaa4710SRishi Srivatsavai static int 6824eaa4710SRishi Srivatsavai trill_do_unbind(trill_sock_t *tsock) 6834eaa4710SRishi Srivatsavai { 6844eaa4710SRishi Srivatsavai /* If a bind has not been done, we can't unbind. */ 6854eaa4710SRishi Srivatsavai if (tsock->ts_state != TS_IDLE) 6864eaa4710SRishi Srivatsavai return (EINVAL); 6874eaa4710SRishi Srivatsavai 6884eaa4710SRishi Srivatsavai trill_stop_recv(tsock); 6894eaa4710SRishi Srivatsavai return (0); 6904eaa4710SRishi Srivatsavai } 6914eaa4710SRishi Srivatsavai 6924eaa4710SRishi Srivatsavai static void 6934eaa4710SRishi Srivatsavai trill_instance_unref(trill_inst_t *tip) 6944eaa4710SRishi Srivatsavai { 6954eaa4710SRishi Srivatsavai rw_enter(&trill_inst_rwlock, RW_WRITER); 6964eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_WRITER); 6974eaa4710SRishi Srivatsavai if (atomic_dec_uint_nv(&tip->ti_refs) == 0) { 6984eaa4710SRishi Srivatsavai list_remove(&trill_inst_list, tip); 6994eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 7004eaa4710SRishi Srivatsavai rw_exit(&trill_inst_rwlock); 7014eaa4710SRishi Srivatsavai if (tip->ti_binst != NULL) 7024eaa4710SRishi Srivatsavai bridge_trill_brunref(tip->ti_binst); 7034eaa4710SRishi Srivatsavai list_destroy(&tip->ti_socklist); 7044eaa4710SRishi Srivatsavai rw_destroy(&tip->ti_rwlock); 7054eaa4710SRishi Srivatsavai kmem_free(tip, sizeof (*tip)); 7064eaa4710SRishi Srivatsavai } else { 7074eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 7084eaa4710SRishi Srivatsavai rw_exit(&trill_inst_rwlock); 7094eaa4710SRishi Srivatsavai } 7104eaa4710SRishi Srivatsavai } 7114eaa4710SRishi Srivatsavai 7124eaa4710SRishi Srivatsavai /* 7134eaa4710SRishi Srivatsavai * This is called when the bridge module receives a TRILL-encapsulated packet 7144eaa4710SRishi Srivatsavai * on a given link or a packet identified as "TRILL control." We must verify 7154eaa4710SRishi Srivatsavai * that it's for us (it almost certainly will be), and then either decapsulate 7164eaa4710SRishi Srivatsavai * (if it's to our nickname), forward (if it's to someone else), or send up one 7174eaa4710SRishi Srivatsavai * of the sockets (if it's control traffic). 7184eaa4710SRishi Srivatsavai * 7194eaa4710SRishi Srivatsavai * Sadly, on Ethernet, the control traffic is identified by Outer.MacDA, and 7204eaa4710SRishi Srivatsavai * not by TRILL header information. 7214eaa4710SRishi Srivatsavai */ 7224eaa4710SRishi Srivatsavai static void 7234eaa4710SRishi Srivatsavai trill_recv_pkt_cb(void *lptr, bridge_link_t *blp, mac_resource_handle_t rsrc, 7244eaa4710SRishi Srivatsavai mblk_t *mp, mac_header_info_t *hdr_info) 7254eaa4710SRishi Srivatsavai { 7264eaa4710SRishi Srivatsavai trill_sock_t *tsock = lptr; 7274eaa4710SRishi Srivatsavai 7284eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(rsrc)); 7294eaa4710SRishi Srivatsavai 7304eaa4710SRishi Srivatsavai ASSERT(tsock->ts_tip != NULL); 7314eaa4710SRishi Srivatsavai ASSERT(tsock->ts_link != NULL); 7324eaa4710SRishi Srivatsavai ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN)); 7334eaa4710SRishi Srivatsavai 7344eaa4710SRishi Srivatsavai /* 7354eaa4710SRishi Srivatsavai * Only receive packet if the source address is not multicast (which is 7364eaa4710SRishi Srivatsavai * bogus). 7374eaa4710SRishi Srivatsavai */ 7384eaa4710SRishi Srivatsavai if (hdr_info->mhi_saddr[0] & 1) 7394eaa4710SRishi Srivatsavai goto discard; 7404eaa4710SRishi Srivatsavai 7414eaa4710SRishi Srivatsavai /* 7424eaa4710SRishi Srivatsavai * Check if this is our own packet reflected back. It should not be. 7434eaa4710SRishi Srivatsavai */ 7444eaa4710SRishi Srivatsavai if (bcmp(hdr_info->mhi_saddr, blp->bl_local_mac, ETHERADDRL) == 0) 7454eaa4710SRishi Srivatsavai goto discard; 7464eaa4710SRishi Srivatsavai 7474eaa4710SRishi Srivatsavai /* Only receive unicast packet if addressed to us */ 7484eaa4710SRishi Srivatsavai if (hdr_info->mhi_dsttype == MAC_ADDRTYPE_UNICAST && 7494eaa4710SRishi Srivatsavai bcmp(hdr_info->mhi_daddr, blp->bl_local_mac, ETHERADDRL) != 0) 7504eaa4710SRishi Srivatsavai goto discard; 7514eaa4710SRishi Srivatsavai 7524eaa4710SRishi Srivatsavai if (hdr_info->mhi_bindsap == ETHERTYPE_TRILL) { 7534eaa4710SRishi Srivatsavai /* TRILL data packets */ 7544eaa4710SRishi Srivatsavai trill_recv(tsock, mp, hdr_info->mhi_saddr); 7554eaa4710SRishi Srivatsavai } else { 7564eaa4710SRishi Srivatsavai /* Design constraint for cheap IS-IS/BPDU comparison */ 7574eaa4710SRishi Srivatsavai ASSERT(all_isis_rbridges[4] != bridge_group_address[4]); 7584eaa4710SRishi Srivatsavai /* Send received control packet upstream */ 7594eaa4710SRishi Srivatsavai trill_ctrl_input(tsock, mp, hdr_info->mhi_saddr, 7604eaa4710SRishi Srivatsavai hdr_info->mhi_daddr[4] == all_isis_rbridges[4] ? 7614eaa4710SRishi Srivatsavai hdr_info->mhi_tci : TRILL_TCI_BPDU); 7624eaa4710SRishi Srivatsavai } 7634eaa4710SRishi Srivatsavai 7644eaa4710SRishi Srivatsavai return; 7654eaa4710SRishi Srivatsavai 7664eaa4710SRishi Srivatsavai discard: 7674eaa4710SRishi Srivatsavai freemsg(mp); 7684eaa4710SRishi Srivatsavai KSPINCR(tks_drops); 7694eaa4710SRishi Srivatsavai } 7704eaa4710SRishi Srivatsavai 7714eaa4710SRishi Srivatsavai /* 7724eaa4710SRishi Srivatsavai * This is called when the bridge module discovers that the destination address 7734eaa4710SRishi Srivatsavai * for a packet is not local -- it's through some remote node. We must verify 7744eaa4710SRishi Srivatsavai * that the remote node isn't our nickname (it shouldn't be), add a TRILL 7754eaa4710SRishi Srivatsavai * header, and then use the IS-IS data to determine which link and which 7764eaa4710SRishi Srivatsavai * next-hop RBridge should be used for output. We then transmit on that link. 7774eaa4710SRishi Srivatsavai * 7784eaa4710SRishi Srivatsavai * The egress_nick is RBRIDGE_NICKNAME_NONE for the "unknown destination" case. 7794eaa4710SRishi Srivatsavai */ 7804eaa4710SRishi Srivatsavai static void 7814eaa4710SRishi Srivatsavai trill_encap_pkt_cb(void *lptr, bridge_link_t *blp, mac_header_info_t *hdr_info, 7824eaa4710SRishi Srivatsavai mblk_t *mp, uint16_t egress_nick) 7834eaa4710SRishi Srivatsavai { 7844eaa4710SRishi Srivatsavai uint16_t ournick; 7854eaa4710SRishi Srivatsavai uint16_t dtnick; 7864eaa4710SRishi Srivatsavai trill_node_t *self = NULL; 7874eaa4710SRishi Srivatsavai trill_sock_t *tsock = lptr; 7884eaa4710SRishi Srivatsavai trill_inst_t *tip = tsock->ts_tip; 7894eaa4710SRishi Srivatsavai int vlan = VLAN_ID_NONE; 7904eaa4710SRishi Srivatsavai 7914eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(blp)); 7924eaa4710SRishi Srivatsavai ASSERT(hdr_info->mhi_bindsap != ETHERTYPE_TRILL); 7934eaa4710SRishi Srivatsavai 7944eaa4710SRishi Srivatsavai /* egress_nick = RBRIDGE_NICKNAME_NONE is valid */ 7954eaa4710SRishi Srivatsavai if (egress_nick != RBRIDGE_NICKNAME_NONE && !VALID_NICK(egress_nick)) 7964eaa4710SRishi Srivatsavai goto discard; 7974eaa4710SRishi Srivatsavai 7984eaa4710SRishi Srivatsavai /* Check if our own nick is valid before we do any forwarding */ 7994eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_READER); 8004eaa4710SRishi Srivatsavai ournick = tip->ti_nick; 8014eaa4710SRishi Srivatsavai dtnick = tip->ti_treeroot; 8024eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 8034eaa4710SRishi Srivatsavai if (!VALID_NICK(ournick)) 8044eaa4710SRishi Srivatsavai goto discard; 8054eaa4710SRishi Srivatsavai 8064eaa4710SRishi Srivatsavai /* 8074eaa4710SRishi Srivatsavai * For Multi-Destination forwarding determine our choice of 8084eaa4710SRishi Srivatsavai * root distribution tree. If we didn't choose a distribution 8094eaa4710SRishi Srivatsavai * tree (dtroots_count=0) then we use the highest priority tree 8104eaa4710SRishi Srivatsavai * root (t_treeroot) else we drop the packet without forwarding. 8114eaa4710SRishi Srivatsavai */ 8124eaa4710SRishi Srivatsavai if (egress_nick == RBRIDGE_NICKNAME_NONE) { 8134eaa4710SRishi Srivatsavai if ((self = trill_node_lookup(tip, ournick)) == NULL) 8144eaa4710SRishi Srivatsavai goto discard; 8154eaa4710SRishi Srivatsavai 8164eaa4710SRishi Srivatsavai /* 8174eaa4710SRishi Srivatsavai * Use the first DT configured for now. In future we 8184eaa4710SRishi Srivatsavai * should have DT selection code here. 8194eaa4710SRishi Srivatsavai */ 8204eaa4710SRishi Srivatsavai if (self->tn_ni->tni_dtrootcount > 0) { 8214eaa4710SRishi Srivatsavai dtnick = TNI_DTROOTNICK(self->tn_ni, 0); 8224eaa4710SRishi Srivatsavai } 8234eaa4710SRishi Srivatsavai 8244eaa4710SRishi Srivatsavai trill_node_unref(tip, self); 8254eaa4710SRishi Srivatsavai if (!VALID_NICK(dtnick)) { 8264eaa4710SRishi Srivatsavai DTRACE_PROBE(trill__fwd__packet__nodtroot); 8274eaa4710SRishi Srivatsavai goto discard; 8284eaa4710SRishi Srivatsavai } 8294eaa4710SRishi Srivatsavai } 8304eaa4710SRishi Srivatsavai 8314eaa4710SRishi Srivatsavai /* 8324eaa4710SRishi Srivatsavai * Retrieve VLAN ID of the native frame used for VLAN 8334eaa4710SRishi Srivatsavai * pruning of multi-destination frames. 8344eaa4710SRishi Srivatsavai */ 8354eaa4710SRishi Srivatsavai if (hdr_info->mhi_istagged) { 8364eaa4710SRishi Srivatsavai vlan = VLAN_ID(hdr_info->mhi_tci); 8374eaa4710SRishi Srivatsavai } 8384eaa4710SRishi Srivatsavai 8394eaa4710SRishi Srivatsavai DTRACE_PROBE2(trill__fwd__packet, mac_header_info_t *, hdr_info, 8404eaa4710SRishi Srivatsavai uint16_t, egress_nick); 8414eaa4710SRishi Srivatsavai if (egress_nick == RBRIDGE_NICKNAME_NONE) { 8424eaa4710SRishi Srivatsavai trill_multidest_fwd(tip, mp, dtnick, 8434eaa4710SRishi Srivatsavai ournick, B_FALSE, NULL, vlan, B_TRUE); 8444eaa4710SRishi Srivatsavai } else { 8454eaa4710SRishi Srivatsavai trill_dest_fwd(tip, mp, egress_nick, B_FALSE, B_FALSE, 8464eaa4710SRishi Srivatsavai RBRIDGE_NICKNAME_NONE); 8474eaa4710SRishi Srivatsavai } 8484eaa4710SRishi Srivatsavai KSPINCR(tks_encap); 8494eaa4710SRishi Srivatsavai return; 8504eaa4710SRishi Srivatsavai 8514eaa4710SRishi Srivatsavai discard: 8524eaa4710SRishi Srivatsavai freemsg(mp); 8534eaa4710SRishi Srivatsavai } 8544eaa4710SRishi Srivatsavai 8554eaa4710SRishi Srivatsavai /* 8564eaa4710SRishi Srivatsavai * This is called when the bridge module has completely torn down a bridge 8574eaa4710SRishi Srivatsavai * instance and all of the attached links. We need to make the TRILL instance 8584eaa4710SRishi Srivatsavai * go away at this point. 8594eaa4710SRishi Srivatsavai */ 8604eaa4710SRishi Srivatsavai static void 8614eaa4710SRishi Srivatsavai trill_br_dstr_cb(void *bptr, bridge_inst_t *bip) 8624eaa4710SRishi Srivatsavai { 8634eaa4710SRishi Srivatsavai trill_inst_t *tip = bptr; 8644eaa4710SRishi Srivatsavai 8654eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(bip)); 8664eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_WRITER); 8674eaa4710SRishi Srivatsavai if (tip->ti_binst != NULL) 8684eaa4710SRishi Srivatsavai bridge_trill_brunref(tip->ti_binst); 8694eaa4710SRishi Srivatsavai tip->ti_binst = NULL; 8704eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 8714eaa4710SRishi Srivatsavai } 8724eaa4710SRishi Srivatsavai 8734eaa4710SRishi Srivatsavai /* 8744eaa4710SRishi Srivatsavai * This is called when the bridge module is tearing down a link, but before the 8754eaa4710SRishi Srivatsavai * actual tear-down starts. When this function returns, we must make sure that 8764eaa4710SRishi Srivatsavai * we will not initiate any new transmits on this link. 8774eaa4710SRishi Srivatsavai */ 8784eaa4710SRishi Srivatsavai static void 8794eaa4710SRishi Srivatsavai trill_ln_dstr_cb(void *lptr, bridge_link_t *blp) 8804eaa4710SRishi Srivatsavai { 8814eaa4710SRishi Srivatsavai trill_sock_t *tsock = lptr; 8824eaa4710SRishi Srivatsavai 8834eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(blp)); 8844eaa4710SRishi Srivatsavai trill_stop_recv(tsock); 8854eaa4710SRishi Srivatsavai } 8864eaa4710SRishi Srivatsavai 8874eaa4710SRishi Srivatsavai static void 8884eaa4710SRishi Srivatsavai trill_init(void) 8894eaa4710SRishi Srivatsavai { 8904eaa4710SRishi Srivatsavai list_create(&trill_inst_list, sizeof (trill_inst_t), 8914eaa4710SRishi Srivatsavai offsetof(trill_inst_t, ti_instnode)); 8924eaa4710SRishi Srivatsavai rw_init(&trill_inst_rwlock, NULL, RW_DRIVER, NULL); 8934eaa4710SRishi Srivatsavai bridge_trill_register_cb(trill_recv_pkt_cb, trill_encap_pkt_cb, 8944eaa4710SRishi Srivatsavai trill_br_dstr_cb, trill_ln_dstr_cb); 8954eaa4710SRishi Srivatsavai } 8964eaa4710SRishi Srivatsavai 8974eaa4710SRishi Srivatsavai static void 8984eaa4710SRishi Srivatsavai trill_fini(void) 8994eaa4710SRishi Srivatsavai { 9004eaa4710SRishi Srivatsavai bridge_trill_register_cb(NULL, NULL, NULL, NULL); 9014eaa4710SRishi Srivatsavai rw_destroy(&trill_inst_rwlock); 9024eaa4710SRishi Srivatsavai list_destroy(&trill_inst_list); 9034eaa4710SRishi Srivatsavai } 9044eaa4710SRishi Srivatsavai 9054eaa4710SRishi Srivatsavai /* Loadable module configuration entry points */ 9064eaa4710SRishi Srivatsavai int 9074eaa4710SRishi Srivatsavai _init(void) 9084eaa4710SRishi Srivatsavai { 9094eaa4710SRishi Srivatsavai int rc; 9104eaa4710SRishi Srivatsavai 9114eaa4710SRishi Srivatsavai trill_init(); 9124eaa4710SRishi Srivatsavai if ((rc = mod_install(&ml)) != 0) 9134eaa4710SRishi Srivatsavai trill_fini(); 9144eaa4710SRishi Srivatsavai return (rc); 9154eaa4710SRishi Srivatsavai } 9164eaa4710SRishi Srivatsavai 9174eaa4710SRishi Srivatsavai int 9184eaa4710SRishi Srivatsavai _info(struct modinfo *modinfop) 9194eaa4710SRishi Srivatsavai { 9204eaa4710SRishi Srivatsavai return (mod_info(&ml, modinfop)); 9214eaa4710SRishi Srivatsavai } 9224eaa4710SRishi Srivatsavai 9234eaa4710SRishi Srivatsavai int 9244eaa4710SRishi Srivatsavai _fini(void) 9254eaa4710SRishi Srivatsavai { 9264eaa4710SRishi Srivatsavai int rc; 9274eaa4710SRishi Srivatsavai 9284eaa4710SRishi Srivatsavai rw_enter(&trill_inst_rwlock, RW_READER); 9294eaa4710SRishi Srivatsavai rc = list_is_empty(&trill_inst_list) ? 0 : EBUSY; 9304eaa4710SRishi Srivatsavai rw_exit(&trill_inst_rwlock); 9314eaa4710SRishi Srivatsavai if (rc == 0 && ((rc = mod_remove(&ml)) == 0)) 9324eaa4710SRishi Srivatsavai trill_fini(); 9334eaa4710SRishi Srivatsavai return (rc); 9344eaa4710SRishi Srivatsavai } 9354eaa4710SRishi Srivatsavai 9364eaa4710SRishi Srivatsavai static void 9374eaa4710SRishi Srivatsavai trill_kstats_init(trill_sock_t *tsock, const char *bname) 9384eaa4710SRishi Srivatsavai { 9394eaa4710SRishi Srivatsavai int i; 9404eaa4710SRishi Srivatsavai char kstatname[KSTAT_STRLEN]; 9414eaa4710SRishi Srivatsavai kstat_named_t *knt; 9424eaa4710SRishi Srivatsavai static const char *sock_kstats_list[] = { TRILL_KSSOCK_NAMES }; 9434eaa4710SRishi Srivatsavai char link_name[MAXNAMELEN]; 9444eaa4710SRishi Srivatsavai int num; 9454eaa4710SRishi Srivatsavai int err; 9464eaa4710SRishi Srivatsavai 9474eaa4710SRishi Srivatsavai bzero(link_name, sizeof (link_name)); 9484eaa4710SRishi Srivatsavai if ((err = dls_mgmt_get_linkinfo(tsock->ts_link->bl_linkid, link_name, 9494eaa4710SRishi Srivatsavai NULL, NULL, NULL)) != 0) { 9504eaa4710SRishi Srivatsavai cmn_err(CE_WARN, "%s: trill_kstats_init: error %d retrieving" 9514eaa4710SRishi Srivatsavai " linkinfo for linkid:%d", "trill", err, 9524eaa4710SRishi Srivatsavai tsock->ts_link->bl_linkid); 9534eaa4710SRishi Srivatsavai return; 9544eaa4710SRishi Srivatsavai } 9554eaa4710SRishi Srivatsavai 9564eaa4710SRishi Srivatsavai bzero(kstatname, sizeof (kstatname)); 9574eaa4710SRishi Srivatsavai (void) snprintf(kstatname, sizeof (kstatname), "%s-%s", 9584eaa4710SRishi Srivatsavai bname, link_name); 9594eaa4710SRishi Srivatsavai 9604eaa4710SRishi Srivatsavai num = sizeof (sock_kstats_list) / sizeof (*sock_kstats_list); 9614eaa4710SRishi Srivatsavai for (i = 0; i < num; i++) { 9624eaa4710SRishi Srivatsavai knt = (kstat_named_t *)&(tsock->ts_kstats); 9634eaa4710SRishi Srivatsavai kstat_named_init(&knt[i], sock_kstats_list[i], 9644eaa4710SRishi Srivatsavai KSTAT_DATA_UINT64); 9654eaa4710SRishi Srivatsavai } 9664eaa4710SRishi Srivatsavai 9674eaa4710SRishi Srivatsavai tsock->ts_ksp = kstat_create_zone("trill", 0, kstatname, "sock", 9684eaa4710SRishi Srivatsavai KSTAT_TYPE_NAMED, num, KSTAT_FLAG_VIRTUAL, GLOBAL_ZONEID); 9694eaa4710SRishi Srivatsavai if (tsock->ts_ksp != NULL) { 9704eaa4710SRishi Srivatsavai tsock->ts_ksp->ks_data = &tsock->ts_kstats; 9714eaa4710SRishi Srivatsavai kstat_install(tsock->ts_ksp); 9724eaa4710SRishi Srivatsavai } 9734eaa4710SRishi Srivatsavai } 9744eaa4710SRishi Srivatsavai 9754eaa4710SRishi Srivatsavai static trill_sock_t * 9764eaa4710SRishi Srivatsavai trill_do_open(int flags) 9774eaa4710SRishi Srivatsavai { 9784eaa4710SRishi Srivatsavai trill_sock_t *tsock; 9794eaa4710SRishi Srivatsavai int kmflag = ((flags & SOCKET_NOSLEEP)) ? KM_NOSLEEP:KM_SLEEP; 9804eaa4710SRishi Srivatsavai 9814eaa4710SRishi Srivatsavai tsock = kmem_zalloc(sizeof (trill_sock_t), kmflag); 9824eaa4710SRishi Srivatsavai if (tsock != NULL) { 9834eaa4710SRishi Srivatsavai tsock->ts_state = TS_UNBND; 9844eaa4710SRishi Srivatsavai tsock->ts_refs++; 9854eaa4710SRishi Srivatsavai mutex_init(&tsock->ts_socklock, NULL, MUTEX_DRIVER, NULL); 9864eaa4710SRishi Srivatsavai cv_init(&tsock->ts_sockthreadwait, NULL, CV_DRIVER, NULL); 9874eaa4710SRishi Srivatsavai cv_init(&tsock->ts_sockclosewait, NULL, CV_DRIVER, NULL); 9884eaa4710SRishi Srivatsavai } 9894eaa4710SRishi Srivatsavai return (tsock); 9904eaa4710SRishi Srivatsavai } 9914eaa4710SRishi Srivatsavai 9924eaa4710SRishi Srivatsavai static int 9934eaa4710SRishi Srivatsavai trill_find_bridge(trill_sock_t *tsock, const char *bname, boolean_t can_create) 9944eaa4710SRishi Srivatsavai { 9954eaa4710SRishi Srivatsavai trill_inst_t *tip, *newtip = NULL; 9964eaa4710SRishi Srivatsavai 9974eaa4710SRishi Srivatsavai /* Allocate some memory (speculatively) before taking locks */ 9984eaa4710SRishi Srivatsavai if (can_create) 9994eaa4710SRishi Srivatsavai newtip = kmem_zalloc(sizeof (*tip), KM_NOSLEEP); 10004eaa4710SRishi Srivatsavai 10014eaa4710SRishi Srivatsavai rw_enter(&trill_inst_rwlock, RW_WRITER); 10024eaa4710SRishi Srivatsavai for (tip = list_head(&trill_inst_list); tip != NULL; 10034eaa4710SRishi Srivatsavai tip = list_next(&trill_inst_list, tip)) { 10044eaa4710SRishi Srivatsavai if (strcmp(tip->ti_bridgename, bname) == 0) 10054eaa4710SRishi Srivatsavai break; 10064eaa4710SRishi Srivatsavai } 10074eaa4710SRishi Srivatsavai if (tip == NULL) { 10084eaa4710SRishi Srivatsavai if (!can_create || newtip == NULL) { 10094eaa4710SRishi Srivatsavai rw_exit(&trill_inst_rwlock); 10104eaa4710SRishi Srivatsavai return (can_create ? ENOMEM : ENOENT); 10114eaa4710SRishi Srivatsavai } 10124eaa4710SRishi Srivatsavai 10134eaa4710SRishi Srivatsavai tip = newtip; 10144eaa4710SRishi Srivatsavai newtip = NULL; 10154eaa4710SRishi Srivatsavai (void) strcpy(tip->ti_bridgename, bname); 10164eaa4710SRishi Srivatsavai 10174eaa4710SRishi Srivatsavai /* Register TRILL instance with bridging */ 10184eaa4710SRishi Srivatsavai tip->ti_binst = bridge_trill_brref(bname, tip); 10194eaa4710SRishi Srivatsavai if (tip->ti_binst == NULL) { 10204eaa4710SRishi Srivatsavai rw_exit(&trill_inst_rwlock); 10214eaa4710SRishi Srivatsavai kmem_free(tip, sizeof (*tip)); 10224eaa4710SRishi Srivatsavai return (ENOENT); 10234eaa4710SRishi Srivatsavai } 10244eaa4710SRishi Srivatsavai 10254eaa4710SRishi Srivatsavai rw_init(&tip->ti_rwlock, NULL, RW_DRIVER, NULL); 10264eaa4710SRishi Srivatsavai list_create(&tip->ti_socklist, sizeof (trill_sock_t), 10274eaa4710SRishi Srivatsavai offsetof(trill_sock_t, ts_socklistnode)); 10284eaa4710SRishi Srivatsavai list_insert_tail(&trill_inst_list, tip); 10294eaa4710SRishi Srivatsavai } 10304eaa4710SRishi Srivatsavai atomic_inc_uint(&tip->ti_refs); 10314eaa4710SRishi Srivatsavai rw_exit(&trill_inst_rwlock); 10324eaa4710SRishi Srivatsavai 10334eaa4710SRishi Srivatsavai /* If we didn't need the preallocated memory, then discard now. */ 10344eaa4710SRishi Srivatsavai if (newtip != NULL) 10354eaa4710SRishi Srivatsavai kmem_free(newtip, sizeof (*newtip)); 10364eaa4710SRishi Srivatsavai 10374eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_WRITER); 10384eaa4710SRishi Srivatsavai list_insert_tail(&(tip->ti_socklist), tsock); 10394eaa4710SRishi Srivatsavai tsock->ts_tip = tip; 10404eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 10414eaa4710SRishi Srivatsavai return (0); 10424eaa4710SRishi Srivatsavai } 10434eaa4710SRishi Srivatsavai 10444eaa4710SRishi Srivatsavai static void 10454eaa4710SRishi Srivatsavai trill_clear_bridge(trill_sock_t *tsock) 10464eaa4710SRishi Srivatsavai { 10474eaa4710SRishi Srivatsavai trill_inst_t *tip; 10484eaa4710SRishi Srivatsavai 10494eaa4710SRishi Srivatsavai if ((tip = tsock->ts_tip) == NULL) 10504eaa4710SRishi Srivatsavai return; 10514eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_WRITER); 10524eaa4710SRishi Srivatsavai list_remove(&tip->ti_socklist, tsock); 10534eaa4710SRishi Srivatsavai if (list_is_empty(&tip->ti_socklist)) 10544eaa4710SRishi Srivatsavai trill_del_all(tip, B_TRUE); 10554eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 10564eaa4710SRishi Srivatsavai } 10574eaa4710SRishi Srivatsavai 10584eaa4710SRishi Srivatsavai static void 10594eaa4710SRishi Srivatsavai trill_sock_unref(trill_sock_t *tsock) 10604eaa4710SRishi Srivatsavai { 10614eaa4710SRishi Srivatsavai if (atomic_dec_uint_nv(&tsock->ts_refs) == 0) { 10624eaa4710SRishi Srivatsavai mutex_destroy(&tsock->ts_socklock); 10634eaa4710SRishi Srivatsavai cv_destroy(&tsock->ts_sockthreadwait); 10644eaa4710SRishi Srivatsavai cv_destroy(&tsock->ts_sockclosewait); 10654eaa4710SRishi Srivatsavai kmem_free(tsock, sizeof (trill_sock_t)); 10664eaa4710SRishi Srivatsavai } 10674eaa4710SRishi Srivatsavai } 10684eaa4710SRishi Srivatsavai 10694eaa4710SRishi Srivatsavai static void 10704eaa4710SRishi Srivatsavai trill_do_close(trill_sock_t *tsock) 10714eaa4710SRishi Srivatsavai { 10724eaa4710SRishi Srivatsavai trill_inst_t *tip; 10734eaa4710SRishi Srivatsavai 10744eaa4710SRishi Srivatsavai tip = tsock->ts_tip; 10754eaa4710SRishi Srivatsavai trill_stop_recv(tsock); 10764eaa4710SRishi Srivatsavai /* Remove socket from TRILL instance socket list */ 10774eaa4710SRishi Srivatsavai trill_clear_bridge(tsock); 10784eaa4710SRishi Srivatsavai tsock->ts_flags |= TSF_SHUTDOWN; 10794eaa4710SRishi Srivatsavai trill_sock_unref(tsock); 10804eaa4710SRishi Srivatsavai if (tip != NULL) 10814eaa4710SRishi Srivatsavai trill_instance_unref(tip); 10824eaa4710SRishi Srivatsavai } 10834eaa4710SRishi Srivatsavai 10844eaa4710SRishi Srivatsavai static void 10854eaa4710SRishi Srivatsavai trill_del_all(trill_inst_t *tip, boolean_t lockheld) 10864eaa4710SRishi Srivatsavai { 10874eaa4710SRishi Srivatsavai int i; 10884eaa4710SRishi Srivatsavai 10894eaa4710SRishi Srivatsavai if (!lockheld) 10904eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_WRITER); 10914eaa4710SRishi Srivatsavai for (i = RBRIDGE_NICKNAME_MIN; i < RBRIDGE_NICKNAME_MAX; i++) { 10924eaa4710SRishi Srivatsavai if (tip->ti_nodes[i] != NULL) 10934eaa4710SRishi Srivatsavai (void) trill_del_nick(tip, i, B_TRUE); 10944eaa4710SRishi Srivatsavai } 10954eaa4710SRishi Srivatsavai if (!lockheld) 10964eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 10974eaa4710SRishi Srivatsavai } 10984eaa4710SRishi Srivatsavai 10994eaa4710SRishi Srivatsavai static void 11004eaa4710SRishi Srivatsavai trill_node_free(trill_node_t *nick_entry) 11014eaa4710SRishi Srivatsavai { 11024eaa4710SRishi Srivatsavai trill_nickinfo_t *tni; 11034eaa4710SRishi Srivatsavai 11044eaa4710SRishi Srivatsavai tni = nick_entry->tn_ni; 11054eaa4710SRishi Srivatsavai kmem_free(tni, TNI_TOTALSIZE(tni)); 11064eaa4710SRishi Srivatsavai kmem_free(nick_entry, sizeof (trill_node_t)); 11074eaa4710SRishi Srivatsavai } 11084eaa4710SRishi Srivatsavai 11094eaa4710SRishi Srivatsavai static void 11104eaa4710SRishi Srivatsavai trill_node_unref(trill_inst_t *tip, trill_node_t *tnp) 11114eaa4710SRishi Srivatsavai { 11124eaa4710SRishi Srivatsavai if (atomic_dec_uint_nv(&tnp->tn_refs) == 0) { 11134eaa4710SRishi Srivatsavai if (tnp->tn_tsp != NULL) 11144eaa4710SRishi Srivatsavai trill_sock_unref(tnp->tn_tsp); 11154eaa4710SRishi Srivatsavai trill_node_free(tnp); 1116*640c1670SJosef 'Jeff' Sipek atomic_dec_uint(&tip->ti_nodecount); 11174eaa4710SRishi Srivatsavai } 11184eaa4710SRishi Srivatsavai } 11194eaa4710SRishi Srivatsavai 11204eaa4710SRishi Srivatsavai static trill_node_t * 11214eaa4710SRishi Srivatsavai trill_node_lookup(trill_inst_t *tip, uint16_t nick) 11224eaa4710SRishi Srivatsavai { 11234eaa4710SRishi Srivatsavai trill_node_t *nick_entry; 11244eaa4710SRishi Srivatsavai 11254eaa4710SRishi Srivatsavai if (!VALID_NICK(nick)) 11264eaa4710SRishi Srivatsavai return (NULL); 11274eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_READER); 11284eaa4710SRishi Srivatsavai nick_entry = tip->ti_nodes[nick]; 11294eaa4710SRishi Srivatsavai if (nick_entry != NULL) { 11304eaa4710SRishi Srivatsavai atomic_inc_uint(&nick_entry->tn_refs); 11314eaa4710SRishi Srivatsavai } 11324eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 11334eaa4710SRishi Srivatsavai return (nick_entry); 11344eaa4710SRishi Srivatsavai } 11354eaa4710SRishi Srivatsavai 11364eaa4710SRishi Srivatsavai static int 11374eaa4710SRishi Srivatsavai trill_del_nick(trill_inst_t *tip, uint16_t nick, boolean_t lockheld) 11384eaa4710SRishi Srivatsavai { 11394eaa4710SRishi Srivatsavai trill_node_t *nick_entry; 11404eaa4710SRishi Srivatsavai int rc = ENOENT; 11414eaa4710SRishi Srivatsavai 11424eaa4710SRishi Srivatsavai if (!lockheld) 11434eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_WRITER); 11444eaa4710SRishi Srivatsavai if (VALID_NICK(nick)) { 11454eaa4710SRishi Srivatsavai nick_entry = tip->ti_nodes[nick]; 11464eaa4710SRishi Srivatsavai if (nick_entry != NULL) { 11474eaa4710SRishi Srivatsavai trill_node_unref(tip, nick_entry); 11484eaa4710SRishi Srivatsavai tip->ti_nodes[nick] = NULL; 11494eaa4710SRishi Srivatsavai rc = 0; 11504eaa4710SRishi Srivatsavai } 11514eaa4710SRishi Srivatsavai } 11524eaa4710SRishi Srivatsavai if (!lockheld) 11534eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 11544eaa4710SRishi Srivatsavai return (rc); 11554eaa4710SRishi Srivatsavai } 11564eaa4710SRishi Srivatsavai 11574eaa4710SRishi Srivatsavai static int 11584eaa4710SRishi Srivatsavai trill_add_nick(trill_inst_t *tip, void *arg, boolean_t self, int mode) 11594eaa4710SRishi Srivatsavai { 11604eaa4710SRishi Srivatsavai uint16_t nick; 11614eaa4710SRishi Srivatsavai int size; 11624eaa4710SRishi Srivatsavai trill_node_t *tnode; 11634eaa4710SRishi Srivatsavai trill_nickinfo_t tnihdr; 11644eaa4710SRishi Srivatsavai 11654eaa4710SRishi Srivatsavai /* First make sure we have at least the header available */ 11664eaa4710SRishi Srivatsavai if (ddi_copyin(arg, &tnihdr, sizeof (trill_nickinfo_t), mode) != 0) 11674eaa4710SRishi Srivatsavai return (EFAULT); 11684eaa4710SRishi Srivatsavai 11694eaa4710SRishi Srivatsavai nick = tnihdr.tni_nick; 11704eaa4710SRishi Srivatsavai if (!VALID_NICK(nick)) { 11714eaa4710SRishi Srivatsavai DTRACE_PROBE1(trill__add__nick__bad, trill_nickinfo_t *, 11724eaa4710SRishi Srivatsavai &tnihdr); 11734eaa4710SRishi Srivatsavai return (EINVAL); 11744eaa4710SRishi Srivatsavai } 11754eaa4710SRishi Srivatsavai 11764eaa4710SRishi Srivatsavai size = TNI_TOTALSIZE(&tnihdr); 11774eaa4710SRishi Srivatsavai if (size > TNI_MAXSIZE) 11784eaa4710SRishi Srivatsavai return (EINVAL); 11794eaa4710SRishi Srivatsavai tnode = kmem_zalloc(sizeof (trill_node_t), KM_SLEEP); 11804eaa4710SRishi Srivatsavai tnode->tn_ni = kmem_zalloc(size, KM_SLEEP); 11814eaa4710SRishi Srivatsavai if (ddi_copyin(arg, tnode->tn_ni, size, mode) != 0) { 11824eaa4710SRishi Srivatsavai kmem_free(tnode->tn_ni, size); 11834eaa4710SRishi Srivatsavai kmem_free(tnode, sizeof (trill_node_t)); 11844eaa4710SRishi Srivatsavai return (EFAULT); 11854eaa4710SRishi Srivatsavai } 11864eaa4710SRishi Srivatsavai 11874eaa4710SRishi Srivatsavai tnode->tn_refs++; 11884eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_WRITER); 11894eaa4710SRishi Srivatsavai if (tip->ti_nodes[nick] != NULL) 11904eaa4710SRishi Srivatsavai (void) trill_del_nick(tip, nick, B_TRUE); 11914eaa4710SRishi Srivatsavai 11924eaa4710SRishi Srivatsavai if (self) { 11934eaa4710SRishi Srivatsavai tip->ti_nick = nick; 11944eaa4710SRishi Srivatsavai } else { 11954eaa4710SRishi Srivatsavai tnode->tn_tsp = find_trill_link(tip, 11964eaa4710SRishi Srivatsavai tnode->tn_ni->tni_linkid); 11974eaa4710SRishi Srivatsavai } 11984eaa4710SRishi Srivatsavai DTRACE_PROBE2(trill__add__nick, trill_node_t *, tnode, 11994eaa4710SRishi Srivatsavai uint16_t, nick); 12004eaa4710SRishi Srivatsavai tip->ti_nodes[nick] = tnode; 12014eaa4710SRishi Srivatsavai tip->ti_nodecount++; 12024eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 12034eaa4710SRishi Srivatsavai return (0); 12044eaa4710SRishi Srivatsavai } 12054eaa4710SRishi Srivatsavai 12064eaa4710SRishi Srivatsavai static int 12074eaa4710SRishi Srivatsavai trill_do_ioctl(trill_sock_t *tsock, int cmd, void *arg, int mode) 12084eaa4710SRishi Srivatsavai { 12094eaa4710SRishi Srivatsavai int error = 0; 12104eaa4710SRishi Srivatsavai trill_inst_t *tip = tsock->ts_tip; 12114eaa4710SRishi Srivatsavai 12124eaa4710SRishi Srivatsavai switch (cmd) { 12134eaa4710SRishi Srivatsavai case TRILL_DESIGVLAN: { 12144eaa4710SRishi Srivatsavai uint16_t desigvlan; 12154eaa4710SRishi Srivatsavai 12164eaa4710SRishi Srivatsavai if (ddi_copyin(arg, &desigvlan, sizeof (desigvlan), mode) != 0) 12174eaa4710SRishi Srivatsavai return (EFAULT); 12184eaa4710SRishi Srivatsavai tsock->ts_desigvlan = desigvlan; 12194eaa4710SRishi Srivatsavai break; 12204eaa4710SRishi Srivatsavai } 12214eaa4710SRishi Srivatsavai case TRILL_VLANFWDER: { 12224eaa4710SRishi Srivatsavai uint8_t vlans[TRILL_VLANS_ARRSIZE]; 12234eaa4710SRishi Srivatsavai 12244eaa4710SRishi Srivatsavai if (tsock->ts_link == NULL) 12254eaa4710SRishi Srivatsavai return (EINVAL); 12264eaa4710SRishi Srivatsavai if ((ddi_copyin(arg, vlans, sizeof (vlans), mode)) != 0) 12274eaa4710SRishi Srivatsavai return (EFAULT); 12284eaa4710SRishi Srivatsavai bridge_trill_setvlans(tsock->ts_link, vlans); 12294eaa4710SRishi Srivatsavai break; 12304eaa4710SRishi Srivatsavai } 12314eaa4710SRishi Srivatsavai case TRILL_SETNICK: 12324eaa4710SRishi Srivatsavai if (tip == NULL) 12334eaa4710SRishi Srivatsavai return (EINVAL); 12344eaa4710SRishi Srivatsavai error = trill_add_nick(tip, arg, B_TRUE, mode); 12354eaa4710SRishi Srivatsavai break; 12364eaa4710SRishi Srivatsavai 12374eaa4710SRishi Srivatsavai case TRILL_GETNICK: 12384eaa4710SRishi Srivatsavai if (tip == NULL) 12394eaa4710SRishi Srivatsavai return (EINVAL); 12404eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_READER); 12414eaa4710SRishi Srivatsavai if (ddi_copyout(&tip->ti_nick, arg, sizeof (tip->ti_nick), 12424eaa4710SRishi Srivatsavai mode) != 0) 12434eaa4710SRishi Srivatsavai error = EFAULT; 12444eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 12454eaa4710SRishi Srivatsavai break; 12464eaa4710SRishi Srivatsavai 12474eaa4710SRishi Srivatsavai case TRILL_ADDNICK: 12484eaa4710SRishi Srivatsavai if (tip == NULL) 12494eaa4710SRishi Srivatsavai break; 12504eaa4710SRishi Srivatsavai error = trill_add_nick(tip, arg, B_FALSE, mode); 12514eaa4710SRishi Srivatsavai break; 12524eaa4710SRishi Srivatsavai 12534eaa4710SRishi Srivatsavai case TRILL_DELNICK: { 12544eaa4710SRishi Srivatsavai uint16_t delnick; 12554eaa4710SRishi Srivatsavai 12564eaa4710SRishi Srivatsavai if (tip == NULL) 12574eaa4710SRishi Srivatsavai break; 12584eaa4710SRishi Srivatsavai if (ddi_copyin(arg, &delnick, sizeof (delnick), mode) != 0) 12594eaa4710SRishi Srivatsavai return (EFAULT); 12604eaa4710SRishi Srivatsavai error = trill_del_nick(tip, delnick, B_FALSE); 12614eaa4710SRishi Srivatsavai break; 12624eaa4710SRishi Srivatsavai } 12634eaa4710SRishi Srivatsavai case TRILL_DELALL: 12644eaa4710SRishi Srivatsavai if (tip == NULL) 12654eaa4710SRishi Srivatsavai break; 12664eaa4710SRishi Srivatsavai trill_del_all(tip, B_FALSE); 12674eaa4710SRishi Srivatsavai break; 12684eaa4710SRishi Srivatsavai 12694eaa4710SRishi Srivatsavai case TRILL_TREEROOT: { 12704eaa4710SRishi Srivatsavai uint16_t treeroot; 12714eaa4710SRishi Srivatsavai 12724eaa4710SRishi Srivatsavai if (tip == NULL) 12734eaa4710SRishi Srivatsavai break; 12744eaa4710SRishi Srivatsavai if (ddi_copyin(arg, &treeroot, sizeof (treeroot), mode) != 0) 12754eaa4710SRishi Srivatsavai return (EFAULT); 12764eaa4710SRishi Srivatsavai if (!VALID_NICK(treeroot)) 12774eaa4710SRishi Srivatsavai return (EINVAL); 12784eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_WRITER); 12794eaa4710SRishi Srivatsavai tip->ti_treeroot = treeroot; 12804eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 12814eaa4710SRishi Srivatsavai break; 12824eaa4710SRishi Srivatsavai } 12834eaa4710SRishi Srivatsavai case TRILL_HWADDR: 12844eaa4710SRishi Srivatsavai if (tsock->ts_link == NULL) 12854eaa4710SRishi Srivatsavai break; 12864eaa4710SRishi Srivatsavai if (ddi_copyout(tsock->ts_link->bl_local_mac, arg, ETHERADDRL, 12874eaa4710SRishi Srivatsavai mode) != 0) 12884eaa4710SRishi Srivatsavai return (EFAULT); 12894eaa4710SRishi Srivatsavai break; 12904eaa4710SRishi Srivatsavai 12914eaa4710SRishi Srivatsavai case TRILL_NEWBRIDGE: { 12924eaa4710SRishi Srivatsavai char bname[MAXLINKNAMELEN]; 12934eaa4710SRishi Srivatsavai 12944eaa4710SRishi Srivatsavai if (tsock->ts_state != TS_UNBND) 12954eaa4710SRishi Srivatsavai return (ENOTSUP); 12964eaa4710SRishi Srivatsavai /* ts_tip can only be set once */ 12974eaa4710SRishi Srivatsavai if (tip != NULL) 12984eaa4710SRishi Srivatsavai return (EEXIST); 12994eaa4710SRishi Srivatsavai if (ddi_copyin(arg, bname, sizeof (bname), mode) != 0) 13004eaa4710SRishi Srivatsavai return (EFAULT); 13014eaa4710SRishi Srivatsavai bname[MAXLINKNAMELEN-1] = '\0'; 13024eaa4710SRishi Srivatsavai error = trill_find_bridge(tsock, bname, B_TRUE); 13034eaa4710SRishi Srivatsavai break; 13044eaa4710SRishi Srivatsavai } 13054eaa4710SRishi Srivatsavai 13064eaa4710SRishi Srivatsavai case TRILL_GETBRIDGE: { 13074eaa4710SRishi Srivatsavai char bname[MAXLINKNAMELEN]; 13084eaa4710SRishi Srivatsavai 13094eaa4710SRishi Srivatsavai /* ts_tip can only be set once */ 13104eaa4710SRishi Srivatsavai if (tip != NULL) 13114eaa4710SRishi Srivatsavai return (EEXIST); 13124eaa4710SRishi Srivatsavai if (ddi_copyin(arg, bname, sizeof (bname), mode) != 0) 13134eaa4710SRishi Srivatsavai return (EFAULT); 13144eaa4710SRishi Srivatsavai bname[MAXLINKNAMELEN - 1] = '\0'; 13154eaa4710SRishi Srivatsavai error = trill_find_bridge(tsock, bname, B_FALSE); 13164eaa4710SRishi Srivatsavai break; 13174eaa4710SRishi Srivatsavai } 13184eaa4710SRishi Srivatsavai 13194eaa4710SRishi Srivatsavai case TRILL_LISTNICK: { 13204eaa4710SRishi Srivatsavai trill_listnick_t tln; 13214eaa4710SRishi Srivatsavai trill_node_t *tnp; 13224eaa4710SRishi Srivatsavai trill_nickinfo_t *tnip; 13234eaa4710SRishi Srivatsavai uint16_t nick; 13244eaa4710SRishi Srivatsavai 13254eaa4710SRishi Srivatsavai if (tip == NULL) 13264eaa4710SRishi Srivatsavai return (EINVAL); 13274eaa4710SRishi Srivatsavai if (ddi_copyin(arg, &tln, sizeof (tln), mode) != 0) 13284eaa4710SRishi Srivatsavai return (EFAULT); 13294eaa4710SRishi Srivatsavai nick = tln.tln_nick; 13304eaa4710SRishi Srivatsavai if (nick >= RBRIDGE_NICKNAME_MAX) { 13314eaa4710SRishi Srivatsavai error = EINVAL; 13324eaa4710SRishi Srivatsavai break; 13334eaa4710SRishi Srivatsavai } 13344eaa4710SRishi Srivatsavai rw_enter(&tip->ti_rwlock, RW_READER); 13354eaa4710SRishi Srivatsavai while (++nick < RBRIDGE_NICKNAME_MAX) { 13364eaa4710SRishi Srivatsavai if ((tnp = tip->ti_nodes[nick]) != NULL) { 13374eaa4710SRishi Srivatsavai tnip = tnp->tn_ni; 13384eaa4710SRishi Srivatsavai ASSERT(nick == tnip->tni_nick); 13394eaa4710SRishi Srivatsavai tln.tln_nick = nick; 13404eaa4710SRishi Srivatsavai bcopy(tnip->tni_adjsnpa, tln.tln_nexthop, 13414eaa4710SRishi Srivatsavai ETHERADDRL); 13424eaa4710SRishi Srivatsavai tln.tln_ours = nick == tip->ti_nick; 13434eaa4710SRishi Srivatsavai if (tln.tln_ours || tnp->tn_tsp == NULL) { 13444eaa4710SRishi Srivatsavai tln.tln_linkid = 13454eaa4710SRishi Srivatsavai DATALINK_INVALID_LINKID; 13464eaa4710SRishi Srivatsavai } else { 13474eaa4710SRishi Srivatsavai tln.tln_linkid = 13484eaa4710SRishi Srivatsavai tnp->tn_tsp->ts_link->bl_linkid; 13494eaa4710SRishi Srivatsavai } 13504eaa4710SRishi Srivatsavai break; 13514eaa4710SRishi Srivatsavai } 13524eaa4710SRishi Srivatsavai } 13534eaa4710SRishi Srivatsavai rw_exit(&tip->ti_rwlock); 13544eaa4710SRishi Srivatsavai if (nick >= RBRIDGE_NICKNAME_MAX) 13554eaa4710SRishi Srivatsavai bzero(&tln, sizeof (tln)); 13564eaa4710SRishi Srivatsavai if (ddi_copyout(&tln, arg, sizeof (tln), mode) != 0) 13574eaa4710SRishi Srivatsavai return (EFAULT); 13584eaa4710SRishi Srivatsavai break; 13594eaa4710SRishi Srivatsavai } 13604eaa4710SRishi Srivatsavai 13614eaa4710SRishi Srivatsavai /* 13624eaa4710SRishi Srivatsavai * Port flush: this is used when we lose AF on a port. We must discard 13634eaa4710SRishi Srivatsavai * all regular bridge forwarding entries on this port with the 13644eaa4710SRishi Srivatsavai * indicated VLAN. 13654eaa4710SRishi Srivatsavai */ 13664eaa4710SRishi Srivatsavai case TRILL_PORTFLUSH: { 13674eaa4710SRishi Srivatsavai uint16_t vlan = (uint16_t)(uintptr_t)arg; 13684eaa4710SRishi Srivatsavai 13694eaa4710SRishi Srivatsavai if (tsock->ts_link == NULL) 13704eaa4710SRishi Srivatsavai return (EINVAL); 13714eaa4710SRishi Srivatsavai bridge_trill_flush(tsock->ts_link, vlan, B_FALSE); 13724eaa4710SRishi Srivatsavai break; 13734eaa4710SRishi Srivatsavai } 13744eaa4710SRishi Srivatsavai 13754eaa4710SRishi Srivatsavai /* 13764eaa4710SRishi Srivatsavai * Nick flush: this is used when we lose AF on a port. We must discard 13774eaa4710SRishi Srivatsavai * all bridge TRILL forwarding entries on this port with the indicated 13784eaa4710SRishi Srivatsavai * VLAN. 13794eaa4710SRishi Srivatsavai */ 13804eaa4710SRishi Srivatsavai case TRILL_NICKFLUSH: { 13814eaa4710SRishi Srivatsavai uint16_t vlan = (uint16_t)(uintptr_t)arg; 13824eaa4710SRishi Srivatsavai 13834eaa4710SRishi Srivatsavai if (tsock->ts_link == NULL) 13844eaa4710SRishi Srivatsavai return (EINVAL); 13854eaa4710SRishi Srivatsavai bridge_trill_flush(tsock->ts_link, vlan, B_TRUE); 13864eaa4710SRishi Srivatsavai break; 13874eaa4710SRishi Srivatsavai } 13884eaa4710SRishi Srivatsavai 13894eaa4710SRishi Srivatsavai case TRILL_GETMTU: 13904eaa4710SRishi Srivatsavai if (tsock->ts_link == NULL) 13914eaa4710SRishi Srivatsavai break; 13924eaa4710SRishi Srivatsavai if (ddi_copyout(&tsock->ts_link->bl_maxsdu, arg, 13934eaa4710SRishi Srivatsavai sizeof (uint_t), mode) != 0) 13944eaa4710SRishi Srivatsavai return (EFAULT); 13954eaa4710SRishi Srivatsavai break; 13964eaa4710SRishi Srivatsavai 13974eaa4710SRishi Srivatsavai default: 13984eaa4710SRishi Srivatsavai error = ENOTSUP; 13994eaa4710SRishi Srivatsavai break; 14004eaa4710SRishi Srivatsavai } 14014eaa4710SRishi Srivatsavai 14024eaa4710SRishi Srivatsavai return (error); 14034eaa4710SRishi Srivatsavai } 14044eaa4710SRishi Srivatsavai 14054eaa4710SRishi Srivatsavai /* 14064eaa4710SRishi Srivatsavai * Sends received packet back upstream on the TRILL socket. 14074eaa4710SRishi Srivatsavai * Consumes passed mblk_t. 14084eaa4710SRishi Srivatsavai */ 14094eaa4710SRishi Srivatsavai static void 14104eaa4710SRishi Srivatsavai trill_ctrl_input(trill_sock_t *tsock, mblk_t *mp, const uint8_t *saddr, 14114eaa4710SRishi Srivatsavai uint16_t tci) 14124eaa4710SRishi Srivatsavai { 14134eaa4710SRishi Srivatsavai int udi_size; 14144eaa4710SRishi Srivatsavai mblk_t *mp1; 14154eaa4710SRishi Srivatsavai struct T_unitdata_ind *tudi; 14164eaa4710SRishi Srivatsavai struct sockaddr_dl *sdl; 14174eaa4710SRishi Srivatsavai char *lladdr; 14184eaa4710SRishi Srivatsavai int error; 14194eaa4710SRishi Srivatsavai 14204eaa4710SRishi Srivatsavai ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN)); 14214eaa4710SRishi Srivatsavai if (tsock->ts_flow_ctrld) { 14224eaa4710SRishi Srivatsavai freemsg(mp); 14234eaa4710SRishi Srivatsavai KSPINCR(tks_drops); 14244eaa4710SRishi Srivatsavai return; 14254eaa4710SRishi Srivatsavai } 14264eaa4710SRishi Srivatsavai 14274eaa4710SRishi Srivatsavai udi_size = sizeof (struct T_unitdata_ind) + 14284eaa4710SRishi Srivatsavai sizeof (struct sockaddr_dl); 14294eaa4710SRishi Srivatsavai mp1 = allocb(udi_size, BPRI_MED); 14304eaa4710SRishi Srivatsavai if (mp1 == NULL) { 14314eaa4710SRishi Srivatsavai freemsg(mp); 14324eaa4710SRishi Srivatsavai KSPINCR(tks_drops); 14334eaa4710SRishi Srivatsavai return; 14344eaa4710SRishi Srivatsavai } 14354eaa4710SRishi Srivatsavai 14364eaa4710SRishi Srivatsavai mp1->b_cont = mp; 14374eaa4710SRishi Srivatsavai mp = mp1; 14384eaa4710SRishi Srivatsavai mp->b_datap->db_type = M_PROTO; 14394eaa4710SRishi Srivatsavai /* LINTED: alignment */ 14404eaa4710SRishi Srivatsavai tudi = (struct T_unitdata_ind *)mp->b_rptr; 14414eaa4710SRishi Srivatsavai mp->b_wptr = (uchar_t *)tudi + udi_size; 14424eaa4710SRishi Srivatsavai 14434eaa4710SRishi Srivatsavai tudi->PRIM_type = T_UNITDATA_IND; 14444eaa4710SRishi Srivatsavai tudi->SRC_length = sizeof (struct sockaddr_dl); 14454eaa4710SRishi Srivatsavai tudi->SRC_offset = sizeof (struct T_unitdata_ind); 14464eaa4710SRishi Srivatsavai tudi->OPT_length = 0; 14474eaa4710SRishi Srivatsavai tudi->OPT_offset = sizeof (struct T_unitdata_ind) + 14484eaa4710SRishi Srivatsavai sizeof (struct sockaddr_dl); 14494eaa4710SRishi Srivatsavai 14504eaa4710SRishi Srivatsavai /* Information of the link on which packet was received. */ 14514eaa4710SRishi Srivatsavai sdl = (struct sockaddr_dl *)&tudi[1]; 14524eaa4710SRishi Srivatsavai (void) memset(sdl, 0, sizeof (struct sockaddr_dl)); 14534eaa4710SRishi Srivatsavai sdl->sdl_family = AF_TRILL; 14544eaa4710SRishi Srivatsavai 14554eaa4710SRishi Srivatsavai /* LINTED: alignment */ 14564eaa4710SRishi Srivatsavai *(datalink_id_t *)sdl->sdl_data = tsock->ts_link->bl_linkid; 14574eaa4710SRishi Srivatsavai sdl->sdl_nlen = sizeof (tsock->ts_link->bl_linkid); 14584eaa4710SRishi Srivatsavai 14594eaa4710SRishi Srivatsavai lladdr = LLADDR(sdl); 14604eaa4710SRishi Srivatsavai (void) memcpy(lladdr, saddr, ETHERADDRL); 14614eaa4710SRishi Srivatsavai lladdr += ETHERADDRL; 14624eaa4710SRishi Srivatsavai sdl->sdl_alen = ETHERADDRL; 14634eaa4710SRishi Srivatsavai 14644eaa4710SRishi Srivatsavai /* LINTED: alignment */ 14654eaa4710SRishi Srivatsavai *(uint16_t *)lladdr = tci; 14664eaa4710SRishi Srivatsavai sdl->sdl_slen = sizeof (uint16_t); 14674eaa4710SRishi Srivatsavai 14684eaa4710SRishi Srivatsavai DTRACE_PROBE2(trill__ctrl__input, trill_sock_t *, tsock, mblk_t *, mp); 14694eaa4710SRishi Srivatsavai (*tsock->ts_conn_upcalls->su_recv)(tsock->ts_conn_upper_handle, 14704eaa4710SRishi Srivatsavai mp, msgdsize(mp), 0, &error, NULL); 14714eaa4710SRishi Srivatsavai 14724eaa4710SRishi Srivatsavai if (error == ENOSPC) { 14734eaa4710SRishi Srivatsavai mutex_enter(&tsock->ts_socklock); 14744eaa4710SRishi Srivatsavai (*tsock->ts_conn_upcalls->su_recv)(tsock->ts_conn_upper_handle, 14754eaa4710SRishi Srivatsavai NULL, 0, 0, &error, NULL); 14764eaa4710SRishi Srivatsavai if (error == ENOSPC) 14774eaa4710SRishi Srivatsavai tsock->ts_flow_ctrld = B_TRUE; 14784eaa4710SRishi Srivatsavai mutex_exit(&tsock->ts_socklock); 14794eaa4710SRishi Srivatsavai KSPINCR(tks_drops); 14804eaa4710SRishi Srivatsavai } else if (error != 0) { 14814eaa4710SRishi Srivatsavai KSPINCR(tks_drops); 14824eaa4710SRishi Srivatsavai } else { 14834eaa4710SRishi Srivatsavai KSPINCR(tks_recv); 14844eaa4710SRishi Srivatsavai } 14854eaa4710SRishi Srivatsavai 14864eaa4710SRishi Srivatsavai DTRACE_PROBE2(trill__ctrl__input__done, trill_sock_t *, 14874eaa4710SRishi Srivatsavai tsock, int, error); 14884eaa4710SRishi Srivatsavai } 14894eaa4710SRishi Srivatsavai 14904eaa4710SRishi Srivatsavai /* ARGSUSED */ 14914eaa4710SRishi Srivatsavai static void 14924eaa4710SRishi Srivatsavai trill_activate(sock_lower_handle_t proto_handle, 14934eaa4710SRishi Srivatsavai sock_upper_handle_t sock_handle, sock_upcalls_t *sock_upcalls, 14944eaa4710SRishi Srivatsavai int flags, cred_t *cr) 14954eaa4710SRishi Srivatsavai { 14964eaa4710SRishi Srivatsavai trill_sock_t *tsock = (trill_sock_t *)proto_handle; 14974eaa4710SRishi Srivatsavai struct sock_proto_props sopp; 14984eaa4710SRishi Srivatsavai 14994eaa4710SRishi Srivatsavai tsock->ts_conn_upcalls = sock_upcalls; 15004eaa4710SRishi Srivatsavai tsock->ts_conn_upper_handle = sock_handle; 15014eaa4710SRishi Srivatsavai 15024eaa4710SRishi Srivatsavai sopp.sopp_flags = SOCKOPT_WROFF | SOCKOPT_RCVHIWAT | 15034eaa4710SRishi Srivatsavai SOCKOPT_RCVLOWAT | SOCKOPT_MAXADDRLEN | SOCKOPT_MAXPSZ | 15044eaa4710SRishi Srivatsavai SOCKOPT_MAXBLK | SOCKOPT_MINPSZ; 15054eaa4710SRishi Srivatsavai sopp.sopp_wroff = 0; 15064eaa4710SRishi Srivatsavai sopp.sopp_rxhiwat = SOCKET_RECVHIWATER; 15074eaa4710SRishi Srivatsavai sopp.sopp_rxlowat = SOCKET_RECVLOWATER; 15084eaa4710SRishi Srivatsavai sopp.sopp_maxaddrlen = sizeof (struct sockaddr_dl); 15094eaa4710SRishi Srivatsavai sopp.sopp_maxpsz = INFPSZ; 15104eaa4710SRishi Srivatsavai sopp.sopp_maxblk = INFPSZ; 15114eaa4710SRishi Srivatsavai sopp.sopp_minpsz = 0; 15124eaa4710SRishi Srivatsavai (*tsock->ts_conn_upcalls->su_set_proto_props)( 15134eaa4710SRishi Srivatsavai tsock->ts_conn_upper_handle, &sopp); 15144eaa4710SRishi Srivatsavai } 15154eaa4710SRishi Srivatsavai 15164eaa4710SRishi Srivatsavai /* ARGSUSED */ 15174eaa4710SRishi Srivatsavai static int 15184eaa4710SRishi Srivatsavai trill_close(sock_lower_handle_t proto_handle, int flags, cred_t *cr) 15194eaa4710SRishi Srivatsavai { 15204eaa4710SRishi Srivatsavai trill_sock_t *tsock = (trill_sock_t *)proto_handle; 15214eaa4710SRishi Srivatsavai 15224eaa4710SRishi Srivatsavai trill_do_close(tsock); 15234eaa4710SRishi Srivatsavai return (0); 15244eaa4710SRishi Srivatsavai } 15254eaa4710SRishi Srivatsavai 15264eaa4710SRishi Srivatsavai /* ARGSUSED */ 15274eaa4710SRishi Srivatsavai static int 15284eaa4710SRishi Srivatsavai trill_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa, 15294eaa4710SRishi Srivatsavai socklen_t len, cred_t *cr) 15304eaa4710SRishi Srivatsavai { 15314eaa4710SRishi Srivatsavai int error; 15324eaa4710SRishi Srivatsavai trill_sock_t *tsock = (trill_sock_t *)proto_handle; 15334eaa4710SRishi Srivatsavai 15344eaa4710SRishi Srivatsavai if (sa == NULL) 15354eaa4710SRishi Srivatsavai error = trill_do_unbind(tsock); 15364eaa4710SRishi Srivatsavai else 15374eaa4710SRishi Srivatsavai error = trill_start_recv(tsock, sa, len); 15384eaa4710SRishi Srivatsavai 15394eaa4710SRishi Srivatsavai return (error); 15404eaa4710SRishi Srivatsavai } 15414eaa4710SRishi Srivatsavai 15424eaa4710SRishi Srivatsavai /* ARGSUSED */ 15434eaa4710SRishi Srivatsavai static int 15444eaa4710SRishi Srivatsavai trill_send(sock_lower_handle_t proto_handle, mblk_t *mp, struct nmsghdr *msg, 15454eaa4710SRishi Srivatsavai cred_t *cr) 15464eaa4710SRishi Srivatsavai { 15474eaa4710SRishi Srivatsavai trill_sock_t *tsock = (trill_sock_t *)proto_handle; 15484eaa4710SRishi Srivatsavai struct sockaddr_dl *laddr; 15494eaa4710SRishi Srivatsavai uint16_t tci; 15504eaa4710SRishi Srivatsavai 15514eaa4710SRishi Srivatsavai ASSERT(DB_TYPE(mp) == M_DATA); 15524eaa4710SRishi Srivatsavai ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN)); 15534eaa4710SRishi Srivatsavai 15544eaa4710SRishi Srivatsavai if (msg->msg_name == NULL || msg->msg_namelen != sizeof (*laddr)) 15554eaa4710SRishi Srivatsavai goto eproto; 15564eaa4710SRishi Srivatsavai 15574eaa4710SRishi Srivatsavai /* 15584eaa4710SRishi Srivatsavai * The name is a datalink_id_t, the address is an Ethernet address, and 15594eaa4710SRishi Srivatsavai * the selector value is the VLAN ID. 15604eaa4710SRishi Srivatsavai */ 15614eaa4710SRishi Srivatsavai laddr = (struct sockaddr_dl *)msg->msg_name; 15624eaa4710SRishi Srivatsavai if (laddr->sdl_nlen != sizeof (datalink_id_t) || 15634eaa4710SRishi Srivatsavai laddr->sdl_alen != ETHERADDRL || 15644eaa4710SRishi Srivatsavai (laddr->sdl_slen != sizeof (tci) && laddr->sdl_slen != 0)) 15654eaa4710SRishi Srivatsavai goto eproto; 15664eaa4710SRishi Srivatsavai 15674eaa4710SRishi Srivatsavai mutex_enter(&tsock->ts_socklock); 15684eaa4710SRishi Srivatsavai if (tsock->ts_state != TS_IDLE || tsock->ts_link == NULL) { 15694eaa4710SRishi Srivatsavai mutex_exit(&tsock->ts_socklock); 15704eaa4710SRishi Srivatsavai goto eproto; 15714eaa4710SRishi Srivatsavai } 15724eaa4710SRishi Srivatsavai atomic_inc_uint(&tsock->ts_sockthreadcount); 15734eaa4710SRishi Srivatsavai mutex_exit(&tsock->ts_socklock); 15744eaa4710SRishi Srivatsavai 15754eaa4710SRishi Srivatsavai /* 15764eaa4710SRishi Srivatsavai * Safe to dereference VLAN now, as we've checked the user's specified 15774eaa4710SRishi Srivatsavai * values, and alignment is now guaranteed. 15784eaa4710SRishi Srivatsavai */ 15794eaa4710SRishi Srivatsavai if (laddr->sdl_slen == 0) { 15804eaa4710SRishi Srivatsavai tci = TRILL_NO_TCI; 15814eaa4710SRishi Srivatsavai } else { 15824eaa4710SRishi Srivatsavai /* LINTED: alignment */ 15834eaa4710SRishi Srivatsavai tci = *(uint16_t *)(LLADDR(laddr) + ETHERADDRL); 15844eaa4710SRishi Srivatsavai } 15854eaa4710SRishi Srivatsavai 15864eaa4710SRishi Srivatsavai mp = create_trill_header(tsock, mp, (const uchar_t *)LLADDR(laddr), 15874eaa4710SRishi Srivatsavai B_TRUE, B_FALSE, tci, msgdsize(mp)); 15884eaa4710SRishi Srivatsavai if (mp != NULL) { 15894eaa4710SRishi Srivatsavai mp = bridge_trill_output(tsock->ts_link, mp); 15904eaa4710SRishi Srivatsavai if (mp == NULL) { 15914eaa4710SRishi Srivatsavai KSPINCR(tks_sent); 15924eaa4710SRishi Srivatsavai } else { 15934eaa4710SRishi Srivatsavai freemsg(mp); 15944eaa4710SRishi Srivatsavai KSPINCR(tks_drops); 15954eaa4710SRishi Srivatsavai } 15964eaa4710SRishi Srivatsavai } 15974eaa4710SRishi Srivatsavai 15984eaa4710SRishi Srivatsavai /* Wake up any threads blocking on us */ 15994eaa4710SRishi Srivatsavai if (atomic_dec_uint_nv(&tsock->ts_sockthreadcount) == 0) 16004eaa4710SRishi Srivatsavai cv_broadcast(&tsock->ts_sockthreadwait); 16014eaa4710SRishi Srivatsavai return (0); 16024eaa4710SRishi Srivatsavai 16034eaa4710SRishi Srivatsavai eproto: 16044eaa4710SRishi Srivatsavai freemsg(mp); 16054eaa4710SRishi Srivatsavai KSPINCR(tks_drops); 16064eaa4710SRishi Srivatsavai return (EPROTO); 16074eaa4710SRishi Srivatsavai } 16084eaa4710SRishi Srivatsavai 16094eaa4710SRishi Srivatsavai /* ARGSUSED */ 16104eaa4710SRishi Srivatsavai static int 16114eaa4710SRishi Srivatsavai trill_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg, 16124eaa4710SRishi Srivatsavai int mode, int32_t *rvalp, cred_t *cr) 16134eaa4710SRishi Srivatsavai { 16144eaa4710SRishi Srivatsavai trill_sock_t *tsock = (trill_sock_t *)proto_handle; 16154eaa4710SRishi Srivatsavai int rc; 16164eaa4710SRishi Srivatsavai 16174eaa4710SRishi Srivatsavai switch (cmd) { 16184eaa4710SRishi Srivatsavai /* List of unprivileged TRILL ioctls */ 16194eaa4710SRishi Srivatsavai case TRILL_GETNICK: 16204eaa4710SRishi Srivatsavai case TRILL_GETBRIDGE: 16214eaa4710SRishi Srivatsavai case TRILL_LISTNICK: 16224eaa4710SRishi Srivatsavai break; 16234eaa4710SRishi Srivatsavai default: 16244eaa4710SRishi Srivatsavai if (secpolicy_dl_config(cr) != 0) 16254eaa4710SRishi Srivatsavai return (EPERM); 16264eaa4710SRishi Srivatsavai break; 16274eaa4710SRishi Srivatsavai } 16284eaa4710SRishi Srivatsavai 16294eaa4710SRishi Srivatsavai /* Lock ensures socket state is unchanged during ioctl handling */ 16304eaa4710SRishi Srivatsavai mutex_enter(&tsock->ts_socklock); 16314eaa4710SRishi Srivatsavai rc = trill_do_ioctl(tsock, cmd, (void *)arg, mode); 16324eaa4710SRishi Srivatsavai mutex_exit(&tsock->ts_socklock); 16334eaa4710SRishi Srivatsavai return (rc); 16344eaa4710SRishi Srivatsavai } 16354eaa4710SRishi Srivatsavai 16364eaa4710SRishi Srivatsavai static void 16374eaa4710SRishi Srivatsavai trill_clr_flowctrl(sock_lower_handle_t proto_handle) 16384eaa4710SRishi Srivatsavai { 16394eaa4710SRishi Srivatsavai trill_sock_t *tsock = (trill_sock_t *)proto_handle; 16404eaa4710SRishi Srivatsavai 16414eaa4710SRishi Srivatsavai mutex_enter(&tsock->ts_socklock); 16424eaa4710SRishi Srivatsavai tsock->ts_flow_ctrld = B_FALSE; 16434eaa4710SRishi Srivatsavai mutex_exit(&tsock->ts_socklock); 16444eaa4710SRishi Srivatsavai } 16454eaa4710SRishi Srivatsavai 16464eaa4710SRishi Srivatsavai static sock_downcalls_t sock_trill_downcalls = { 16474eaa4710SRishi Srivatsavai trill_activate, /* sd_activate */ 16486f40bf67SRishi Srivatsavai sock_accept_notsupp, /* sd_accept */ 16494eaa4710SRishi Srivatsavai trill_bind, /* sd_bind */ 16506f40bf67SRishi Srivatsavai sock_listen_notsupp, /* sd_listen */ 16516f40bf67SRishi Srivatsavai sock_connect_notsupp, /* sd_connect */ 16526f40bf67SRishi Srivatsavai sock_getpeername_notsupp, /* sd_getpeername */ 16536f40bf67SRishi Srivatsavai sock_getsockname_notsupp, /* sd_getsockname */ 16546f40bf67SRishi Srivatsavai sock_getsockopt_notsupp, /* sd_getsockopt */ 16556f40bf67SRishi Srivatsavai sock_setsockopt_notsupp, /* sd_setsockopt */ 16564eaa4710SRishi Srivatsavai trill_send, /* sd_send */ 16574eaa4710SRishi Srivatsavai NULL, /* sd_send_uio */ 16584eaa4710SRishi Srivatsavai NULL, /* sd_recv_uio */ 16594eaa4710SRishi Srivatsavai NULL, /* sd_poll */ 16606f40bf67SRishi Srivatsavai sock_shutdown_notsupp, /* sd_shutdown */ 16614eaa4710SRishi Srivatsavai trill_clr_flowctrl, /* sd_setflowctrl */ 16624eaa4710SRishi Srivatsavai trill_ioctl, /* sd_ioctl */ 16634eaa4710SRishi Srivatsavai trill_close /* sd_close */ 16644eaa4710SRishi Srivatsavai }; 16654eaa4710SRishi Srivatsavai 16664eaa4710SRishi Srivatsavai /* ARGSUSED */ 16674eaa4710SRishi Srivatsavai static sock_lower_handle_t 16684eaa4710SRishi Srivatsavai trill_create(int family, int type, int proto, sock_downcalls_t **sock_downcalls, 16694eaa4710SRishi Srivatsavai uint_t *smodep, int *errorp, int flags, cred_t *credp) 16704eaa4710SRishi Srivatsavai { 16714eaa4710SRishi Srivatsavai trill_sock_t *tsock; 16724eaa4710SRishi Srivatsavai 16734eaa4710SRishi Srivatsavai if (family != AF_TRILL || type != SOCK_DGRAM || proto != 0) { 16744eaa4710SRishi Srivatsavai *errorp = EPROTONOSUPPORT; 16754eaa4710SRishi Srivatsavai return (NULL); 16764eaa4710SRishi Srivatsavai } 16774eaa4710SRishi Srivatsavai 16784eaa4710SRishi Srivatsavai *sock_downcalls = &sock_trill_downcalls; 16794eaa4710SRishi Srivatsavai *smodep = SM_ATOMIC; 16804eaa4710SRishi Srivatsavai tsock = trill_do_open(flags); 16814eaa4710SRishi Srivatsavai *errorp = (tsock != NULL) ? 0:ENOMEM; 16824eaa4710SRishi Srivatsavai return ((sock_lower_handle_t)tsock); 16834eaa4710SRishi Srivatsavai } 1684