xref: /illumos-gate/usr/src/uts/common/io/trill.c (revision 640c1670)
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 *
create_trill_header(trill_sock_t * tsock,mblk_t * mp,const uint8_t * daddr,boolean_t trill_hdr_ok,boolean_t multidest,uint16_t tci,size_t msglen)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
trill_recv_local(trill_sock_t * tsock,mblk_t * mp,uint16_t ingressnick)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 *
find_trill_link(trill_inst_t * tip,datalink_id_t linkid)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
trill_dest_fwd(trill_inst_t * tip,mblk_t * fwd_mp,uint16_t adj_nick,boolean_t has_trill_hdr,boolean_t multidest,uint16_t dtnick)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
trill_multidest_fwd(trill_inst_t * tip,mblk_t * mp,uint16_t egressnick,uint16_t ingressnick,boolean_t is_trill_pkt,const uint8_t * saddr,int inner_vlan,boolean_t free_mblk)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
trill_recv(trill_sock_t * tsock,mblk_t * mp,const uint8_t * mpsaddr)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
trill_stop_recv(trill_sock_t * tsock)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
trill_start_recv(trill_sock_t * tsock,const struct sockaddr * sa,socklen_t len)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
trill_do_unbind(trill_sock_t * tsock)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
trill_instance_unref(trill_inst_t * tip)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
trill_recv_pkt_cb(void * lptr,bridge_link_t * blp,mac_resource_handle_t rsrc,mblk_t * mp,mac_header_info_t * hdr_info)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
trill_encap_pkt_cb(void * lptr,bridge_link_t * blp,mac_header_info_t * hdr_info,mblk_t * mp,uint16_t egress_nick)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
trill_br_dstr_cb(void * bptr,bridge_inst_t * bip)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
trill_ln_dstr_cb(void * lptr,bridge_link_t * blp)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
trill_init(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
trill_fini(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
_init(void)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
_info(struct modinfo * modinfop)9184eaa4710SRishi Srivatsavai _info(struct modinfo *modinfop)
9194eaa4710SRishi Srivatsavai {
9204eaa4710SRishi Srivatsavai 	return (mod_info(&ml, modinfop));
9214eaa4710SRishi Srivatsavai }
9224eaa4710SRishi Srivatsavai 
9234eaa4710SRishi Srivatsavai int
_fini(void)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
trill_kstats_init(trill_sock_t * tsock,const char * bname)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 *
trill_do_open(int flags)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
trill_find_bridge(trill_sock_t * tsock,const char * bname,boolean_t can_create)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
trill_clear_bridge(trill_sock_t * tsock)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
trill_sock_unref(trill_sock_t * tsock)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
trill_do_close(trill_sock_t * tsock)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
trill_del_all(trill_inst_t * tip,boolean_t lockheld)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
trill_node_free(trill_node_t * nick_entry)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
trill_node_unref(trill_inst_t * tip,trill_node_t * tnp)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 *
trill_node_lookup(trill_inst_t * tip,uint16_t nick)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
trill_del_nick(trill_inst_t * tip,uint16_t nick,boolean_t lockheld)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
trill_add_nick(trill_inst_t * tip,void * arg,boolean_t self,int mode)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
trill_do_ioctl(trill_sock_t * tsock,int cmd,void * arg,int mode)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
trill_ctrl_input(trill_sock_t * tsock,mblk_t * mp,const uint8_t * saddr,uint16_t tci)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
trill_activate(sock_lower_handle_t proto_handle,sock_upper_handle_t sock_handle,sock_upcalls_t * sock_upcalls,int flags,cred_t * cr)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
trill_close(sock_lower_handle_t proto_handle,int flags,cred_t * cr)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
trill_bind(sock_lower_handle_t proto_handle,struct sockaddr * sa,socklen_t len,cred_t * cr)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
trill_send(sock_lower_handle_t proto_handle,mblk_t * mp,struct nmsghdr * msg,cred_t * cr)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
trill_ioctl(sock_lower_handle_t proto_handle,int cmd,intptr_t arg,int mode,int32_t * rvalp,cred_t * cr)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
trill_clr_flowctrl(sock_lower_handle_t proto_handle)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 = {
16476f40bf67SRishi Srivatsavai 	trill_activate,			/* sd_activate */
16486f40bf67SRishi Srivatsavai 	sock_accept_notsupp,		/* sd_accept */
16496f40bf67SRishi 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 */
16566f40bf67SRishi Srivatsavai 	trill_send,			/* sd_send */
16576f40bf67SRishi Srivatsavai 	NULL,				/* sd_send_uio */
16586f40bf67SRishi Srivatsavai 	NULL,				/* sd_recv_uio */
16596f40bf67SRishi Srivatsavai 	NULL,				/* sd_poll */
16606f40bf67SRishi Srivatsavai 	sock_shutdown_notsupp,		/* sd_shutdown */
16616f40bf67SRishi Srivatsavai 	trill_clr_flowctrl,		/* sd_setflowctrl */
16626f40bf67SRishi Srivatsavai 	trill_ioctl,			/* sd_ioctl */
16636f40bf67SRishi Srivatsavai 	trill_close			/* sd_close */
16644eaa4710SRishi Srivatsavai };
16654eaa4710SRishi Srivatsavai 
16664eaa4710SRishi Srivatsavai /* ARGSUSED */
16674eaa4710SRishi Srivatsavai static sock_lower_handle_t
trill_create(int family,int type,int proto,sock_downcalls_t ** sock_downcalls,uint_t * smodep,int * errorp,int flags,cred_t * credp)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