xref: /onnv-gate/usr/src/uts/common/io/trill.c (revision 11483:802d270d2ab7)
110491SRishi.Srivatsavai@Sun.COM /*
210491SRishi.Srivatsavai@Sun.COM  * CDDL HEADER START
310491SRishi.Srivatsavai@Sun.COM  *
410491SRishi.Srivatsavai@Sun.COM  * The contents of this file are subject to the terms of the
510491SRishi.Srivatsavai@Sun.COM  * Common Development and Distribution License (the "License").
610491SRishi.Srivatsavai@Sun.COM  * You may not use this file except in compliance with the License.
710491SRishi.Srivatsavai@Sun.COM  *
810491SRishi.Srivatsavai@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910491SRishi.Srivatsavai@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010491SRishi.Srivatsavai@Sun.COM  * See the License for the specific language governing permissions
1110491SRishi.Srivatsavai@Sun.COM  * and limitations under the License.
1210491SRishi.Srivatsavai@Sun.COM  *
1310491SRishi.Srivatsavai@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410491SRishi.Srivatsavai@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510491SRishi.Srivatsavai@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610491SRishi.Srivatsavai@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710491SRishi.Srivatsavai@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810491SRishi.Srivatsavai@Sun.COM  *
1910491SRishi.Srivatsavai@Sun.COM  * CDDL HEADER END
2010491SRishi.Srivatsavai@Sun.COM  */
2110491SRishi.Srivatsavai@Sun.COM 
2210491SRishi.Srivatsavai@Sun.COM /*
23*11483SRishi.Srivatsavai@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2410491SRishi.Srivatsavai@Sun.COM  * Use is subject to license terms.
2510491SRishi.Srivatsavai@Sun.COM  */
2610491SRishi.Srivatsavai@Sun.COM 
2710491SRishi.Srivatsavai@Sun.COM /*
2810491SRishi.Srivatsavai@Sun.COM  *  This module supports AF_TRILL sockets and TRILL layer-2 forwarding.
2910491SRishi.Srivatsavai@Sun.COM  */
3010491SRishi.Srivatsavai@Sun.COM 
3110491SRishi.Srivatsavai@Sun.COM #include <sys/strsubr.h>
3210491SRishi.Srivatsavai@Sun.COM #include <sys/socket.h>
3310491SRishi.Srivatsavai@Sun.COM #include <sys/socketvar.h>
3410491SRishi.Srivatsavai@Sun.COM #include <sys/modctl.h>
3510491SRishi.Srivatsavai@Sun.COM #include <sys/cmn_err.h>
3610491SRishi.Srivatsavai@Sun.COM #include <sys/tihdr.h>
3710491SRishi.Srivatsavai@Sun.COM #include <sys/strsun.h>
3810491SRishi.Srivatsavai@Sun.COM #include <sys/policy.h>
3910491SRishi.Srivatsavai@Sun.COM #include <sys/ethernet.h>
4010491SRishi.Srivatsavai@Sun.COM #include <sys/vlan.h>
4110491SRishi.Srivatsavai@Sun.COM #include <net/trill.h>
4210491SRishi.Srivatsavai@Sun.COM #include <net/if_dl.h>
4310491SRishi.Srivatsavai@Sun.COM #include <sys/mac.h>
4410491SRishi.Srivatsavai@Sun.COM #include <sys/mac_client.h>
4510491SRishi.Srivatsavai@Sun.COM #include <sys/mac_provider.h>
4610491SRishi.Srivatsavai@Sun.COM #include <sys/mac_client_priv.h>
4710491SRishi.Srivatsavai@Sun.COM #include <sys/sdt.h>
4810491SRishi.Srivatsavai@Sun.COM #include <sys/dls.h>
4910491SRishi.Srivatsavai@Sun.COM #include <sys/sunddi.h>
5010491SRishi.Srivatsavai@Sun.COM 
5110491SRishi.Srivatsavai@Sun.COM #include "trill_impl.h"
5210491SRishi.Srivatsavai@Sun.COM 
5310491SRishi.Srivatsavai@Sun.COM static void trill_del_all(trill_inst_t *, boolean_t);
5410491SRishi.Srivatsavai@Sun.COM static int trill_del_nick(trill_inst_t *, uint16_t, boolean_t);
5510491SRishi.Srivatsavai@Sun.COM static void trill_stop_recv(trill_sock_t *);
5610491SRishi.Srivatsavai@Sun.COM static void trill_ctrl_input(trill_sock_t *, mblk_t *, const uint8_t *,
5710491SRishi.Srivatsavai@Sun.COM     uint16_t);
5810491SRishi.Srivatsavai@Sun.COM static trill_node_t *trill_node_lookup(trill_inst_t *, uint16_t);
5910491SRishi.Srivatsavai@Sun.COM static void trill_node_unref(trill_inst_t *, trill_node_t *);
6010491SRishi.Srivatsavai@Sun.COM static void trill_sock_unref(trill_sock_t *);
6110491SRishi.Srivatsavai@Sun.COM static void trill_kstats_init(trill_sock_t *, const char *);
6210491SRishi.Srivatsavai@Sun.COM 
6310491SRishi.Srivatsavai@Sun.COM static list_t trill_inst_list;
6410491SRishi.Srivatsavai@Sun.COM static krwlock_t trill_inst_rwlock;
6510491SRishi.Srivatsavai@Sun.COM 
6610491SRishi.Srivatsavai@Sun.COM static sock_lower_handle_t trill_create(int, int, int, sock_downcalls_t **,
6710491SRishi.Srivatsavai@Sun.COM     uint_t *, int *, int, cred_t *);
6810491SRishi.Srivatsavai@Sun.COM 
6910491SRishi.Srivatsavai@Sun.COM static smod_reg_t sinfo = {
7010491SRishi.Srivatsavai@Sun.COM 	SOCKMOD_VERSION,
7110491SRishi.Srivatsavai@Sun.COM 	"trill",
7210491SRishi.Srivatsavai@Sun.COM 	SOCK_UC_VERSION,
7310491SRishi.Srivatsavai@Sun.COM 	SOCK_DC_VERSION,
7410491SRishi.Srivatsavai@Sun.COM 	trill_create,
7510491SRishi.Srivatsavai@Sun.COM 	NULL,
7610491SRishi.Srivatsavai@Sun.COM };
7710491SRishi.Srivatsavai@Sun.COM 
7810491SRishi.Srivatsavai@Sun.COM /* modldrv structure */
7910491SRishi.Srivatsavai@Sun.COM static struct modlsockmod sockmod = {
8010491SRishi.Srivatsavai@Sun.COM 	&mod_sockmodops, "AF_TRILL socket module", &sinfo
8110491SRishi.Srivatsavai@Sun.COM };
8210491SRishi.Srivatsavai@Sun.COM 
8310491SRishi.Srivatsavai@Sun.COM /* modlinkage structure */
8410491SRishi.Srivatsavai@Sun.COM static struct modlinkage ml = {
8510491SRishi.Srivatsavai@Sun.COM 	MODREV_1,
8610491SRishi.Srivatsavai@Sun.COM 	&sockmod,
8710491SRishi.Srivatsavai@Sun.COM 	NULL
8810491SRishi.Srivatsavai@Sun.COM };
8910491SRishi.Srivatsavai@Sun.COM 
9010491SRishi.Srivatsavai@Sun.COM #define	VALID_NICK(n)	((n) != RBRIDGE_NICKNAME_NONE && \
9110491SRishi.Srivatsavai@Sun.COM 			(n) != RBRIDGE_NICKNAME_UNUSED)
9210491SRishi.Srivatsavai@Sun.COM 
9310491SRishi.Srivatsavai@Sun.COM 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)9410491SRishi.Srivatsavai@Sun.COM create_trill_header(trill_sock_t *tsock, mblk_t *mp, const uint8_t *daddr,
9510491SRishi.Srivatsavai@Sun.COM     boolean_t trill_hdr_ok, boolean_t multidest, uint16_t tci,
9610491SRishi.Srivatsavai@Sun.COM     size_t msglen)
9710491SRishi.Srivatsavai@Sun.COM {
9810491SRishi.Srivatsavai@Sun.COM 	int extra_hdr_len;
9910491SRishi.Srivatsavai@Sun.COM 	struct ether_vlan_header *ethvlanhdr;
10010491SRishi.Srivatsavai@Sun.COM 	mblk_t *hdr_mp;
10110491SRishi.Srivatsavai@Sun.COM 	uint16_t etype;
10210491SRishi.Srivatsavai@Sun.COM 
10310491SRishi.Srivatsavai@Sun.COM 	etype = msglen > 0 ? (uint16_t)msglen : ETHERTYPE_TRILL;
10410491SRishi.Srivatsavai@Sun.COM 
10510491SRishi.Srivatsavai@Sun.COM 	/* When sending on the PVID, we must not give a VLAN ID */
10610491SRishi.Srivatsavai@Sun.COM 	if (tci == tsock->ts_link->bl_pvid)
10710491SRishi.Srivatsavai@Sun.COM 		tci = TRILL_NO_TCI;
10810491SRishi.Srivatsavai@Sun.COM 
10910491SRishi.Srivatsavai@Sun.COM 	/*
11010491SRishi.Srivatsavai@Sun.COM 	 * Create new Ethernet header and include additional space
11110491SRishi.Srivatsavai@Sun.COM 	 * for writing TRILL header and/or VLAN tag.
11210491SRishi.Srivatsavai@Sun.COM 	 */
11310491SRishi.Srivatsavai@Sun.COM 	extra_hdr_len = (trill_hdr_ok ? 0 : sizeof (trill_header_t)) +
11410491SRishi.Srivatsavai@Sun.COM 	    (tci != TRILL_NO_TCI ? sizeof (struct ether_vlan_extinfo) : 0);
11510491SRishi.Srivatsavai@Sun.COM 	hdr_mp = mac_header(tsock->ts_link->bl_mh, daddr,
11610491SRishi.Srivatsavai@Sun.COM 	    tci != TRILL_NO_TCI ? ETHERTYPE_VLAN : etype, mp, extra_hdr_len);
11710491SRishi.Srivatsavai@Sun.COM 	if (hdr_mp == NULL) {
11810491SRishi.Srivatsavai@Sun.COM 		freemsg(mp);
11910491SRishi.Srivatsavai@Sun.COM 		return (NULL);
12010491SRishi.Srivatsavai@Sun.COM 	}
12110491SRishi.Srivatsavai@Sun.COM 
12210491SRishi.Srivatsavai@Sun.COM 	if (tci != TRILL_NO_TCI) {
12310491SRishi.Srivatsavai@Sun.COM 		/* LINTED: alignment */
12410491SRishi.Srivatsavai@Sun.COM 		ethvlanhdr = (struct ether_vlan_header *)hdr_mp->b_rptr;
12510491SRishi.Srivatsavai@Sun.COM 		ethvlanhdr->ether_tci = htons(tci);
12610491SRishi.Srivatsavai@Sun.COM 		ethvlanhdr->ether_type = htons(etype);
12710491SRishi.Srivatsavai@Sun.COM 		hdr_mp->b_wptr += sizeof (struct ether_vlan_extinfo);
12810491SRishi.Srivatsavai@Sun.COM 	}
12910491SRishi.Srivatsavai@Sun.COM 
13010491SRishi.Srivatsavai@Sun.COM 	if (!trill_hdr_ok) {
13110491SRishi.Srivatsavai@Sun.COM 		trill_header_t *thp;
13210491SRishi.Srivatsavai@Sun.COM 		/* LINTED: alignment */
13310491SRishi.Srivatsavai@Sun.COM 		thp = (trill_header_t *)hdr_mp->b_wptr;
13410491SRishi.Srivatsavai@Sun.COM 		(void) memset(thp, 0, sizeof (trill_header_t));
13510491SRishi.Srivatsavai@Sun.COM 		thp->th_hopcount = TRILL_DEFAULT_HOPS;
13610491SRishi.Srivatsavai@Sun.COM 		thp->th_multidest = (multidest ? 1:0);
13710491SRishi.Srivatsavai@Sun.COM 		hdr_mp->b_wptr += sizeof (trill_header_t);
13810491SRishi.Srivatsavai@Sun.COM 	}
13910491SRishi.Srivatsavai@Sun.COM 
14010491SRishi.Srivatsavai@Sun.COM 	hdr_mp->b_cont = mp;
14110491SRishi.Srivatsavai@Sun.COM 	return (hdr_mp);
14210491SRishi.Srivatsavai@Sun.COM }
14310491SRishi.Srivatsavai@Sun.COM 
14410491SRishi.Srivatsavai@Sun.COM /*
14510491SRishi.Srivatsavai@Sun.COM  * TRILL local recv function. TRILL data frames that should be received
14610491SRishi.Srivatsavai@Sun.COM  * by the local system are decapsulated here and passed to bridging for
14710491SRishi.Srivatsavai@Sun.COM  * learning and local system receive. Only called when we are the forwarder
14810491SRishi.Srivatsavai@Sun.COM  * on the link (multi-dest frames) or the frame was destined for us.
14910491SRishi.Srivatsavai@Sun.COM  */
15010491SRishi.Srivatsavai@Sun.COM static void
trill_recv_local(trill_sock_t * tsock,mblk_t * mp,uint16_t ingressnick)15110491SRishi.Srivatsavai@Sun.COM trill_recv_local(trill_sock_t *tsock, mblk_t *mp, uint16_t ingressnick)
15210491SRishi.Srivatsavai@Sun.COM {
15310491SRishi.Srivatsavai@Sun.COM 	struct ether_header *inner_ethhdr;
15410491SRishi.Srivatsavai@Sun.COM 
15510491SRishi.Srivatsavai@Sun.COM 	/* LINTED: alignment */
15610491SRishi.Srivatsavai@Sun.COM 	inner_ethhdr = (struct ether_header *)mp->b_rptr;
15710491SRishi.Srivatsavai@Sun.COM 	DTRACE_PROBE1(trill__recv__local, struct ether_header *, inner_ethhdr);
15810491SRishi.Srivatsavai@Sun.COM 
15910491SRishi.Srivatsavai@Sun.COM 	DB_CKSUMFLAGS(mp) = 0;
16010491SRishi.Srivatsavai@Sun.COM 	/*
16110491SRishi.Srivatsavai@Sun.COM 	 * Transmit the decapsulated frame on the link via Bridging.
16210491SRishi.Srivatsavai@Sun.COM 	 * Bridging does source address learning and appropriate forwarding.
16310491SRishi.Srivatsavai@Sun.COM 	 */
16410491SRishi.Srivatsavai@Sun.COM 	bridge_trill_decaps(tsock->ts_link, mp, ingressnick);
16510491SRishi.Srivatsavai@Sun.COM 	KSPINCR(tks_decap);
16610491SRishi.Srivatsavai@Sun.COM }
16710491SRishi.Srivatsavai@Sun.COM 
16810491SRishi.Srivatsavai@Sun.COM /*
16910491SRishi.Srivatsavai@Sun.COM  * Determines the outgoing link to reach a RBridge having the given nick
17010491SRishi.Srivatsavai@Sun.COM  * Assumes caller has acquired the trill instance rwlock.
17110491SRishi.Srivatsavai@Sun.COM  */
17210491SRishi.Srivatsavai@Sun.COM static trill_sock_t *
find_trill_link(trill_inst_t * tip,datalink_id_t linkid)17310491SRishi.Srivatsavai@Sun.COM find_trill_link(trill_inst_t *tip, datalink_id_t linkid)
17410491SRishi.Srivatsavai@Sun.COM {
17510491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsp = NULL;
17610491SRishi.Srivatsavai@Sun.COM 
17710491SRishi.Srivatsavai@Sun.COM 	ASSERT(RW_LOCK_HELD(&tip->ti_rwlock));
17810491SRishi.Srivatsavai@Sun.COM 	for (tsp = list_head(&tip->ti_socklist); tsp != NULL;
17910491SRishi.Srivatsavai@Sun.COM 	    tsp = list_next(&tip->ti_socklist, tsp)) {
18010491SRishi.Srivatsavai@Sun.COM 		if (tsp->ts_link != NULL && tsp->ts_link->bl_linkid == linkid) {
18110491SRishi.Srivatsavai@Sun.COM 			ASSERT(tsp->ts_link->bl_mh != NULL);
18210491SRishi.Srivatsavai@Sun.COM 			ASSERT(!(tsp->ts_flags & TSF_SHUTDOWN));
18310491SRishi.Srivatsavai@Sun.COM 			atomic_inc_uint(&tsp->ts_refs);
18410491SRishi.Srivatsavai@Sun.COM 			break;
18510491SRishi.Srivatsavai@Sun.COM 		}
18610491SRishi.Srivatsavai@Sun.COM 	}
18710491SRishi.Srivatsavai@Sun.COM 	return (tsp);
18810491SRishi.Srivatsavai@Sun.COM }
18910491SRishi.Srivatsavai@Sun.COM 
19010491SRishi.Srivatsavai@Sun.COM /*
19110491SRishi.Srivatsavai@Sun.COM  * TRILL destination forwarding function. Transmits the TRILL data packet
19210491SRishi.Srivatsavai@Sun.COM  * to the next-hop, adjacent RBridge.  Consumes passed mblk_t.
19310491SRishi.Srivatsavai@Sun.COM  */
19410491SRishi.Srivatsavai@Sun.COM 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)19510491SRishi.Srivatsavai@Sun.COM trill_dest_fwd(trill_inst_t *tip, mblk_t *fwd_mp, uint16_t adj_nick,
19610491SRishi.Srivatsavai@Sun.COM     boolean_t has_trill_hdr, boolean_t multidest, uint16_t dtnick)
19710491SRishi.Srivatsavai@Sun.COM {
19810491SRishi.Srivatsavai@Sun.COM 	trill_node_t *adj;
19910491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock = NULL;
20010491SRishi.Srivatsavai@Sun.COM 	trill_header_t *trillhdr;
20110491SRishi.Srivatsavai@Sun.COM 	struct ether_header *ethhdr;
20210491SRishi.Srivatsavai@Sun.COM 	int ethtype;
20310491SRishi.Srivatsavai@Sun.COM 	int ethhdrlen;
20410491SRishi.Srivatsavai@Sun.COM 
20510491SRishi.Srivatsavai@Sun.COM 	adj = trill_node_lookup(tip, adj_nick);
20610491SRishi.Srivatsavai@Sun.COM 	if (adj == NULL || ((tsock = adj->tn_tsp) == NULL))
20710491SRishi.Srivatsavai@Sun.COM 		goto dest_fwd_fail;
20810491SRishi.Srivatsavai@Sun.COM 
20910491SRishi.Srivatsavai@Sun.COM 	ASSERT(tsock->ts_link != NULL);
21010491SRishi.Srivatsavai@Sun.COM 	ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN));
21110491SRishi.Srivatsavai@Sun.COM 	ASSERT(adj->tn_ni != NULL);
21210491SRishi.Srivatsavai@Sun.COM 
21310491SRishi.Srivatsavai@Sun.COM 	DTRACE_PROBE3(trill__dest__fwd, uint16_t, adj_nick, trill_node_t,
21410491SRishi.Srivatsavai@Sun.COM 	    adj, trill_sock_t, tsock);
21510491SRishi.Srivatsavai@Sun.COM 
21610491SRishi.Srivatsavai@Sun.COM 	/*
21710491SRishi.Srivatsavai@Sun.COM 	 * For broadcast links by using the dest address of
21810491SRishi.Srivatsavai@Sun.COM 	 * the RBridge to forward the frame should result in
21910491SRishi.Srivatsavai@Sun.COM 	 * savings. When the link is a bridged LAN or there are
22010491SRishi.Srivatsavai@Sun.COM 	 * many end stations the frame will not always be flooded.
22110491SRishi.Srivatsavai@Sun.COM 	 */
22210491SRishi.Srivatsavai@Sun.COM 	fwd_mp = create_trill_header(tsock, fwd_mp, adj->tn_ni->tni_adjsnpa,
22310491SRishi.Srivatsavai@Sun.COM 	    has_trill_hdr, multidest, tsock->ts_desigvlan, 0);
22410491SRishi.Srivatsavai@Sun.COM 	if (fwd_mp == NULL)
22510491SRishi.Srivatsavai@Sun.COM 		goto dest_fwd_fail;
22610491SRishi.Srivatsavai@Sun.COM 
22710491SRishi.Srivatsavai@Sun.COM 	/* LINTED: alignment */
22810491SRishi.Srivatsavai@Sun.COM 	ethhdr = (struct ether_header *)fwd_mp->b_rptr;
22910491SRishi.Srivatsavai@Sun.COM 	ethtype = ntohs(ethhdr->ether_type);
23010491SRishi.Srivatsavai@Sun.COM 	ASSERT(ethtype == ETHERTYPE_VLAN || ethtype == ETHERTYPE_TRILL);
23110491SRishi.Srivatsavai@Sun.COM 
23210491SRishi.Srivatsavai@Sun.COM 	/* Pullup Ethernet and TRILL header (w/o TRILL options) */
23310491SRishi.Srivatsavai@Sun.COM 	ethhdrlen = sizeof (struct ether_header) +
23410491SRishi.Srivatsavai@Sun.COM 	    (ethtype == ETHERTYPE_VLAN ? sizeof (struct ether_vlan_extinfo):0);
23510491SRishi.Srivatsavai@Sun.COM 	if (!pullupmsg(fwd_mp, ethhdrlen + sizeof (trill_header_t)))
23610491SRishi.Srivatsavai@Sun.COM 		goto dest_fwd_fail;
23710491SRishi.Srivatsavai@Sun.COM 	/* LINTED: alignment */
23810491SRishi.Srivatsavai@Sun.COM 	trillhdr = (struct trill_header *)(fwd_mp->b_rptr + ethhdrlen);
23910491SRishi.Srivatsavai@Sun.COM 
24010491SRishi.Srivatsavai@Sun.COM 	/* Update TRILL header with ingress and egress nicks for new frames */
24110491SRishi.Srivatsavai@Sun.COM 	if (!has_trill_hdr) {
24210491SRishi.Srivatsavai@Sun.COM 		/* We are creating a new TRILL frame */
24310491SRishi.Srivatsavai@Sun.COM 		trillhdr->th_egressnick = (multidest ? dtnick:adj_nick);
24410491SRishi.Srivatsavai@Sun.COM 		rw_enter(&tip->ti_rwlock, RW_READER);
24510491SRishi.Srivatsavai@Sun.COM 		trillhdr->th_ingressnick = tip->ti_nick;
24610491SRishi.Srivatsavai@Sun.COM 		rw_exit(&tip->ti_rwlock);
24710491SRishi.Srivatsavai@Sun.COM 		if (!VALID_NICK(trillhdr->th_ingressnick))
24810491SRishi.Srivatsavai@Sun.COM 			goto dest_fwd_fail;
24910491SRishi.Srivatsavai@Sun.COM 	}
25010491SRishi.Srivatsavai@Sun.COM 
25110491SRishi.Srivatsavai@Sun.COM 	/* Set hop count and update header in packet */
25210491SRishi.Srivatsavai@Sun.COM 	ASSERT(trillhdr->th_hopcount != 0);
25310491SRishi.Srivatsavai@Sun.COM 	trillhdr->th_hopcount--;
25410491SRishi.Srivatsavai@Sun.COM 
25510491SRishi.Srivatsavai@Sun.COM 	/* Clear checksum flag and transmit frame on the link */
25610491SRishi.Srivatsavai@Sun.COM 	DB_CKSUMFLAGS(fwd_mp) = 0;
25710491SRishi.Srivatsavai@Sun.COM 	DTRACE_PROBE1(trill__dest__fwd__tx, trill_header_t *, &trillhdr);
25810491SRishi.Srivatsavai@Sun.COM 	fwd_mp = bridge_trill_output(tsock->ts_link, fwd_mp);
25910491SRishi.Srivatsavai@Sun.COM 	if (fwd_mp == NULL) {
26010491SRishi.Srivatsavai@Sun.COM 		KSPINCR(tks_sent);
26110491SRishi.Srivatsavai@Sun.COM 		KSPINCR(tks_forward);
26210491SRishi.Srivatsavai@Sun.COM 	} else {
26310491SRishi.Srivatsavai@Sun.COM 		freemsg(fwd_mp);
26410491SRishi.Srivatsavai@Sun.COM 		KSPINCR(tks_drops);
26510491SRishi.Srivatsavai@Sun.COM 	}
26610491SRishi.Srivatsavai@Sun.COM 	trill_node_unref(tip, adj);
26710491SRishi.Srivatsavai@Sun.COM 	return;
26810491SRishi.Srivatsavai@Sun.COM 
26910491SRishi.Srivatsavai@Sun.COM dest_fwd_fail:
27010491SRishi.Srivatsavai@Sun.COM 	if (adj != NULL)
27110491SRishi.Srivatsavai@Sun.COM 		trill_node_unref(tip, adj);
27210491SRishi.Srivatsavai@Sun.COM 	if (tsock != NULL)
27310491SRishi.Srivatsavai@Sun.COM 		KSPINCR(tks_drops);
27410491SRishi.Srivatsavai@Sun.COM 	freemsg(fwd_mp);
27510491SRishi.Srivatsavai@Sun.COM }
27610491SRishi.Srivatsavai@Sun.COM 
27710491SRishi.Srivatsavai@Sun.COM /*
27810491SRishi.Srivatsavai@Sun.COM  * TRILL multi-destination forwarding. Transmits the packet to the adjacencies
27910491SRishi.Srivatsavai@Sun.COM  * on the distribution tree determined by the egress nick. Source addr (saddr)
28010491SRishi.Srivatsavai@Sun.COM  * is NULL for new TRILL packets originating from us.
28110491SRishi.Srivatsavai@Sun.COM  */
28210491SRishi.Srivatsavai@Sun.COM 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)28310491SRishi.Srivatsavai@Sun.COM trill_multidest_fwd(trill_inst_t *tip, mblk_t *mp, uint16_t egressnick,
28410491SRishi.Srivatsavai@Sun.COM     uint16_t ingressnick, boolean_t is_trill_pkt, const uint8_t *saddr,
28510491SRishi.Srivatsavai@Sun.COM     int inner_vlan, boolean_t free_mblk)
28610491SRishi.Srivatsavai@Sun.COM {
28710491SRishi.Srivatsavai@Sun.COM 	int idx;
28810491SRishi.Srivatsavai@Sun.COM 	uint16_t adjnick;
28910491SRishi.Srivatsavai@Sun.COM 	trill_node_t *dest;
29010491SRishi.Srivatsavai@Sun.COM 	trill_node_t *adj;
29110491SRishi.Srivatsavai@Sun.COM 	mblk_t *fwd_mp;
29210491SRishi.Srivatsavai@Sun.COM 	boolean_t nicksaved = B_FALSE;
29310491SRishi.Srivatsavai@Sun.COM 	uint16_t adjnicksaved;
29410491SRishi.Srivatsavai@Sun.COM 
29510491SRishi.Srivatsavai@Sun.COM 	/* Lookup the egress nick info, this is the DT root */
29610491SRishi.Srivatsavai@Sun.COM 	if ((dest = trill_node_lookup(tip, egressnick)) == NULL)
29710491SRishi.Srivatsavai@Sun.COM 		goto fail_multidest_fwd;
29810491SRishi.Srivatsavai@Sun.COM 
29910491SRishi.Srivatsavai@Sun.COM 	/* Send a copy to all our adjacencies on the DT root  */
30010491SRishi.Srivatsavai@Sun.COM 	ASSERT(dest->tn_ni);
30110491SRishi.Srivatsavai@Sun.COM 	for (idx = 0; idx < dest->tn_ni->tni_adjcount; idx++) {
30210491SRishi.Srivatsavai@Sun.COM 
30310491SRishi.Srivatsavai@Sun.COM 		/* Check for a valid adjacency node */
30410491SRishi.Srivatsavai@Sun.COM 		adjnick = TNI_ADJNICK(dest->tn_ni, idx);
30510491SRishi.Srivatsavai@Sun.COM 		if (!VALID_NICK(adjnick) || ingressnick == adjnick ||
30610491SRishi.Srivatsavai@Sun.COM 		    ((adj = trill_node_lookup(tip, adjnick)) == NULL))
30710491SRishi.Srivatsavai@Sun.COM 			continue;
30810491SRishi.Srivatsavai@Sun.COM 
30910491SRishi.Srivatsavai@Sun.COM 		/* Do not forward back to adjacency that sent the pkt to us */
31010491SRishi.Srivatsavai@Sun.COM 		ASSERT(adj->tn_ni != NULL);
31110491SRishi.Srivatsavai@Sun.COM 		if ((saddr != NULL) &&
31210491SRishi.Srivatsavai@Sun.COM 		    (memcmp(adj->tn_ni->tni_adjsnpa, saddr,
31310491SRishi.Srivatsavai@Sun.COM 		    ETHERADDRL) == 0)) {
31410491SRishi.Srivatsavai@Sun.COM 			trill_node_unref(tip, adj);
31510491SRishi.Srivatsavai@Sun.COM 			continue;
31610491SRishi.Srivatsavai@Sun.COM 		}
31710491SRishi.Srivatsavai@Sun.COM 
31810491SRishi.Srivatsavai@Sun.COM 		/* Check if adj is marked as reaching inner VLAN downstream */
31910491SRishi.Srivatsavai@Sun.COM 		if ((inner_vlan != VLAN_ID_NONE) &&
32010491SRishi.Srivatsavai@Sun.COM 		    !TRILL_VLANISSET(TNI_VLANFILTERMAP(dest->tn_ni, idx),
32110491SRishi.Srivatsavai@Sun.COM 		    inner_vlan)) {
32210491SRishi.Srivatsavai@Sun.COM 			trill_node_unref(tip, adj);
32310491SRishi.Srivatsavai@Sun.COM 			DTRACE_PROBE4(trill__multi__dest__fwd__vlanfiltered,
32410491SRishi.Srivatsavai@Sun.COM 			    uint16_t, adjnick, uint16_t, ingressnick,
32510491SRishi.Srivatsavai@Sun.COM 			    uint16_t, egressnick, int, inner_vlan);
32610491SRishi.Srivatsavai@Sun.COM 			continue;
32710491SRishi.Srivatsavai@Sun.COM 		}
32810491SRishi.Srivatsavai@Sun.COM 
32910491SRishi.Srivatsavai@Sun.COM 		trill_node_unref(tip, adj);
33010491SRishi.Srivatsavai@Sun.COM 
33110491SRishi.Srivatsavai@Sun.COM 		/*
33210491SRishi.Srivatsavai@Sun.COM 		 * Save the nick and look ahead to see if we should forward the
33310491SRishi.Srivatsavai@Sun.COM 		 * frame to more adjacencies. We avoid doing a copy for this
33410491SRishi.Srivatsavai@Sun.COM 		 * nick and use the passed mblk when we can consume the passed
33510491SRishi.Srivatsavai@Sun.COM 		 * mblk.
33610491SRishi.Srivatsavai@Sun.COM 		 */
33710491SRishi.Srivatsavai@Sun.COM 		if (free_mblk && !nicksaved) {
33810491SRishi.Srivatsavai@Sun.COM 			adjnicksaved = adjnick;
33910491SRishi.Srivatsavai@Sun.COM 			nicksaved = B_TRUE;
34010491SRishi.Srivatsavai@Sun.COM 			continue;
34110491SRishi.Srivatsavai@Sun.COM 		}
34210491SRishi.Srivatsavai@Sun.COM 
34310491SRishi.Srivatsavai@Sun.COM 		fwd_mp = copymsg(mp);
34410491SRishi.Srivatsavai@Sun.COM 		if (fwd_mp == NULL)
34510491SRishi.Srivatsavai@Sun.COM 			break;
34610491SRishi.Srivatsavai@Sun.COM 		DTRACE_PROBE2(trill__multi__dest__fwd, uint16_t,
34710491SRishi.Srivatsavai@Sun.COM 		    adjnick, uint16_t, ingressnick);
34810491SRishi.Srivatsavai@Sun.COM 		trill_dest_fwd(tip, fwd_mp, adjnick, is_trill_pkt,
34910491SRishi.Srivatsavai@Sun.COM 		    B_TRUE, egressnick);
35010491SRishi.Srivatsavai@Sun.COM 	}
35110491SRishi.Srivatsavai@Sun.COM 	trill_node_unref(tip, dest);
35210491SRishi.Srivatsavai@Sun.COM 
35310491SRishi.Srivatsavai@Sun.COM 	if (nicksaved) {
35410491SRishi.Srivatsavai@Sun.COM 		ASSERT(free_mblk);
35510491SRishi.Srivatsavai@Sun.COM 		DTRACE_PROBE2(trill__multi__dest__fwd, uint16_t,
35610491SRishi.Srivatsavai@Sun.COM 		    adjnicksaved, uint16_t, ingressnick);
35710491SRishi.Srivatsavai@Sun.COM 		trill_dest_fwd(tip, mp, adjnicksaved, is_trill_pkt,
35810491SRishi.Srivatsavai@Sun.COM 		    B_TRUE, egressnick);
35910491SRishi.Srivatsavai@Sun.COM 		return;
36010491SRishi.Srivatsavai@Sun.COM 	}
36110491SRishi.Srivatsavai@Sun.COM 
36210491SRishi.Srivatsavai@Sun.COM fail_multidest_fwd:
36310491SRishi.Srivatsavai@Sun.COM 	DTRACE_PROBE2(trill__multi__dest__fwd__fail, uint16_t,
36410491SRishi.Srivatsavai@Sun.COM 	    egressnick, uint16_t, ingressnick);
36510491SRishi.Srivatsavai@Sun.COM 	if (free_mblk) {
36610491SRishi.Srivatsavai@Sun.COM 		freemsg(mp);
36710491SRishi.Srivatsavai@Sun.COM 	}
36810491SRishi.Srivatsavai@Sun.COM }
36910491SRishi.Srivatsavai@Sun.COM 
37010491SRishi.Srivatsavai@Sun.COM /*
37110491SRishi.Srivatsavai@Sun.COM  * TRILL data receive function. Forwards the received frame if necessary
37210491SRishi.Srivatsavai@Sun.COM  * and also determines if the received frame should be consumed locally.
37310491SRishi.Srivatsavai@Sun.COM  * Consumes passed mblk.
37410491SRishi.Srivatsavai@Sun.COM  */
37510491SRishi.Srivatsavai@Sun.COM static void
trill_recv(trill_sock_t * tsock,mblk_t * mp,const uint8_t * mpsaddr)37610491SRishi.Srivatsavai@Sun.COM trill_recv(trill_sock_t *tsock, mblk_t *mp, const uint8_t *mpsaddr)
37710491SRishi.Srivatsavai@Sun.COM {
37810491SRishi.Srivatsavai@Sun.COM 	trill_header_t *trillhdr;
37910491SRishi.Srivatsavai@Sun.COM 	trill_node_t *dest = NULL;
38010491SRishi.Srivatsavai@Sun.COM 	trill_node_t *source = NULL;
38110491SRishi.Srivatsavai@Sun.COM 	trill_node_t *adj;
38210491SRishi.Srivatsavai@Sun.COM 	uint16_t ournick, adjnick, treeroot;
38310491SRishi.Srivatsavai@Sun.COM 	struct ether_header *ethhdr;
38410491SRishi.Srivatsavai@Sun.COM 	trill_inst_t *tip = tsock->ts_tip;
38510491SRishi.Srivatsavai@Sun.COM 	uint8_t srcaddr[ETHERADDRL];
38610491SRishi.Srivatsavai@Sun.COM 	size_t trillhdrlen;
38710491SRishi.Srivatsavai@Sun.COM 	int inner_vlan = VLAN_ID_NONE;
38810491SRishi.Srivatsavai@Sun.COM 	int tci;
38910491SRishi.Srivatsavai@Sun.COM 	int idx;
39010491SRishi.Srivatsavai@Sun.COM 	size_t min_size;
39110491SRishi.Srivatsavai@Sun.COM 
39210491SRishi.Srivatsavai@Sun.COM 	/* Copy Ethernet source address before modifying packet */
39310491SRishi.Srivatsavai@Sun.COM 	(void) memcpy(srcaddr, mpsaddr, ETHERADDRL);
39410491SRishi.Srivatsavai@Sun.COM 
39510491SRishi.Srivatsavai@Sun.COM 	/* Pull up TRILL header if necessary. */
39610491SRishi.Srivatsavai@Sun.COM 	min_size = sizeof (trill_header_t);
39710491SRishi.Srivatsavai@Sun.COM 	if ((MBLKL(mp) < min_size ||
39810491SRishi.Srivatsavai@Sun.COM 	    !IS_P2ALIGNED(mp->b_rptr, TRILL_HDR_ALIGN)) &&
39910491SRishi.Srivatsavai@Sun.COM 	    !pullupmsg(mp, min_size))
40010491SRishi.Srivatsavai@Sun.COM 		goto fail;
40110491SRishi.Srivatsavai@Sun.COM 
40210491SRishi.Srivatsavai@Sun.COM 	/* LINTED: alignment */
40310491SRishi.Srivatsavai@Sun.COM 	trillhdr = (trill_header_t *)mp->b_rptr;
40410491SRishi.Srivatsavai@Sun.COM 	if (trillhdr->th_version != TRILL_PROTOCOL_VERS) {
40510491SRishi.Srivatsavai@Sun.COM 		DTRACE_PROBE1(trill__recv__wrongversion,
40610491SRishi.Srivatsavai@Sun.COM 		    trill_header_t *, trillhdr);
40710491SRishi.Srivatsavai@Sun.COM 		goto fail;
40810491SRishi.Srivatsavai@Sun.COM 	}
40910491SRishi.Srivatsavai@Sun.COM 
41010491SRishi.Srivatsavai@Sun.COM 	/* Drop if unknown or invalid nickname */
41110491SRishi.Srivatsavai@Sun.COM 	if (!VALID_NICK(trillhdr->th_egressnick) ||
41210491SRishi.Srivatsavai@Sun.COM 	    !VALID_NICK(trillhdr->th_ingressnick)) {
41310491SRishi.Srivatsavai@Sun.COM 		DTRACE_PROBE1(trill__recv__invalidnick,
41410491SRishi.Srivatsavai@Sun.COM 		    trill_header_t *, trillhdr);
41510491SRishi.Srivatsavai@Sun.COM 		goto fail;
41610491SRishi.Srivatsavai@Sun.COM 	}
41710491SRishi.Srivatsavai@Sun.COM 
41810491SRishi.Srivatsavai@Sun.COM 	rw_enter(&tip->ti_rwlock, RW_READER);
41910491SRishi.Srivatsavai@Sun.COM 	ournick = tip->ti_nick;
42010491SRishi.Srivatsavai@Sun.COM 	treeroot = tip->ti_treeroot;
42110491SRishi.Srivatsavai@Sun.COM 	rw_exit(&tip->ti_rwlock);
42210491SRishi.Srivatsavai@Sun.COM 	/* Drop if we received a packet with our nick as ingress */
42310491SRishi.Srivatsavai@Sun.COM 	if (trillhdr->th_ingressnick == ournick)
42410491SRishi.Srivatsavai@Sun.COM 		goto fail;
42510491SRishi.Srivatsavai@Sun.COM 
42610491SRishi.Srivatsavai@Sun.COM 	/* Re-pull any TRILL options and inner Ethernet header */
42710491SRishi.Srivatsavai@Sun.COM 	min_size += GET_TRILL_OPTS_LEN(trillhdr) * sizeof (uint32_t) +
42810491SRishi.Srivatsavai@Sun.COM 	    sizeof (struct ether_header);
42910491SRishi.Srivatsavai@Sun.COM 	if (MBLKL(mp) < min_size) {
43010491SRishi.Srivatsavai@Sun.COM 		if (!pullupmsg(mp, min_size))
43110491SRishi.Srivatsavai@Sun.COM 			goto fail;
43210491SRishi.Srivatsavai@Sun.COM 		/* LINTED: alignment */
43310491SRishi.Srivatsavai@Sun.COM 		trillhdr = (trill_header_t *)mp->b_rptr;
43410491SRishi.Srivatsavai@Sun.COM 	}
43510491SRishi.Srivatsavai@Sun.COM 	trillhdrlen = sizeof (trill_header_t) +
43610491SRishi.Srivatsavai@Sun.COM 	    (GET_TRILL_OPTS_LEN(trillhdr) * sizeof (uint32_t));
43710491SRishi.Srivatsavai@Sun.COM 
43810491SRishi.Srivatsavai@Sun.COM 	/*
43910491SRishi.Srivatsavai@Sun.COM 	 * Get the inner Ethernet header, plus the inner VLAN header if there
44010491SRishi.Srivatsavai@Sun.COM 	 * is one.
44110491SRishi.Srivatsavai@Sun.COM 	 */
44210491SRishi.Srivatsavai@Sun.COM 	/* LINTED: alignment */
44310491SRishi.Srivatsavai@Sun.COM 	ethhdr = (struct ether_header *)(mp->b_rptr + trillhdrlen);
44410491SRishi.Srivatsavai@Sun.COM 	if (ethhdr->ether_type == htons(ETHERTYPE_VLAN)) {
44510491SRishi.Srivatsavai@Sun.COM 		min_size += sizeof (struct ether_vlan_extinfo);
44610491SRishi.Srivatsavai@Sun.COM 		if (MBLKL(mp) < min_size) {
44710491SRishi.Srivatsavai@Sun.COM 			if (!pullupmsg(mp, min_size))
44810491SRishi.Srivatsavai@Sun.COM 				goto fail;
44910491SRishi.Srivatsavai@Sun.COM 			/* LINTED: alignment */
45010491SRishi.Srivatsavai@Sun.COM 			trillhdr = (trill_header_t *)mp->b_rptr;
45110491SRishi.Srivatsavai@Sun.COM 			/* LINTED: alignment */
45210491SRishi.Srivatsavai@Sun.COM 			ethhdr = (struct ether_header *)(mp->b_rptr +
45310491SRishi.Srivatsavai@Sun.COM 			    trillhdrlen);
45410491SRishi.Srivatsavai@Sun.COM 		}
45510491SRishi.Srivatsavai@Sun.COM 
45610491SRishi.Srivatsavai@Sun.COM 		tci = ntohs(((struct ether_vlan_header *)ethhdr)->ether_tci);
45710491SRishi.Srivatsavai@Sun.COM 		inner_vlan = VLAN_ID(tci);
45810491SRishi.Srivatsavai@Sun.COM 	}
45910491SRishi.Srivatsavai@Sun.COM 
46010491SRishi.Srivatsavai@Sun.COM 	/* Known/single destination forwarding. */
46110491SRishi.Srivatsavai@Sun.COM 	if (!trillhdr->th_multidest) {
46210491SRishi.Srivatsavai@Sun.COM 
46310491SRishi.Srivatsavai@Sun.COM 		/* Inner MacDA must be unicast */
46410491SRishi.Srivatsavai@Sun.COM 		if (ethhdr->ether_dhost.ether_addr_octet[0] & 1)
46510491SRishi.Srivatsavai@Sun.COM 			goto fail;
46610491SRishi.Srivatsavai@Sun.COM 
46710491SRishi.Srivatsavai@Sun.COM 		/* Ingress and Egress nicks must be different */
46810491SRishi.Srivatsavai@Sun.COM 		if (trillhdr->th_egressnick == trillhdr->th_ingressnick)
46910491SRishi.Srivatsavai@Sun.COM 			goto fail;
47010491SRishi.Srivatsavai@Sun.COM 
47110491SRishi.Srivatsavai@Sun.COM 		DTRACE_PROBE1(trill__recv__singledest,
47210491SRishi.Srivatsavai@Sun.COM 		    trill_header_t *, trillhdr);
47310491SRishi.Srivatsavai@Sun.COM 		if (trillhdr->th_egressnick == ournick) {
47410491SRishi.Srivatsavai@Sun.COM 			mp->b_rptr += trillhdrlen;
47510491SRishi.Srivatsavai@Sun.COM 			trill_recv_local(tsock, mp, trillhdr->th_ingressnick);
47610491SRishi.Srivatsavai@Sun.COM 		} else if (trillhdr->th_hopcount > 0) {
47710491SRishi.Srivatsavai@Sun.COM 			trill_dest_fwd(tip, mp, trillhdr->th_egressnick,
47810491SRishi.Srivatsavai@Sun.COM 			    B_TRUE, B_FALSE, RBRIDGE_NICKNAME_NONE);
47910491SRishi.Srivatsavai@Sun.COM 		} else {
48010491SRishi.Srivatsavai@Sun.COM 			goto fail;
48110491SRishi.Srivatsavai@Sun.COM 		}
48210491SRishi.Srivatsavai@Sun.COM 		return;
48310491SRishi.Srivatsavai@Sun.COM 	}
48410491SRishi.Srivatsavai@Sun.COM 
48510491SRishi.Srivatsavai@Sun.COM 	/*
48610491SRishi.Srivatsavai@Sun.COM 	 * Multi-destination frame: perform checks verifying we have
48710491SRishi.Srivatsavai@Sun.COM 	 * received a valid multi-destination frame before receiving the
48810491SRishi.Srivatsavai@Sun.COM 	 * frame locally and forwarding the frame to other RBridges.
48910491SRishi.Srivatsavai@Sun.COM 	 *
49010491SRishi.Srivatsavai@Sun.COM 	 * Check if we received this multi-destination frame on a
49110491SRishi.Srivatsavai@Sun.COM 	 * adjacency in the distribution tree indicated by the frame's
49210491SRishi.Srivatsavai@Sun.COM 	 * egress nickname.
49310491SRishi.Srivatsavai@Sun.COM 	 */
49410491SRishi.Srivatsavai@Sun.COM 	if ((dest = trill_node_lookup(tip, trillhdr->th_egressnick)) == NULL)
49510491SRishi.Srivatsavai@Sun.COM 		goto fail;
49610491SRishi.Srivatsavai@Sun.COM 	for (idx = 0; idx < dest->tn_ni->tni_adjcount; idx++) {
49710491SRishi.Srivatsavai@Sun.COM 		adjnick = TNI_ADJNICK(dest->tn_ni, idx);
49810491SRishi.Srivatsavai@Sun.COM 		if ((adj = trill_node_lookup(tip, adjnick)) == NULL)
49910491SRishi.Srivatsavai@Sun.COM 			continue;
50010491SRishi.Srivatsavai@Sun.COM 		if (memcmp(adj->tn_ni->tni_adjsnpa, srcaddr, ETHERADDRL) == 0) {
50110491SRishi.Srivatsavai@Sun.COM 			trill_node_unref(tip, adj);
50210491SRishi.Srivatsavai@Sun.COM 			break;
50310491SRishi.Srivatsavai@Sun.COM 		}
50410491SRishi.Srivatsavai@Sun.COM 		trill_node_unref(tip, adj);
50510491SRishi.Srivatsavai@Sun.COM 	}
50610491SRishi.Srivatsavai@Sun.COM 
50710491SRishi.Srivatsavai@Sun.COM 	if (idx >= dest->tn_ni->tni_adjcount) {
50810491SRishi.Srivatsavai@Sun.COM 		DTRACE_PROBE2(trill__recv__multidest__adjcheckfail,
50910491SRishi.Srivatsavai@Sun.COM 		    trill_header_t *, trillhdr, trill_node_t *, dest);
51010491SRishi.Srivatsavai@Sun.COM 		goto fail;
51110491SRishi.Srivatsavai@Sun.COM 	}
51210491SRishi.Srivatsavai@Sun.COM 
51310491SRishi.Srivatsavai@Sun.COM 	/*
51410491SRishi.Srivatsavai@Sun.COM 	 * Reverse path forwarding check. Check if the ingress RBridge
51510491SRishi.Srivatsavai@Sun.COM 	 * that has forwarded the frame advertised the use of the
51610491SRishi.Srivatsavai@Sun.COM 	 * distribution tree specified in the egress nick.
51710491SRishi.Srivatsavai@Sun.COM 	 */
51810491SRishi.Srivatsavai@Sun.COM 	if ((source = trill_node_lookup(tip, trillhdr->th_ingressnick)) == NULL)
51910491SRishi.Srivatsavai@Sun.COM 		goto fail;
52010491SRishi.Srivatsavai@Sun.COM 	for (idx = 0; idx < source->tn_ni->tni_dtrootcount; idx++) {
52110491SRishi.Srivatsavai@Sun.COM 		if (TNI_DTROOTNICK(source->tn_ni, idx) ==
52210491SRishi.Srivatsavai@Sun.COM 		    trillhdr->th_egressnick)
52310491SRishi.Srivatsavai@Sun.COM 			break;
52410491SRishi.Srivatsavai@Sun.COM 	}
52510491SRishi.Srivatsavai@Sun.COM 
52610491SRishi.Srivatsavai@Sun.COM 	if (idx >= source->tn_ni->tni_dtrootcount) {
52710491SRishi.Srivatsavai@Sun.COM 		/*
52810491SRishi.Srivatsavai@Sun.COM 		 * Allow receipt of forwarded frame with the highest
52910491SRishi.Srivatsavai@Sun.COM 		 * tree root RBridge as the egress RBridge when the
53010491SRishi.Srivatsavai@Sun.COM 		 * ingress RBridge has not advertised the use of any
53110491SRishi.Srivatsavai@Sun.COM 		 * distribution trees.
53210491SRishi.Srivatsavai@Sun.COM 		 */
53310491SRishi.Srivatsavai@Sun.COM 		if (source->tn_ni->tni_dtrootcount != 0 ||
53410491SRishi.Srivatsavai@Sun.COM 		    trillhdr->th_egressnick != treeroot) {
53510491SRishi.Srivatsavai@Sun.COM 			DTRACE_PROBE3(
53610491SRishi.Srivatsavai@Sun.COM 			    trill__recv__multidest__rpfcheckfail,
53710491SRishi.Srivatsavai@Sun.COM 			    trill_header_t *, trillhdr, trill_node_t *,
53810491SRishi.Srivatsavai@Sun.COM 			    source, trill_inst_t *, tip);
53910491SRishi.Srivatsavai@Sun.COM 			goto fail;
54010491SRishi.Srivatsavai@Sun.COM 		}
54110491SRishi.Srivatsavai@Sun.COM 	}
54210491SRishi.Srivatsavai@Sun.COM 
54310491SRishi.Srivatsavai@Sun.COM 	/* Check hop count before doing any forwarding */
54410491SRishi.Srivatsavai@Sun.COM 	if (trillhdr->th_hopcount == 0)
54510491SRishi.Srivatsavai@Sun.COM 		goto fail;
54610491SRishi.Srivatsavai@Sun.COM 
54710491SRishi.Srivatsavai@Sun.COM 	/* Forward frame using the distribution tree specified by egress nick */
54810491SRishi.Srivatsavai@Sun.COM 	DTRACE_PROBE2(trill__recv__multidest, trill_header_t *,
54910491SRishi.Srivatsavai@Sun.COM 	    trillhdr, trill_node_t *, source);
55010491SRishi.Srivatsavai@Sun.COM 	trill_node_unref(tip, source);
55110491SRishi.Srivatsavai@Sun.COM 	trill_node_unref(tip, dest);
55210491SRishi.Srivatsavai@Sun.COM 
55310491SRishi.Srivatsavai@Sun.COM 	/* Tell forwarding not to free if we're the link forwarder. */
55410491SRishi.Srivatsavai@Sun.COM 	trill_multidest_fwd(tip, mp, trillhdr->th_egressnick,
55510491SRishi.Srivatsavai@Sun.COM 	    trillhdr->th_ingressnick, B_TRUE, srcaddr, inner_vlan,
55610491SRishi.Srivatsavai@Sun.COM 	    B_FALSE);
55710491SRishi.Srivatsavai@Sun.COM 
55810491SRishi.Srivatsavai@Sun.COM 	/*
55910491SRishi.Srivatsavai@Sun.COM 	 * Send de-capsulated frame locally if we are the link forwarder (also
56010491SRishi.Srivatsavai@Sun.COM 	 * does bridge learning).
56110491SRishi.Srivatsavai@Sun.COM 	 */
56210491SRishi.Srivatsavai@Sun.COM 	mp->b_rptr += trillhdrlen;
56310491SRishi.Srivatsavai@Sun.COM 	trill_recv_local(tsock, mp, trillhdr->th_ingressnick);
56410491SRishi.Srivatsavai@Sun.COM 	KSPINCR(tks_recv);
56510491SRishi.Srivatsavai@Sun.COM 	return;
56610491SRishi.Srivatsavai@Sun.COM 
56710491SRishi.Srivatsavai@Sun.COM fail:
56810491SRishi.Srivatsavai@Sun.COM 	DTRACE_PROBE2(trill__recv__multidest__fail, mblk_t *, mp,
56910491SRishi.Srivatsavai@Sun.COM 	    trill_sock_t *, tsock);
57010491SRishi.Srivatsavai@Sun.COM 	if (dest != NULL)
57110491SRishi.Srivatsavai@Sun.COM 		trill_node_unref(tip, dest);
57210491SRishi.Srivatsavai@Sun.COM 	if (source != NULL)
57310491SRishi.Srivatsavai@Sun.COM 		trill_node_unref(tip, source);
57410491SRishi.Srivatsavai@Sun.COM 	freemsg(mp);
57510491SRishi.Srivatsavai@Sun.COM 	KSPINCR(tks_drops);
57610491SRishi.Srivatsavai@Sun.COM }
57710491SRishi.Srivatsavai@Sun.COM 
57810491SRishi.Srivatsavai@Sun.COM static void
trill_stop_recv(trill_sock_t * tsock)57910491SRishi.Srivatsavai@Sun.COM trill_stop_recv(trill_sock_t *tsock)
58010491SRishi.Srivatsavai@Sun.COM {
58110491SRishi.Srivatsavai@Sun.COM 	mutex_enter(&tsock->ts_socklock);
58210491SRishi.Srivatsavai@Sun.COM stop_retry:
58310491SRishi.Srivatsavai@Sun.COM 	if (tsock->ts_state == TS_UNBND || tsock->ts_link == NULL) {
58410491SRishi.Srivatsavai@Sun.COM 		mutex_exit(&tsock->ts_socklock);
58510491SRishi.Srivatsavai@Sun.COM 		return;
58610491SRishi.Srivatsavai@Sun.COM 	}
58710491SRishi.Srivatsavai@Sun.COM 
58810491SRishi.Srivatsavai@Sun.COM 	/*
58910491SRishi.Srivatsavai@Sun.COM 	 * If another thread is closing the socket then wait. Our callers
59010491SRishi.Srivatsavai@Sun.COM 	 * expect us to return only after the socket is closed.
59110491SRishi.Srivatsavai@Sun.COM 	 */
59210491SRishi.Srivatsavai@Sun.COM 	if (tsock->ts_flags & TSF_CLOSEWAIT) {
59310491SRishi.Srivatsavai@Sun.COM 		cv_wait(&tsock->ts_sockclosewait, &tsock->ts_socklock);
59410491SRishi.Srivatsavai@Sun.COM 		goto stop_retry;
59510491SRishi.Srivatsavai@Sun.COM 	}
59610491SRishi.Srivatsavai@Sun.COM 
59710491SRishi.Srivatsavai@Sun.COM 	/*
59810491SRishi.Srivatsavai@Sun.COM 	 * Set state and flags to block new bind or close calls
59910491SRishi.Srivatsavai@Sun.COM 	 * while we close the socket.
60010491SRishi.Srivatsavai@Sun.COM 	 */
60110491SRishi.Srivatsavai@Sun.COM 	tsock->ts_flags |= TSF_CLOSEWAIT;
60210491SRishi.Srivatsavai@Sun.COM 
60310491SRishi.Srivatsavai@Sun.COM 	/* Wait until all AF_TRILL socket transmit operations are done */
60410491SRishi.Srivatsavai@Sun.COM 	while (tsock->ts_sockthreadcount > 0)
60510491SRishi.Srivatsavai@Sun.COM 		cv_wait(&tsock->ts_sockthreadwait, &tsock->ts_socklock);
60610491SRishi.Srivatsavai@Sun.COM 
60710491SRishi.Srivatsavai@Sun.COM 	/*
60810491SRishi.Srivatsavai@Sun.COM 	 * We are guaranteed to be the only thread closing on the
60910491SRishi.Srivatsavai@Sun.COM 	 * socket while the TSF_CLOSEWAIT flag is set, all others cv_wait
61010491SRishi.Srivatsavai@Sun.COM 	 * for us to finish.
61110491SRishi.Srivatsavai@Sun.COM 	 */
61210491SRishi.Srivatsavai@Sun.COM 	ASSERT(tsock->ts_link != NULL);
61310491SRishi.Srivatsavai@Sun.COM 	if (tsock->ts_ksp != NULL)
61410491SRishi.Srivatsavai@Sun.COM 		kstat_delete(tsock->ts_ksp);
61510491SRishi.Srivatsavai@Sun.COM 
61610491SRishi.Srivatsavai@Sun.COM 	/*
61710491SRishi.Srivatsavai@Sun.COM 	 * Release lock before bridge_trill_lnunref to prevent deadlock
61810491SRishi.Srivatsavai@Sun.COM 	 * between trill_ctrl_input thread waiting to acquire ts_socklock
61910491SRishi.Srivatsavai@Sun.COM 	 * and bridge_trill_lnunref waiting for the trill thread to finish.
62010491SRishi.Srivatsavai@Sun.COM 	 */
62110491SRishi.Srivatsavai@Sun.COM 	mutex_exit(&tsock->ts_socklock);
62210491SRishi.Srivatsavai@Sun.COM 
62310491SRishi.Srivatsavai@Sun.COM 	/*
62410491SRishi.Srivatsavai@Sun.COM 	 * Release TRILL link reference from Bridging. On return from
62510491SRishi.Srivatsavai@Sun.COM 	 * bridge_trill_lnunref we can be sure there are no active TRILL data
62610491SRishi.Srivatsavai@Sun.COM 	 * threads for this link.
62710491SRishi.Srivatsavai@Sun.COM 	 */
62810491SRishi.Srivatsavai@Sun.COM 	bridge_trill_lnunref(tsock->ts_link);
62910491SRishi.Srivatsavai@Sun.COM 
63010491SRishi.Srivatsavai@Sun.COM 	/* Set socket as unbound & wakeup threads waiting for socket to close */
63110491SRishi.Srivatsavai@Sun.COM 	mutex_enter(&tsock->ts_socklock);
63210491SRishi.Srivatsavai@Sun.COM 	ASSERT(tsock->ts_link != NULL);
63310491SRishi.Srivatsavai@Sun.COM 	tsock->ts_link = NULL;
63410491SRishi.Srivatsavai@Sun.COM 	tsock->ts_state = TS_UNBND;
63510491SRishi.Srivatsavai@Sun.COM 	tsock->ts_flags &= ~TSF_CLOSEWAIT;
63610491SRishi.Srivatsavai@Sun.COM 	cv_broadcast(&tsock->ts_sockclosewait);
63710491SRishi.Srivatsavai@Sun.COM 	mutex_exit(&tsock->ts_socklock);
63810491SRishi.Srivatsavai@Sun.COM }
63910491SRishi.Srivatsavai@Sun.COM 
64010491SRishi.Srivatsavai@Sun.COM static int
trill_start_recv(trill_sock_t * tsock,const struct sockaddr * sa,socklen_t len)64110491SRishi.Srivatsavai@Sun.COM trill_start_recv(trill_sock_t *tsock, const struct sockaddr *sa, socklen_t len)
64210491SRishi.Srivatsavai@Sun.COM {
64310491SRishi.Srivatsavai@Sun.COM 	struct sockaddr_dl *lladdr = (struct sockaddr_dl *)sa;
64410491SRishi.Srivatsavai@Sun.COM 	datalink_id_t linkid;
64510491SRishi.Srivatsavai@Sun.COM 	int err = 0;
64610491SRishi.Srivatsavai@Sun.COM 
64710491SRishi.Srivatsavai@Sun.COM 	if (len != sizeof (*lladdr))
64810491SRishi.Srivatsavai@Sun.COM 		return (EINVAL);
64910491SRishi.Srivatsavai@Sun.COM 
65010491SRishi.Srivatsavai@Sun.COM 	mutex_enter(&tsock->ts_socklock);
65110491SRishi.Srivatsavai@Sun.COM 	if (tsock->ts_tip == NULL || tsock->ts_state != TS_UNBND) {
65210491SRishi.Srivatsavai@Sun.COM 		err = EINVAL;
65310491SRishi.Srivatsavai@Sun.COM 		goto bind_error;
65410491SRishi.Srivatsavai@Sun.COM 	}
65510491SRishi.Srivatsavai@Sun.COM 
65610491SRishi.Srivatsavai@Sun.COM 	if (tsock->ts_flags & TSF_CLOSEWAIT || tsock->ts_link != NULL) {
65710491SRishi.Srivatsavai@Sun.COM 		err = EBUSY;
65810491SRishi.Srivatsavai@Sun.COM 		goto bind_error;
65910491SRishi.Srivatsavai@Sun.COM 	}
66010491SRishi.Srivatsavai@Sun.COM 
66110491SRishi.Srivatsavai@Sun.COM 	(void) memcpy(&(tsock->ts_lladdr), lladdr,
66210491SRishi.Srivatsavai@Sun.COM 	    sizeof (struct sockaddr_dl));
66310491SRishi.Srivatsavai@Sun.COM 	(void) memcpy(&linkid, tsock->ts_lladdr.sdl_data,
66410491SRishi.Srivatsavai@Sun.COM 	    sizeof (datalink_id_t));
66510491SRishi.Srivatsavai@Sun.COM 
66610491SRishi.Srivatsavai@Sun.COM 	tsock->ts_link = bridge_trill_lnref(tsock->ts_tip->ti_binst,
66710491SRishi.Srivatsavai@Sun.COM 	    linkid, tsock);
66810491SRishi.Srivatsavai@Sun.COM 	if (tsock->ts_link == NULL) {
66910491SRishi.Srivatsavai@Sun.COM 		err = EINVAL;
67010491SRishi.Srivatsavai@Sun.COM 		goto bind_error;
67110491SRishi.Srivatsavai@Sun.COM 	}
67210491SRishi.Srivatsavai@Sun.COM 
67310491SRishi.Srivatsavai@Sun.COM 	trill_kstats_init(tsock, tsock->ts_tip->ti_bridgename);
67410491SRishi.Srivatsavai@Sun.COM 	tsock->ts_state = TS_IDLE;
67510491SRishi.Srivatsavai@Sun.COM 
67610491SRishi.Srivatsavai@Sun.COM bind_error:
67710491SRishi.Srivatsavai@Sun.COM 	mutex_exit(&tsock->ts_socklock);
67810491SRishi.Srivatsavai@Sun.COM 	return (err);
67910491SRishi.Srivatsavai@Sun.COM }
68010491SRishi.Srivatsavai@Sun.COM 
68110491SRishi.Srivatsavai@Sun.COM static int
trill_do_unbind(trill_sock_t * tsock)68210491SRishi.Srivatsavai@Sun.COM trill_do_unbind(trill_sock_t *tsock)
68310491SRishi.Srivatsavai@Sun.COM {
68410491SRishi.Srivatsavai@Sun.COM 	/* If a bind has not been done, we can't unbind. */
68510491SRishi.Srivatsavai@Sun.COM 	if (tsock->ts_state != TS_IDLE)
68610491SRishi.Srivatsavai@Sun.COM 		return (EINVAL);
68710491SRishi.Srivatsavai@Sun.COM 
68810491SRishi.Srivatsavai@Sun.COM 	trill_stop_recv(tsock);
68910491SRishi.Srivatsavai@Sun.COM 	return (0);
69010491SRishi.Srivatsavai@Sun.COM }
69110491SRishi.Srivatsavai@Sun.COM 
69210491SRishi.Srivatsavai@Sun.COM static void
trill_instance_unref(trill_inst_t * tip)69310491SRishi.Srivatsavai@Sun.COM trill_instance_unref(trill_inst_t *tip)
69410491SRishi.Srivatsavai@Sun.COM {
69510491SRishi.Srivatsavai@Sun.COM 	rw_enter(&trill_inst_rwlock, RW_WRITER);
69610491SRishi.Srivatsavai@Sun.COM 	rw_enter(&tip->ti_rwlock, RW_WRITER);
69710491SRishi.Srivatsavai@Sun.COM 	if (atomic_dec_uint_nv(&tip->ti_refs) == 0) {
69810491SRishi.Srivatsavai@Sun.COM 		list_remove(&trill_inst_list, tip);
69910491SRishi.Srivatsavai@Sun.COM 		rw_exit(&tip->ti_rwlock);
70010491SRishi.Srivatsavai@Sun.COM 		rw_exit(&trill_inst_rwlock);
70110491SRishi.Srivatsavai@Sun.COM 		if (tip->ti_binst != NULL)
70210491SRishi.Srivatsavai@Sun.COM 			bridge_trill_brunref(tip->ti_binst);
70310491SRishi.Srivatsavai@Sun.COM 		list_destroy(&tip->ti_socklist);
70410491SRishi.Srivatsavai@Sun.COM 		rw_destroy(&tip->ti_rwlock);
70510491SRishi.Srivatsavai@Sun.COM 		kmem_free(tip, sizeof (*tip));
70610491SRishi.Srivatsavai@Sun.COM 	} else {
70710491SRishi.Srivatsavai@Sun.COM 		rw_exit(&tip->ti_rwlock);
70810491SRishi.Srivatsavai@Sun.COM 		rw_exit(&trill_inst_rwlock);
70910491SRishi.Srivatsavai@Sun.COM 	}
71010491SRishi.Srivatsavai@Sun.COM }
71110491SRishi.Srivatsavai@Sun.COM 
71210491SRishi.Srivatsavai@Sun.COM /*
71310491SRishi.Srivatsavai@Sun.COM  * This is called when the bridge module receives a TRILL-encapsulated packet
71410491SRishi.Srivatsavai@Sun.COM  * on a given link or a packet identified as "TRILL control."  We must verify
71510491SRishi.Srivatsavai@Sun.COM  * that it's for us (it almost certainly will be), and then either decapsulate
71610491SRishi.Srivatsavai@Sun.COM  * (if it's to our nickname), forward (if it's to someone else), or send up one
71710491SRishi.Srivatsavai@Sun.COM  * of the sockets (if it's control traffic).
71810491SRishi.Srivatsavai@Sun.COM  *
71910491SRishi.Srivatsavai@Sun.COM  * Sadly, on Ethernet, the control traffic is identified by Outer.MacDA, and
72010491SRishi.Srivatsavai@Sun.COM  * not by TRILL header information.
72110491SRishi.Srivatsavai@Sun.COM  */
72210491SRishi.Srivatsavai@Sun.COM 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)72310491SRishi.Srivatsavai@Sun.COM trill_recv_pkt_cb(void *lptr, bridge_link_t *blp, mac_resource_handle_t rsrc,
72410491SRishi.Srivatsavai@Sun.COM     mblk_t *mp, mac_header_info_t *hdr_info)
72510491SRishi.Srivatsavai@Sun.COM {
72610491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock = lptr;
72710491SRishi.Srivatsavai@Sun.COM 
72810491SRishi.Srivatsavai@Sun.COM 	_NOTE(ARGUNUSED(rsrc));
72910491SRishi.Srivatsavai@Sun.COM 
73010491SRishi.Srivatsavai@Sun.COM 	ASSERT(tsock->ts_tip != NULL);
73110491SRishi.Srivatsavai@Sun.COM 	ASSERT(tsock->ts_link != NULL);
73210491SRishi.Srivatsavai@Sun.COM 	ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN));
73310491SRishi.Srivatsavai@Sun.COM 
73410491SRishi.Srivatsavai@Sun.COM 	/*
73510491SRishi.Srivatsavai@Sun.COM 	 * Only receive packet if the source address is not multicast (which is
73610491SRishi.Srivatsavai@Sun.COM 	 * bogus).
73710491SRishi.Srivatsavai@Sun.COM 	 */
73810491SRishi.Srivatsavai@Sun.COM 	if (hdr_info->mhi_saddr[0] & 1)
73910491SRishi.Srivatsavai@Sun.COM 		goto discard;
74010491SRishi.Srivatsavai@Sun.COM 
74110491SRishi.Srivatsavai@Sun.COM 	/*
74210491SRishi.Srivatsavai@Sun.COM 	 * Check if this is our own packet reflected back.  It should not be.
74310491SRishi.Srivatsavai@Sun.COM 	 */
74410491SRishi.Srivatsavai@Sun.COM 	if (bcmp(hdr_info->mhi_saddr, blp->bl_local_mac, ETHERADDRL) == 0)
74510491SRishi.Srivatsavai@Sun.COM 		goto discard;
74610491SRishi.Srivatsavai@Sun.COM 
74710491SRishi.Srivatsavai@Sun.COM 	/* Only receive unicast packet if addressed to us */
74810491SRishi.Srivatsavai@Sun.COM 	if (hdr_info->mhi_dsttype == MAC_ADDRTYPE_UNICAST &&
74910491SRishi.Srivatsavai@Sun.COM 	    bcmp(hdr_info->mhi_daddr, blp->bl_local_mac, ETHERADDRL) != 0)
75010491SRishi.Srivatsavai@Sun.COM 		goto discard;
75110491SRishi.Srivatsavai@Sun.COM 
75210491SRishi.Srivatsavai@Sun.COM 	if (hdr_info->mhi_bindsap == ETHERTYPE_TRILL) {
75310491SRishi.Srivatsavai@Sun.COM 		/* TRILL data packets */
75410491SRishi.Srivatsavai@Sun.COM 		trill_recv(tsock, mp, hdr_info->mhi_saddr);
75510491SRishi.Srivatsavai@Sun.COM 	} else {
75610491SRishi.Srivatsavai@Sun.COM 		/* Design constraint for cheap IS-IS/BPDU comparison */
75710491SRishi.Srivatsavai@Sun.COM 		ASSERT(all_isis_rbridges[4] != bridge_group_address[4]);
75810491SRishi.Srivatsavai@Sun.COM 		/* Send received control packet upstream */
75910491SRishi.Srivatsavai@Sun.COM 		trill_ctrl_input(tsock, mp, hdr_info->mhi_saddr,
76010491SRishi.Srivatsavai@Sun.COM 		    hdr_info->mhi_daddr[4] == all_isis_rbridges[4] ?
76110491SRishi.Srivatsavai@Sun.COM 		    hdr_info->mhi_tci : TRILL_TCI_BPDU);
76210491SRishi.Srivatsavai@Sun.COM 	}
76310491SRishi.Srivatsavai@Sun.COM 
76410491SRishi.Srivatsavai@Sun.COM 	return;
76510491SRishi.Srivatsavai@Sun.COM 
76610491SRishi.Srivatsavai@Sun.COM discard:
76710491SRishi.Srivatsavai@Sun.COM 	freemsg(mp);
76810491SRishi.Srivatsavai@Sun.COM 	KSPINCR(tks_drops);
76910491SRishi.Srivatsavai@Sun.COM }
77010491SRishi.Srivatsavai@Sun.COM 
77110491SRishi.Srivatsavai@Sun.COM /*
77210491SRishi.Srivatsavai@Sun.COM  * This is called when the bridge module discovers that the destination address
77310491SRishi.Srivatsavai@Sun.COM  * for a packet is not local -- it's through some remote node.  We must verify
77410491SRishi.Srivatsavai@Sun.COM  * that the remote node isn't our nickname (it shouldn't be), add a TRILL
77510491SRishi.Srivatsavai@Sun.COM  * header, and then use the IS-IS data to determine which link and which
77610491SRishi.Srivatsavai@Sun.COM  * next-hop RBridge should be used for output.  We then transmit on that link.
77710491SRishi.Srivatsavai@Sun.COM  *
77810491SRishi.Srivatsavai@Sun.COM  * The egress_nick is RBRIDGE_NICKNAME_NONE for the "unknown destination" case.
77910491SRishi.Srivatsavai@Sun.COM  */
78010491SRishi.Srivatsavai@Sun.COM 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)78110491SRishi.Srivatsavai@Sun.COM trill_encap_pkt_cb(void *lptr, bridge_link_t *blp, mac_header_info_t *hdr_info,
78210491SRishi.Srivatsavai@Sun.COM     mblk_t *mp, uint16_t egress_nick)
78310491SRishi.Srivatsavai@Sun.COM {
78410491SRishi.Srivatsavai@Sun.COM 	uint16_t ournick;
78510491SRishi.Srivatsavai@Sun.COM 	uint16_t dtnick;
78610491SRishi.Srivatsavai@Sun.COM 	trill_node_t *self = NULL;
78710491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock = lptr;
78810491SRishi.Srivatsavai@Sun.COM 	trill_inst_t *tip = tsock->ts_tip;
78910491SRishi.Srivatsavai@Sun.COM 	int vlan = VLAN_ID_NONE;
79010491SRishi.Srivatsavai@Sun.COM 
79110491SRishi.Srivatsavai@Sun.COM 	_NOTE(ARGUNUSED(blp));
79210491SRishi.Srivatsavai@Sun.COM 	ASSERT(hdr_info->mhi_bindsap != ETHERTYPE_TRILL);
79310491SRishi.Srivatsavai@Sun.COM 
79410491SRishi.Srivatsavai@Sun.COM 	/* egress_nick = RBRIDGE_NICKNAME_NONE is valid */
79510491SRishi.Srivatsavai@Sun.COM 	if (egress_nick != RBRIDGE_NICKNAME_NONE && !VALID_NICK(egress_nick))
79610491SRishi.Srivatsavai@Sun.COM 		goto discard;
79710491SRishi.Srivatsavai@Sun.COM 
79810491SRishi.Srivatsavai@Sun.COM 	/* Check if our own nick is valid before we do any forwarding */
79910491SRishi.Srivatsavai@Sun.COM 	rw_enter(&tip->ti_rwlock, RW_READER);
80010491SRishi.Srivatsavai@Sun.COM 	ournick = tip->ti_nick;
80110491SRishi.Srivatsavai@Sun.COM 	dtnick = tip->ti_treeroot;
80210491SRishi.Srivatsavai@Sun.COM 	rw_exit(&tip->ti_rwlock);
80310491SRishi.Srivatsavai@Sun.COM 	if (!VALID_NICK(ournick))
80410491SRishi.Srivatsavai@Sun.COM 		goto discard;
80510491SRishi.Srivatsavai@Sun.COM 
80610491SRishi.Srivatsavai@Sun.COM 	/*
80710491SRishi.Srivatsavai@Sun.COM 	 * For Multi-Destination forwarding determine our choice of
80810491SRishi.Srivatsavai@Sun.COM 	 * root distribution tree. If we didn't choose a distribution
80910491SRishi.Srivatsavai@Sun.COM 	 * tree (dtroots_count=0) then we use the highest priority tree
81010491SRishi.Srivatsavai@Sun.COM 	 * root (t_treeroot) else we drop the packet without forwarding.
81110491SRishi.Srivatsavai@Sun.COM 	 */
81210491SRishi.Srivatsavai@Sun.COM 	if (egress_nick == RBRIDGE_NICKNAME_NONE) {
81310491SRishi.Srivatsavai@Sun.COM 		if ((self = trill_node_lookup(tip, ournick)) == NULL)
81410491SRishi.Srivatsavai@Sun.COM 			goto discard;
81510491SRishi.Srivatsavai@Sun.COM 
81610491SRishi.Srivatsavai@Sun.COM 		/*
81710491SRishi.Srivatsavai@Sun.COM 		 * Use the first DT configured for now. In future we
81810491SRishi.Srivatsavai@Sun.COM 		 * should have DT selection code here.
81910491SRishi.Srivatsavai@Sun.COM 		 */
82010491SRishi.Srivatsavai@Sun.COM 		if (self->tn_ni->tni_dtrootcount > 0) {
82110491SRishi.Srivatsavai@Sun.COM 			dtnick = TNI_DTROOTNICK(self->tn_ni, 0);
82210491SRishi.Srivatsavai@Sun.COM 		}
82310491SRishi.Srivatsavai@Sun.COM 
82410491SRishi.Srivatsavai@Sun.COM 		trill_node_unref(tip, self);
82510491SRishi.Srivatsavai@Sun.COM 		if (!VALID_NICK(dtnick)) {
82610491SRishi.Srivatsavai@Sun.COM 			DTRACE_PROBE(trill__fwd__packet__nodtroot);
82710491SRishi.Srivatsavai@Sun.COM 			goto discard;
82810491SRishi.Srivatsavai@Sun.COM 		}
82910491SRishi.Srivatsavai@Sun.COM 	}
83010491SRishi.Srivatsavai@Sun.COM 
83110491SRishi.Srivatsavai@Sun.COM 	/*
83210491SRishi.Srivatsavai@Sun.COM 	 * Retrieve VLAN ID of the native frame used for VLAN
83310491SRishi.Srivatsavai@Sun.COM 	 * pruning of multi-destination frames.
83410491SRishi.Srivatsavai@Sun.COM 	 */
83510491SRishi.Srivatsavai@Sun.COM 	if (hdr_info->mhi_istagged) {
83610491SRishi.Srivatsavai@Sun.COM 		vlan = VLAN_ID(hdr_info->mhi_tci);
83710491SRishi.Srivatsavai@Sun.COM 	}
83810491SRishi.Srivatsavai@Sun.COM 
83910491SRishi.Srivatsavai@Sun.COM 	DTRACE_PROBE2(trill__fwd__packet, mac_header_info_t *, hdr_info,
84010491SRishi.Srivatsavai@Sun.COM 	    uint16_t, egress_nick);
84110491SRishi.Srivatsavai@Sun.COM 	if (egress_nick == RBRIDGE_NICKNAME_NONE) {
84210491SRishi.Srivatsavai@Sun.COM 		trill_multidest_fwd(tip, mp, dtnick,
84310491SRishi.Srivatsavai@Sun.COM 		    ournick, B_FALSE, NULL, vlan, B_TRUE);
84410491SRishi.Srivatsavai@Sun.COM 	} else {
84510491SRishi.Srivatsavai@Sun.COM 		trill_dest_fwd(tip, mp, egress_nick, B_FALSE, B_FALSE,
84610491SRishi.Srivatsavai@Sun.COM 		    RBRIDGE_NICKNAME_NONE);
84710491SRishi.Srivatsavai@Sun.COM 	}
84810491SRishi.Srivatsavai@Sun.COM 	KSPINCR(tks_encap);
84910491SRishi.Srivatsavai@Sun.COM 	return;
85010491SRishi.Srivatsavai@Sun.COM 
85110491SRishi.Srivatsavai@Sun.COM discard:
85210491SRishi.Srivatsavai@Sun.COM 	freemsg(mp);
85310491SRishi.Srivatsavai@Sun.COM }
85410491SRishi.Srivatsavai@Sun.COM 
85510491SRishi.Srivatsavai@Sun.COM /*
85610491SRishi.Srivatsavai@Sun.COM  * This is called when the bridge module has completely torn down a bridge
85710491SRishi.Srivatsavai@Sun.COM  * instance and all of the attached links.  We need to make the TRILL instance
85810491SRishi.Srivatsavai@Sun.COM  * go away at this point.
85910491SRishi.Srivatsavai@Sun.COM  */
86010491SRishi.Srivatsavai@Sun.COM static void
trill_br_dstr_cb(void * bptr,bridge_inst_t * bip)86110491SRishi.Srivatsavai@Sun.COM trill_br_dstr_cb(void *bptr, bridge_inst_t *bip)
86210491SRishi.Srivatsavai@Sun.COM {
86310491SRishi.Srivatsavai@Sun.COM 	trill_inst_t *tip = bptr;
86410491SRishi.Srivatsavai@Sun.COM 
86510491SRishi.Srivatsavai@Sun.COM 	_NOTE(ARGUNUSED(bip));
86610491SRishi.Srivatsavai@Sun.COM 	rw_enter(&tip->ti_rwlock, RW_WRITER);
86710491SRishi.Srivatsavai@Sun.COM 	if (tip->ti_binst != NULL)
86810491SRishi.Srivatsavai@Sun.COM 		bridge_trill_brunref(tip->ti_binst);
86910491SRishi.Srivatsavai@Sun.COM 	tip->ti_binst = NULL;
87010491SRishi.Srivatsavai@Sun.COM 	rw_exit(&tip->ti_rwlock);
87110491SRishi.Srivatsavai@Sun.COM }
87210491SRishi.Srivatsavai@Sun.COM 
87310491SRishi.Srivatsavai@Sun.COM /*
87410491SRishi.Srivatsavai@Sun.COM  * This is called when the bridge module is tearing down a link, but before the
87510491SRishi.Srivatsavai@Sun.COM  * actual tear-down starts.  When this function returns, we must make sure that
87610491SRishi.Srivatsavai@Sun.COM  * we will not initiate any new transmits on this link.
87710491SRishi.Srivatsavai@Sun.COM  */
87810491SRishi.Srivatsavai@Sun.COM static void
trill_ln_dstr_cb(void * lptr,bridge_link_t * blp)87910491SRishi.Srivatsavai@Sun.COM trill_ln_dstr_cb(void *lptr, bridge_link_t *blp)
88010491SRishi.Srivatsavai@Sun.COM {
88110491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock = lptr;
88210491SRishi.Srivatsavai@Sun.COM 
88310491SRishi.Srivatsavai@Sun.COM 	_NOTE(ARGUNUSED(blp));
88410491SRishi.Srivatsavai@Sun.COM 	trill_stop_recv(tsock);
88510491SRishi.Srivatsavai@Sun.COM }
88610491SRishi.Srivatsavai@Sun.COM 
88710491SRishi.Srivatsavai@Sun.COM static void
trill_init(void)88810491SRishi.Srivatsavai@Sun.COM trill_init(void)
88910491SRishi.Srivatsavai@Sun.COM {
89010491SRishi.Srivatsavai@Sun.COM 	list_create(&trill_inst_list, sizeof (trill_inst_t),
89110491SRishi.Srivatsavai@Sun.COM 	    offsetof(trill_inst_t, ti_instnode));
89210491SRishi.Srivatsavai@Sun.COM 	rw_init(&trill_inst_rwlock, NULL, RW_DRIVER, NULL);
89310491SRishi.Srivatsavai@Sun.COM 	bridge_trill_register_cb(trill_recv_pkt_cb, trill_encap_pkt_cb,
89410491SRishi.Srivatsavai@Sun.COM 	    trill_br_dstr_cb, trill_ln_dstr_cb);
89510491SRishi.Srivatsavai@Sun.COM }
89610491SRishi.Srivatsavai@Sun.COM 
89710491SRishi.Srivatsavai@Sun.COM static void
trill_fini(void)89810491SRishi.Srivatsavai@Sun.COM trill_fini(void)
89910491SRishi.Srivatsavai@Sun.COM {
90010491SRishi.Srivatsavai@Sun.COM 	bridge_trill_register_cb(NULL, NULL, NULL, NULL);
90110491SRishi.Srivatsavai@Sun.COM 	rw_destroy(&trill_inst_rwlock);
90210491SRishi.Srivatsavai@Sun.COM 	list_destroy(&trill_inst_list);
90310491SRishi.Srivatsavai@Sun.COM }
90410491SRishi.Srivatsavai@Sun.COM 
90510491SRishi.Srivatsavai@Sun.COM /* Loadable module configuration entry points */
90610491SRishi.Srivatsavai@Sun.COM int
_init(void)90710491SRishi.Srivatsavai@Sun.COM _init(void)
90810491SRishi.Srivatsavai@Sun.COM {
90910491SRishi.Srivatsavai@Sun.COM 	int rc;
91010491SRishi.Srivatsavai@Sun.COM 
91110491SRishi.Srivatsavai@Sun.COM 	trill_init();
91210491SRishi.Srivatsavai@Sun.COM 	if ((rc = mod_install(&ml)) != 0)
91310491SRishi.Srivatsavai@Sun.COM 		trill_fini();
91410491SRishi.Srivatsavai@Sun.COM 	return (rc);
91510491SRishi.Srivatsavai@Sun.COM }
91610491SRishi.Srivatsavai@Sun.COM 
91710491SRishi.Srivatsavai@Sun.COM int
_info(struct modinfo * modinfop)91810491SRishi.Srivatsavai@Sun.COM _info(struct modinfo *modinfop)
91910491SRishi.Srivatsavai@Sun.COM {
92010491SRishi.Srivatsavai@Sun.COM 	return (mod_info(&ml, modinfop));
92110491SRishi.Srivatsavai@Sun.COM }
92210491SRishi.Srivatsavai@Sun.COM 
92310491SRishi.Srivatsavai@Sun.COM int
_fini(void)92410491SRishi.Srivatsavai@Sun.COM _fini(void)
92510491SRishi.Srivatsavai@Sun.COM {
92610491SRishi.Srivatsavai@Sun.COM 	int rc;
92710491SRishi.Srivatsavai@Sun.COM 
92810491SRishi.Srivatsavai@Sun.COM 	rw_enter(&trill_inst_rwlock, RW_READER);
92910491SRishi.Srivatsavai@Sun.COM 	rc = list_is_empty(&trill_inst_list) ? 0 : EBUSY;
93010491SRishi.Srivatsavai@Sun.COM 	rw_exit(&trill_inst_rwlock);
93110491SRishi.Srivatsavai@Sun.COM 	if (rc == 0 && ((rc = mod_remove(&ml)) == 0))
93210491SRishi.Srivatsavai@Sun.COM 		trill_fini();
93310491SRishi.Srivatsavai@Sun.COM 	return (rc);
93410491SRishi.Srivatsavai@Sun.COM }
93510491SRishi.Srivatsavai@Sun.COM 
93610491SRishi.Srivatsavai@Sun.COM static void
trill_kstats_init(trill_sock_t * tsock,const char * bname)93710491SRishi.Srivatsavai@Sun.COM trill_kstats_init(trill_sock_t *tsock, const char *bname)
93810491SRishi.Srivatsavai@Sun.COM {
93910491SRishi.Srivatsavai@Sun.COM 	int i;
94010491SRishi.Srivatsavai@Sun.COM 	char kstatname[KSTAT_STRLEN];
94110491SRishi.Srivatsavai@Sun.COM 	kstat_named_t  *knt;
94210491SRishi.Srivatsavai@Sun.COM 	static const char *sock_kstats_list[] = { TRILL_KSSOCK_NAMES };
94310491SRishi.Srivatsavai@Sun.COM 	char link_name[MAXNAMELEN];
94410491SRishi.Srivatsavai@Sun.COM 	int num;
94510491SRishi.Srivatsavai@Sun.COM 	int err;
94610491SRishi.Srivatsavai@Sun.COM 
94710491SRishi.Srivatsavai@Sun.COM 	bzero(link_name, sizeof (link_name));
94810491SRishi.Srivatsavai@Sun.COM 	if ((err = dls_mgmt_get_linkinfo(tsock->ts_link->bl_linkid, link_name,
94910491SRishi.Srivatsavai@Sun.COM 	    NULL, NULL, NULL)) != 0) {
95010491SRishi.Srivatsavai@Sun.COM 		cmn_err(CE_WARN, "%s: trill_kstats_init: error %d retrieving"
95110491SRishi.Srivatsavai@Sun.COM 		    " linkinfo for linkid:%d", "trill", err,
95210491SRishi.Srivatsavai@Sun.COM 		    tsock->ts_link->bl_linkid);
95310491SRishi.Srivatsavai@Sun.COM 		return;
95410491SRishi.Srivatsavai@Sun.COM 	}
95510491SRishi.Srivatsavai@Sun.COM 
95610491SRishi.Srivatsavai@Sun.COM 	bzero(kstatname, sizeof (kstatname));
95710491SRishi.Srivatsavai@Sun.COM 	(void) snprintf(kstatname, sizeof (kstatname), "%s-%s",
95810491SRishi.Srivatsavai@Sun.COM 	    bname, link_name);
95910491SRishi.Srivatsavai@Sun.COM 
96010491SRishi.Srivatsavai@Sun.COM 	num = sizeof (sock_kstats_list) / sizeof (*sock_kstats_list);
96110491SRishi.Srivatsavai@Sun.COM 	for (i = 0; i < num; i++) {
96210491SRishi.Srivatsavai@Sun.COM 		knt = (kstat_named_t *)&(tsock->ts_kstats);
96310491SRishi.Srivatsavai@Sun.COM 		kstat_named_init(&knt[i], sock_kstats_list[i],
96410491SRishi.Srivatsavai@Sun.COM 		    KSTAT_DATA_UINT64);
96510491SRishi.Srivatsavai@Sun.COM 	}
96610491SRishi.Srivatsavai@Sun.COM 
96710491SRishi.Srivatsavai@Sun.COM 	tsock->ts_ksp = kstat_create_zone("trill", 0, kstatname, "sock",
96810491SRishi.Srivatsavai@Sun.COM 	    KSTAT_TYPE_NAMED, num, KSTAT_FLAG_VIRTUAL, GLOBAL_ZONEID);
96910491SRishi.Srivatsavai@Sun.COM 	if (tsock->ts_ksp != NULL) {
97010491SRishi.Srivatsavai@Sun.COM 		tsock->ts_ksp->ks_data = &tsock->ts_kstats;
97110491SRishi.Srivatsavai@Sun.COM 		kstat_install(tsock->ts_ksp);
97210491SRishi.Srivatsavai@Sun.COM 	}
97310491SRishi.Srivatsavai@Sun.COM }
97410491SRishi.Srivatsavai@Sun.COM 
97510491SRishi.Srivatsavai@Sun.COM static trill_sock_t *
trill_do_open(int flags)97610491SRishi.Srivatsavai@Sun.COM trill_do_open(int flags)
97710491SRishi.Srivatsavai@Sun.COM {
97810491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock;
97910491SRishi.Srivatsavai@Sun.COM 	int kmflag = ((flags & SOCKET_NOSLEEP)) ? KM_NOSLEEP:KM_SLEEP;
98010491SRishi.Srivatsavai@Sun.COM 
98110491SRishi.Srivatsavai@Sun.COM 	tsock = kmem_zalloc(sizeof (trill_sock_t), kmflag);
98210491SRishi.Srivatsavai@Sun.COM 	if (tsock != NULL) {
98310491SRishi.Srivatsavai@Sun.COM 		tsock->ts_state = TS_UNBND;
98410491SRishi.Srivatsavai@Sun.COM 		tsock->ts_refs++;
98510491SRishi.Srivatsavai@Sun.COM 		mutex_init(&tsock->ts_socklock, NULL, MUTEX_DRIVER, NULL);
98610491SRishi.Srivatsavai@Sun.COM 		cv_init(&tsock->ts_sockthreadwait, NULL, CV_DRIVER, NULL);
98710491SRishi.Srivatsavai@Sun.COM 		cv_init(&tsock->ts_sockclosewait, NULL, CV_DRIVER, NULL);
98810491SRishi.Srivatsavai@Sun.COM 	}
98910491SRishi.Srivatsavai@Sun.COM 	return (tsock);
99010491SRishi.Srivatsavai@Sun.COM }
99110491SRishi.Srivatsavai@Sun.COM 
99210491SRishi.Srivatsavai@Sun.COM static int
trill_find_bridge(trill_sock_t * tsock,const char * bname,boolean_t can_create)99310491SRishi.Srivatsavai@Sun.COM trill_find_bridge(trill_sock_t *tsock, const char *bname, boolean_t can_create)
99410491SRishi.Srivatsavai@Sun.COM {
99510491SRishi.Srivatsavai@Sun.COM 	trill_inst_t *tip, *newtip = NULL;
99610491SRishi.Srivatsavai@Sun.COM 
99710491SRishi.Srivatsavai@Sun.COM 	/* Allocate some memory (speculatively) before taking locks */
99810491SRishi.Srivatsavai@Sun.COM 	if (can_create)
99910491SRishi.Srivatsavai@Sun.COM 		newtip = kmem_zalloc(sizeof (*tip), KM_NOSLEEP);
100010491SRishi.Srivatsavai@Sun.COM 
100110491SRishi.Srivatsavai@Sun.COM 	rw_enter(&trill_inst_rwlock, RW_WRITER);
100210491SRishi.Srivatsavai@Sun.COM 	for (tip = list_head(&trill_inst_list); tip != NULL;
100310491SRishi.Srivatsavai@Sun.COM 	    tip = list_next(&trill_inst_list, tip)) {
100410491SRishi.Srivatsavai@Sun.COM 		if (strcmp(tip->ti_bridgename, bname) == 0)
100510491SRishi.Srivatsavai@Sun.COM 			break;
100610491SRishi.Srivatsavai@Sun.COM 	}
100710491SRishi.Srivatsavai@Sun.COM 	if (tip == NULL) {
100810491SRishi.Srivatsavai@Sun.COM 		if (!can_create || newtip == NULL) {
100910491SRishi.Srivatsavai@Sun.COM 			rw_exit(&trill_inst_rwlock);
101010491SRishi.Srivatsavai@Sun.COM 			return (can_create ? ENOMEM : ENOENT);
101110491SRishi.Srivatsavai@Sun.COM 		}
101210491SRishi.Srivatsavai@Sun.COM 
101310491SRishi.Srivatsavai@Sun.COM 		tip = newtip;
101410491SRishi.Srivatsavai@Sun.COM 		newtip = NULL;
101510491SRishi.Srivatsavai@Sun.COM 		(void) strcpy(tip->ti_bridgename, bname);
101610491SRishi.Srivatsavai@Sun.COM 
101710491SRishi.Srivatsavai@Sun.COM 		/* Register TRILL instance with bridging */
101810491SRishi.Srivatsavai@Sun.COM 		tip->ti_binst = bridge_trill_brref(bname, tip);
101910491SRishi.Srivatsavai@Sun.COM 		if (tip->ti_binst == NULL) {
102010491SRishi.Srivatsavai@Sun.COM 			rw_exit(&trill_inst_rwlock);
102110491SRishi.Srivatsavai@Sun.COM 			kmem_free(tip, sizeof (*tip));
102210491SRishi.Srivatsavai@Sun.COM 			return (ENOENT);
102310491SRishi.Srivatsavai@Sun.COM 		}
102410491SRishi.Srivatsavai@Sun.COM 
102510491SRishi.Srivatsavai@Sun.COM 		rw_init(&tip->ti_rwlock, NULL, RW_DRIVER, NULL);
102610491SRishi.Srivatsavai@Sun.COM 		list_create(&tip->ti_socklist, sizeof (trill_sock_t),
102710491SRishi.Srivatsavai@Sun.COM 		    offsetof(trill_sock_t, ts_socklistnode));
102810491SRishi.Srivatsavai@Sun.COM 		list_insert_tail(&trill_inst_list, tip);
102910491SRishi.Srivatsavai@Sun.COM 	}
103010491SRishi.Srivatsavai@Sun.COM 	atomic_inc_uint(&tip->ti_refs);
103110491SRishi.Srivatsavai@Sun.COM 	rw_exit(&trill_inst_rwlock);
103210491SRishi.Srivatsavai@Sun.COM 
103310491SRishi.Srivatsavai@Sun.COM 	/* If we didn't need the preallocated memory, then discard now. */
103410491SRishi.Srivatsavai@Sun.COM 	if (newtip != NULL)
103510491SRishi.Srivatsavai@Sun.COM 		kmem_free(newtip, sizeof (*newtip));
103610491SRishi.Srivatsavai@Sun.COM 
103710491SRishi.Srivatsavai@Sun.COM 	rw_enter(&tip->ti_rwlock, RW_WRITER);
103810491SRishi.Srivatsavai@Sun.COM 	list_insert_tail(&(tip->ti_socklist), tsock);
103910491SRishi.Srivatsavai@Sun.COM 	tsock->ts_tip = tip;
104010491SRishi.Srivatsavai@Sun.COM 	rw_exit(&tip->ti_rwlock);
104110491SRishi.Srivatsavai@Sun.COM 	return (0);
104210491SRishi.Srivatsavai@Sun.COM }
104310491SRishi.Srivatsavai@Sun.COM 
104410491SRishi.Srivatsavai@Sun.COM static void
trill_clear_bridge(trill_sock_t * tsock)104510491SRishi.Srivatsavai@Sun.COM trill_clear_bridge(trill_sock_t *tsock)
104610491SRishi.Srivatsavai@Sun.COM {
104710491SRishi.Srivatsavai@Sun.COM 	trill_inst_t *tip;
104810491SRishi.Srivatsavai@Sun.COM 
104910491SRishi.Srivatsavai@Sun.COM 	if ((tip = tsock->ts_tip) == NULL)
105010491SRishi.Srivatsavai@Sun.COM 		return;
105110491SRishi.Srivatsavai@Sun.COM 	rw_enter(&tip->ti_rwlock, RW_WRITER);
105210491SRishi.Srivatsavai@Sun.COM 	list_remove(&tip->ti_socklist, tsock);
105310491SRishi.Srivatsavai@Sun.COM 	if (list_is_empty(&tip->ti_socklist))
105410491SRishi.Srivatsavai@Sun.COM 		trill_del_all(tip, B_TRUE);
105510491SRishi.Srivatsavai@Sun.COM 	rw_exit(&tip->ti_rwlock);
105610491SRishi.Srivatsavai@Sun.COM }
105710491SRishi.Srivatsavai@Sun.COM 
105810491SRishi.Srivatsavai@Sun.COM static void
trill_sock_unref(trill_sock_t * tsock)105910491SRishi.Srivatsavai@Sun.COM trill_sock_unref(trill_sock_t *tsock)
106010491SRishi.Srivatsavai@Sun.COM {
106110491SRishi.Srivatsavai@Sun.COM 	if (atomic_dec_uint_nv(&tsock->ts_refs) == 0) {
106210491SRishi.Srivatsavai@Sun.COM 		mutex_destroy(&tsock->ts_socklock);
106310491SRishi.Srivatsavai@Sun.COM 		cv_destroy(&tsock->ts_sockthreadwait);
106410491SRishi.Srivatsavai@Sun.COM 		cv_destroy(&tsock->ts_sockclosewait);
106510491SRishi.Srivatsavai@Sun.COM 		kmem_free(tsock, sizeof (trill_sock_t));
106610491SRishi.Srivatsavai@Sun.COM 	}
106710491SRishi.Srivatsavai@Sun.COM }
106810491SRishi.Srivatsavai@Sun.COM 
106910491SRishi.Srivatsavai@Sun.COM static void
trill_do_close(trill_sock_t * tsock)107010491SRishi.Srivatsavai@Sun.COM trill_do_close(trill_sock_t *tsock)
107110491SRishi.Srivatsavai@Sun.COM {
107210491SRishi.Srivatsavai@Sun.COM 	trill_inst_t *tip;
107310491SRishi.Srivatsavai@Sun.COM 
107410491SRishi.Srivatsavai@Sun.COM 	tip = tsock->ts_tip;
107510491SRishi.Srivatsavai@Sun.COM 	trill_stop_recv(tsock);
107610491SRishi.Srivatsavai@Sun.COM 	/* Remove socket from TRILL instance socket list */
107710491SRishi.Srivatsavai@Sun.COM 	trill_clear_bridge(tsock);
107810491SRishi.Srivatsavai@Sun.COM 	tsock->ts_flags |= TSF_SHUTDOWN;
107910491SRishi.Srivatsavai@Sun.COM 	trill_sock_unref(tsock);
108010491SRishi.Srivatsavai@Sun.COM 	if (tip != NULL)
108110491SRishi.Srivatsavai@Sun.COM 		trill_instance_unref(tip);
108210491SRishi.Srivatsavai@Sun.COM }
108310491SRishi.Srivatsavai@Sun.COM 
108410491SRishi.Srivatsavai@Sun.COM static void
trill_del_all(trill_inst_t * tip,boolean_t lockheld)108510491SRishi.Srivatsavai@Sun.COM trill_del_all(trill_inst_t *tip, boolean_t lockheld)
108610491SRishi.Srivatsavai@Sun.COM {
108710491SRishi.Srivatsavai@Sun.COM 	int i;
108810491SRishi.Srivatsavai@Sun.COM 
108910491SRishi.Srivatsavai@Sun.COM 	if (!lockheld)
109010491SRishi.Srivatsavai@Sun.COM 		rw_enter(&tip->ti_rwlock, RW_WRITER);
109110491SRishi.Srivatsavai@Sun.COM 	for (i = RBRIDGE_NICKNAME_MIN; i < RBRIDGE_NICKNAME_MAX; i++) {
109210491SRishi.Srivatsavai@Sun.COM 		if (tip->ti_nodes[i] != NULL)
109310491SRishi.Srivatsavai@Sun.COM 			(void) trill_del_nick(tip, i, B_TRUE);
109410491SRishi.Srivatsavai@Sun.COM 	}
109510491SRishi.Srivatsavai@Sun.COM 	if (!lockheld)
109610491SRishi.Srivatsavai@Sun.COM 		rw_exit(&tip->ti_rwlock);
109710491SRishi.Srivatsavai@Sun.COM }
109810491SRishi.Srivatsavai@Sun.COM 
109910491SRishi.Srivatsavai@Sun.COM static void
trill_node_free(trill_node_t * nick_entry)110010491SRishi.Srivatsavai@Sun.COM trill_node_free(trill_node_t *nick_entry)
110110491SRishi.Srivatsavai@Sun.COM {
110210491SRishi.Srivatsavai@Sun.COM 	trill_nickinfo_t *tni;
110310491SRishi.Srivatsavai@Sun.COM 
110410491SRishi.Srivatsavai@Sun.COM 	tni = nick_entry->tn_ni;
110510491SRishi.Srivatsavai@Sun.COM 	kmem_free(tni, TNI_TOTALSIZE(tni));
110610491SRishi.Srivatsavai@Sun.COM 	kmem_free(nick_entry, sizeof (trill_node_t));
110710491SRishi.Srivatsavai@Sun.COM }
110810491SRishi.Srivatsavai@Sun.COM 
110910491SRishi.Srivatsavai@Sun.COM static void
trill_node_unref(trill_inst_t * tip,trill_node_t * tnp)111010491SRishi.Srivatsavai@Sun.COM trill_node_unref(trill_inst_t *tip, trill_node_t *tnp)
111110491SRishi.Srivatsavai@Sun.COM {
111210491SRishi.Srivatsavai@Sun.COM 	if (atomic_dec_uint_nv(&tnp->tn_refs) == 0) {
111310491SRishi.Srivatsavai@Sun.COM 		if (tnp->tn_tsp != NULL)
111410491SRishi.Srivatsavai@Sun.COM 			trill_sock_unref(tnp->tn_tsp);
111510491SRishi.Srivatsavai@Sun.COM 		trill_node_free(tnp);
111610491SRishi.Srivatsavai@Sun.COM 		(void) atomic_dec_uint_nv(&tip->ti_nodecount);
111710491SRishi.Srivatsavai@Sun.COM 	}
111810491SRishi.Srivatsavai@Sun.COM }
111910491SRishi.Srivatsavai@Sun.COM 
112010491SRishi.Srivatsavai@Sun.COM static trill_node_t *
trill_node_lookup(trill_inst_t * tip,uint16_t nick)112110491SRishi.Srivatsavai@Sun.COM trill_node_lookup(trill_inst_t *tip, uint16_t nick)
112210491SRishi.Srivatsavai@Sun.COM {
112310491SRishi.Srivatsavai@Sun.COM 	trill_node_t *nick_entry;
112410491SRishi.Srivatsavai@Sun.COM 
112510491SRishi.Srivatsavai@Sun.COM 	if (!VALID_NICK(nick))
112610491SRishi.Srivatsavai@Sun.COM 		return (NULL);
112710491SRishi.Srivatsavai@Sun.COM 	rw_enter(&tip->ti_rwlock, RW_READER);
112810491SRishi.Srivatsavai@Sun.COM 	nick_entry = tip->ti_nodes[nick];
112910491SRishi.Srivatsavai@Sun.COM 	if (nick_entry != NULL) {
113010491SRishi.Srivatsavai@Sun.COM 		atomic_inc_uint(&nick_entry->tn_refs);
113110491SRishi.Srivatsavai@Sun.COM 	}
113210491SRishi.Srivatsavai@Sun.COM 	rw_exit(&tip->ti_rwlock);
113310491SRishi.Srivatsavai@Sun.COM 	return (nick_entry);
113410491SRishi.Srivatsavai@Sun.COM }
113510491SRishi.Srivatsavai@Sun.COM 
113610491SRishi.Srivatsavai@Sun.COM static int
trill_del_nick(trill_inst_t * tip,uint16_t nick,boolean_t lockheld)113710491SRishi.Srivatsavai@Sun.COM trill_del_nick(trill_inst_t *tip, uint16_t nick, boolean_t lockheld)
113810491SRishi.Srivatsavai@Sun.COM {
113910491SRishi.Srivatsavai@Sun.COM 	trill_node_t *nick_entry;
114010491SRishi.Srivatsavai@Sun.COM 	int rc = ENOENT;
114110491SRishi.Srivatsavai@Sun.COM 
114210491SRishi.Srivatsavai@Sun.COM 	if (!lockheld)
114310491SRishi.Srivatsavai@Sun.COM 		rw_enter(&tip->ti_rwlock, RW_WRITER);
114410491SRishi.Srivatsavai@Sun.COM 	if (VALID_NICK(nick)) {
114510491SRishi.Srivatsavai@Sun.COM 		nick_entry = tip->ti_nodes[nick];
114610491SRishi.Srivatsavai@Sun.COM 		if (nick_entry != NULL) {
114710491SRishi.Srivatsavai@Sun.COM 			trill_node_unref(tip, nick_entry);
114810491SRishi.Srivatsavai@Sun.COM 			tip->ti_nodes[nick] = NULL;
114910491SRishi.Srivatsavai@Sun.COM 			rc = 0;
115010491SRishi.Srivatsavai@Sun.COM 		}
115110491SRishi.Srivatsavai@Sun.COM 	}
115210491SRishi.Srivatsavai@Sun.COM 	if (!lockheld)
115310491SRishi.Srivatsavai@Sun.COM 		rw_exit(&tip->ti_rwlock);
115410491SRishi.Srivatsavai@Sun.COM 	return (rc);
115510491SRishi.Srivatsavai@Sun.COM }
115610491SRishi.Srivatsavai@Sun.COM 
115710491SRishi.Srivatsavai@Sun.COM static int
trill_add_nick(trill_inst_t * tip,void * arg,boolean_t self,int mode)115810491SRishi.Srivatsavai@Sun.COM trill_add_nick(trill_inst_t *tip, void *arg, boolean_t self, int mode)
115910491SRishi.Srivatsavai@Sun.COM {
116010491SRishi.Srivatsavai@Sun.COM 	uint16_t nick;
116110491SRishi.Srivatsavai@Sun.COM 	int size;
116210491SRishi.Srivatsavai@Sun.COM 	trill_node_t *tnode;
116310491SRishi.Srivatsavai@Sun.COM 	trill_nickinfo_t tnihdr;
116410491SRishi.Srivatsavai@Sun.COM 
116510491SRishi.Srivatsavai@Sun.COM 	/* First make sure we have at least the header available */
116610491SRishi.Srivatsavai@Sun.COM 	if (ddi_copyin(arg, &tnihdr, sizeof (trill_nickinfo_t), mode) != 0)
116710491SRishi.Srivatsavai@Sun.COM 		return (EFAULT);
116810491SRishi.Srivatsavai@Sun.COM 
116910491SRishi.Srivatsavai@Sun.COM 	nick = tnihdr.tni_nick;
117010491SRishi.Srivatsavai@Sun.COM 	if (!VALID_NICK(nick)) {
117110491SRishi.Srivatsavai@Sun.COM 		DTRACE_PROBE1(trill__add__nick__bad, trill_nickinfo_t *,
117210491SRishi.Srivatsavai@Sun.COM 		    &tnihdr);
117310491SRishi.Srivatsavai@Sun.COM 		return (EINVAL);
117410491SRishi.Srivatsavai@Sun.COM 	}
117510491SRishi.Srivatsavai@Sun.COM 
117610491SRishi.Srivatsavai@Sun.COM 	size = TNI_TOTALSIZE(&tnihdr);
117710491SRishi.Srivatsavai@Sun.COM 	if (size > TNI_MAXSIZE)
117810491SRishi.Srivatsavai@Sun.COM 		return (EINVAL);
117910491SRishi.Srivatsavai@Sun.COM 	tnode = kmem_zalloc(sizeof (trill_node_t), KM_SLEEP);
118010491SRishi.Srivatsavai@Sun.COM 	tnode->tn_ni = kmem_zalloc(size, KM_SLEEP);
118110491SRishi.Srivatsavai@Sun.COM 	if (ddi_copyin(arg, tnode->tn_ni, size, mode) != 0) {
118210491SRishi.Srivatsavai@Sun.COM 		kmem_free(tnode->tn_ni, size);
118310491SRishi.Srivatsavai@Sun.COM 		kmem_free(tnode, sizeof (trill_node_t));
118410491SRishi.Srivatsavai@Sun.COM 		return (EFAULT);
118510491SRishi.Srivatsavai@Sun.COM 	}
118610491SRishi.Srivatsavai@Sun.COM 
118710491SRishi.Srivatsavai@Sun.COM 	tnode->tn_refs++;
118810491SRishi.Srivatsavai@Sun.COM 	rw_enter(&tip->ti_rwlock, RW_WRITER);
118910491SRishi.Srivatsavai@Sun.COM 	if (tip->ti_nodes[nick] != NULL)
119010491SRishi.Srivatsavai@Sun.COM 		(void) trill_del_nick(tip, nick, B_TRUE);
119110491SRishi.Srivatsavai@Sun.COM 
119210491SRishi.Srivatsavai@Sun.COM 	if (self) {
119310491SRishi.Srivatsavai@Sun.COM 		tip->ti_nick = nick;
119410491SRishi.Srivatsavai@Sun.COM 	} else {
119510491SRishi.Srivatsavai@Sun.COM 		tnode->tn_tsp = find_trill_link(tip,
119610491SRishi.Srivatsavai@Sun.COM 		    tnode->tn_ni->tni_linkid);
119710491SRishi.Srivatsavai@Sun.COM 	}
119810491SRishi.Srivatsavai@Sun.COM 	DTRACE_PROBE2(trill__add__nick, trill_node_t *, tnode,
119910491SRishi.Srivatsavai@Sun.COM 	    uint16_t, nick);
120010491SRishi.Srivatsavai@Sun.COM 	tip->ti_nodes[nick] = tnode;
120110491SRishi.Srivatsavai@Sun.COM 	tip->ti_nodecount++;
120210491SRishi.Srivatsavai@Sun.COM 	rw_exit(&tip->ti_rwlock);
120310491SRishi.Srivatsavai@Sun.COM 	return (0);
120410491SRishi.Srivatsavai@Sun.COM }
120510491SRishi.Srivatsavai@Sun.COM 
120610491SRishi.Srivatsavai@Sun.COM static int
trill_do_ioctl(trill_sock_t * tsock,int cmd,void * arg,int mode)120710491SRishi.Srivatsavai@Sun.COM trill_do_ioctl(trill_sock_t *tsock, int cmd, void *arg, int mode)
120810491SRishi.Srivatsavai@Sun.COM {
120910491SRishi.Srivatsavai@Sun.COM 	int error = 0;
121010491SRishi.Srivatsavai@Sun.COM 	trill_inst_t *tip = tsock->ts_tip;
121110491SRishi.Srivatsavai@Sun.COM 
121210491SRishi.Srivatsavai@Sun.COM 	switch (cmd) {
121310491SRishi.Srivatsavai@Sun.COM 	case TRILL_DESIGVLAN: {
121410491SRishi.Srivatsavai@Sun.COM 		uint16_t desigvlan;
121510491SRishi.Srivatsavai@Sun.COM 
121610491SRishi.Srivatsavai@Sun.COM 		if (ddi_copyin(arg, &desigvlan, sizeof (desigvlan), mode) != 0)
121710491SRishi.Srivatsavai@Sun.COM 			return (EFAULT);
121810491SRishi.Srivatsavai@Sun.COM 		tsock->ts_desigvlan = desigvlan;
121910491SRishi.Srivatsavai@Sun.COM 		break;
122010491SRishi.Srivatsavai@Sun.COM 	}
122110491SRishi.Srivatsavai@Sun.COM 	case TRILL_VLANFWDER: {
122210491SRishi.Srivatsavai@Sun.COM 		uint8_t vlans[TRILL_VLANS_ARRSIZE];
122310491SRishi.Srivatsavai@Sun.COM 
122410491SRishi.Srivatsavai@Sun.COM 		if (tsock->ts_link == NULL)
122510491SRishi.Srivatsavai@Sun.COM 			return (EINVAL);
122610491SRishi.Srivatsavai@Sun.COM 		if ((ddi_copyin(arg, vlans, sizeof (vlans), mode)) != 0)
122710491SRishi.Srivatsavai@Sun.COM 			return (EFAULT);
122810491SRishi.Srivatsavai@Sun.COM 		bridge_trill_setvlans(tsock->ts_link, vlans);
122910491SRishi.Srivatsavai@Sun.COM 		break;
123010491SRishi.Srivatsavai@Sun.COM 	}
123110491SRishi.Srivatsavai@Sun.COM 	case TRILL_SETNICK:
123210491SRishi.Srivatsavai@Sun.COM 		if (tip == NULL)
123310491SRishi.Srivatsavai@Sun.COM 			return (EINVAL);
123410491SRishi.Srivatsavai@Sun.COM 		error = trill_add_nick(tip, arg, B_TRUE, mode);
123510491SRishi.Srivatsavai@Sun.COM 		break;
123610491SRishi.Srivatsavai@Sun.COM 
123710491SRishi.Srivatsavai@Sun.COM 	case TRILL_GETNICK:
123810491SRishi.Srivatsavai@Sun.COM 		if (tip == NULL)
123910491SRishi.Srivatsavai@Sun.COM 			return (EINVAL);
124010491SRishi.Srivatsavai@Sun.COM 		rw_enter(&tip->ti_rwlock, RW_READER);
124110491SRishi.Srivatsavai@Sun.COM 		if (ddi_copyout(&tip->ti_nick, arg, sizeof (tip->ti_nick),
124210491SRishi.Srivatsavai@Sun.COM 		    mode) != 0)
124310491SRishi.Srivatsavai@Sun.COM 			error = EFAULT;
124410491SRishi.Srivatsavai@Sun.COM 		rw_exit(&tip->ti_rwlock);
124510491SRishi.Srivatsavai@Sun.COM 		break;
124610491SRishi.Srivatsavai@Sun.COM 
124710491SRishi.Srivatsavai@Sun.COM 	case TRILL_ADDNICK:
124810491SRishi.Srivatsavai@Sun.COM 		if (tip == NULL)
124910491SRishi.Srivatsavai@Sun.COM 			break;
125010491SRishi.Srivatsavai@Sun.COM 		error = trill_add_nick(tip, arg, B_FALSE, mode);
125110491SRishi.Srivatsavai@Sun.COM 		break;
125210491SRishi.Srivatsavai@Sun.COM 
125310491SRishi.Srivatsavai@Sun.COM 	case TRILL_DELNICK: {
125410491SRishi.Srivatsavai@Sun.COM 		uint16_t delnick;
125510491SRishi.Srivatsavai@Sun.COM 
125610491SRishi.Srivatsavai@Sun.COM 		if (tip == NULL)
125710491SRishi.Srivatsavai@Sun.COM 			break;
125810491SRishi.Srivatsavai@Sun.COM 		if (ddi_copyin(arg, &delnick, sizeof (delnick), mode) != 0)
125910491SRishi.Srivatsavai@Sun.COM 			return (EFAULT);
126010491SRishi.Srivatsavai@Sun.COM 		error = trill_del_nick(tip, delnick, B_FALSE);
126110491SRishi.Srivatsavai@Sun.COM 		break;
126210491SRishi.Srivatsavai@Sun.COM 	}
126310491SRishi.Srivatsavai@Sun.COM 	case TRILL_DELALL:
126410491SRishi.Srivatsavai@Sun.COM 		if (tip == NULL)
126510491SRishi.Srivatsavai@Sun.COM 			break;
126610491SRishi.Srivatsavai@Sun.COM 		trill_del_all(tip, B_FALSE);
126710491SRishi.Srivatsavai@Sun.COM 		break;
126810491SRishi.Srivatsavai@Sun.COM 
126910491SRishi.Srivatsavai@Sun.COM 	case TRILL_TREEROOT: {
127010491SRishi.Srivatsavai@Sun.COM 		uint16_t treeroot;
127110491SRishi.Srivatsavai@Sun.COM 
127210491SRishi.Srivatsavai@Sun.COM 		if (tip == NULL)
127310491SRishi.Srivatsavai@Sun.COM 			break;
127410491SRishi.Srivatsavai@Sun.COM 		if (ddi_copyin(arg, &treeroot, sizeof (treeroot), mode) != 0)
127510491SRishi.Srivatsavai@Sun.COM 			return (EFAULT);
127610491SRishi.Srivatsavai@Sun.COM 		if (!VALID_NICK(treeroot))
127710491SRishi.Srivatsavai@Sun.COM 			return (EINVAL);
127810491SRishi.Srivatsavai@Sun.COM 		rw_enter(&tip->ti_rwlock, RW_WRITER);
127910491SRishi.Srivatsavai@Sun.COM 		tip->ti_treeroot = treeroot;
128010491SRishi.Srivatsavai@Sun.COM 		rw_exit(&tip->ti_rwlock);
128110491SRishi.Srivatsavai@Sun.COM 		break;
128210491SRishi.Srivatsavai@Sun.COM 	}
128310491SRishi.Srivatsavai@Sun.COM 	case TRILL_HWADDR:
128410491SRishi.Srivatsavai@Sun.COM 		if (tsock->ts_link == NULL)
128510491SRishi.Srivatsavai@Sun.COM 			break;
128610491SRishi.Srivatsavai@Sun.COM 		if (ddi_copyout(tsock->ts_link->bl_local_mac, arg, ETHERADDRL,
128710491SRishi.Srivatsavai@Sun.COM 		    mode) != 0)
128810491SRishi.Srivatsavai@Sun.COM 			return (EFAULT);
128910491SRishi.Srivatsavai@Sun.COM 		break;
129010491SRishi.Srivatsavai@Sun.COM 
129110491SRishi.Srivatsavai@Sun.COM 	case TRILL_NEWBRIDGE: {
129210491SRishi.Srivatsavai@Sun.COM 		char bname[MAXLINKNAMELEN];
129310491SRishi.Srivatsavai@Sun.COM 
129410491SRishi.Srivatsavai@Sun.COM 		if (tsock->ts_state != TS_UNBND)
129510491SRishi.Srivatsavai@Sun.COM 			return (ENOTSUP);
129610491SRishi.Srivatsavai@Sun.COM 		/* ts_tip can only be set once */
129710491SRishi.Srivatsavai@Sun.COM 		if (tip != NULL)
129810491SRishi.Srivatsavai@Sun.COM 			return (EEXIST);
129910491SRishi.Srivatsavai@Sun.COM 		if (ddi_copyin(arg, bname, sizeof (bname), mode) != 0)
130010491SRishi.Srivatsavai@Sun.COM 			return (EFAULT);
130110491SRishi.Srivatsavai@Sun.COM 		bname[MAXLINKNAMELEN-1] = '\0';
130210491SRishi.Srivatsavai@Sun.COM 		error = trill_find_bridge(tsock, bname, B_TRUE);
130310491SRishi.Srivatsavai@Sun.COM 		break;
130410491SRishi.Srivatsavai@Sun.COM 	}
130510491SRishi.Srivatsavai@Sun.COM 
130610491SRishi.Srivatsavai@Sun.COM 	case TRILL_GETBRIDGE: {
130710491SRishi.Srivatsavai@Sun.COM 		char bname[MAXLINKNAMELEN];
130810491SRishi.Srivatsavai@Sun.COM 
130910491SRishi.Srivatsavai@Sun.COM 		/* ts_tip can only be set once */
131010491SRishi.Srivatsavai@Sun.COM 		if (tip != NULL)
131110491SRishi.Srivatsavai@Sun.COM 			return (EEXIST);
131210491SRishi.Srivatsavai@Sun.COM 		if (ddi_copyin(arg, bname, sizeof (bname), mode) != 0)
131310491SRishi.Srivatsavai@Sun.COM 			return (EFAULT);
131410491SRishi.Srivatsavai@Sun.COM 		bname[MAXLINKNAMELEN - 1] = '\0';
131510491SRishi.Srivatsavai@Sun.COM 		error = trill_find_bridge(tsock, bname, B_FALSE);
131610491SRishi.Srivatsavai@Sun.COM 		break;
131710491SRishi.Srivatsavai@Sun.COM 	}
131810491SRishi.Srivatsavai@Sun.COM 
131910491SRishi.Srivatsavai@Sun.COM 	case TRILL_LISTNICK: {
132010491SRishi.Srivatsavai@Sun.COM 		trill_listnick_t tln;
132110491SRishi.Srivatsavai@Sun.COM 		trill_node_t *tnp;
132210491SRishi.Srivatsavai@Sun.COM 		trill_nickinfo_t *tnip;
132310491SRishi.Srivatsavai@Sun.COM 		uint16_t nick;
132410491SRishi.Srivatsavai@Sun.COM 
132510491SRishi.Srivatsavai@Sun.COM 		if (tip == NULL)
132610491SRishi.Srivatsavai@Sun.COM 			return (EINVAL);
132710491SRishi.Srivatsavai@Sun.COM 		if (ddi_copyin(arg, &tln, sizeof (tln), mode) != 0)
132810491SRishi.Srivatsavai@Sun.COM 			return (EFAULT);
132910491SRishi.Srivatsavai@Sun.COM 		nick = tln.tln_nick;
133010491SRishi.Srivatsavai@Sun.COM 		if (nick >= RBRIDGE_NICKNAME_MAX) {
133110491SRishi.Srivatsavai@Sun.COM 			error = EINVAL;
133210491SRishi.Srivatsavai@Sun.COM 			break;
133310491SRishi.Srivatsavai@Sun.COM 		}
133410491SRishi.Srivatsavai@Sun.COM 		rw_enter(&tip->ti_rwlock, RW_READER);
133510491SRishi.Srivatsavai@Sun.COM 		while (++nick < RBRIDGE_NICKNAME_MAX) {
133610491SRishi.Srivatsavai@Sun.COM 			if ((tnp = tip->ti_nodes[nick]) != NULL) {
133710491SRishi.Srivatsavai@Sun.COM 				tnip = tnp->tn_ni;
133810491SRishi.Srivatsavai@Sun.COM 				ASSERT(nick == tnip->tni_nick);
133910491SRishi.Srivatsavai@Sun.COM 				tln.tln_nick = nick;
134010491SRishi.Srivatsavai@Sun.COM 				bcopy(tnip->tni_adjsnpa, tln.tln_nexthop,
134110491SRishi.Srivatsavai@Sun.COM 				    ETHERADDRL);
134210491SRishi.Srivatsavai@Sun.COM 				tln.tln_ours = nick == tip->ti_nick;
134310491SRishi.Srivatsavai@Sun.COM 				if (tln.tln_ours || tnp->tn_tsp == NULL) {
134410491SRishi.Srivatsavai@Sun.COM 					tln.tln_linkid =
134510491SRishi.Srivatsavai@Sun.COM 					    DATALINK_INVALID_LINKID;
134610491SRishi.Srivatsavai@Sun.COM 				} else {
134710491SRishi.Srivatsavai@Sun.COM 					tln.tln_linkid =
134810491SRishi.Srivatsavai@Sun.COM 					    tnp->tn_tsp->ts_link->bl_linkid;
134910491SRishi.Srivatsavai@Sun.COM 				}
135010491SRishi.Srivatsavai@Sun.COM 				break;
135110491SRishi.Srivatsavai@Sun.COM 			}
135210491SRishi.Srivatsavai@Sun.COM 		}
135310491SRishi.Srivatsavai@Sun.COM 		rw_exit(&tip->ti_rwlock);
135410491SRishi.Srivatsavai@Sun.COM 		if (nick >= RBRIDGE_NICKNAME_MAX)
135510491SRishi.Srivatsavai@Sun.COM 			bzero(&tln, sizeof (tln));
135610491SRishi.Srivatsavai@Sun.COM 		if (ddi_copyout(&tln, arg, sizeof (tln), mode) != 0)
135710491SRishi.Srivatsavai@Sun.COM 			return (EFAULT);
135810491SRishi.Srivatsavai@Sun.COM 		break;
135910491SRishi.Srivatsavai@Sun.COM 	}
136010491SRishi.Srivatsavai@Sun.COM 
136110491SRishi.Srivatsavai@Sun.COM 	/*
136210491SRishi.Srivatsavai@Sun.COM 	 * Port flush: this is used when we lose AF on a port.  We must discard
136310491SRishi.Srivatsavai@Sun.COM 	 * all regular bridge forwarding entries on this port with the
136410491SRishi.Srivatsavai@Sun.COM 	 * indicated VLAN.
136510491SRishi.Srivatsavai@Sun.COM 	 */
136610491SRishi.Srivatsavai@Sun.COM 	case TRILL_PORTFLUSH: {
136710491SRishi.Srivatsavai@Sun.COM 		uint16_t vlan = (uint16_t)(uintptr_t)arg;
136810491SRishi.Srivatsavai@Sun.COM 
136910491SRishi.Srivatsavai@Sun.COM 		if (tsock->ts_link == NULL)
137010491SRishi.Srivatsavai@Sun.COM 			return (EINVAL);
137110491SRishi.Srivatsavai@Sun.COM 		bridge_trill_flush(tsock->ts_link, vlan, B_FALSE);
137210491SRishi.Srivatsavai@Sun.COM 		break;
137310491SRishi.Srivatsavai@Sun.COM 	}
137410491SRishi.Srivatsavai@Sun.COM 
137510491SRishi.Srivatsavai@Sun.COM 	/*
137610491SRishi.Srivatsavai@Sun.COM 	 * Nick flush: this is used when we lose AF on a port.  We must discard
137710491SRishi.Srivatsavai@Sun.COM 	 * all bridge TRILL forwarding entries on this port with the indicated
137810491SRishi.Srivatsavai@Sun.COM 	 * VLAN.
137910491SRishi.Srivatsavai@Sun.COM 	 */
138010491SRishi.Srivatsavai@Sun.COM 	case TRILL_NICKFLUSH: {
138110491SRishi.Srivatsavai@Sun.COM 		uint16_t vlan = (uint16_t)(uintptr_t)arg;
138210491SRishi.Srivatsavai@Sun.COM 
138310491SRishi.Srivatsavai@Sun.COM 		if (tsock->ts_link == NULL)
138410491SRishi.Srivatsavai@Sun.COM 			return (EINVAL);
138510491SRishi.Srivatsavai@Sun.COM 		bridge_trill_flush(tsock->ts_link, vlan, B_TRUE);
138610491SRishi.Srivatsavai@Sun.COM 		break;
138710491SRishi.Srivatsavai@Sun.COM 	}
138810491SRishi.Srivatsavai@Sun.COM 
138910491SRishi.Srivatsavai@Sun.COM 	case TRILL_GETMTU:
139010491SRishi.Srivatsavai@Sun.COM 		if (tsock->ts_link == NULL)
139110491SRishi.Srivatsavai@Sun.COM 			break;
139210491SRishi.Srivatsavai@Sun.COM 		if (ddi_copyout(&tsock->ts_link->bl_maxsdu, arg,
139310491SRishi.Srivatsavai@Sun.COM 		    sizeof (uint_t), mode) != 0)
139410491SRishi.Srivatsavai@Sun.COM 			return (EFAULT);
139510491SRishi.Srivatsavai@Sun.COM 		break;
139610491SRishi.Srivatsavai@Sun.COM 
139710491SRishi.Srivatsavai@Sun.COM 	default:
139810491SRishi.Srivatsavai@Sun.COM 		error = ENOTSUP;
139910491SRishi.Srivatsavai@Sun.COM 		break;
140010491SRishi.Srivatsavai@Sun.COM 	}
140110491SRishi.Srivatsavai@Sun.COM 
140210491SRishi.Srivatsavai@Sun.COM 	return (error);
140310491SRishi.Srivatsavai@Sun.COM }
140410491SRishi.Srivatsavai@Sun.COM 
140510491SRishi.Srivatsavai@Sun.COM /*
140610491SRishi.Srivatsavai@Sun.COM  * Sends received packet back upstream on the TRILL socket.
140710491SRishi.Srivatsavai@Sun.COM  * Consumes passed mblk_t.
140810491SRishi.Srivatsavai@Sun.COM  */
140910491SRishi.Srivatsavai@Sun.COM static void
trill_ctrl_input(trill_sock_t * tsock,mblk_t * mp,const uint8_t * saddr,uint16_t tci)141010491SRishi.Srivatsavai@Sun.COM trill_ctrl_input(trill_sock_t *tsock, mblk_t *mp, const uint8_t *saddr,
141110491SRishi.Srivatsavai@Sun.COM     uint16_t tci)
141210491SRishi.Srivatsavai@Sun.COM {
141310491SRishi.Srivatsavai@Sun.COM 	int udi_size;
141410491SRishi.Srivatsavai@Sun.COM 	mblk_t *mp1;
141510491SRishi.Srivatsavai@Sun.COM 	struct T_unitdata_ind *tudi;
141610491SRishi.Srivatsavai@Sun.COM 	struct sockaddr_dl *sdl;
141710491SRishi.Srivatsavai@Sun.COM 	char *lladdr;
141810491SRishi.Srivatsavai@Sun.COM 	int error;
141910491SRishi.Srivatsavai@Sun.COM 
142010491SRishi.Srivatsavai@Sun.COM 	ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN));
142110491SRishi.Srivatsavai@Sun.COM 	if (tsock->ts_flow_ctrld) {
142210491SRishi.Srivatsavai@Sun.COM 		freemsg(mp);
142310491SRishi.Srivatsavai@Sun.COM 		KSPINCR(tks_drops);
142410491SRishi.Srivatsavai@Sun.COM 		return;
142510491SRishi.Srivatsavai@Sun.COM 	}
142610491SRishi.Srivatsavai@Sun.COM 
142710491SRishi.Srivatsavai@Sun.COM 	udi_size =  sizeof (struct T_unitdata_ind) +
142810491SRishi.Srivatsavai@Sun.COM 	    sizeof (struct sockaddr_dl);
142910491SRishi.Srivatsavai@Sun.COM 	mp1 = allocb(udi_size, BPRI_MED);
143010491SRishi.Srivatsavai@Sun.COM 	if (mp1 == NULL) {
143110491SRishi.Srivatsavai@Sun.COM 		freemsg(mp);
143210491SRishi.Srivatsavai@Sun.COM 		KSPINCR(tks_drops);
143310491SRishi.Srivatsavai@Sun.COM 		return;
143410491SRishi.Srivatsavai@Sun.COM 	}
143510491SRishi.Srivatsavai@Sun.COM 
143610491SRishi.Srivatsavai@Sun.COM 	mp1->b_cont = mp;
143710491SRishi.Srivatsavai@Sun.COM 	mp = mp1;
143810491SRishi.Srivatsavai@Sun.COM 	mp->b_datap->db_type = M_PROTO;
143910491SRishi.Srivatsavai@Sun.COM 	/* LINTED: alignment */
144010491SRishi.Srivatsavai@Sun.COM 	tudi = (struct T_unitdata_ind *)mp->b_rptr;
144110491SRishi.Srivatsavai@Sun.COM 	mp->b_wptr = (uchar_t *)tudi + udi_size;
144210491SRishi.Srivatsavai@Sun.COM 
144310491SRishi.Srivatsavai@Sun.COM 	tudi->PRIM_type = T_UNITDATA_IND;
144410491SRishi.Srivatsavai@Sun.COM 	tudi->SRC_length = sizeof (struct sockaddr_dl);
144510491SRishi.Srivatsavai@Sun.COM 	tudi->SRC_offset = sizeof (struct T_unitdata_ind);
144610491SRishi.Srivatsavai@Sun.COM 	tudi->OPT_length = 0;
144710491SRishi.Srivatsavai@Sun.COM 	tudi->OPT_offset = sizeof (struct T_unitdata_ind) +
144810491SRishi.Srivatsavai@Sun.COM 	    sizeof (struct sockaddr_dl);
144910491SRishi.Srivatsavai@Sun.COM 
145010491SRishi.Srivatsavai@Sun.COM 	/* Information of the link on which packet was received. */
145110491SRishi.Srivatsavai@Sun.COM 	sdl = (struct sockaddr_dl *)&tudi[1];
145210491SRishi.Srivatsavai@Sun.COM 	(void) memset(sdl, 0, sizeof (struct sockaddr_dl));
145310491SRishi.Srivatsavai@Sun.COM 	sdl->sdl_family = AF_TRILL;
145410491SRishi.Srivatsavai@Sun.COM 
145510491SRishi.Srivatsavai@Sun.COM 	/* LINTED: alignment */
145610491SRishi.Srivatsavai@Sun.COM 	*(datalink_id_t *)sdl->sdl_data = tsock->ts_link->bl_linkid;
145710491SRishi.Srivatsavai@Sun.COM 	sdl->sdl_nlen = sizeof (tsock->ts_link->bl_linkid);
145810491SRishi.Srivatsavai@Sun.COM 
145910491SRishi.Srivatsavai@Sun.COM 	lladdr = LLADDR(sdl);
146010491SRishi.Srivatsavai@Sun.COM 	(void) memcpy(lladdr, saddr, ETHERADDRL);
146110491SRishi.Srivatsavai@Sun.COM 	lladdr += ETHERADDRL;
146210491SRishi.Srivatsavai@Sun.COM 	sdl->sdl_alen = ETHERADDRL;
146310491SRishi.Srivatsavai@Sun.COM 
146410491SRishi.Srivatsavai@Sun.COM 	/* LINTED: alignment */
146510491SRishi.Srivatsavai@Sun.COM 	*(uint16_t *)lladdr = tci;
146610491SRishi.Srivatsavai@Sun.COM 	sdl->sdl_slen = sizeof (uint16_t);
146710491SRishi.Srivatsavai@Sun.COM 
146810491SRishi.Srivatsavai@Sun.COM 	DTRACE_PROBE2(trill__ctrl__input, trill_sock_t *, tsock, mblk_t *, mp);
146910491SRishi.Srivatsavai@Sun.COM 	(*tsock->ts_conn_upcalls->su_recv)(tsock->ts_conn_upper_handle,
147010491SRishi.Srivatsavai@Sun.COM 	    mp, msgdsize(mp), 0, &error, NULL);
147110491SRishi.Srivatsavai@Sun.COM 
147210491SRishi.Srivatsavai@Sun.COM 	if (error == ENOSPC) {
147310491SRishi.Srivatsavai@Sun.COM 		mutex_enter(&tsock->ts_socklock);
147410491SRishi.Srivatsavai@Sun.COM 		(*tsock->ts_conn_upcalls->su_recv)(tsock->ts_conn_upper_handle,
147510491SRishi.Srivatsavai@Sun.COM 		    NULL, 0, 0, &error, NULL);
147610491SRishi.Srivatsavai@Sun.COM 		if (error == ENOSPC)
147710491SRishi.Srivatsavai@Sun.COM 			tsock->ts_flow_ctrld = B_TRUE;
147810491SRishi.Srivatsavai@Sun.COM 		mutex_exit(&tsock->ts_socklock);
147910491SRishi.Srivatsavai@Sun.COM 		KSPINCR(tks_drops);
148010491SRishi.Srivatsavai@Sun.COM 	} else if (error != 0) {
148110491SRishi.Srivatsavai@Sun.COM 		KSPINCR(tks_drops);
148210491SRishi.Srivatsavai@Sun.COM 	} else {
148310491SRishi.Srivatsavai@Sun.COM 		KSPINCR(tks_recv);
148410491SRishi.Srivatsavai@Sun.COM 	}
148510491SRishi.Srivatsavai@Sun.COM 
148610491SRishi.Srivatsavai@Sun.COM 	DTRACE_PROBE2(trill__ctrl__input__done, trill_sock_t *,
148710491SRishi.Srivatsavai@Sun.COM 	    tsock, int, error);
148810491SRishi.Srivatsavai@Sun.COM }
148910491SRishi.Srivatsavai@Sun.COM 
149010491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */
149110491SRishi.Srivatsavai@Sun.COM 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)149210491SRishi.Srivatsavai@Sun.COM trill_activate(sock_lower_handle_t proto_handle,
149310491SRishi.Srivatsavai@Sun.COM     sock_upper_handle_t sock_handle, sock_upcalls_t *sock_upcalls,
149410491SRishi.Srivatsavai@Sun.COM     int flags, cred_t *cr)
149510491SRishi.Srivatsavai@Sun.COM {
149610491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
149710491SRishi.Srivatsavai@Sun.COM 	struct sock_proto_props sopp;
149810491SRishi.Srivatsavai@Sun.COM 
149910491SRishi.Srivatsavai@Sun.COM 	tsock->ts_conn_upcalls = sock_upcalls;
150010491SRishi.Srivatsavai@Sun.COM 	tsock->ts_conn_upper_handle = sock_handle;
150110491SRishi.Srivatsavai@Sun.COM 
150210491SRishi.Srivatsavai@Sun.COM 	sopp.sopp_flags = SOCKOPT_WROFF | SOCKOPT_RCVHIWAT |
150310491SRishi.Srivatsavai@Sun.COM 	    SOCKOPT_RCVLOWAT | SOCKOPT_MAXADDRLEN | SOCKOPT_MAXPSZ |
150410491SRishi.Srivatsavai@Sun.COM 	    SOCKOPT_MAXBLK | SOCKOPT_MINPSZ;
150510491SRishi.Srivatsavai@Sun.COM 	sopp.sopp_wroff = 0;
150610491SRishi.Srivatsavai@Sun.COM 	sopp.sopp_rxhiwat = SOCKET_RECVHIWATER;
150710491SRishi.Srivatsavai@Sun.COM 	sopp.sopp_rxlowat = SOCKET_RECVLOWATER;
150810491SRishi.Srivatsavai@Sun.COM 	sopp.sopp_maxaddrlen = sizeof (struct sockaddr_dl);
150910491SRishi.Srivatsavai@Sun.COM 	sopp.sopp_maxpsz = INFPSZ;
151010491SRishi.Srivatsavai@Sun.COM 	sopp.sopp_maxblk = INFPSZ;
151110491SRishi.Srivatsavai@Sun.COM 	sopp.sopp_minpsz = 0;
151210491SRishi.Srivatsavai@Sun.COM 	(*tsock->ts_conn_upcalls->su_set_proto_props)(
151310491SRishi.Srivatsavai@Sun.COM 	    tsock->ts_conn_upper_handle, &sopp);
151410491SRishi.Srivatsavai@Sun.COM }
151510491SRishi.Srivatsavai@Sun.COM 
151610491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */
151710491SRishi.Srivatsavai@Sun.COM static int
trill_close(sock_lower_handle_t proto_handle,int flags,cred_t * cr)151810491SRishi.Srivatsavai@Sun.COM trill_close(sock_lower_handle_t proto_handle, int flags, cred_t *cr)
151910491SRishi.Srivatsavai@Sun.COM {
152010491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
152110491SRishi.Srivatsavai@Sun.COM 
152210491SRishi.Srivatsavai@Sun.COM 	trill_do_close(tsock);
152310491SRishi.Srivatsavai@Sun.COM 	return (0);
152410491SRishi.Srivatsavai@Sun.COM }
152510491SRishi.Srivatsavai@Sun.COM 
152610491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */
152710491SRishi.Srivatsavai@Sun.COM static int
trill_bind(sock_lower_handle_t proto_handle,struct sockaddr * sa,socklen_t len,cred_t * cr)152810491SRishi.Srivatsavai@Sun.COM trill_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa,
152910491SRishi.Srivatsavai@Sun.COM     socklen_t len, cred_t *cr)
153010491SRishi.Srivatsavai@Sun.COM {
153110491SRishi.Srivatsavai@Sun.COM 	int error;
153210491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
153310491SRishi.Srivatsavai@Sun.COM 
153410491SRishi.Srivatsavai@Sun.COM 	if (sa == NULL)
153510491SRishi.Srivatsavai@Sun.COM 		error = trill_do_unbind(tsock);
153610491SRishi.Srivatsavai@Sun.COM 	else
153710491SRishi.Srivatsavai@Sun.COM 		error = trill_start_recv(tsock, sa, len);
153810491SRishi.Srivatsavai@Sun.COM 
153910491SRishi.Srivatsavai@Sun.COM 	return (error);
154010491SRishi.Srivatsavai@Sun.COM }
154110491SRishi.Srivatsavai@Sun.COM 
154210491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */
154310491SRishi.Srivatsavai@Sun.COM static int
trill_send(sock_lower_handle_t proto_handle,mblk_t * mp,struct nmsghdr * msg,cred_t * cr)154410491SRishi.Srivatsavai@Sun.COM trill_send(sock_lower_handle_t proto_handle, mblk_t *mp, struct nmsghdr *msg,
154510491SRishi.Srivatsavai@Sun.COM     cred_t *cr)
154610491SRishi.Srivatsavai@Sun.COM {
154710491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
154810491SRishi.Srivatsavai@Sun.COM 	struct sockaddr_dl *laddr;
154910491SRishi.Srivatsavai@Sun.COM 	uint16_t tci;
155010491SRishi.Srivatsavai@Sun.COM 
155110491SRishi.Srivatsavai@Sun.COM 	ASSERT(DB_TYPE(mp) == M_DATA);
155210491SRishi.Srivatsavai@Sun.COM 	ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN));
155310491SRishi.Srivatsavai@Sun.COM 
155410491SRishi.Srivatsavai@Sun.COM 	if (msg->msg_name == NULL || msg->msg_namelen != sizeof (*laddr))
155510491SRishi.Srivatsavai@Sun.COM 		goto eproto;
155610491SRishi.Srivatsavai@Sun.COM 
155710491SRishi.Srivatsavai@Sun.COM 	/*
155810491SRishi.Srivatsavai@Sun.COM 	 * The name is a datalink_id_t, the address is an Ethernet address, and
155910491SRishi.Srivatsavai@Sun.COM 	 * the selector value is the VLAN ID.
156010491SRishi.Srivatsavai@Sun.COM 	 */
156110491SRishi.Srivatsavai@Sun.COM 	laddr = (struct sockaddr_dl *)msg->msg_name;
156210491SRishi.Srivatsavai@Sun.COM 	if (laddr->sdl_nlen != sizeof (datalink_id_t) ||
156310491SRishi.Srivatsavai@Sun.COM 	    laddr->sdl_alen != ETHERADDRL ||
156410491SRishi.Srivatsavai@Sun.COM 	    (laddr->sdl_slen != sizeof (tci) && laddr->sdl_slen != 0))
156510491SRishi.Srivatsavai@Sun.COM 		goto eproto;
156610491SRishi.Srivatsavai@Sun.COM 
156710491SRishi.Srivatsavai@Sun.COM 	mutex_enter(&tsock->ts_socklock);
156810491SRishi.Srivatsavai@Sun.COM 	if (tsock->ts_state != TS_IDLE || tsock->ts_link == NULL) {
156910491SRishi.Srivatsavai@Sun.COM 		mutex_exit(&tsock->ts_socklock);
157010491SRishi.Srivatsavai@Sun.COM 		goto eproto;
157110491SRishi.Srivatsavai@Sun.COM 	}
157210491SRishi.Srivatsavai@Sun.COM 	atomic_inc_uint(&tsock->ts_sockthreadcount);
157310491SRishi.Srivatsavai@Sun.COM 	mutex_exit(&tsock->ts_socklock);
157410491SRishi.Srivatsavai@Sun.COM 
157510491SRishi.Srivatsavai@Sun.COM 	/*
157610491SRishi.Srivatsavai@Sun.COM 	 * Safe to dereference VLAN now, as we've checked the user's specified
157710491SRishi.Srivatsavai@Sun.COM 	 * values, and alignment is now guaranteed.
157810491SRishi.Srivatsavai@Sun.COM 	 */
157910491SRishi.Srivatsavai@Sun.COM 	if (laddr->sdl_slen == 0) {
158010491SRishi.Srivatsavai@Sun.COM 		tci = TRILL_NO_TCI;
158110491SRishi.Srivatsavai@Sun.COM 	} else {
158210491SRishi.Srivatsavai@Sun.COM 		/* LINTED: alignment */
158310491SRishi.Srivatsavai@Sun.COM 		tci = *(uint16_t *)(LLADDR(laddr) + ETHERADDRL);
158410491SRishi.Srivatsavai@Sun.COM 	}
158510491SRishi.Srivatsavai@Sun.COM 
158610491SRishi.Srivatsavai@Sun.COM 	mp = create_trill_header(tsock, mp, (const uchar_t *)LLADDR(laddr),
158710491SRishi.Srivatsavai@Sun.COM 	    B_TRUE, B_FALSE, tci, msgdsize(mp));
158810491SRishi.Srivatsavai@Sun.COM 	if (mp != NULL) {
158910491SRishi.Srivatsavai@Sun.COM 		mp = bridge_trill_output(tsock->ts_link, mp);
159010491SRishi.Srivatsavai@Sun.COM 		if (mp == NULL) {
159110491SRishi.Srivatsavai@Sun.COM 			KSPINCR(tks_sent);
159210491SRishi.Srivatsavai@Sun.COM 		} else {
159310491SRishi.Srivatsavai@Sun.COM 			freemsg(mp);
159410491SRishi.Srivatsavai@Sun.COM 			KSPINCR(tks_drops);
159510491SRishi.Srivatsavai@Sun.COM 		}
159610491SRishi.Srivatsavai@Sun.COM 	}
159710491SRishi.Srivatsavai@Sun.COM 
159810491SRishi.Srivatsavai@Sun.COM 	/* Wake up any threads blocking on us */
159910491SRishi.Srivatsavai@Sun.COM 	if (atomic_dec_uint_nv(&tsock->ts_sockthreadcount) == 0)
160010491SRishi.Srivatsavai@Sun.COM 		cv_broadcast(&tsock->ts_sockthreadwait);
160110491SRishi.Srivatsavai@Sun.COM 	return (0);
160210491SRishi.Srivatsavai@Sun.COM 
160310491SRishi.Srivatsavai@Sun.COM eproto:
160410491SRishi.Srivatsavai@Sun.COM 	freemsg(mp);
160510491SRishi.Srivatsavai@Sun.COM 	KSPINCR(tks_drops);
160610491SRishi.Srivatsavai@Sun.COM 	return (EPROTO);
160710491SRishi.Srivatsavai@Sun.COM }
160810491SRishi.Srivatsavai@Sun.COM 
160910491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */
161010491SRishi.Srivatsavai@Sun.COM static int
trill_ioctl(sock_lower_handle_t proto_handle,int cmd,intptr_t arg,int mode,int32_t * rvalp,cred_t * cr)161110491SRishi.Srivatsavai@Sun.COM trill_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg,
161210491SRishi.Srivatsavai@Sun.COM     int mode, int32_t *rvalp, cred_t *cr)
161310491SRishi.Srivatsavai@Sun.COM {
161410491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
161510491SRishi.Srivatsavai@Sun.COM 	int rc;
161610491SRishi.Srivatsavai@Sun.COM 
161710491SRishi.Srivatsavai@Sun.COM 	switch (cmd) {
161810491SRishi.Srivatsavai@Sun.COM 	/* List of unprivileged TRILL ioctls */
161910491SRishi.Srivatsavai@Sun.COM 	case TRILL_GETNICK:
162010491SRishi.Srivatsavai@Sun.COM 	case TRILL_GETBRIDGE:
162110491SRishi.Srivatsavai@Sun.COM 	case TRILL_LISTNICK:
162210491SRishi.Srivatsavai@Sun.COM 		break;
162310491SRishi.Srivatsavai@Sun.COM 	default:
162410491SRishi.Srivatsavai@Sun.COM 		if (secpolicy_dl_config(cr) != 0)
162510491SRishi.Srivatsavai@Sun.COM 			return (EPERM);
162610491SRishi.Srivatsavai@Sun.COM 		break;
162710491SRishi.Srivatsavai@Sun.COM 	}
162810491SRishi.Srivatsavai@Sun.COM 
162910491SRishi.Srivatsavai@Sun.COM 	/* Lock ensures socket state is unchanged during ioctl handling */
163010491SRishi.Srivatsavai@Sun.COM 	mutex_enter(&tsock->ts_socklock);
163110491SRishi.Srivatsavai@Sun.COM 	rc = trill_do_ioctl(tsock, cmd, (void *)arg, mode);
163210491SRishi.Srivatsavai@Sun.COM 	mutex_exit(&tsock->ts_socklock);
163310491SRishi.Srivatsavai@Sun.COM 	return (rc);
163410491SRishi.Srivatsavai@Sun.COM }
163510491SRishi.Srivatsavai@Sun.COM 
163610491SRishi.Srivatsavai@Sun.COM static void
trill_clr_flowctrl(sock_lower_handle_t proto_handle)163710491SRishi.Srivatsavai@Sun.COM trill_clr_flowctrl(sock_lower_handle_t proto_handle)
163810491SRishi.Srivatsavai@Sun.COM {
163910491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
164010491SRishi.Srivatsavai@Sun.COM 
164110491SRishi.Srivatsavai@Sun.COM 	mutex_enter(&tsock->ts_socklock);
164210491SRishi.Srivatsavai@Sun.COM 	tsock->ts_flow_ctrld = B_FALSE;
164310491SRishi.Srivatsavai@Sun.COM 	mutex_exit(&tsock->ts_socklock);
164410491SRishi.Srivatsavai@Sun.COM }
164510491SRishi.Srivatsavai@Sun.COM 
164610491SRishi.Srivatsavai@Sun.COM static sock_downcalls_t sock_trill_downcalls = {
1647*11483SRishi.Srivatsavai@Sun.COM 	trill_activate,			/* sd_activate */
1648*11483SRishi.Srivatsavai@Sun.COM 	sock_accept_notsupp,		/* sd_accept */
1649*11483SRishi.Srivatsavai@Sun.COM 	trill_bind,			/* sd_bind */
1650*11483SRishi.Srivatsavai@Sun.COM 	sock_listen_notsupp,		/* sd_listen */
1651*11483SRishi.Srivatsavai@Sun.COM 	sock_connect_notsupp,		/* sd_connect */
1652*11483SRishi.Srivatsavai@Sun.COM 	sock_getpeername_notsupp,	/* sd_getpeername */
1653*11483SRishi.Srivatsavai@Sun.COM 	sock_getsockname_notsupp,	/* sd_getsockname */
1654*11483SRishi.Srivatsavai@Sun.COM 	sock_getsockopt_notsupp,	/* sd_getsockopt */
1655*11483SRishi.Srivatsavai@Sun.COM 	sock_setsockopt_notsupp,	/* sd_setsockopt */
1656*11483SRishi.Srivatsavai@Sun.COM 	trill_send,			/* sd_send */
1657*11483SRishi.Srivatsavai@Sun.COM 	NULL,				/* sd_send_uio */
1658*11483SRishi.Srivatsavai@Sun.COM 	NULL,				/* sd_recv_uio */
1659*11483SRishi.Srivatsavai@Sun.COM 	NULL,				/* sd_poll */
1660*11483SRishi.Srivatsavai@Sun.COM 	sock_shutdown_notsupp,		/* sd_shutdown */
1661*11483SRishi.Srivatsavai@Sun.COM 	trill_clr_flowctrl,		/* sd_setflowctrl */
1662*11483SRishi.Srivatsavai@Sun.COM 	trill_ioctl,			/* sd_ioctl */
1663*11483SRishi.Srivatsavai@Sun.COM 	trill_close			/* sd_close */
166410491SRishi.Srivatsavai@Sun.COM };
166510491SRishi.Srivatsavai@Sun.COM 
166610491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */
166710491SRishi.Srivatsavai@Sun.COM 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)166810491SRishi.Srivatsavai@Sun.COM trill_create(int family, int type, int proto, sock_downcalls_t **sock_downcalls,
166910491SRishi.Srivatsavai@Sun.COM     uint_t *smodep, int *errorp, int flags, cred_t *credp)
167010491SRishi.Srivatsavai@Sun.COM {
167110491SRishi.Srivatsavai@Sun.COM 	trill_sock_t *tsock;
167210491SRishi.Srivatsavai@Sun.COM 
167310491SRishi.Srivatsavai@Sun.COM 	if (family != AF_TRILL || type != SOCK_DGRAM || proto != 0) {
167410491SRishi.Srivatsavai@Sun.COM 		*errorp = EPROTONOSUPPORT;
167510491SRishi.Srivatsavai@Sun.COM 		return (NULL);
167610491SRishi.Srivatsavai@Sun.COM 	}
167710491SRishi.Srivatsavai@Sun.COM 
167810491SRishi.Srivatsavai@Sun.COM 	*sock_downcalls = &sock_trill_downcalls;
167910491SRishi.Srivatsavai@Sun.COM 	*smodep = SM_ATOMIC;
168010491SRishi.Srivatsavai@Sun.COM 	tsock = trill_do_open(flags);
168110491SRishi.Srivatsavai@Sun.COM 	*errorp = (tsock != NULL) ? 0:ENOMEM;
168210491SRishi.Srivatsavai@Sun.COM 	return ((sock_lower_handle_t)tsock);
168310491SRishi.Srivatsavai@Sun.COM }
1684