xref: /titanic_54/usr/src/uts/common/io/trill.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
1*4eaa4710SRishi Srivatsavai /*
2*4eaa4710SRishi Srivatsavai  * CDDL HEADER START
3*4eaa4710SRishi Srivatsavai  *
4*4eaa4710SRishi Srivatsavai  * The contents of this file are subject to the terms of the
5*4eaa4710SRishi Srivatsavai  * Common Development and Distribution License (the "License").
6*4eaa4710SRishi Srivatsavai  * You may not use this file except in compliance with the License.
7*4eaa4710SRishi Srivatsavai  *
8*4eaa4710SRishi Srivatsavai  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4eaa4710SRishi Srivatsavai  * or http://www.opensolaris.org/os/licensing.
10*4eaa4710SRishi Srivatsavai  * See the License for the specific language governing permissions
11*4eaa4710SRishi Srivatsavai  * and limitations under the License.
12*4eaa4710SRishi Srivatsavai  *
13*4eaa4710SRishi Srivatsavai  * When distributing Covered Code, include this CDDL HEADER in each
14*4eaa4710SRishi Srivatsavai  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4eaa4710SRishi Srivatsavai  * If applicable, add the following below this CDDL HEADER, with the
16*4eaa4710SRishi Srivatsavai  * fields enclosed by brackets "[]" replaced with your own identifying
17*4eaa4710SRishi Srivatsavai  * information: Portions Copyright [yyyy] [name of copyright owner]
18*4eaa4710SRishi Srivatsavai  *
19*4eaa4710SRishi Srivatsavai  * CDDL HEADER END
20*4eaa4710SRishi Srivatsavai  */
21*4eaa4710SRishi Srivatsavai 
22*4eaa4710SRishi Srivatsavai /*
23*4eaa4710SRishi Srivatsavai  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*4eaa4710SRishi Srivatsavai  * Use is subject to license terms.
25*4eaa4710SRishi Srivatsavai  */
26*4eaa4710SRishi Srivatsavai 
27*4eaa4710SRishi Srivatsavai /*
28*4eaa4710SRishi Srivatsavai  *  This module supports AF_TRILL sockets and TRILL layer-2 forwarding.
29*4eaa4710SRishi Srivatsavai  */
30*4eaa4710SRishi Srivatsavai 
31*4eaa4710SRishi Srivatsavai #include <sys/strsubr.h>
32*4eaa4710SRishi Srivatsavai #include <sys/socket.h>
33*4eaa4710SRishi Srivatsavai #include <sys/socketvar.h>
34*4eaa4710SRishi Srivatsavai #include <sys/modctl.h>
35*4eaa4710SRishi Srivatsavai #include <sys/cmn_err.h>
36*4eaa4710SRishi Srivatsavai #include <sys/tihdr.h>
37*4eaa4710SRishi Srivatsavai #include <sys/strsun.h>
38*4eaa4710SRishi Srivatsavai #include <sys/policy.h>
39*4eaa4710SRishi Srivatsavai #include <sys/ethernet.h>
40*4eaa4710SRishi Srivatsavai #include <sys/vlan.h>
41*4eaa4710SRishi Srivatsavai #include <net/trill.h>
42*4eaa4710SRishi Srivatsavai #include <net/if_dl.h>
43*4eaa4710SRishi Srivatsavai #include <sys/mac.h>
44*4eaa4710SRishi Srivatsavai #include <sys/mac_client.h>
45*4eaa4710SRishi Srivatsavai #include <sys/mac_provider.h>
46*4eaa4710SRishi Srivatsavai #include <sys/mac_client_priv.h>
47*4eaa4710SRishi Srivatsavai #include <sys/sdt.h>
48*4eaa4710SRishi Srivatsavai #include <sys/dls.h>
49*4eaa4710SRishi Srivatsavai #include <sys/sunddi.h>
50*4eaa4710SRishi Srivatsavai 
51*4eaa4710SRishi Srivatsavai #include "trill_impl.h"
52*4eaa4710SRishi Srivatsavai 
53*4eaa4710SRishi Srivatsavai static void trill_del_all(trill_inst_t *, boolean_t);
54*4eaa4710SRishi Srivatsavai static int trill_del_nick(trill_inst_t *, uint16_t, boolean_t);
55*4eaa4710SRishi Srivatsavai static void trill_stop_recv(trill_sock_t *);
56*4eaa4710SRishi Srivatsavai static void trill_ctrl_input(trill_sock_t *, mblk_t *, const uint8_t *,
57*4eaa4710SRishi Srivatsavai     uint16_t);
58*4eaa4710SRishi Srivatsavai static trill_node_t *trill_node_lookup(trill_inst_t *, uint16_t);
59*4eaa4710SRishi Srivatsavai static void trill_node_unref(trill_inst_t *, trill_node_t *);
60*4eaa4710SRishi Srivatsavai static void trill_sock_unref(trill_sock_t *);
61*4eaa4710SRishi Srivatsavai static void trill_kstats_init(trill_sock_t *, const char *);
62*4eaa4710SRishi Srivatsavai 
63*4eaa4710SRishi Srivatsavai static list_t trill_inst_list;
64*4eaa4710SRishi Srivatsavai static krwlock_t trill_inst_rwlock;
65*4eaa4710SRishi Srivatsavai 
66*4eaa4710SRishi Srivatsavai static sock_lower_handle_t trill_create(int, int, int, sock_downcalls_t **,
67*4eaa4710SRishi Srivatsavai     uint_t *, int *, int, cred_t *);
68*4eaa4710SRishi Srivatsavai 
69*4eaa4710SRishi Srivatsavai static smod_reg_t sinfo = {
70*4eaa4710SRishi Srivatsavai 	SOCKMOD_VERSION,
71*4eaa4710SRishi Srivatsavai 	"trill",
72*4eaa4710SRishi Srivatsavai 	SOCK_UC_VERSION,
73*4eaa4710SRishi Srivatsavai 	SOCK_DC_VERSION,
74*4eaa4710SRishi Srivatsavai 	trill_create,
75*4eaa4710SRishi Srivatsavai 	NULL,
76*4eaa4710SRishi Srivatsavai };
77*4eaa4710SRishi Srivatsavai 
78*4eaa4710SRishi Srivatsavai /* modldrv structure */
79*4eaa4710SRishi Srivatsavai static struct modlsockmod sockmod = {
80*4eaa4710SRishi Srivatsavai 	&mod_sockmodops, "AF_TRILL socket module", &sinfo
81*4eaa4710SRishi Srivatsavai };
82*4eaa4710SRishi Srivatsavai 
83*4eaa4710SRishi Srivatsavai /* modlinkage structure */
84*4eaa4710SRishi Srivatsavai static struct modlinkage ml = {
85*4eaa4710SRishi Srivatsavai 	MODREV_1,
86*4eaa4710SRishi Srivatsavai 	&sockmod,
87*4eaa4710SRishi Srivatsavai 	NULL
88*4eaa4710SRishi Srivatsavai };
89*4eaa4710SRishi Srivatsavai 
90*4eaa4710SRishi Srivatsavai #define	VALID_NICK(n)	((n) != RBRIDGE_NICKNAME_NONE && \
91*4eaa4710SRishi Srivatsavai 			(n) != RBRIDGE_NICKNAME_UNUSED)
92*4eaa4710SRishi Srivatsavai 
93*4eaa4710SRishi Srivatsavai static mblk_t *
94*4eaa4710SRishi Srivatsavai create_trill_header(trill_sock_t *tsock, mblk_t *mp, const uint8_t *daddr,
95*4eaa4710SRishi Srivatsavai     boolean_t trill_hdr_ok, boolean_t multidest, uint16_t tci,
96*4eaa4710SRishi Srivatsavai     size_t msglen)
97*4eaa4710SRishi Srivatsavai {
98*4eaa4710SRishi Srivatsavai 	int extra_hdr_len;
99*4eaa4710SRishi Srivatsavai 	struct ether_vlan_header *ethvlanhdr;
100*4eaa4710SRishi Srivatsavai 	mblk_t *hdr_mp;
101*4eaa4710SRishi Srivatsavai 	uint16_t etype;
102*4eaa4710SRishi Srivatsavai 
103*4eaa4710SRishi Srivatsavai 	etype = msglen > 0 ? (uint16_t)msglen : ETHERTYPE_TRILL;
104*4eaa4710SRishi Srivatsavai 
105*4eaa4710SRishi Srivatsavai 	/* When sending on the PVID, we must not give a VLAN ID */
106*4eaa4710SRishi Srivatsavai 	if (tci == tsock->ts_link->bl_pvid)
107*4eaa4710SRishi Srivatsavai 		tci = TRILL_NO_TCI;
108*4eaa4710SRishi Srivatsavai 
109*4eaa4710SRishi Srivatsavai 	/*
110*4eaa4710SRishi Srivatsavai 	 * Create new Ethernet header and include additional space
111*4eaa4710SRishi Srivatsavai 	 * for writing TRILL header and/or VLAN tag.
112*4eaa4710SRishi Srivatsavai 	 */
113*4eaa4710SRishi Srivatsavai 	extra_hdr_len = (trill_hdr_ok ? 0 : sizeof (trill_header_t)) +
114*4eaa4710SRishi Srivatsavai 	    (tci != TRILL_NO_TCI ? sizeof (struct ether_vlan_extinfo) : 0);
115*4eaa4710SRishi Srivatsavai 	hdr_mp = mac_header(tsock->ts_link->bl_mh, daddr,
116*4eaa4710SRishi Srivatsavai 	    tci != TRILL_NO_TCI ? ETHERTYPE_VLAN : etype, mp, extra_hdr_len);
117*4eaa4710SRishi Srivatsavai 	if (hdr_mp == NULL) {
118*4eaa4710SRishi Srivatsavai 		freemsg(mp);
119*4eaa4710SRishi Srivatsavai 		return (NULL);
120*4eaa4710SRishi Srivatsavai 	}
121*4eaa4710SRishi Srivatsavai 
122*4eaa4710SRishi Srivatsavai 	if (tci != TRILL_NO_TCI) {
123*4eaa4710SRishi Srivatsavai 		/* LINTED: alignment */
124*4eaa4710SRishi Srivatsavai 		ethvlanhdr = (struct ether_vlan_header *)hdr_mp->b_rptr;
125*4eaa4710SRishi Srivatsavai 		ethvlanhdr->ether_tci = htons(tci);
126*4eaa4710SRishi Srivatsavai 		ethvlanhdr->ether_type = htons(etype);
127*4eaa4710SRishi Srivatsavai 		hdr_mp->b_wptr += sizeof (struct ether_vlan_extinfo);
128*4eaa4710SRishi Srivatsavai 	}
129*4eaa4710SRishi Srivatsavai 
130*4eaa4710SRishi Srivatsavai 	if (!trill_hdr_ok) {
131*4eaa4710SRishi Srivatsavai 		trill_header_t *thp;
132*4eaa4710SRishi Srivatsavai 		/* LINTED: alignment */
133*4eaa4710SRishi Srivatsavai 		thp = (trill_header_t *)hdr_mp->b_wptr;
134*4eaa4710SRishi Srivatsavai 		(void) memset(thp, 0, sizeof (trill_header_t));
135*4eaa4710SRishi Srivatsavai 		thp->th_hopcount = TRILL_DEFAULT_HOPS;
136*4eaa4710SRishi Srivatsavai 		thp->th_multidest = (multidest ? 1:0);
137*4eaa4710SRishi Srivatsavai 		hdr_mp->b_wptr += sizeof (trill_header_t);
138*4eaa4710SRishi Srivatsavai 	}
139*4eaa4710SRishi Srivatsavai 
140*4eaa4710SRishi Srivatsavai 	hdr_mp->b_cont = mp;
141*4eaa4710SRishi Srivatsavai 	return (hdr_mp);
142*4eaa4710SRishi Srivatsavai }
143*4eaa4710SRishi Srivatsavai 
144*4eaa4710SRishi Srivatsavai /*
145*4eaa4710SRishi Srivatsavai  * TRILL local recv function. TRILL data frames that should be received
146*4eaa4710SRishi Srivatsavai  * by the local system are decapsulated here and passed to bridging for
147*4eaa4710SRishi Srivatsavai  * learning and local system receive. Only called when we are the forwarder
148*4eaa4710SRishi Srivatsavai  * on the link (multi-dest frames) or the frame was destined for us.
149*4eaa4710SRishi Srivatsavai  */
150*4eaa4710SRishi Srivatsavai static void
151*4eaa4710SRishi Srivatsavai trill_recv_local(trill_sock_t *tsock, mblk_t *mp, uint16_t ingressnick)
152*4eaa4710SRishi Srivatsavai {
153*4eaa4710SRishi Srivatsavai 	struct ether_header *inner_ethhdr;
154*4eaa4710SRishi Srivatsavai 
155*4eaa4710SRishi Srivatsavai 	/* LINTED: alignment */
156*4eaa4710SRishi Srivatsavai 	inner_ethhdr = (struct ether_header *)mp->b_rptr;
157*4eaa4710SRishi Srivatsavai 	DTRACE_PROBE1(trill__recv__local, struct ether_header *, inner_ethhdr);
158*4eaa4710SRishi Srivatsavai 
159*4eaa4710SRishi Srivatsavai 	DB_CKSUMFLAGS(mp) = 0;
160*4eaa4710SRishi Srivatsavai 	/*
161*4eaa4710SRishi Srivatsavai 	 * Transmit the decapsulated frame on the link via Bridging.
162*4eaa4710SRishi Srivatsavai 	 * Bridging does source address learning and appropriate forwarding.
163*4eaa4710SRishi Srivatsavai 	 */
164*4eaa4710SRishi Srivatsavai 	bridge_trill_decaps(tsock->ts_link, mp, ingressnick);
165*4eaa4710SRishi Srivatsavai 	KSPINCR(tks_decap);
166*4eaa4710SRishi Srivatsavai }
167*4eaa4710SRishi Srivatsavai 
168*4eaa4710SRishi Srivatsavai /*
169*4eaa4710SRishi Srivatsavai  * Determines the outgoing link to reach a RBridge having the given nick
170*4eaa4710SRishi Srivatsavai  * Assumes caller has acquired the trill instance rwlock.
171*4eaa4710SRishi Srivatsavai  */
172*4eaa4710SRishi Srivatsavai static trill_sock_t *
173*4eaa4710SRishi Srivatsavai find_trill_link(trill_inst_t *tip, datalink_id_t linkid)
174*4eaa4710SRishi Srivatsavai {
175*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsp = NULL;
176*4eaa4710SRishi Srivatsavai 
177*4eaa4710SRishi Srivatsavai 	ASSERT(RW_LOCK_HELD(&tip->ti_rwlock));
178*4eaa4710SRishi Srivatsavai 	for (tsp = list_head(&tip->ti_socklist); tsp != NULL;
179*4eaa4710SRishi Srivatsavai 	    tsp = list_next(&tip->ti_socklist, tsp)) {
180*4eaa4710SRishi Srivatsavai 		if (tsp->ts_link != NULL && tsp->ts_link->bl_linkid == linkid) {
181*4eaa4710SRishi Srivatsavai 			ASSERT(tsp->ts_link->bl_mh != NULL);
182*4eaa4710SRishi Srivatsavai 			ASSERT(!(tsp->ts_flags & TSF_SHUTDOWN));
183*4eaa4710SRishi Srivatsavai 			atomic_inc_uint(&tsp->ts_refs);
184*4eaa4710SRishi Srivatsavai 			break;
185*4eaa4710SRishi Srivatsavai 		}
186*4eaa4710SRishi Srivatsavai 	}
187*4eaa4710SRishi Srivatsavai 	return (tsp);
188*4eaa4710SRishi Srivatsavai }
189*4eaa4710SRishi Srivatsavai 
190*4eaa4710SRishi Srivatsavai /*
191*4eaa4710SRishi Srivatsavai  * TRILL destination forwarding function. Transmits the TRILL data packet
192*4eaa4710SRishi Srivatsavai  * to the next-hop, adjacent RBridge.  Consumes passed mblk_t.
193*4eaa4710SRishi Srivatsavai  */
194*4eaa4710SRishi Srivatsavai static void
195*4eaa4710SRishi Srivatsavai trill_dest_fwd(trill_inst_t *tip, mblk_t *fwd_mp, uint16_t adj_nick,
196*4eaa4710SRishi Srivatsavai     boolean_t has_trill_hdr, boolean_t multidest, uint16_t dtnick)
197*4eaa4710SRishi Srivatsavai {
198*4eaa4710SRishi Srivatsavai 	trill_node_t *adj;
199*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock = NULL;
200*4eaa4710SRishi Srivatsavai 	trill_header_t *trillhdr;
201*4eaa4710SRishi Srivatsavai 	struct ether_header *ethhdr;
202*4eaa4710SRishi Srivatsavai 	int ethtype;
203*4eaa4710SRishi Srivatsavai 	int ethhdrlen;
204*4eaa4710SRishi Srivatsavai 
205*4eaa4710SRishi Srivatsavai 	adj = trill_node_lookup(tip, adj_nick);
206*4eaa4710SRishi Srivatsavai 	if (adj == NULL || ((tsock = adj->tn_tsp) == NULL))
207*4eaa4710SRishi Srivatsavai 		goto dest_fwd_fail;
208*4eaa4710SRishi Srivatsavai 
209*4eaa4710SRishi Srivatsavai 	ASSERT(tsock->ts_link != NULL);
210*4eaa4710SRishi Srivatsavai 	ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN));
211*4eaa4710SRishi Srivatsavai 	ASSERT(adj->tn_ni != NULL);
212*4eaa4710SRishi Srivatsavai 
213*4eaa4710SRishi Srivatsavai 	DTRACE_PROBE3(trill__dest__fwd, uint16_t, adj_nick, trill_node_t,
214*4eaa4710SRishi Srivatsavai 	    adj, trill_sock_t, tsock);
215*4eaa4710SRishi Srivatsavai 
216*4eaa4710SRishi Srivatsavai 	/*
217*4eaa4710SRishi Srivatsavai 	 * For broadcast links by using the dest address of
218*4eaa4710SRishi Srivatsavai 	 * the RBridge to forward the frame should result in
219*4eaa4710SRishi Srivatsavai 	 * savings. When the link is a bridged LAN or there are
220*4eaa4710SRishi Srivatsavai 	 * many end stations the frame will not always be flooded.
221*4eaa4710SRishi Srivatsavai 	 */
222*4eaa4710SRishi Srivatsavai 	fwd_mp = create_trill_header(tsock, fwd_mp, adj->tn_ni->tni_adjsnpa,
223*4eaa4710SRishi Srivatsavai 	    has_trill_hdr, multidest, tsock->ts_desigvlan, 0);
224*4eaa4710SRishi Srivatsavai 	if (fwd_mp == NULL)
225*4eaa4710SRishi Srivatsavai 		goto dest_fwd_fail;
226*4eaa4710SRishi Srivatsavai 
227*4eaa4710SRishi Srivatsavai 	/* LINTED: alignment */
228*4eaa4710SRishi Srivatsavai 	ethhdr = (struct ether_header *)fwd_mp->b_rptr;
229*4eaa4710SRishi Srivatsavai 	ethtype = ntohs(ethhdr->ether_type);
230*4eaa4710SRishi Srivatsavai 	ASSERT(ethtype == ETHERTYPE_VLAN || ethtype == ETHERTYPE_TRILL);
231*4eaa4710SRishi Srivatsavai 
232*4eaa4710SRishi Srivatsavai 	/* Pullup Ethernet and TRILL header (w/o TRILL options) */
233*4eaa4710SRishi Srivatsavai 	ethhdrlen = sizeof (struct ether_header) +
234*4eaa4710SRishi Srivatsavai 	    (ethtype == ETHERTYPE_VLAN ? sizeof (struct ether_vlan_extinfo):0);
235*4eaa4710SRishi Srivatsavai 	if (!pullupmsg(fwd_mp, ethhdrlen + sizeof (trill_header_t)))
236*4eaa4710SRishi Srivatsavai 		goto dest_fwd_fail;
237*4eaa4710SRishi Srivatsavai 	/* LINTED: alignment */
238*4eaa4710SRishi Srivatsavai 	trillhdr = (struct trill_header *)(fwd_mp->b_rptr + ethhdrlen);
239*4eaa4710SRishi Srivatsavai 
240*4eaa4710SRishi Srivatsavai 	/* Update TRILL header with ingress and egress nicks for new frames */
241*4eaa4710SRishi Srivatsavai 	if (!has_trill_hdr) {
242*4eaa4710SRishi Srivatsavai 		/* We are creating a new TRILL frame */
243*4eaa4710SRishi Srivatsavai 		trillhdr->th_egressnick = (multidest ? dtnick:adj_nick);
244*4eaa4710SRishi Srivatsavai 		rw_enter(&tip->ti_rwlock, RW_READER);
245*4eaa4710SRishi Srivatsavai 		trillhdr->th_ingressnick = tip->ti_nick;
246*4eaa4710SRishi Srivatsavai 		rw_exit(&tip->ti_rwlock);
247*4eaa4710SRishi Srivatsavai 		if (!VALID_NICK(trillhdr->th_ingressnick))
248*4eaa4710SRishi Srivatsavai 			goto dest_fwd_fail;
249*4eaa4710SRishi Srivatsavai 	}
250*4eaa4710SRishi Srivatsavai 
251*4eaa4710SRishi Srivatsavai 	/* Set hop count and update header in packet */
252*4eaa4710SRishi Srivatsavai 	ASSERT(trillhdr->th_hopcount != 0);
253*4eaa4710SRishi Srivatsavai 	trillhdr->th_hopcount--;
254*4eaa4710SRishi Srivatsavai 
255*4eaa4710SRishi Srivatsavai 	/* Clear checksum flag and transmit frame on the link */
256*4eaa4710SRishi Srivatsavai 	DB_CKSUMFLAGS(fwd_mp) = 0;
257*4eaa4710SRishi Srivatsavai 	DTRACE_PROBE1(trill__dest__fwd__tx, trill_header_t *, &trillhdr);
258*4eaa4710SRishi Srivatsavai 	fwd_mp = bridge_trill_output(tsock->ts_link, fwd_mp);
259*4eaa4710SRishi Srivatsavai 	if (fwd_mp == NULL) {
260*4eaa4710SRishi Srivatsavai 		KSPINCR(tks_sent);
261*4eaa4710SRishi Srivatsavai 		KSPINCR(tks_forward);
262*4eaa4710SRishi Srivatsavai 	} else {
263*4eaa4710SRishi Srivatsavai 		freemsg(fwd_mp);
264*4eaa4710SRishi Srivatsavai 		KSPINCR(tks_drops);
265*4eaa4710SRishi Srivatsavai 	}
266*4eaa4710SRishi Srivatsavai 	trill_node_unref(tip, adj);
267*4eaa4710SRishi Srivatsavai 	return;
268*4eaa4710SRishi Srivatsavai 
269*4eaa4710SRishi Srivatsavai dest_fwd_fail:
270*4eaa4710SRishi Srivatsavai 	if (adj != NULL)
271*4eaa4710SRishi Srivatsavai 		trill_node_unref(tip, adj);
272*4eaa4710SRishi Srivatsavai 	if (tsock != NULL)
273*4eaa4710SRishi Srivatsavai 		KSPINCR(tks_drops);
274*4eaa4710SRishi Srivatsavai 	freemsg(fwd_mp);
275*4eaa4710SRishi Srivatsavai }
276*4eaa4710SRishi Srivatsavai 
277*4eaa4710SRishi Srivatsavai /*
278*4eaa4710SRishi Srivatsavai  * TRILL multi-destination forwarding. Transmits the packet to the adjacencies
279*4eaa4710SRishi Srivatsavai  * on the distribution tree determined by the egress nick. Source addr (saddr)
280*4eaa4710SRishi Srivatsavai  * is NULL for new TRILL packets originating from us.
281*4eaa4710SRishi Srivatsavai  */
282*4eaa4710SRishi Srivatsavai static void
283*4eaa4710SRishi Srivatsavai trill_multidest_fwd(trill_inst_t *tip, mblk_t *mp, uint16_t egressnick,
284*4eaa4710SRishi Srivatsavai     uint16_t ingressnick, boolean_t is_trill_pkt, const uint8_t *saddr,
285*4eaa4710SRishi Srivatsavai     int inner_vlan, boolean_t free_mblk)
286*4eaa4710SRishi Srivatsavai {
287*4eaa4710SRishi Srivatsavai 	int idx;
288*4eaa4710SRishi Srivatsavai 	uint16_t adjnick;
289*4eaa4710SRishi Srivatsavai 	trill_node_t *dest;
290*4eaa4710SRishi Srivatsavai 	trill_node_t *adj;
291*4eaa4710SRishi Srivatsavai 	mblk_t *fwd_mp;
292*4eaa4710SRishi Srivatsavai 	boolean_t nicksaved = B_FALSE;
293*4eaa4710SRishi Srivatsavai 	uint16_t adjnicksaved;
294*4eaa4710SRishi Srivatsavai 
295*4eaa4710SRishi Srivatsavai 	/* Lookup the egress nick info, this is the DT root */
296*4eaa4710SRishi Srivatsavai 	if ((dest = trill_node_lookup(tip, egressnick)) == NULL)
297*4eaa4710SRishi Srivatsavai 		goto fail_multidest_fwd;
298*4eaa4710SRishi Srivatsavai 
299*4eaa4710SRishi Srivatsavai 	/* Send a copy to all our adjacencies on the DT root  */
300*4eaa4710SRishi Srivatsavai 	ASSERT(dest->tn_ni);
301*4eaa4710SRishi Srivatsavai 	for (idx = 0; idx < dest->tn_ni->tni_adjcount; idx++) {
302*4eaa4710SRishi Srivatsavai 
303*4eaa4710SRishi Srivatsavai 		/* Check for a valid adjacency node */
304*4eaa4710SRishi Srivatsavai 		adjnick = TNI_ADJNICK(dest->tn_ni, idx);
305*4eaa4710SRishi Srivatsavai 		if (!VALID_NICK(adjnick) || ingressnick == adjnick ||
306*4eaa4710SRishi Srivatsavai 		    ((adj = trill_node_lookup(tip, adjnick)) == NULL))
307*4eaa4710SRishi Srivatsavai 			continue;
308*4eaa4710SRishi Srivatsavai 
309*4eaa4710SRishi Srivatsavai 		/* Do not forward back to adjacency that sent the pkt to us */
310*4eaa4710SRishi Srivatsavai 		ASSERT(adj->tn_ni != NULL);
311*4eaa4710SRishi Srivatsavai 		if ((saddr != NULL) &&
312*4eaa4710SRishi Srivatsavai 		    (memcmp(adj->tn_ni->tni_adjsnpa, saddr,
313*4eaa4710SRishi Srivatsavai 		    ETHERADDRL) == 0)) {
314*4eaa4710SRishi Srivatsavai 			trill_node_unref(tip, adj);
315*4eaa4710SRishi Srivatsavai 			continue;
316*4eaa4710SRishi Srivatsavai 		}
317*4eaa4710SRishi Srivatsavai 
318*4eaa4710SRishi Srivatsavai 		/* Check if adj is marked as reaching inner VLAN downstream */
319*4eaa4710SRishi Srivatsavai 		if ((inner_vlan != VLAN_ID_NONE) &&
320*4eaa4710SRishi Srivatsavai 		    !TRILL_VLANISSET(TNI_VLANFILTERMAP(dest->tn_ni, idx),
321*4eaa4710SRishi Srivatsavai 		    inner_vlan)) {
322*4eaa4710SRishi Srivatsavai 			trill_node_unref(tip, adj);
323*4eaa4710SRishi Srivatsavai 			DTRACE_PROBE4(trill__multi__dest__fwd__vlanfiltered,
324*4eaa4710SRishi Srivatsavai 			    uint16_t, adjnick, uint16_t, ingressnick,
325*4eaa4710SRishi Srivatsavai 			    uint16_t, egressnick, int, inner_vlan);
326*4eaa4710SRishi Srivatsavai 			continue;
327*4eaa4710SRishi Srivatsavai 		}
328*4eaa4710SRishi Srivatsavai 
329*4eaa4710SRishi Srivatsavai 		trill_node_unref(tip, adj);
330*4eaa4710SRishi Srivatsavai 
331*4eaa4710SRishi Srivatsavai 		/*
332*4eaa4710SRishi Srivatsavai 		 * Save the nick and look ahead to see if we should forward the
333*4eaa4710SRishi Srivatsavai 		 * frame to more adjacencies. We avoid doing a copy for this
334*4eaa4710SRishi Srivatsavai 		 * nick and use the passed mblk when we can consume the passed
335*4eaa4710SRishi Srivatsavai 		 * mblk.
336*4eaa4710SRishi Srivatsavai 		 */
337*4eaa4710SRishi Srivatsavai 		if (free_mblk && !nicksaved) {
338*4eaa4710SRishi Srivatsavai 			adjnicksaved = adjnick;
339*4eaa4710SRishi Srivatsavai 			nicksaved = B_TRUE;
340*4eaa4710SRishi Srivatsavai 			continue;
341*4eaa4710SRishi Srivatsavai 		}
342*4eaa4710SRishi Srivatsavai 
343*4eaa4710SRishi Srivatsavai 		fwd_mp = copymsg(mp);
344*4eaa4710SRishi Srivatsavai 		if (fwd_mp == NULL)
345*4eaa4710SRishi Srivatsavai 			break;
346*4eaa4710SRishi Srivatsavai 		DTRACE_PROBE2(trill__multi__dest__fwd, uint16_t,
347*4eaa4710SRishi Srivatsavai 		    adjnick, uint16_t, ingressnick);
348*4eaa4710SRishi Srivatsavai 		trill_dest_fwd(tip, fwd_mp, adjnick, is_trill_pkt,
349*4eaa4710SRishi Srivatsavai 		    B_TRUE, egressnick);
350*4eaa4710SRishi Srivatsavai 	}
351*4eaa4710SRishi Srivatsavai 	trill_node_unref(tip, dest);
352*4eaa4710SRishi Srivatsavai 
353*4eaa4710SRishi Srivatsavai 	if (nicksaved) {
354*4eaa4710SRishi Srivatsavai 		ASSERT(free_mblk);
355*4eaa4710SRishi Srivatsavai 		DTRACE_PROBE2(trill__multi__dest__fwd, uint16_t,
356*4eaa4710SRishi Srivatsavai 		    adjnicksaved, uint16_t, ingressnick);
357*4eaa4710SRishi Srivatsavai 		trill_dest_fwd(tip, mp, adjnicksaved, is_trill_pkt,
358*4eaa4710SRishi Srivatsavai 		    B_TRUE, egressnick);
359*4eaa4710SRishi Srivatsavai 		return;
360*4eaa4710SRishi Srivatsavai 	}
361*4eaa4710SRishi Srivatsavai 
362*4eaa4710SRishi Srivatsavai fail_multidest_fwd:
363*4eaa4710SRishi Srivatsavai 	DTRACE_PROBE2(trill__multi__dest__fwd__fail, uint16_t,
364*4eaa4710SRishi Srivatsavai 	    egressnick, uint16_t, ingressnick);
365*4eaa4710SRishi Srivatsavai 	if (free_mblk) {
366*4eaa4710SRishi Srivatsavai 		freemsg(mp);
367*4eaa4710SRishi Srivatsavai 	}
368*4eaa4710SRishi Srivatsavai }
369*4eaa4710SRishi Srivatsavai 
370*4eaa4710SRishi Srivatsavai /*
371*4eaa4710SRishi Srivatsavai  * TRILL data receive function. Forwards the received frame if necessary
372*4eaa4710SRishi Srivatsavai  * and also determines if the received frame should be consumed locally.
373*4eaa4710SRishi Srivatsavai  * Consumes passed mblk.
374*4eaa4710SRishi Srivatsavai  */
375*4eaa4710SRishi Srivatsavai static void
376*4eaa4710SRishi Srivatsavai trill_recv(trill_sock_t *tsock, mblk_t *mp, const uint8_t *mpsaddr)
377*4eaa4710SRishi Srivatsavai {
378*4eaa4710SRishi Srivatsavai 	trill_header_t *trillhdr;
379*4eaa4710SRishi Srivatsavai 	trill_node_t *dest = NULL;
380*4eaa4710SRishi Srivatsavai 	trill_node_t *source = NULL;
381*4eaa4710SRishi Srivatsavai 	trill_node_t *adj;
382*4eaa4710SRishi Srivatsavai 	uint16_t ournick, adjnick, treeroot;
383*4eaa4710SRishi Srivatsavai 	struct ether_header *ethhdr;
384*4eaa4710SRishi Srivatsavai 	trill_inst_t *tip = tsock->ts_tip;
385*4eaa4710SRishi Srivatsavai 	uint8_t srcaddr[ETHERADDRL];
386*4eaa4710SRishi Srivatsavai 	size_t trillhdrlen;
387*4eaa4710SRishi Srivatsavai 	int inner_vlan = VLAN_ID_NONE;
388*4eaa4710SRishi Srivatsavai 	int tci;
389*4eaa4710SRishi Srivatsavai 	int idx;
390*4eaa4710SRishi Srivatsavai 	size_t min_size;
391*4eaa4710SRishi Srivatsavai 
392*4eaa4710SRishi Srivatsavai 	/* Copy Ethernet source address before modifying packet */
393*4eaa4710SRishi Srivatsavai 	(void) memcpy(srcaddr, mpsaddr, ETHERADDRL);
394*4eaa4710SRishi Srivatsavai 
395*4eaa4710SRishi Srivatsavai 	/* Pull up TRILL header if necessary. */
396*4eaa4710SRishi Srivatsavai 	min_size = sizeof (trill_header_t);
397*4eaa4710SRishi Srivatsavai 	if ((MBLKL(mp) < min_size ||
398*4eaa4710SRishi Srivatsavai 	    !IS_P2ALIGNED(mp->b_rptr, TRILL_HDR_ALIGN)) &&
399*4eaa4710SRishi Srivatsavai 	    !pullupmsg(mp, min_size))
400*4eaa4710SRishi Srivatsavai 		goto fail;
401*4eaa4710SRishi Srivatsavai 
402*4eaa4710SRishi Srivatsavai 	/* LINTED: alignment */
403*4eaa4710SRishi Srivatsavai 	trillhdr = (trill_header_t *)mp->b_rptr;
404*4eaa4710SRishi Srivatsavai 	if (trillhdr->th_version != TRILL_PROTOCOL_VERS) {
405*4eaa4710SRishi Srivatsavai 		DTRACE_PROBE1(trill__recv__wrongversion,
406*4eaa4710SRishi Srivatsavai 		    trill_header_t *, trillhdr);
407*4eaa4710SRishi Srivatsavai 		goto fail;
408*4eaa4710SRishi Srivatsavai 	}
409*4eaa4710SRishi Srivatsavai 
410*4eaa4710SRishi Srivatsavai 	/* Drop if unknown or invalid nickname */
411*4eaa4710SRishi Srivatsavai 	if (!VALID_NICK(trillhdr->th_egressnick) ||
412*4eaa4710SRishi Srivatsavai 	    !VALID_NICK(trillhdr->th_ingressnick)) {
413*4eaa4710SRishi Srivatsavai 		DTRACE_PROBE1(trill__recv__invalidnick,
414*4eaa4710SRishi Srivatsavai 		    trill_header_t *, trillhdr);
415*4eaa4710SRishi Srivatsavai 		goto fail;
416*4eaa4710SRishi Srivatsavai 	}
417*4eaa4710SRishi Srivatsavai 
418*4eaa4710SRishi Srivatsavai 	rw_enter(&tip->ti_rwlock, RW_READER);
419*4eaa4710SRishi Srivatsavai 	ournick = tip->ti_nick;
420*4eaa4710SRishi Srivatsavai 	treeroot = tip->ti_treeroot;
421*4eaa4710SRishi Srivatsavai 	rw_exit(&tip->ti_rwlock);
422*4eaa4710SRishi Srivatsavai 	/* Drop if we received a packet with our nick as ingress */
423*4eaa4710SRishi Srivatsavai 	if (trillhdr->th_ingressnick == ournick)
424*4eaa4710SRishi Srivatsavai 		goto fail;
425*4eaa4710SRishi Srivatsavai 
426*4eaa4710SRishi Srivatsavai 	/* Re-pull any TRILL options and inner Ethernet header */
427*4eaa4710SRishi Srivatsavai 	min_size += GET_TRILL_OPTS_LEN(trillhdr) * sizeof (uint32_t) +
428*4eaa4710SRishi Srivatsavai 	    sizeof (struct ether_header);
429*4eaa4710SRishi Srivatsavai 	if (MBLKL(mp) < min_size) {
430*4eaa4710SRishi Srivatsavai 		if (!pullupmsg(mp, min_size))
431*4eaa4710SRishi Srivatsavai 			goto fail;
432*4eaa4710SRishi Srivatsavai 		/* LINTED: alignment */
433*4eaa4710SRishi Srivatsavai 		trillhdr = (trill_header_t *)mp->b_rptr;
434*4eaa4710SRishi Srivatsavai 	}
435*4eaa4710SRishi Srivatsavai 	trillhdrlen = sizeof (trill_header_t) +
436*4eaa4710SRishi Srivatsavai 	    (GET_TRILL_OPTS_LEN(trillhdr) * sizeof (uint32_t));
437*4eaa4710SRishi Srivatsavai 
438*4eaa4710SRishi Srivatsavai 	/*
439*4eaa4710SRishi Srivatsavai 	 * Get the inner Ethernet header, plus the inner VLAN header if there
440*4eaa4710SRishi Srivatsavai 	 * is one.
441*4eaa4710SRishi Srivatsavai 	 */
442*4eaa4710SRishi Srivatsavai 	/* LINTED: alignment */
443*4eaa4710SRishi Srivatsavai 	ethhdr = (struct ether_header *)(mp->b_rptr + trillhdrlen);
444*4eaa4710SRishi Srivatsavai 	if (ethhdr->ether_type == htons(ETHERTYPE_VLAN)) {
445*4eaa4710SRishi Srivatsavai 		min_size += sizeof (struct ether_vlan_extinfo);
446*4eaa4710SRishi Srivatsavai 		if (MBLKL(mp) < min_size) {
447*4eaa4710SRishi Srivatsavai 			if (!pullupmsg(mp, min_size))
448*4eaa4710SRishi Srivatsavai 				goto fail;
449*4eaa4710SRishi Srivatsavai 			/* LINTED: alignment */
450*4eaa4710SRishi Srivatsavai 			trillhdr = (trill_header_t *)mp->b_rptr;
451*4eaa4710SRishi Srivatsavai 			/* LINTED: alignment */
452*4eaa4710SRishi Srivatsavai 			ethhdr = (struct ether_header *)(mp->b_rptr +
453*4eaa4710SRishi Srivatsavai 			    trillhdrlen);
454*4eaa4710SRishi Srivatsavai 		}
455*4eaa4710SRishi Srivatsavai 
456*4eaa4710SRishi Srivatsavai 		tci = ntohs(((struct ether_vlan_header *)ethhdr)->ether_tci);
457*4eaa4710SRishi Srivatsavai 		inner_vlan = VLAN_ID(tci);
458*4eaa4710SRishi Srivatsavai 	}
459*4eaa4710SRishi Srivatsavai 
460*4eaa4710SRishi Srivatsavai 	/* Known/single destination forwarding. */
461*4eaa4710SRishi Srivatsavai 	if (!trillhdr->th_multidest) {
462*4eaa4710SRishi Srivatsavai 
463*4eaa4710SRishi Srivatsavai 		/* Inner MacDA must be unicast */
464*4eaa4710SRishi Srivatsavai 		if (ethhdr->ether_dhost.ether_addr_octet[0] & 1)
465*4eaa4710SRishi Srivatsavai 			goto fail;
466*4eaa4710SRishi Srivatsavai 
467*4eaa4710SRishi Srivatsavai 		/* Ingress and Egress nicks must be different */
468*4eaa4710SRishi Srivatsavai 		if (trillhdr->th_egressnick == trillhdr->th_ingressnick)
469*4eaa4710SRishi Srivatsavai 			goto fail;
470*4eaa4710SRishi Srivatsavai 
471*4eaa4710SRishi Srivatsavai 		DTRACE_PROBE1(trill__recv__singledest,
472*4eaa4710SRishi Srivatsavai 		    trill_header_t *, trillhdr);
473*4eaa4710SRishi Srivatsavai 		if (trillhdr->th_egressnick == ournick) {
474*4eaa4710SRishi Srivatsavai 			mp->b_rptr += trillhdrlen;
475*4eaa4710SRishi Srivatsavai 			trill_recv_local(tsock, mp, trillhdr->th_ingressnick);
476*4eaa4710SRishi Srivatsavai 		} else if (trillhdr->th_hopcount > 0) {
477*4eaa4710SRishi Srivatsavai 			trill_dest_fwd(tip, mp, trillhdr->th_egressnick,
478*4eaa4710SRishi Srivatsavai 			    B_TRUE, B_FALSE, RBRIDGE_NICKNAME_NONE);
479*4eaa4710SRishi Srivatsavai 		} else {
480*4eaa4710SRishi Srivatsavai 			goto fail;
481*4eaa4710SRishi Srivatsavai 		}
482*4eaa4710SRishi Srivatsavai 		return;
483*4eaa4710SRishi Srivatsavai 	}
484*4eaa4710SRishi Srivatsavai 
485*4eaa4710SRishi Srivatsavai 	/*
486*4eaa4710SRishi Srivatsavai 	 * Multi-destination frame: perform checks verifying we have
487*4eaa4710SRishi Srivatsavai 	 * received a valid multi-destination frame before receiving the
488*4eaa4710SRishi Srivatsavai 	 * frame locally and forwarding the frame to other RBridges.
489*4eaa4710SRishi Srivatsavai 	 *
490*4eaa4710SRishi Srivatsavai 	 * Check if we received this multi-destination frame on a
491*4eaa4710SRishi Srivatsavai 	 * adjacency in the distribution tree indicated by the frame's
492*4eaa4710SRishi Srivatsavai 	 * egress nickname.
493*4eaa4710SRishi Srivatsavai 	 */
494*4eaa4710SRishi Srivatsavai 	if ((dest = trill_node_lookup(tip, trillhdr->th_egressnick)) == NULL)
495*4eaa4710SRishi Srivatsavai 		goto fail;
496*4eaa4710SRishi Srivatsavai 	for (idx = 0; idx < dest->tn_ni->tni_adjcount; idx++) {
497*4eaa4710SRishi Srivatsavai 		adjnick = TNI_ADJNICK(dest->tn_ni, idx);
498*4eaa4710SRishi Srivatsavai 		if ((adj = trill_node_lookup(tip, adjnick)) == NULL)
499*4eaa4710SRishi Srivatsavai 			continue;
500*4eaa4710SRishi Srivatsavai 		if (memcmp(adj->tn_ni->tni_adjsnpa, srcaddr, ETHERADDRL) == 0) {
501*4eaa4710SRishi Srivatsavai 			trill_node_unref(tip, adj);
502*4eaa4710SRishi Srivatsavai 			break;
503*4eaa4710SRishi Srivatsavai 		}
504*4eaa4710SRishi Srivatsavai 		trill_node_unref(tip, adj);
505*4eaa4710SRishi Srivatsavai 	}
506*4eaa4710SRishi Srivatsavai 
507*4eaa4710SRishi Srivatsavai 	if (idx >= dest->tn_ni->tni_adjcount) {
508*4eaa4710SRishi Srivatsavai 		DTRACE_PROBE2(trill__recv__multidest__adjcheckfail,
509*4eaa4710SRishi Srivatsavai 		    trill_header_t *, trillhdr, trill_node_t *, dest);
510*4eaa4710SRishi Srivatsavai 		goto fail;
511*4eaa4710SRishi Srivatsavai 	}
512*4eaa4710SRishi Srivatsavai 
513*4eaa4710SRishi Srivatsavai 	/*
514*4eaa4710SRishi Srivatsavai 	 * Reverse path forwarding check. Check if the ingress RBridge
515*4eaa4710SRishi Srivatsavai 	 * that has forwarded the frame advertised the use of the
516*4eaa4710SRishi Srivatsavai 	 * distribution tree specified in the egress nick.
517*4eaa4710SRishi Srivatsavai 	 */
518*4eaa4710SRishi Srivatsavai 	if ((source = trill_node_lookup(tip, trillhdr->th_ingressnick)) == NULL)
519*4eaa4710SRishi Srivatsavai 		goto fail;
520*4eaa4710SRishi Srivatsavai 	for (idx = 0; idx < source->tn_ni->tni_dtrootcount; idx++) {
521*4eaa4710SRishi Srivatsavai 		if (TNI_DTROOTNICK(source->tn_ni, idx) ==
522*4eaa4710SRishi Srivatsavai 		    trillhdr->th_egressnick)
523*4eaa4710SRishi Srivatsavai 			break;
524*4eaa4710SRishi Srivatsavai 	}
525*4eaa4710SRishi Srivatsavai 
526*4eaa4710SRishi Srivatsavai 	if (idx >= source->tn_ni->tni_dtrootcount) {
527*4eaa4710SRishi Srivatsavai 		/*
528*4eaa4710SRishi Srivatsavai 		 * Allow receipt of forwarded frame with the highest
529*4eaa4710SRishi Srivatsavai 		 * tree root RBridge as the egress RBridge when the
530*4eaa4710SRishi Srivatsavai 		 * ingress RBridge has not advertised the use of any
531*4eaa4710SRishi Srivatsavai 		 * distribution trees.
532*4eaa4710SRishi Srivatsavai 		 */
533*4eaa4710SRishi Srivatsavai 		if (source->tn_ni->tni_dtrootcount != 0 ||
534*4eaa4710SRishi Srivatsavai 		    trillhdr->th_egressnick != treeroot) {
535*4eaa4710SRishi Srivatsavai 			DTRACE_PROBE3(
536*4eaa4710SRishi Srivatsavai 			    trill__recv__multidest__rpfcheckfail,
537*4eaa4710SRishi Srivatsavai 			    trill_header_t *, trillhdr, trill_node_t *,
538*4eaa4710SRishi Srivatsavai 			    source, trill_inst_t *, tip);
539*4eaa4710SRishi Srivatsavai 			goto fail;
540*4eaa4710SRishi Srivatsavai 		}
541*4eaa4710SRishi Srivatsavai 	}
542*4eaa4710SRishi Srivatsavai 
543*4eaa4710SRishi Srivatsavai 	/* Check hop count before doing any forwarding */
544*4eaa4710SRishi Srivatsavai 	if (trillhdr->th_hopcount == 0)
545*4eaa4710SRishi Srivatsavai 		goto fail;
546*4eaa4710SRishi Srivatsavai 
547*4eaa4710SRishi Srivatsavai 	/* Forward frame using the distribution tree specified by egress nick */
548*4eaa4710SRishi Srivatsavai 	DTRACE_PROBE2(trill__recv__multidest, trill_header_t *,
549*4eaa4710SRishi Srivatsavai 	    trillhdr, trill_node_t *, source);
550*4eaa4710SRishi Srivatsavai 	trill_node_unref(tip, source);
551*4eaa4710SRishi Srivatsavai 	trill_node_unref(tip, dest);
552*4eaa4710SRishi Srivatsavai 
553*4eaa4710SRishi Srivatsavai 	/* Tell forwarding not to free if we're the link forwarder. */
554*4eaa4710SRishi Srivatsavai 	trill_multidest_fwd(tip, mp, trillhdr->th_egressnick,
555*4eaa4710SRishi Srivatsavai 	    trillhdr->th_ingressnick, B_TRUE, srcaddr, inner_vlan,
556*4eaa4710SRishi Srivatsavai 	    B_FALSE);
557*4eaa4710SRishi Srivatsavai 
558*4eaa4710SRishi Srivatsavai 	/*
559*4eaa4710SRishi Srivatsavai 	 * Send de-capsulated frame locally if we are the link forwarder (also
560*4eaa4710SRishi Srivatsavai 	 * does bridge learning).
561*4eaa4710SRishi Srivatsavai 	 */
562*4eaa4710SRishi Srivatsavai 	mp->b_rptr += trillhdrlen;
563*4eaa4710SRishi Srivatsavai 	trill_recv_local(tsock, mp, trillhdr->th_ingressnick);
564*4eaa4710SRishi Srivatsavai 	KSPINCR(tks_recv);
565*4eaa4710SRishi Srivatsavai 	return;
566*4eaa4710SRishi Srivatsavai 
567*4eaa4710SRishi Srivatsavai fail:
568*4eaa4710SRishi Srivatsavai 	DTRACE_PROBE2(trill__recv__multidest__fail, mblk_t *, mp,
569*4eaa4710SRishi Srivatsavai 	    trill_sock_t *, tsock);
570*4eaa4710SRishi Srivatsavai 	if (dest != NULL)
571*4eaa4710SRishi Srivatsavai 		trill_node_unref(tip, dest);
572*4eaa4710SRishi Srivatsavai 	if (source != NULL)
573*4eaa4710SRishi Srivatsavai 		trill_node_unref(tip, source);
574*4eaa4710SRishi Srivatsavai 	freemsg(mp);
575*4eaa4710SRishi Srivatsavai 	KSPINCR(tks_drops);
576*4eaa4710SRishi Srivatsavai }
577*4eaa4710SRishi Srivatsavai 
578*4eaa4710SRishi Srivatsavai static void
579*4eaa4710SRishi Srivatsavai trill_stop_recv(trill_sock_t *tsock)
580*4eaa4710SRishi Srivatsavai {
581*4eaa4710SRishi Srivatsavai 	mutex_enter(&tsock->ts_socklock);
582*4eaa4710SRishi Srivatsavai stop_retry:
583*4eaa4710SRishi Srivatsavai 	if (tsock->ts_state == TS_UNBND || tsock->ts_link == NULL) {
584*4eaa4710SRishi Srivatsavai 		mutex_exit(&tsock->ts_socklock);
585*4eaa4710SRishi Srivatsavai 		return;
586*4eaa4710SRishi Srivatsavai 	}
587*4eaa4710SRishi Srivatsavai 
588*4eaa4710SRishi Srivatsavai 	/*
589*4eaa4710SRishi Srivatsavai 	 * If another thread is closing the socket then wait. Our callers
590*4eaa4710SRishi Srivatsavai 	 * expect us to return only after the socket is closed.
591*4eaa4710SRishi Srivatsavai 	 */
592*4eaa4710SRishi Srivatsavai 	if (tsock->ts_flags & TSF_CLOSEWAIT) {
593*4eaa4710SRishi Srivatsavai 		cv_wait(&tsock->ts_sockclosewait, &tsock->ts_socklock);
594*4eaa4710SRishi Srivatsavai 		goto stop_retry;
595*4eaa4710SRishi Srivatsavai 	}
596*4eaa4710SRishi Srivatsavai 
597*4eaa4710SRishi Srivatsavai 	/*
598*4eaa4710SRishi Srivatsavai 	 * Set state and flags to block new bind or close calls
599*4eaa4710SRishi Srivatsavai 	 * while we close the socket.
600*4eaa4710SRishi Srivatsavai 	 */
601*4eaa4710SRishi Srivatsavai 	tsock->ts_flags |= TSF_CLOSEWAIT;
602*4eaa4710SRishi Srivatsavai 
603*4eaa4710SRishi Srivatsavai 	/* Wait until all AF_TRILL socket transmit operations are done */
604*4eaa4710SRishi Srivatsavai 	while (tsock->ts_sockthreadcount > 0)
605*4eaa4710SRishi Srivatsavai 		cv_wait(&tsock->ts_sockthreadwait, &tsock->ts_socklock);
606*4eaa4710SRishi Srivatsavai 
607*4eaa4710SRishi Srivatsavai 	/*
608*4eaa4710SRishi Srivatsavai 	 * We are guaranteed to be the only thread closing on the
609*4eaa4710SRishi Srivatsavai 	 * socket while the TSF_CLOSEWAIT flag is set, all others cv_wait
610*4eaa4710SRishi Srivatsavai 	 * for us to finish.
611*4eaa4710SRishi Srivatsavai 	 */
612*4eaa4710SRishi Srivatsavai 	ASSERT(tsock->ts_link != NULL);
613*4eaa4710SRishi Srivatsavai 	if (tsock->ts_ksp != NULL)
614*4eaa4710SRishi Srivatsavai 		kstat_delete(tsock->ts_ksp);
615*4eaa4710SRishi Srivatsavai 
616*4eaa4710SRishi Srivatsavai 	/*
617*4eaa4710SRishi Srivatsavai 	 * Release lock before bridge_trill_lnunref to prevent deadlock
618*4eaa4710SRishi Srivatsavai 	 * between trill_ctrl_input thread waiting to acquire ts_socklock
619*4eaa4710SRishi Srivatsavai 	 * and bridge_trill_lnunref waiting for the trill thread to finish.
620*4eaa4710SRishi Srivatsavai 	 */
621*4eaa4710SRishi Srivatsavai 	mutex_exit(&tsock->ts_socklock);
622*4eaa4710SRishi Srivatsavai 
623*4eaa4710SRishi Srivatsavai 	/*
624*4eaa4710SRishi Srivatsavai 	 * Release TRILL link reference from Bridging. On return from
625*4eaa4710SRishi Srivatsavai 	 * bridge_trill_lnunref we can be sure there are no active TRILL data
626*4eaa4710SRishi Srivatsavai 	 * threads for this link.
627*4eaa4710SRishi Srivatsavai 	 */
628*4eaa4710SRishi Srivatsavai 	bridge_trill_lnunref(tsock->ts_link);
629*4eaa4710SRishi Srivatsavai 
630*4eaa4710SRishi Srivatsavai 	/* Set socket as unbound & wakeup threads waiting for socket to close */
631*4eaa4710SRishi Srivatsavai 	mutex_enter(&tsock->ts_socklock);
632*4eaa4710SRishi Srivatsavai 	ASSERT(tsock->ts_link != NULL);
633*4eaa4710SRishi Srivatsavai 	tsock->ts_link = NULL;
634*4eaa4710SRishi Srivatsavai 	tsock->ts_state = TS_UNBND;
635*4eaa4710SRishi Srivatsavai 	tsock->ts_flags &= ~TSF_CLOSEWAIT;
636*4eaa4710SRishi Srivatsavai 	cv_broadcast(&tsock->ts_sockclosewait);
637*4eaa4710SRishi Srivatsavai 	mutex_exit(&tsock->ts_socklock);
638*4eaa4710SRishi Srivatsavai }
639*4eaa4710SRishi Srivatsavai 
640*4eaa4710SRishi Srivatsavai static int
641*4eaa4710SRishi Srivatsavai trill_start_recv(trill_sock_t *tsock, const struct sockaddr *sa, socklen_t len)
642*4eaa4710SRishi Srivatsavai {
643*4eaa4710SRishi Srivatsavai 	struct sockaddr_dl *lladdr = (struct sockaddr_dl *)sa;
644*4eaa4710SRishi Srivatsavai 	datalink_id_t linkid;
645*4eaa4710SRishi Srivatsavai 	int err = 0;
646*4eaa4710SRishi Srivatsavai 
647*4eaa4710SRishi Srivatsavai 	if (len != sizeof (*lladdr))
648*4eaa4710SRishi Srivatsavai 		return (EINVAL);
649*4eaa4710SRishi Srivatsavai 
650*4eaa4710SRishi Srivatsavai 	mutex_enter(&tsock->ts_socklock);
651*4eaa4710SRishi Srivatsavai 	if (tsock->ts_tip == NULL || tsock->ts_state != TS_UNBND) {
652*4eaa4710SRishi Srivatsavai 		err = EINVAL;
653*4eaa4710SRishi Srivatsavai 		goto bind_error;
654*4eaa4710SRishi Srivatsavai 	}
655*4eaa4710SRishi Srivatsavai 
656*4eaa4710SRishi Srivatsavai 	if (tsock->ts_flags & TSF_CLOSEWAIT || tsock->ts_link != NULL) {
657*4eaa4710SRishi Srivatsavai 		err = EBUSY;
658*4eaa4710SRishi Srivatsavai 		goto bind_error;
659*4eaa4710SRishi Srivatsavai 	}
660*4eaa4710SRishi Srivatsavai 
661*4eaa4710SRishi Srivatsavai 	(void) memcpy(&(tsock->ts_lladdr), lladdr,
662*4eaa4710SRishi Srivatsavai 	    sizeof (struct sockaddr_dl));
663*4eaa4710SRishi Srivatsavai 	(void) memcpy(&linkid, tsock->ts_lladdr.sdl_data,
664*4eaa4710SRishi Srivatsavai 	    sizeof (datalink_id_t));
665*4eaa4710SRishi Srivatsavai 
666*4eaa4710SRishi Srivatsavai 	tsock->ts_link = bridge_trill_lnref(tsock->ts_tip->ti_binst,
667*4eaa4710SRishi Srivatsavai 	    linkid, tsock);
668*4eaa4710SRishi Srivatsavai 	if (tsock->ts_link == NULL) {
669*4eaa4710SRishi Srivatsavai 		err = EINVAL;
670*4eaa4710SRishi Srivatsavai 		goto bind_error;
671*4eaa4710SRishi Srivatsavai 	}
672*4eaa4710SRishi Srivatsavai 
673*4eaa4710SRishi Srivatsavai 	trill_kstats_init(tsock, tsock->ts_tip->ti_bridgename);
674*4eaa4710SRishi Srivatsavai 	tsock->ts_state = TS_IDLE;
675*4eaa4710SRishi Srivatsavai 
676*4eaa4710SRishi Srivatsavai bind_error:
677*4eaa4710SRishi Srivatsavai 	mutex_exit(&tsock->ts_socklock);
678*4eaa4710SRishi Srivatsavai 	return (err);
679*4eaa4710SRishi Srivatsavai }
680*4eaa4710SRishi Srivatsavai 
681*4eaa4710SRishi Srivatsavai static int
682*4eaa4710SRishi Srivatsavai trill_do_unbind(trill_sock_t *tsock)
683*4eaa4710SRishi Srivatsavai {
684*4eaa4710SRishi Srivatsavai 	/* If a bind has not been done, we can't unbind. */
685*4eaa4710SRishi Srivatsavai 	if (tsock->ts_state != TS_IDLE)
686*4eaa4710SRishi Srivatsavai 		return (EINVAL);
687*4eaa4710SRishi Srivatsavai 
688*4eaa4710SRishi Srivatsavai 	trill_stop_recv(tsock);
689*4eaa4710SRishi Srivatsavai 	return (0);
690*4eaa4710SRishi Srivatsavai }
691*4eaa4710SRishi Srivatsavai 
692*4eaa4710SRishi Srivatsavai static void
693*4eaa4710SRishi Srivatsavai trill_instance_unref(trill_inst_t *tip)
694*4eaa4710SRishi Srivatsavai {
695*4eaa4710SRishi Srivatsavai 	rw_enter(&trill_inst_rwlock, RW_WRITER);
696*4eaa4710SRishi Srivatsavai 	rw_enter(&tip->ti_rwlock, RW_WRITER);
697*4eaa4710SRishi Srivatsavai 	if (atomic_dec_uint_nv(&tip->ti_refs) == 0) {
698*4eaa4710SRishi Srivatsavai 		list_remove(&trill_inst_list, tip);
699*4eaa4710SRishi Srivatsavai 		rw_exit(&tip->ti_rwlock);
700*4eaa4710SRishi Srivatsavai 		rw_exit(&trill_inst_rwlock);
701*4eaa4710SRishi Srivatsavai 		if (tip->ti_binst != NULL)
702*4eaa4710SRishi Srivatsavai 			bridge_trill_brunref(tip->ti_binst);
703*4eaa4710SRishi Srivatsavai 		list_destroy(&tip->ti_socklist);
704*4eaa4710SRishi Srivatsavai 		rw_destroy(&tip->ti_rwlock);
705*4eaa4710SRishi Srivatsavai 		kmem_free(tip, sizeof (*tip));
706*4eaa4710SRishi Srivatsavai 	} else {
707*4eaa4710SRishi Srivatsavai 		rw_exit(&tip->ti_rwlock);
708*4eaa4710SRishi Srivatsavai 		rw_exit(&trill_inst_rwlock);
709*4eaa4710SRishi Srivatsavai 	}
710*4eaa4710SRishi Srivatsavai }
711*4eaa4710SRishi Srivatsavai 
712*4eaa4710SRishi Srivatsavai /*
713*4eaa4710SRishi Srivatsavai  * This is called when the bridge module receives a TRILL-encapsulated packet
714*4eaa4710SRishi Srivatsavai  * on a given link or a packet identified as "TRILL control."  We must verify
715*4eaa4710SRishi Srivatsavai  * that it's for us (it almost certainly will be), and then either decapsulate
716*4eaa4710SRishi Srivatsavai  * (if it's to our nickname), forward (if it's to someone else), or send up one
717*4eaa4710SRishi Srivatsavai  * of the sockets (if it's control traffic).
718*4eaa4710SRishi Srivatsavai  *
719*4eaa4710SRishi Srivatsavai  * Sadly, on Ethernet, the control traffic is identified by Outer.MacDA, and
720*4eaa4710SRishi Srivatsavai  * not by TRILL header information.
721*4eaa4710SRishi Srivatsavai  */
722*4eaa4710SRishi Srivatsavai static void
723*4eaa4710SRishi Srivatsavai trill_recv_pkt_cb(void *lptr, bridge_link_t *blp, mac_resource_handle_t rsrc,
724*4eaa4710SRishi Srivatsavai     mblk_t *mp, mac_header_info_t *hdr_info)
725*4eaa4710SRishi Srivatsavai {
726*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock = lptr;
727*4eaa4710SRishi Srivatsavai 
728*4eaa4710SRishi Srivatsavai 	_NOTE(ARGUNUSED(rsrc));
729*4eaa4710SRishi Srivatsavai 
730*4eaa4710SRishi Srivatsavai 	ASSERT(tsock->ts_tip != NULL);
731*4eaa4710SRishi Srivatsavai 	ASSERT(tsock->ts_link != NULL);
732*4eaa4710SRishi Srivatsavai 	ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN));
733*4eaa4710SRishi Srivatsavai 
734*4eaa4710SRishi Srivatsavai 	/*
735*4eaa4710SRishi Srivatsavai 	 * Only receive packet if the source address is not multicast (which is
736*4eaa4710SRishi Srivatsavai 	 * bogus).
737*4eaa4710SRishi Srivatsavai 	 */
738*4eaa4710SRishi Srivatsavai 	if (hdr_info->mhi_saddr[0] & 1)
739*4eaa4710SRishi Srivatsavai 		goto discard;
740*4eaa4710SRishi Srivatsavai 
741*4eaa4710SRishi Srivatsavai 	/*
742*4eaa4710SRishi Srivatsavai 	 * Check if this is our own packet reflected back.  It should not be.
743*4eaa4710SRishi Srivatsavai 	 */
744*4eaa4710SRishi Srivatsavai 	if (bcmp(hdr_info->mhi_saddr, blp->bl_local_mac, ETHERADDRL) == 0)
745*4eaa4710SRishi Srivatsavai 		goto discard;
746*4eaa4710SRishi Srivatsavai 
747*4eaa4710SRishi Srivatsavai 	/* Only receive unicast packet if addressed to us */
748*4eaa4710SRishi Srivatsavai 	if (hdr_info->mhi_dsttype == MAC_ADDRTYPE_UNICAST &&
749*4eaa4710SRishi Srivatsavai 	    bcmp(hdr_info->mhi_daddr, blp->bl_local_mac, ETHERADDRL) != 0)
750*4eaa4710SRishi Srivatsavai 		goto discard;
751*4eaa4710SRishi Srivatsavai 
752*4eaa4710SRishi Srivatsavai 	if (hdr_info->mhi_bindsap == ETHERTYPE_TRILL) {
753*4eaa4710SRishi Srivatsavai 		/* TRILL data packets */
754*4eaa4710SRishi Srivatsavai 		trill_recv(tsock, mp, hdr_info->mhi_saddr);
755*4eaa4710SRishi Srivatsavai 	} else {
756*4eaa4710SRishi Srivatsavai 		/* Design constraint for cheap IS-IS/BPDU comparison */
757*4eaa4710SRishi Srivatsavai 		ASSERT(all_isis_rbridges[4] != bridge_group_address[4]);
758*4eaa4710SRishi Srivatsavai 		/* Send received control packet upstream */
759*4eaa4710SRishi Srivatsavai 		trill_ctrl_input(tsock, mp, hdr_info->mhi_saddr,
760*4eaa4710SRishi Srivatsavai 		    hdr_info->mhi_daddr[4] == all_isis_rbridges[4] ?
761*4eaa4710SRishi Srivatsavai 		    hdr_info->mhi_tci : TRILL_TCI_BPDU);
762*4eaa4710SRishi Srivatsavai 	}
763*4eaa4710SRishi Srivatsavai 
764*4eaa4710SRishi Srivatsavai 	return;
765*4eaa4710SRishi Srivatsavai 
766*4eaa4710SRishi Srivatsavai discard:
767*4eaa4710SRishi Srivatsavai 	freemsg(mp);
768*4eaa4710SRishi Srivatsavai 	KSPINCR(tks_drops);
769*4eaa4710SRishi Srivatsavai }
770*4eaa4710SRishi Srivatsavai 
771*4eaa4710SRishi Srivatsavai /*
772*4eaa4710SRishi Srivatsavai  * This is called when the bridge module discovers that the destination address
773*4eaa4710SRishi Srivatsavai  * for a packet is not local -- it's through some remote node.  We must verify
774*4eaa4710SRishi Srivatsavai  * that the remote node isn't our nickname (it shouldn't be), add a TRILL
775*4eaa4710SRishi Srivatsavai  * header, and then use the IS-IS data to determine which link and which
776*4eaa4710SRishi Srivatsavai  * next-hop RBridge should be used for output.  We then transmit on that link.
777*4eaa4710SRishi Srivatsavai  *
778*4eaa4710SRishi Srivatsavai  * The egress_nick is RBRIDGE_NICKNAME_NONE for the "unknown destination" case.
779*4eaa4710SRishi Srivatsavai  */
780*4eaa4710SRishi Srivatsavai static void
781*4eaa4710SRishi Srivatsavai trill_encap_pkt_cb(void *lptr, bridge_link_t *blp, mac_header_info_t *hdr_info,
782*4eaa4710SRishi Srivatsavai     mblk_t *mp, uint16_t egress_nick)
783*4eaa4710SRishi Srivatsavai {
784*4eaa4710SRishi Srivatsavai 	uint16_t ournick;
785*4eaa4710SRishi Srivatsavai 	uint16_t dtnick;
786*4eaa4710SRishi Srivatsavai 	trill_node_t *self = NULL;
787*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock = lptr;
788*4eaa4710SRishi Srivatsavai 	trill_inst_t *tip = tsock->ts_tip;
789*4eaa4710SRishi Srivatsavai 	int vlan = VLAN_ID_NONE;
790*4eaa4710SRishi Srivatsavai 
791*4eaa4710SRishi Srivatsavai 	_NOTE(ARGUNUSED(blp));
792*4eaa4710SRishi Srivatsavai 	ASSERT(hdr_info->mhi_bindsap != ETHERTYPE_TRILL);
793*4eaa4710SRishi Srivatsavai 
794*4eaa4710SRishi Srivatsavai 	/* egress_nick = RBRIDGE_NICKNAME_NONE is valid */
795*4eaa4710SRishi Srivatsavai 	if (egress_nick != RBRIDGE_NICKNAME_NONE && !VALID_NICK(egress_nick))
796*4eaa4710SRishi Srivatsavai 		goto discard;
797*4eaa4710SRishi Srivatsavai 
798*4eaa4710SRishi Srivatsavai 	/* Check if our own nick is valid before we do any forwarding */
799*4eaa4710SRishi Srivatsavai 	rw_enter(&tip->ti_rwlock, RW_READER);
800*4eaa4710SRishi Srivatsavai 	ournick = tip->ti_nick;
801*4eaa4710SRishi Srivatsavai 	dtnick = tip->ti_treeroot;
802*4eaa4710SRishi Srivatsavai 	rw_exit(&tip->ti_rwlock);
803*4eaa4710SRishi Srivatsavai 	if (!VALID_NICK(ournick))
804*4eaa4710SRishi Srivatsavai 		goto discard;
805*4eaa4710SRishi Srivatsavai 
806*4eaa4710SRishi Srivatsavai 	/*
807*4eaa4710SRishi Srivatsavai 	 * For Multi-Destination forwarding determine our choice of
808*4eaa4710SRishi Srivatsavai 	 * root distribution tree. If we didn't choose a distribution
809*4eaa4710SRishi Srivatsavai 	 * tree (dtroots_count=0) then we use the highest priority tree
810*4eaa4710SRishi Srivatsavai 	 * root (t_treeroot) else we drop the packet without forwarding.
811*4eaa4710SRishi Srivatsavai 	 */
812*4eaa4710SRishi Srivatsavai 	if (egress_nick == RBRIDGE_NICKNAME_NONE) {
813*4eaa4710SRishi Srivatsavai 		if ((self = trill_node_lookup(tip, ournick)) == NULL)
814*4eaa4710SRishi Srivatsavai 			goto discard;
815*4eaa4710SRishi Srivatsavai 
816*4eaa4710SRishi Srivatsavai 		/*
817*4eaa4710SRishi Srivatsavai 		 * Use the first DT configured for now. In future we
818*4eaa4710SRishi Srivatsavai 		 * should have DT selection code here.
819*4eaa4710SRishi Srivatsavai 		 */
820*4eaa4710SRishi Srivatsavai 		if (self->tn_ni->tni_dtrootcount > 0) {
821*4eaa4710SRishi Srivatsavai 			dtnick = TNI_DTROOTNICK(self->tn_ni, 0);
822*4eaa4710SRishi Srivatsavai 		}
823*4eaa4710SRishi Srivatsavai 
824*4eaa4710SRishi Srivatsavai 		trill_node_unref(tip, self);
825*4eaa4710SRishi Srivatsavai 		if (!VALID_NICK(dtnick)) {
826*4eaa4710SRishi Srivatsavai 			DTRACE_PROBE(trill__fwd__packet__nodtroot);
827*4eaa4710SRishi Srivatsavai 			goto discard;
828*4eaa4710SRishi Srivatsavai 		}
829*4eaa4710SRishi Srivatsavai 	}
830*4eaa4710SRishi Srivatsavai 
831*4eaa4710SRishi Srivatsavai 	/*
832*4eaa4710SRishi Srivatsavai 	 * Retrieve VLAN ID of the native frame used for VLAN
833*4eaa4710SRishi Srivatsavai 	 * pruning of multi-destination frames.
834*4eaa4710SRishi Srivatsavai 	 */
835*4eaa4710SRishi Srivatsavai 	if (hdr_info->mhi_istagged) {
836*4eaa4710SRishi Srivatsavai 		vlan = VLAN_ID(hdr_info->mhi_tci);
837*4eaa4710SRishi Srivatsavai 	}
838*4eaa4710SRishi Srivatsavai 
839*4eaa4710SRishi Srivatsavai 	DTRACE_PROBE2(trill__fwd__packet, mac_header_info_t *, hdr_info,
840*4eaa4710SRishi Srivatsavai 	    uint16_t, egress_nick);
841*4eaa4710SRishi Srivatsavai 	if (egress_nick == RBRIDGE_NICKNAME_NONE) {
842*4eaa4710SRishi Srivatsavai 		trill_multidest_fwd(tip, mp, dtnick,
843*4eaa4710SRishi Srivatsavai 		    ournick, B_FALSE, NULL, vlan, B_TRUE);
844*4eaa4710SRishi Srivatsavai 	} else {
845*4eaa4710SRishi Srivatsavai 		trill_dest_fwd(tip, mp, egress_nick, B_FALSE, B_FALSE,
846*4eaa4710SRishi Srivatsavai 		    RBRIDGE_NICKNAME_NONE);
847*4eaa4710SRishi Srivatsavai 	}
848*4eaa4710SRishi Srivatsavai 	KSPINCR(tks_encap);
849*4eaa4710SRishi Srivatsavai 	return;
850*4eaa4710SRishi Srivatsavai 
851*4eaa4710SRishi Srivatsavai discard:
852*4eaa4710SRishi Srivatsavai 	freemsg(mp);
853*4eaa4710SRishi Srivatsavai }
854*4eaa4710SRishi Srivatsavai 
855*4eaa4710SRishi Srivatsavai /*
856*4eaa4710SRishi Srivatsavai  * This is called when the bridge module has completely torn down a bridge
857*4eaa4710SRishi Srivatsavai  * instance and all of the attached links.  We need to make the TRILL instance
858*4eaa4710SRishi Srivatsavai  * go away at this point.
859*4eaa4710SRishi Srivatsavai  */
860*4eaa4710SRishi Srivatsavai static void
861*4eaa4710SRishi Srivatsavai trill_br_dstr_cb(void *bptr, bridge_inst_t *bip)
862*4eaa4710SRishi Srivatsavai {
863*4eaa4710SRishi Srivatsavai 	trill_inst_t *tip = bptr;
864*4eaa4710SRishi Srivatsavai 
865*4eaa4710SRishi Srivatsavai 	_NOTE(ARGUNUSED(bip));
866*4eaa4710SRishi Srivatsavai 	rw_enter(&tip->ti_rwlock, RW_WRITER);
867*4eaa4710SRishi Srivatsavai 	if (tip->ti_binst != NULL)
868*4eaa4710SRishi Srivatsavai 		bridge_trill_brunref(tip->ti_binst);
869*4eaa4710SRishi Srivatsavai 	tip->ti_binst = NULL;
870*4eaa4710SRishi Srivatsavai 	rw_exit(&tip->ti_rwlock);
871*4eaa4710SRishi Srivatsavai }
872*4eaa4710SRishi Srivatsavai 
873*4eaa4710SRishi Srivatsavai /*
874*4eaa4710SRishi Srivatsavai  * This is called when the bridge module is tearing down a link, but before the
875*4eaa4710SRishi Srivatsavai  * actual tear-down starts.  When this function returns, we must make sure that
876*4eaa4710SRishi Srivatsavai  * we will not initiate any new transmits on this link.
877*4eaa4710SRishi Srivatsavai  */
878*4eaa4710SRishi Srivatsavai static void
879*4eaa4710SRishi Srivatsavai trill_ln_dstr_cb(void *lptr, bridge_link_t *blp)
880*4eaa4710SRishi Srivatsavai {
881*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock = lptr;
882*4eaa4710SRishi Srivatsavai 
883*4eaa4710SRishi Srivatsavai 	_NOTE(ARGUNUSED(blp));
884*4eaa4710SRishi Srivatsavai 	trill_stop_recv(tsock);
885*4eaa4710SRishi Srivatsavai }
886*4eaa4710SRishi Srivatsavai 
887*4eaa4710SRishi Srivatsavai static void
888*4eaa4710SRishi Srivatsavai trill_init(void)
889*4eaa4710SRishi Srivatsavai {
890*4eaa4710SRishi Srivatsavai 	list_create(&trill_inst_list, sizeof (trill_inst_t),
891*4eaa4710SRishi Srivatsavai 	    offsetof(trill_inst_t, ti_instnode));
892*4eaa4710SRishi Srivatsavai 	rw_init(&trill_inst_rwlock, NULL, RW_DRIVER, NULL);
893*4eaa4710SRishi Srivatsavai 	bridge_trill_register_cb(trill_recv_pkt_cb, trill_encap_pkt_cb,
894*4eaa4710SRishi Srivatsavai 	    trill_br_dstr_cb, trill_ln_dstr_cb);
895*4eaa4710SRishi Srivatsavai }
896*4eaa4710SRishi Srivatsavai 
897*4eaa4710SRishi Srivatsavai static void
898*4eaa4710SRishi Srivatsavai trill_fini(void)
899*4eaa4710SRishi Srivatsavai {
900*4eaa4710SRishi Srivatsavai 	bridge_trill_register_cb(NULL, NULL, NULL, NULL);
901*4eaa4710SRishi Srivatsavai 	rw_destroy(&trill_inst_rwlock);
902*4eaa4710SRishi Srivatsavai 	list_destroy(&trill_inst_list);
903*4eaa4710SRishi Srivatsavai }
904*4eaa4710SRishi Srivatsavai 
905*4eaa4710SRishi Srivatsavai /* Loadable module configuration entry points */
906*4eaa4710SRishi Srivatsavai int
907*4eaa4710SRishi Srivatsavai _init(void)
908*4eaa4710SRishi Srivatsavai {
909*4eaa4710SRishi Srivatsavai 	int rc;
910*4eaa4710SRishi Srivatsavai 
911*4eaa4710SRishi Srivatsavai 	trill_init();
912*4eaa4710SRishi Srivatsavai 	if ((rc = mod_install(&ml)) != 0)
913*4eaa4710SRishi Srivatsavai 		trill_fini();
914*4eaa4710SRishi Srivatsavai 	return (rc);
915*4eaa4710SRishi Srivatsavai }
916*4eaa4710SRishi Srivatsavai 
917*4eaa4710SRishi Srivatsavai int
918*4eaa4710SRishi Srivatsavai _info(struct modinfo *modinfop)
919*4eaa4710SRishi Srivatsavai {
920*4eaa4710SRishi Srivatsavai 	return (mod_info(&ml, modinfop));
921*4eaa4710SRishi Srivatsavai }
922*4eaa4710SRishi Srivatsavai 
923*4eaa4710SRishi Srivatsavai int
924*4eaa4710SRishi Srivatsavai _fini(void)
925*4eaa4710SRishi Srivatsavai {
926*4eaa4710SRishi Srivatsavai 	int rc;
927*4eaa4710SRishi Srivatsavai 
928*4eaa4710SRishi Srivatsavai 	rw_enter(&trill_inst_rwlock, RW_READER);
929*4eaa4710SRishi Srivatsavai 	rc = list_is_empty(&trill_inst_list) ? 0 : EBUSY;
930*4eaa4710SRishi Srivatsavai 	rw_exit(&trill_inst_rwlock);
931*4eaa4710SRishi Srivatsavai 	if (rc == 0 && ((rc = mod_remove(&ml)) == 0))
932*4eaa4710SRishi Srivatsavai 		trill_fini();
933*4eaa4710SRishi Srivatsavai 	return (rc);
934*4eaa4710SRishi Srivatsavai }
935*4eaa4710SRishi Srivatsavai 
936*4eaa4710SRishi Srivatsavai static void
937*4eaa4710SRishi Srivatsavai trill_kstats_init(trill_sock_t *tsock, const char *bname)
938*4eaa4710SRishi Srivatsavai {
939*4eaa4710SRishi Srivatsavai 	int i;
940*4eaa4710SRishi Srivatsavai 	char kstatname[KSTAT_STRLEN];
941*4eaa4710SRishi Srivatsavai 	kstat_named_t  *knt;
942*4eaa4710SRishi Srivatsavai 	static const char *sock_kstats_list[] = { TRILL_KSSOCK_NAMES };
943*4eaa4710SRishi Srivatsavai 	char link_name[MAXNAMELEN];
944*4eaa4710SRishi Srivatsavai 	int num;
945*4eaa4710SRishi Srivatsavai 	int err;
946*4eaa4710SRishi Srivatsavai 
947*4eaa4710SRishi Srivatsavai 	bzero(link_name, sizeof (link_name));
948*4eaa4710SRishi Srivatsavai 	if ((err = dls_mgmt_get_linkinfo(tsock->ts_link->bl_linkid, link_name,
949*4eaa4710SRishi Srivatsavai 	    NULL, NULL, NULL)) != 0) {
950*4eaa4710SRishi Srivatsavai 		cmn_err(CE_WARN, "%s: trill_kstats_init: error %d retrieving"
951*4eaa4710SRishi Srivatsavai 		    " linkinfo for linkid:%d", "trill", err,
952*4eaa4710SRishi Srivatsavai 		    tsock->ts_link->bl_linkid);
953*4eaa4710SRishi Srivatsavai 		return;
954*4eaa4710SRishi Srivatsavai 	}
955*4eaa4710SRishi Srivatsavai 
956*4eaa4710SRishi Srivatsavai 	bzero(kstatname, sizeof (kstatname));
957*4eaa4710SRishi Srivatsavai 	(void) snprintf(kstatname, sizeof (kstatname), "%s-%s",
958*4eaa4710SRishi Srivatsavai 	    bname, link_name);
959*4eaa4710SRishi Srivatsavai 
960*4eaa4710SRishi Srivatsavai 	num = sizeof (sock_kstats_list) / sizeof (*sock_kstats_list);
961*4eaa4710SRishi Srivatsavai 	for (i = 0; i < num; i++) {
962*4eaa4710SRishi Srivatsavai 		knt = (kstat_named_t *)&(tsock->ts_kstats);
963*4eaa4710SRishi Srivatsavai 		kstat_named_init(&knt[i], sock_kstats_list[i],
964*4eaa4710SRishi Srivatsavai 		    KSTAT_DATA_UINT64);
965*4eaa4710SRishi Srivatsavai 	}
966*4eaa4710SRishi Srivatsavai 
967*4eaa4710SRishi Srivatsavai 	tsock->ts_ksp = kstat_create_zone("trill", 0, kstatname, "sock",
968*4eaa4710SRishi Srivatsavai 	    KSTAT_TYPE_NAMED, num, KSTAT_FLAG_VIRTUAL, GLOBAL_ZONEID);
969*4eaa4710SRishi Srivatsavai 	if (tsock->ts_ksp != NULL) {
970*4eaa4710SRishi Srivatsavai 		tsock->ts_ksp->ks_data = &tsock->ts_kstats;
971*4eaa4710SRishi Srivatsavai 		kstat_install(tsock->ts_ksp);
972*4eaa4710SRishi Srivatsavai 	}
973*4eaa4710SRishi Srivatsavai }
974*4eaa4710SRishi Srivatsavai 
975*4eaa4710SRishi Srivatsavai static trill_sock_t *
976*4eaa4710SRishi Srivatsavai trill_do_open(int flags)
977*4eaa4710SRishi Srivatsavai {
978*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock;
979*4eaa4710SRishi Srivatsavai 	int kmflag = ((flags & SOCKET_NOSLEEP)) ? KM_NOSLEEP:KM_SLEEP;
980*4eaa4710SRishi Srivatsavai 
981*4eaa4710SRishi Srivatsavai 	tsock = kmem_zalloc(sizeof (trill_sock_t), kmflag);
982*4eaa4710SRishi Srivatsavai 	if (tsock != NULL) {
983*4eaa4710SRishi Srivatsavai 		tsock->ts_state = TS_UNBND;
984*4eaa4710SRishi Srivatsavai 		tsock->ts_refs++;
985*4eaa4710SRishi Srivatsavai 		mutex_init(&tsock->ts_socklock, NULL, MUTEX_DRIVER, NULL);
986*4eaa4710SRishi Srivatsavai 		cv_init(&tsock->ts_sockthreadwait, NULL, CV_DRIVER, NULL);
987*4eaa4710SRishi Srivatsavai 		cv_init(&tsock->ts_sockclosewait, NULL, CV_DRIVER, NULL);
988*4eaa4710SRishi Srivatsavai 	}
989*4eaa4710SRishi Srivatsavai 	return (tsock);
990*4eaa4710SRishi Srivatsavai }
991*4eaa4710SRishi Srivatsavai 
992*4eaa4710SRishi Srivatsavai static int
993*4eaa4710SRishi Srivatsavai trill_find_bridge(trill_sock_t *tsock, const char *bname, boolean_t can_create)
994*4eaa4710SRishi Srivatsavai {
995*4eaa4710SRishi Srivatsavai 	trill_inst_t *tip, *newtip = NULL;
996*4eaa4710SRishi Srivatsavai 
997*4eaa4710SRishi Srivatsavai 	/* Allocate some memory (speculatively) before taking locks */
998*4eaa4710SRishi Srivatsavai 	if (can_create)
999*4eaa4710SRishi Srivatsavai 		newtip = kmem_zalloc(sizeof (*tip), KM_NOSLEEP);
1000*4eaa4710SRishi Srivatsavai 
1001*4eaa4710SRishi Srivatsavai 	rw_enter(&trill_inst_rwlock, RW_WRITER);
1002*4eaa4710SRishi Srivatsavai 	for (tip = list_head(&trill_inst_list); tip != NULL;
1003*4eaa4710SRishi Srivatsavai 	    tip = list_next(&trill_inst_list, tip)) {
1004*4eaa4710SRishi Srivatsavai 		if (strcmp(tip->ti_bridgename, bname) == 0)
1005*4eaa4710SRishi Srivatsavai 			break;
1006*4eaa4710SRishi Srivatsavai 	}
1007*4eaa4710SRishi Srivatsavai 	if (tip == NULL) {
1008*4eaa4710SRishi Srivatsavai 		if (!can_create || newtip == NULL) {
1009*4eaa4710SRishi Srivatsavai 			rw_exit(&trill_inst_rwlock);
1010*4eaa4710SRishi Srivatsavai 			return (can_create ? ENOMEM : ENOENT);
1011*4eaa4710SRishi Srivatsavai 		}
1012*4eaa4710SRishi Srivatsavai 
1013*4eaa4710SRishi Srivatsavai 		tip = newtip;
1014*4eaa4710SRishi Srivatsavai 		newtip = NULL;
1015*4eaa4710SRishi Srivatsavai 		(void) strcpy(tip->ti_bridgename, bname);
1016*4eaa4710SRishi Srivatsavai 
1017*4eaa4710SRishi Srivatsavai 		/* Register TRILL instance with bridging */
1018*4eaa4710SRishi Srivatsavai 		tip->ti_binst = bridge_trill_brref(bname, tip);
1019*4eaa4710SRishi Srivatsavai 		if (tip->ti_binst == NULL) {
1020*4eaa4710SRishi Srivatsavai 			rw_exit(&trill_inst_rwlock);
1021*4eaa4710SRishi Srivatsavai 			kmem_free(tip, sizeof (*tip));
1022*4eaa4710SRishi Srivatsavai 			return (ENOENT);
1023*4eaa4710SRishi Srivatsavai 		}
1024*4eaa4710SRishi Srivatsavai 
1025*4eaa4710SRishi Srivatsavai 		rw_init(&tip->ti_rwlock, NULL, RW_DRIVER, NULL);
1026*4eaa4710SRishi Srivatsavai 		list_create(&tip->ti_socklist, sizeof (trill_sock_t),
1027*4eaa4710SRishi Srivatsavai 		    offsetof(trill_sock_t, ts_socklistnode));
1028*4eaa4710SRishi Srivatsavai 		list_insert_tail(&trill_inst_list, tip);
1029*4eaa4710SRishi Srivatsavai 	}
1030*4eaa4710SRishi Srivatsavai 	atomic_inc_uint(&tip->ti_refs);
1031*4eaa4710SRishi Srivatsavai 	rw_exit(&trill_inst_rwlock);
1032*4eaa4710SRishi Srivatsavai 
1033*4eaa4710SRishi Srivatsavai 	/* If we didn't need the preallocated memory, then discard now. */
1034*4eaa4710SRishi Srivatsavai 	if (newtip != NULL)
1035*4eaa4710SRishi Srivatsavai 		kmem_free(newtip, sizeof (*newtip));
1036*4eaa4710SRishi Srivatsavai 
1037*4eaa4710SRishi Srivatsavai 	rw_enter(&tip->ti_rwlock, RW_WRITER);
1038*4eaa4710SRishi Srivatsavai 	list_insert_tail(&(tip->ti_socklist), tsock);
1039*4eaa4710SRishi Srivatsavai 	tsock->ts_tip = tip;
1040*4eaa4710SRishi Srivatsavai 	rw_exit(&tip->ti_rwlock);
1041*4eaa4710SRishi Srivatsavai 	return (0);
1042*4eaa4710SRishi Srivatsavai }
1043*4eaa4710SRishi Srivatsavai 
1044*4eaa4710SRishi Srivatsavai static void
1045*4eaa4710SRishi Srivatsavai trill_clear_bridge(trill_sock_t *tsock)
1046*4eaa4710SRishi Srivatsavai {
1047*4eaa4710SRishi Srivatsavai 	trill_inst_t *tip;
1048*4eaa4710SRishi Srivatsavai 
1049*4eaa4710SRishi Srivatsavai 	if ((tip = tsock->ts_tip) == NULL)
1050*4eaa4710SRishi Srivatsavai 		return;
1051*4eaa4710SRishi Srivatsavai 	rw_enter(&tip->ti_rwlock, RW_WRITER);
1052*4eaa4710SRishi Srivatsavai 	list_remove(&tip->ti_socklist, tsock);
1053*4eaa4710SRishi Srivatsavai 	if (list_is_empty(&tip->ti_socklist))
1054*4eaa4710SRishi Srivatsavai 		trill_del_all(tip, B_TRUE);
1055*4eaa4710SRishi Srivatsavai 	rw_exit(&tip->ti_rwlock);
1056*4eaa4710SRishi Srivatsavai }
1057*4eaa4710SRishi Srivatsavai 
1058*4eaa4710SRishi Srivatsavai static void
1059*4eaa4710SRishi Srivatsavai trill_sock_unref(trill_sock_t *tsock)
1060*4eaa4710SRishi Srivatsavai {
1061*4eaa4710SRishi Srivatsavai 	if (atomic_dec_uint_nv(&tsock->ts_refs) == 0) {
1062*4eaa4710SRishi Srivatsavai 		mutex_destroy(&tsock->ts_socklock);
1063*4eaa4710SRishi Srivatsavai 		cv_destroy(&tsock->ts_sockthreadwait);
1064*4eaa4710SRishi Srivatsavai 		cv_destroy(&tsock->ts_sockclosewait);
1065*4eaa4710SRishi Srivatsavai 		kmem_free(tsock, sizeof (trill_sock_t));
1066*4eaa4710SRishi Srivatsavai 	}
1067*4eaa4710SRishi Srivatsavai }
1068*4eaa4710SRishi Srivatsavai 
1069*4eaa4710SRishi Srivatsavai static void
1070*4eaa4710SRishi Srivatsavai trill_do_close(trill_sock_t *tsock)
1071*4eaa4710SRishi Srivatsavai {
1072*4eaa4710SRishi Srivatsavai 	trill_inst_t *tip;
1073*4eaa4710SRishi Srivatsavai 
1074*4eaa4710SRishi Srivatsavai 	tip = tsock->ts_tip;
1075*4eaa4710SRishi Srivatsavai 	trill_stop_recv(tsock);
1076*4eaa4710SRishi Srivatsavai 	/* Remove socket from TRILL instance socket list */
1077*4eaa4710SRishi Srivatsavai 	trill_clear_bridge(tsock);
1078*4eaa4710SRishi Srivatsavai 	tsock->ts_flags |= TSF_SHUTDOWN;
1079*4eaa4710SRishi Srivatsavai 	trill_sock_unref(tsock);
1080*4eaa4710SRishi Srivatsavai 	if (tip != NULL)
1081*4eaa4710SRishi Srivatsavai 		trill_instance_unref(tip);
1082*4eaa4710SRishi Srivatsavai }
1083*4eaa4710SRishi Srivatsavai 
1084*4eaa4710SRishi Srivatsavai static void
1085*4eaa4710SRishi Srivatsavai trill_del_all(trill_inst_t *tip, boolean_t lockheld)
1086*4eaa4710SRishi Srivatsavai {
1087*4eaa4710SRishi Srivatsavai 	int i;
1088*4eaa4710SRishi Srivatsavai 
1089*4eaa4710SRishi Srivatsavai 	if (!lockheld)
1090*4eaa4710SRishi Srivatsavai 		rw_enter(&tip->ti_rwlock, RW_WRITER);
1091*4eaa4710SRishi Srivatsavai 	for (i = RBRIDGE_NICKNAME_MIN; i < RBRIDGE_NICKNAME_MAX; i++) {
1092*4eaa4710SRishi Srivatsavai 		if (tip->ti_nodes[i] != NULL)
1093*4eaa4710SRishi Srivatsavai 			(void) trill_del_nick(tip, i, B_TRUE);
1094*4eaa4710SRishi Srivatsavai 	}
1095*4eaa4710SRishi Srivatsavai 	if (!lockheld)
1096*4eaa4710SRishi Srivatsavai 		rw_exit(&tip->ti_rwlock);
1097*4eaa4710SRishi Srivatsavai }
1098*4eaa4710SRishi Srivatsavai 
1099*4eaa4710SRishi Srivatsavai static void
1100*4eaa4710SRishi Srivatsavai trill_node_free(trill_node_t *nick_entry)
1101*4eaa4710SRishi Srivatsavai {
1102*4eaa4710SRishi Srivatsavai 	trill_nickinfo_t *tni;
1103*4eaa4710SRishi Srivatsavai 
1104*4eaa4710SRishi Srivatsavai 	tni = nick_entry->tn_ni;
1105*4eaa4710SRishi Srivatsavai 	kmem_free(tni, TNI_TOTALSIZE(tni));
1106*4eaa4710SRishi Srivatsavai 	kmem_free(nick_entry, sizeof (trill_node_t));
1107*4eaa4710SRishi Srivatsavai }
1108*4eaa4710SRishi Srivatsavai 
1109*4eaa4710SRishi Srivatsavai static void
1110*4eaa4710SRishi Srivatsavai trill_node_unref(trill_inst_t *tip, trill_node_t *tnp)
1111*4eaa4710SRishi Srivatsavai {
1112*4eaa4710SRishi Srivatsavai 	if (atomic_dec_uint_nv(&tnp->tn_refs) == 0) {
1113*4eaa4710SRishi Srivatsavai 		if (tnp->tn_tsp != NULL)
1114*4eaa4710SRishi Srivatsavai 			trill_sock_unref(tnp->tn_tsp);
1115*4eaa4710SRishi Srivatsavai 		trill_node_free(tnp);
1116*4eaa4710SRishi Srivatsavai 		(void) atomic_dec_uint_nv(&tip->ti_nodecount);
1117*4eaa4710SRishi Srivatsavai 	}
1118*4eaa4710SRishi Srivatsavai }
1119*4eaa4710SRishi Srivatsavai 
1120*4eaa4710SRishi Srivatsavai static trill_node_t *
1121*4eaa4710SRishi Srivatsavai trill_node_lookup(trill_inst_t *tip, uint16_t nick)
1122*4eaa4710SRishi Srivatsavai {
1123*4eaa4710SRishi Srivatsavai 	trill_node_t *nick_entry;
1124*4eaa4710SRishi Srivatsavai 
1125*4eaa4710SRishi Srivatsavai 	if (!VALID_NICK(nick))
1126*4eaa4710SRishi Srivatsavai 		return (NULL);
1127*4eaa4710SRishi Srivatsavai 	rw_enter(&tip->ti_rwlock, RW_READER);
1128*4eaa4710SRishi Srivatsavai 	nick_entry = tip->ti_nodes[nick];
1129*4eaa4710SRishi Srivatsavai 	if (nick_entry != NULL) {
1130*4eaa4710SRishi Srivatsavai 		atomic_inc_uint(&nick_entry->tn_refs);
1131*4eaa4710SRishi Srivatsavai 	}
1132*4eaa4710SRishi Srivatsavai 	rw_exit(&tip->ti_rwlock);
1133*4eaa4710SRishi Srivatsavai 	return (nick_entry);
1134*4eaa4710SRishi Srivatsavai }
1135*4eaa4710SRishi Srivatsavai 
1136*4eaa4710SRishi Srivatsavai static int
1137*4eaa4710SRishi Srivatsavai trill_del_nick(trill_inst_t *tip, uint16_t nick, boolean_t lockheld)
1138*4eaa4710SRishi Srivatsavai {
1139*4eaa4710SRishi Srivatsavai 	trill_node_t *nick_entry;
1140*4eaa4710SRishi Srivatsavai 	int rc = ENOENT;
1141*4eaa4710SRishi Srivatsavai 
1142*4eaa4710SRishi Srivatsavai 	if (!lockheld)
1143*4eaa4710SRishi Srivatsavai 		rw_enter(&tip->ti_rwlock, RW_WRITER);
1144*4eaa4710SRishi Srivatsavai 	if (VALID_NICK(nick)) {
1145*4eaa4710SRishi Srivatsavai 		nick_entry = tip->ti_nodes[nick];
1146*4eaa4710SRishi Srivatsavai 		if (nick_entry != NULL) {
1147*4eaa4710SRishi Srivatsavai 			trill_node_unref(tip, nick_entry);
1148*4eaa4710SRishi Srivatsavai 			tip->ti_nodes[nick] = NULL;
1149*4eaa4710SRishi Srivatsavai 			rc = 0;
1150*4eaa4710SRishi Srivatsavai 		}
1151*4eaa4710SRishi Srivatsavai 	}
1152*4eaa4710SRishi Srivatsavai 	if (!lockheld)
1153*4eaa4710SRishi Srivatsavai 		rw_exit(&tip->ti_rwlock);
1154*4eaa4710SRishi Srivatsavai 	return (rc);
1155*4eaa4710SRishi Srivatsavai }
1156*4eaa4710SRishi Srivatsavai 
1157*4eaa4710SRishi Srivatsavai static int
1158*4eaa4710SRishi Srivatsavai trill_add_nick(trill_inst_t *tip, void *arg, boolean_t self, int mode)
1159*4eaa4710SRishi Srivatsavai {
1160*4eaa4710SRishi Srivatsavai 	uint16_t nick;
1161*4eaa4710SRishi Srivatsavai 	int size;
1162*4eaa4710SRishi Srivatsavai 	trill_node_t *tnode;
1163*4eaa4710SRishi Srivatsavai 	trill_nickinfo_t tnihdr;
1164*4eaa4710SRishi Srivatsavai 
1165*4eaa4710SRishi Srivatsavai 	/* First make sure we have at least the header available */
1166*4eaa4710SRishi Srivatsavai 	if (ddi_copyin(arg, &tnihdr, sizeof (trill_nickinfo_t), mode) != 0)
1167*4eaa4710SRishi Srivatsavai 		return (EFAULT);
1168*4eaa4710SRishi Srivatsavai 
1169*4eaa4710SRishi Srivatsavai 	nick = tnihdr.tni_nick;
1170*4eaa4710SRishi Srivatsavai 	if (!VALID_NICK(nick)) {
1171*4eaa4710SRishi Srivatsavai 		DTRACE_PROBE1(trill__add__nick__bad, trill_nickinfo_t *,
1172*4eaa4710SRishi Srivatsavai 		    &tnihdr);
1173*4eaa4710SRishi Srivatsavai 		return (EINVAL);
1174*4eaa4710SRishi Srivatsavai 	}
1175*4eaa4710SRishi Srivatsavai 
1176*4eaa4710SRishi Srivatsavai 	size = TNI_TOTALSIZE(&tnihdr);
1177*4eaa4710SRishi Srivatsavai 	if (size > TNI_MAXSIZE)
1178*4eaa4710SRishi Srivatsavai 		return (EINVAL);
1179*4eaa4710SRishi Srivatsavai 	tnode = kmem_zalloc(sizeof (trill_node_t), KM_SLEEP);
1180*4eaa4710SRishi Srivatsavai 	tnode->tn_ni = kmem_zalloc(size, KM_SLEEP);
1181*4eaa4710SRishi Srivatsavai 	if (ddi_copyin(arg, tnode->tn_ni, size, mode) != 0) {
1182*4eaa4710SRishi Srivatsavai 		kmem_free(tnode->tn_ni, size);
1183*4eaa4710SRishi Srivatsavai 		kmem_free(tnode, sizeof (trill_node_t));
1184*4eaa4710SRishi Srivatsavai 		return (EFAULT);
1185*4eaa4710SRishi Srivatsavai 	}
1186*4eaa4710SRishi Srivatsavai 
1187*4eaa4710SRishi Srivatsavai 	tnode->tn_refs++;
1188*4eaa4710SRishi Srivatsavai 	rw_enter(&tip->ti_rwlock, RW_WRITER);
1189*4eaa4710SRishi Srivatsavai 	if (tip->ti_nodes[nick] != NULL)
1190*4eaa4710SRishi Srivatsavai 		(void) trill_del_nick(tip, nick, B_TRUE);
1191*4eaa4710SRishi Srivatsavai 
1192*4eaa4710SRishi Srivatsavai 	if (self) {
1193*4eaa4710SRishi Srivatsavai 		tip->ti_nick = nick;
1194*4eaa4710SRishi Srivatsavai 	} else {
1195*4eaa4710SRishi Srivatsavai 		tnode->tn_tsp = find_trill_link(tip,
1196*4eaa4710SRishi Srivatsavai 		    tnode->tn_ni->tni_linkid);
1197*4eaa4710SRishi Srivatsavai 	}
1198*4eaa4710SRishi Srivatsavai 	DTRACE_PROBE2(trill__add__nick, trill_node_t *, tnode,
1199*4eaa4710SRishi Srivatsavai 	    uint16_t, nick);
1200*4eaa4710SRishi Srivatsavai 	tip->ti_nodes[nick] = tnode;
1201*4eaa4710SRishi Srivatsavai 	tip->ti_nodecount++;
1202*4eaa4710SRishi Srivatsavai 	rw_exit(&tip->ti_rwlock);
1203*4eaa4710SRishi Srivatsavai 	return (0);
1204*4eaa4710SRishi Srivatsavai }
1205*4eaa4710SRishi Srivatsavai 
1206*4eaa4710SRishi Srivatsavai static int
1207*4eaa4710SRishi Srivatsavai trill_do_ioctl(trill_sock_t *tsock, int cmd, void *arg, int mode)
1208*4eaa4710SRishi Srivatsavai {
1209*4eaa4710SRishi Srivatsavai 	int error = 0;
1210*4eaa4710SRishi Srivatsavai 	trill_inst_t *tip = tsock->ts_tip;
1211*4eaa4710SRishi Srivatsavai 
1212*4eaa4710SRishi Srivatsavai 	switch (cmd) {
1213*4eaa4710SRishi Srivatsavai 	case TRILL_DESIGVLAN: {
1214*4eaa4710SRishi Srivatsavai 		uint16_t desigvlan;
1215*4eaa4710SRishi Srivatsavai 
1216*4eaa4710SRishi Srivatsavai 		if (ddi_copyin(arg, &desigvlan, sizeof (desigvlan), mode) != 0)
1217*4eaa4710SRishi Srivatsavai 			return (EFAULT);
1218*4eaa4710SRishi Srivatsavai 		tsock->ts_desigvlan = desigvlan;
1219*4eaa4710SRishi Srivatsavai 		break;
1220*4eaa4710SRishi Srivatsavai 	}
1221*4eaa4710SRishi Srivatsavai 	case TRILL_VLANFWDER: {
1222*4eaa4710SRishi Srivatsavai 		uint8_t vlans[TRILL_VLANS_ARRSIZE];
1223*4eaa4710SRishi Srivatsavai 
1224*4eaa4710SRishi Srivatsavai 		if (tsock->ts_link == NULL)
1225*4eaa4710SRishi Srivatsavai 			return (EINVAL);
1226*4eaa4710SRishi Srivatsavai 		if ((ddi_copyin(arg, vlans, sizeof (vlans), mode)) != 0)
1227*4eaa4710SRishi Srivatsavai 			return (EFAULT);
1228*4eaa4710SRishi Srivatsavai 		bridge_trill_setvlans(tsock->ts_link, vlans);
1229*4eaa4710SRishi Srivatsavai 		break;
1230*4eaa4710SRishi Srivatsavai 	}
1231*4eaa4710SRishi Srivatsavai 	case TRILL_SETNICK:
1232*4eaa4710SRishi Srivatsavai 		if (tip == NULL)
1233*4eaa4710SRishi Srivatsavai 			return (EINVAL);
1234*4eaa4710SRishi Srivatsavai 		error = trill_add_nick(tip, arg, B_TRUE, mode);
1235*4eaa4710SRishi Srivatsavai 		break;
1236*4eaa4710SRishi Srivatsavai 
1237*4eaa4710SRishi Srivatsavai 	case TRILL_GETNICK:
1238*4eaa4710SRishi Srivatsavai 		if (tip == NULL)
1239*4eaa4710SRishi Srivatsavai 			return (EINVAL);
1240*4eaa4710SRishi Srivatsavai 		rw_enter(&tip->ti_rwlock, RW_READER);
1241*4eaa4710SRishi Srivatsavai 		if (ddi_copyout(&tip->ti_nick, arg, sizeof (tip->ti_nick),
1242*4eaa4710SRishi Srivatsavai 		    mode) != 0)
1243*4eaa4710SRishi Srivatsavai 			error = EFAULT;
1244*4eaa4710SRishi Srivatsavai 		rw_exit(&tip->ti_rwlock);
1245*4eaa4710SRishi Srivatsavai 		break;
1246*4eaa4710SRishi Srivatsavai 
1247*4eaa4710SRishi Srivatsavai 	case TRILL_ADDNICK:
1248*4eaa4710SRishi Srivatsavai 		if (tip == NULL)
1249*4eaa4710SRishi Srivatsavai 			break;
1250*4eaa4710SRishi Srivatsavai 		error = trill_add_nick(tip, arg, B_FALSE, mode);
1251*4eaa4710SRishi Srivatsavai 		break;
1252*4eaa4710SRishi Srivatsavai 
1253*4eaa4710SRishi Srivatsavai 	case TRILL_DELNICK: {
1254*4eaa4710SRishi Srivatsavai 		uint16_t delnick;
1255*4eaa4710SRishi Srivatsavai 
1256*4eaa4710SRishi Srivatsavai 		if (tip == NULL)
1257*4eaa4710SRishi Srivatsavai 			break;
1258*4eaa4710SRishi Srivatsavai 		if (ddi_copyin(arg, &delnick, sizeof (delnick), mode) != 0)
1259*4eaa4710SRishi Srivatsavai 			return (EFAULT);
1260*4eaa4710SRishi Srivatsavai 		error = trill_del_nick(tip, delnick, B_FALSE);
1261*4eaa4710SRishi Srivatsavai 		break;
1262*4eaa4710SRishi Srivatsavai 	}
1263*4eaa4710SRishi Srivatsavai 	case TRILL_DELALL:
1264*4eaa4710SRishi Srivatsavai 		if (tip == NULL)
1265*4eaa4710SRishi Srivatsavai 			break;
1266*4eaa4710SRishi Srivatsavai 		trill_del_all(tip, B_FALSE);
1267*4eaa4710SRishi Srivatsavai 		break;
1268*4eaa4710SRishi Srivatsavai 
1269*4eaa4710SRishi Srivatsavai 	case TRILL_TREEROOT: {
1270*4eaa4710SRishi Srivatsavai 		uint16_t treeroot;
1271*4eaa4710SRishi Srivatsavai 
1272*4eaa4710SRishi Srivatsavai 		if (tip == NULL)
1273*4eaa4710SRishi Srivatsavai 			break;
1274*4eaa4710SRishi Srivatsavai 		if (ddi_copyin(arg, &treeroot, sizeof (treeroot), mode) != 0)
1275*4eaa4710SRishi Srivatsavai 			return (EFAULT);
1276*4eaa4710SRishi Srivatsavai 		if (!VALID_NICK(treeroot))
1277*4eaa4710SRishi Srivatsavai 			return (EINVAL);
1278*4eaa4710SRishi Srivatsavai 		rw_enter(&tip->ti_rwlock, RW_WRITER);
1279*4eaa4710SRishi Srivatsavai 		tip->ti_treeroot = treeroot;
1280*4eaa4710SRishi Srivatsavai 		rw_exit(&tip->ti_rwlock);
1281*4eaa4710SRishi Srivatsavai 		break;
1282*4eaa4710SRishi Srivatsavai 	}
1283*4eaa4710SRishi Srivatsavai 	case TRILL_HWADDR:
1284*4eaa4710SRishi Srivatsavai 		if (tsock->ts_link == NULL)
1285*4eaa4710SRishi Srivatsavai 			break;
1286*4eaa4710SRishi Srivatsavai 		if (ddi_copyout(tsock->ts_link->bl_local_mac, arg, ETHERADDRL,
1287*4eaa4710SRishi Srivatsavai 		    mode) != 0)
1288*4eaa4710SRishi Srivatsavai 			return (EFAULT);
1289*4eaa4710SRishi Srivatsavai 		break;
1290*4eaa4710SRishi Srivatsavai 
1291*4eaa4710SRishi Srivatsavai 	case TRILL_NEWBRIDGE: {
1292*4eaa4710SRishi Srivatsavai 		char bname[MAXLINKNAMELEN];
1293*4eaa4710SRishi Srivatsavai 
1294*4eaa4710SRishi Srivatsavai 		if (tsock->ts_state != TS_UNBND)
1295*4eaa4710SRishi Srivatsavai 			return (ENOTSUP);
1296*4eaa4710SRishi Srivatsavai 		/* ts_tip can only be set once */
1297*4eaa4710SRishi Srivatsavai 		if (tip != NULL)
1298*4eaa4710SRishi Srivatsavai 			return (EEXIST);
1299*4eaa4710SRishi Srivatsavai 		if (ddi_copyin(arg, bname, sizeof (bname), mode) != 0)
1300*4eaa4710SRishi Srivatsavai 			return (EFAULT);
1301*4eaa4710SRishi Srivatsavai 		bname[MAXLINKNAMELEN-1] = '\0';
1302*4eaa4710SRishi Srivatsavai 		error = trill_find_bridge(tsock, bname, B_TRUE);
1303*4eaa4710SRishi Srivatsavai 		break;
1304*4eaa4710SRishi Srivatsavai 	}
1305*4eaa4710SRishi Srivatsavai 
1306*4eaa4710SRishi Srivatsavai 	case TRILL_GETBRIDGE: {
1307*4eaa4710SRishi Srivatsavai 		char bname[MAXLINKNAMELEN];
1308*4eaa4710SRishi Srivatsavai 
1309*4eaa4710SRishi Srivatsavai 		/* ts_tip can only be set once */
1310*4eaa4710SRishi Srivatsavai 		if (tip != NULL)
1311*4eaa4710SRishi Srivatsavai 			return (EEXIST);
1312*4eaa4710SRishi Srivatsavai 		if (ddi_copyin(arg, bname, sizeof (bname), mode) != 0)
1313*4eaa4710SRishi Srivatsavai 			return (EFAULT);
1314*4eaa4710SRishi Srivatsavai 		bname[MAXLINKNAMELEN - 1] = '\0';
1315*4eaa4710SRishi Srivatsavai 		error = trill_find_bridge(tsock, bname, B_FALSE);
1316*4eaa4710SRishi Srivatsavai 		break;
1317*4eaa4710SRishi Srivatsavai 	}
1318*4eaa4710SRishi Srivatsavai 
1319*4eaa4710SRishi Srivatsavai 	case TRILL_LISTNICK: {
1320*4eaa4710SRishi Srivatsavai 		trill_listnick_t tln;
1321*4eaa4710SRishi Srivatsavai 		trill_node_t *tnp;
1322*4eaa4710SRishi Srivatsavai 		trill_nickinfo_t *tnip;
1323*4eaa4710SRishi Srivatsavai 		uint16_t nick;
1324*4eaa4710SRishi Srivatsavai 
1325*4eaa4710SRishi Srivatsavai 		if (tip == NULL)
1326*4eaa4710SRishi Srivatsavai 			return (EINVAL);
1327*4eaa4710SRishi Srivatsavai 		if (ddi_copyin(arg, &tln, sizeof (tln), mode) != 0)
1328*4eaa4710SRishi Srivatsavai 			return (EFAULT);
1329*4eaa4710SRishi Srivatsavai 		nick = tln.tln_nick;
1330*4eaa4710SRishi Srivatsavai 		if (nick >= RBRIDGE_NICKNAME_MAX) {
1331*4eaa4710SRishi Srivatsavai 			error = EINVAL;
1332*4eaa4710SRishi Srivatsavai 			break;
1333*4eaa4710SRishi Srivatsavai 		}
1334*4eaa4710SRishi Srivatsavai 		rw_enter(&tip->ti_rwlock, RW_READER);
1335*4eaa4710SRishi Srivatsavai 		while (++nick < RBRIDGE_NICKNAME_MAX) {
1336*4eaa4710SRishi Srivatsavai 			if ((tnp = tip->ti_nodes[nick]) != NULL) {
1337*4eaa4710SRishi Srivatsavai 				tnip = tnp->tn_ni;
1338*4eaa4710SRishi Srivatsavai 				ASSERT(nick == tnip->tni_nick);
1339*4eaa4710SRishi Srivatsavai 				tln.tln_nick = nick;
1340*4eaa4710SRishi Srivatsavai 				bcopy(tnip->tni_adjsnpa, tln.tln_nexthop,
1341*4eaa4710SRishi Srivatsavai 				    ETHERADDRL);
1342*4eaa4710SRishi Srivatsavai 				tln.tln_ours = nick == tip->ti_nick;
1343*4eaa4710SRishi Srivatsavai 				if (tln.tln_ours || tnp->tn_tsp == NULL) {
1344*4eaa4710SRishi Srivatsavai 					tln.tln_linkid =
1345*4eaa4710SRishi Srivatsavai 					    DATALINK_INVALID_LINKID;
1346*4eaa4710SRishi Srivatsavai 				} else {
1347*4eaa4710SRishi Srivatsavai 					tln.tln_linkid =
1348*4eaa4710SRishi Srivatsavai 					    tnp->tn_tsp->ts_link->bl_linkid;
1349*4eaa4710SRishi Srivatsavai 				}
1350*4eaa4710SRishi Srivatsavai 				break;
1351*4eaa4710SRishi Srivatsavai 			}
1352*4eaa4710SRishi Srivatsavai 		}
1353*4eaa4710SRishi Srivatsavai 		rw_exit(&tip->ti_rwlock);
1354*4eaa4710SRishi Srivatsavai 		if (nick >= RBRIDGE_NICKNAME_MAX)
1355*4eaa4710SRishi Srivatsavai 			bzero(&tln, sizeof (tln));
1356*4eaa4710SRishi Srivatsavai 		if (ddi_copyout(&tln, arg, sizeof (tln), mode) != 0)
1357*4eaa4710SRishi Srivatsavai 			return (EFAULT);
1358*4eaa4710SRishi Srivatsavai 		break;
1359*4eaa4710SRishi Srivatsavai 	}
1360*4eaa4710SRishi Srivatsavai 
1361*4eaa4710SRishi Srivatsavai 	/*
1362*4eaa4710SRishi Srivatsavai 	 * Port flush: this is used when we lose AF on a port.  We must discard
1363*4eaa4710SRishi Srivatsavai 	 * all regular bridge forwarding entries on this port with the
1364*4eaa4710SRishi Srivatsavai 	 * indicated VLAN.
1365*4eaa4710SRishi Srivatsavai 	 */
1366*4eaa4710SRishi Srivatsavai 	case TRILL_PORTFLUSH: {
1367*4eaa4710SRishi Srivatsavai 		uint16_t vlan = (uint16_t)(uintptr_t)arg;
1368*4eaa4710SRishi Srivatsavai 
1369*4eaa4710SRishi Srivatsavai 		if (tsock->ts_link == NULL)
1370*4eaa4710SRishi Srivatsavai 			return (EINVAL);
1371*4eaa4710SRishi Srivatsavai 		bridge_trill_flush(tsock->ts_link, vlan, B_FALSE);
1372*4eaa4710SRishi Srivatsavai 		break;
1373*4eaa4710SRishi Srivatsavai 	}
1374*4eaa4710SRishi Srivatsavai 
1375*4eaa4710SRishi Srivatsavai 	/*
1376*4eaa4710SRishi Srivatsavai 	 * Nick flush: this is used when we lose AF on a port.  We must discard
1377*4eaa4710SRishi Srivatsavai 	 * all bridge TRILL forwarding entries on this port with the indicated
1378*4eaa4710SRishi Srivatsavai 	 * VLAN.
1379*4eaa4710SRishi Srivatsavai 	 */
1380*4eaa4710SRishi Srivatsavai 	case TRILL_NICKFLUSH: {
1381*4eaa4710SRishi Srivatsavai 		uint16_t vlan = (uint16_t)(uintptr_t)arg;
1382*4eaa4710SRishi Srivatsavai 
1383*4eaa4710SRishi Srivatsavai 		if (tsock->ts_link == NULL)
1384*4eaa4710SRishi Srivatsavai 			return (EINVAL);
1385*4eaa4710SRishi Srivatsavai 		bridge_trill_flush(tsock->ts_link, vlan, B_TRUE);
1386*4eaa4710SRishi Srivatsavai 		break;
1387*4eaa4710SRishi Srivatsavai 	}
1388*4eaa4710SRishi Srivatsavai 
1389*4eaa4710SRishi Srivatsavai 	case TRILL_GETMTU:
1390*4eaa4710SRishi Srivatsavai 		if (tsock->ts_link == NULL)
1391*4eaa4710SRishi Srivatsavai 			break;
1392*4eaa4710SRishi Srivatsavai 		if (ddi_copyout(&tsock->ts_link->bl_maxsdu, arg,
1393*4eaa4710SRishi Srivatsavai 		    sizeof (uint_t), mode) != 0)
1394*4eaa4710SRishi Srivatsavai 			return (EFAULT);
1395*4eaa4710SRishi Srivatsavai 		break;
1396*4eaa4710SRishi Srivatsavai 
1397*4eaa4710SRishi Srivatsavai 	default:
1398*4eaa4710SRishi Srivatsavai 		error = ENOTSUP;
1399*4eaa4710SRishi Srivatsavai 		break;
1400*4eaa4710SRishi Srivatsavai 	}
1401*4eaa4710SRishi Srivatsavai 
1402*4eaa4710SRishi Srivatsavai 	return (error);
1403*4eaa4710SRishi Srivatsavai }
1404*4eaa4710SRishi Srivatsavai 
1405*4eaa4710SRishi Srivatsavai /*
1406*4eaa4710SRishi Srivatsavai  * Sends received packet back upstream on the TRILL socket.
1407*4eaa4710SRishi Srivatsavai  * Consumes passed mblk_t.
1408*4eaa4710SRishi Srivatsavai  */
1409*4eaa4710SRishi Srivatsavai static void
1410*4eaa4710SRishi Srivatsavai trill_ctrl_input(trill_sock_t *tsock, mblk_t *mp, const uint8_t *saddr,
1411*4eaa4710SRishi Srivatsavai     uint16_t tci)
1412*4eaa4710SRishi Srivatsavai {
1413*4eaa4710SRishi Srivatsavai 	int udi_size;
1414*4eaa4710SRishi Srivatsavai 	mblk_t *mp1;
1415*4eaa4710SRishi Srivatsavai 	struct T_unitdata_ind *tudi;
1416*4eaa4710SRishi Srivatsavai 	struct sockaddr_dl *sdl;
1417*4eaa4710SRishi Srivatsavai 	char *lladdr;
1418*4eaa4710SRishi Srivatsavai 	int error;
1419*4eaa4710SRishi Srivatsavai 
1420*4eaa4710SRishi Srivatsavai 	ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN));
1421*4eaa4710SRishi Srivatsavai 	if (tsock->ts_flow_ctrld) {
1422*4eaa4710SRishi Srivatsavai 		freemsg(mp);
1423*4eaa4710SRishi Srivatsavai 		KSPINCR(tks_drops);
1424*4eaa4710SRishi Srivatsavai 		return;
1425*4eaa4710SRishi Srivatsavai 	}
1426*4eaa4710SRishi Srivatsavai 
1427*4eaa4710SRishi Srivatsavai 	udi_size =  sizeof (struct T_unitdata_ind) +
1428*4eaa4710SRishi Srivatsavai 	    sizeof (struct sockaddr_dl);
1429*4eaa4710SRishi Srivatsavai 	mp1 = allocb(udi_size, BPRI_MED);
1430*4eaa4710SRishi Srivatsavai 	if (mp1 == NULL) {
1431*4eaa4710SRishi Srivatsavai 		freemsg(mp);
1432*4eaa4710SRishi Srivatsavai 		KSPINCR(tks_drops);
1433*4eaa4710SRishi Srivatsavai 		return;
1434*4eaa4710SRishi Srivatsavai 	}
1435*4eaa4710SRishi Srivatsavai 
1436*4eaa4710SRishi Srivatsavai 	mp1->b_cont = mp;
1437*4eaa4710SRishi Srivatsavai 	mp = mp1;
1438*4eaa4710SRishi Srivatsavai 	mp->b_datap->db_type = M_PROTO;
1439*4eaa4710SRishi Srivatsavai 	/* LINTED: alignment */
1440*4eaa4710SRishi Srivatsavai 	tudi = (struct T_unitdata_ind *)mp->b_rptr;
1441*4eaa4710SRishi Srivatsavai 	mp->b_wptr = (uchar_t *)tudi + udi_size;
1442*4eaa4710SRishi Srivatsavai 
1443*4eaa4710SRishi Srivatsavai 	tudi->PRIM_type = T_UNITDATA_IND;
1444*4eaa4710SRishi Srivatsavai 	tudi->SRC_length = sizeof (struct sockaddr_dl);
1445*4eaa4710SRishi Srivatsavai 	tudi->SRC_offset = sizeof (struct T_unitdata_ind);
1446*4eaa4710SRishi Srivatsavai 	tudi->OPT_length = 0;
1447*4eaa4710SRishi Srivatsavai 	tudi->OPT_offset = sizeof (struct T_unitdata_ind) +
1448*4eaa4710SRishi Srivatsavai 	    sizeof (struct sockaddr_dl);
1449*4eaa4710SRishi Srivatsavai 
1450*4eaa4710SRishi Srivatsavai 	/* Information of the link on which packet was received. */
1451*4eaa4710SRishi Srivatsavai 	sdl = (struct sockaddr_dl *)&tudi[1];
1452*4eaa4710SRishi Srivatsavai 	(void) memset(sdl, 0, sizeof (struct sockaddr_dl));
1453*4eaa4710SRishi Srivatsavai 	sdl->sdl_family = AF_TRILL;
1454*4eaa4710SRishi Srivatsavai 
1455*4eaa4710SRishi Srivatsavai 	/* LINTED: alignment */
1456*4eaa4710SRishi Srivatsavai 	*(datalink_id_t *)sdl->sdl_data = tsock->ts_link->bl_linkid;
1457*4eaa4710SRishi Srivatsavai 	sdl->sdl_nlen = sizeof (tsock->ts_link->bl_linkid);
1458*4eaa4710SRishi Srivatsavai 
1459*4eaa4710SRishi Srivatsavai 	lladdr = LLADDR(sdl);
1460*4eaa4710SRishi Srivatsavai 	(void) memcpy(lladdr, saddr, ETHERADDRL);
1461*4eaa4710SRishi Srivatsavai 	lladdr += ETHERADDRL;
1462*4eaa4710SRishi Srivatsavai 	sdl->sdl_alen = ETHERADDRL;
1463*4eaa4710SRishi Srivatsavai 
1464*4eaa4710SRishi Srivatsavai 	/* LINTED: alignment */
1465*4eaa4710SRishi Srivatsavai 	*(uint16_t *)lladdr = tci;
1466*4eaa4710SRishi Srivatsavai 	sdl->sdl_slen = sizeof (uint16_t);
1467*4eaa4710SRishi Srivatsavai 
1468*4eaa4710SRishi Srivatsavai 	DTRACE_PROBE2(trill__ctrl__input, trill_sock_t *, tsock, mblk_t *, mp);
1469*4eaa4710SRishi Srivatsavai 	(*tsock->ts_conn_upcalls->su_recv)(tsock->ts_conn_upper_handle,
1470*4eaa4710SRishi Srivatsavai 	    mp, msgdsize(mp), 0, &error, NULL);
1471*4eaa4710SRishi Srivatsavai 
1472*4eaa4710SRishi Srivatsavai 	if (error == ENOSPC) {
1473*4eaa4710SRishi Srivatsavai 		mutex_enter(&tsock->ts_socklock);
1474*4eaa4710SRishi Srivatsavai 		(*tsock->ts_conn_upcalls->su_recv)(tsock->ts_conn_upper_handle,
1475*4eaa4710SRishi Srivatsavai 		    NULL, 0, 0, &error, NULL);
1476*4eaa4710SRishi Srivatsavai 		if (error == ENOSPC)
1477*4eaa4710SRishi Srivatsavai 			tsock->ts_flow_ctrld = B_TRUE;
1478*4eaa4710SRishi Srivatsavai 		mutex_exit(&tsock->ts_socklock);
1479*4eaa4710SRishi Srivatsavai 		KSPINCR(tks_drops);
1480*4eaa4710SRishi Srivatsavai 	} else if (error != 0) {
1481*4eaa4710SRishi Srivatsavai 		KSPINCR(tks_drops);
1482*4eaa4710SRishi Srivatsavai 	} else {
1483*4eaa4710SRishi Srivatsavai 		KSPINCR(tks_recv);
1484*4eaa4710SRishi Srivatsavai 	}
1485*4eaa4710SRishi Srivatsavai 
1486*4eaa4710SRishi Srivatsavai 	DTRACE_PROBE2(trill__ctrl__input__done, trill_sock_t *,
1487*4eaa4710SRishi Srivatsavai 	    tsock, int, error);
1488*4eaa4710SRishi Srivatsavai }
1489*4eaa4710SRishi Srivatsavai 
1490*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1491*4eaa4710SRishi Srivatsavai static void
1492*4eaa4710SRishi Srivatsavai trill_activate(sock_lower_handle_t proto_handle,
1493*4eaa4710SRishi Srivatsavai     sock_upper_handle_t sock_handle, sock_upcalls_t *sock_upcalls,
1494*4eaa4710SRishi Srivatsavai     int flags, cred_t *cr)
1495*4eaa4710SRishi Srivatsavai {
1496*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
1497*4eaa4710SRishi Srivatsavai 	struct sock_proto_props sopp;
1498*4eaa4710SRishi Srivatsavai 
1499*4eaa4710SRishi Srivatsavai 	tsock->ts_conn_upcalls = sock_upcalls;
1500*4eaa4710SRishi Srivatsavai 	tsock->ts_conn_upper_handle = sock_handle;
1501*4eaa4710SRishi Srivatsavai 
1502*4eaa4710SRishi Srivatsavai 	sopp.sopp_flags = SOCKOPT_WROFF | SOCKOPT_RCVHIWAT |
1503*4eaa4710SRishi Srivatsavai 	    SOCKOPT_RCVLOWAT | SOCKOPT_MAXADDRLEN | SOCKOPT_MAXPSZ |
1504*4eaa4710SRishi Srivatsavai 	    SOCKOPT_MAXBLK | SOCKOPT_MINPSZ;
1505*4eaa4710SRishi Srivatsavai 	sopp.sopp_wroff = 0;
1506*4eaa4710SRishi Srivatsavai 	sopp.sopp_rxhiwat = SOCKET_RECVHIWATER;
1507*4eaa4710SRishi Srivatsavai 	sopp.sopp_rxlowat = SOCKET_RECVLOWATER;
1508*4eaa4710SRishi Srivatsavai 	sopp.sopp_maxaddrlen = sizeof (struct sockaddr_dl);
1509*4eaa4710SRishi Srivatsavai 	sopp.sopp_maxpsz = INFPSZ;
1510*4eaa4710SRishi Srivatsavai 	sopp.sopp_maxblk = INFPSZ;
1511*4eaa4710SRishi Srivatsavai 	sopp.sopp_minpsz = 0;
1512*4eaa4710SRishi Srivatsavai 	(*tsock->ts_conn_upcalls->su_set_proto_props)(
1513*4eaa4710SRishi Srivatsavai 	    tsock->ts_conn_upper_handle, &sopp);
1514*4eaa4710SRishi Srivatsavai }
1515*4eaa4710SRishi Srivatsavai 
1516*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1517*4eaa4710SRishi Srivatsavai static int
1518*4eaa4710SRishi Srivatsavai trill_close(sock_lower_handle_t proto_handle, int flags, cred_t *cr)
1519*4eaa4710SRishi Srivatsavai {
1520*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
1521*4eaa4710SRishi Srivatsavai 
1522*4eaa4710SRishi Srivatsavai 	trill_do_close(tsock);
1523*4eaa4710SRishi Srivatsavai 	return (0);
1524*4eaa4710SRishi Srivatsavai }
1525*4eaa4710SRishi Srivatsavai 
1526*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1527*4eaa4710SRishi Srivatsavai static int
1528*4eaa4710SRishi Srivatsavai trill_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa,
1529*4eaa4710SRishi Srivatsavai     socklen_t len, cred_t *cr)
1530*4eaa4710SRishi Srivatsavai {
1531*4eaa4710SRishi Srivatsavai 	int error;
1532*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
1533*4eaa4710SRishi Srivatsavai 
1534*4eaa4710SRishi Srivatsavai 	if (sa == NULL)
1535*4eaa4710SRishi Srivatsavai 		error = trill_do_unbind(tsock);
1536*4eaa4710SRishi Srivatsavai 	else
1537*4eaa4710SRishi Srivatsavai 		error = trill_start_recv(tsock, sa, len);
1538*4eaa4710SRishi Srivatsavai 
1539*4eaa4710SRishi Srivatsavai 	return (error);
1540*4eaa4710SRishi Srivatsavai }
1541*4eaa4710SRishi Srivatsavai 
1542*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1543*4eaa4710SRishi Srivatsavai static int
1544*4eaa4710SRishi Srivatsavai trill_connect(sock_lower_handle_t proto_handle, const struct sockaddr *sa,
1545*4eaa4710SRishi Srivatsavai     socklen_t len, sock_connid_t *id, cred_t *cr)
1546*4eaa4710SRishi Srivatsavai {
1547*4eaa4710SRishi Srivatsavai 	return (EOPNOTSUPP);
1548*4eaa4710SRishi Srivatsavai }
1549*4eaa4710SRishi Srivatsavai 
1550*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1551*4eaa4710SRishi Srivatsavai static int
1552*4eaa4710SRishi Srivatsavai trill_send(sock_lower_handle_t proto_handle, mblk_t *mp, struct nmsghdr *msg,
1553*4eaa4710SRishi Srivatsavai     cred_t *cr)
1554*4eaa4710SRishi Srivatsavai {
1555*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
1556*4eaa4710SRishi Srivatsavai 	struct sockaddr_dl *laddr;
1557*4eaa4710SRishi Srivatsavai 	uint16_t tci;
1558*4eaa4710SRishi Srivatsavai 
1559*4eaa4710SRishi Srivatsavai 	ASSERT(DB_TYPE(mp) == M_DATA);
1560*4eaa4710SRishi Srivatsavai 	ASSERT(!(tsock->ts_flags & TSF_SHUTDOWN));
1561*4eaa4710SRishi Srivatsavai 
1562*4eaa4710SRishi Srivatsavai 	if (msg->msg_name == NULL || msg->msg_namelen != sizeof (*laddr))
1563*4eaa4710SRishi Srivatsavai 		goto eproto;
1564*4eaa4710SRishi Srivatsavai 
1565*4eaa4710SRishi Srivatsavai 	/*
1566*4eaa4710SRishi Srivatsavai 	 * The name is a datalink_id_t, the address is an Ethernet address, and
1567*4eaa4710SRishi Srivatsavai 	 * the selector value is the VLAN ID.
1568*4eaa4710SRishi Srivatsavai 	 */
1569*4eaa4710SRishi Srivatsavai 	laddr = (struct sockaddr_dl *)msg->msg_name;
1570*4eaa4710SRishi Srivatsavai 	if (laddr->sdl_nlen != sizeof (datalink_id_t) ||
1571*4eaa4710SRishi Srivatsavai 	    laddr->sdl_alen != ETHERADDRL ||
1572*4eaa4710SRishi Srivatsavai 	    (laddr->sdl_slen != sizeof (tci) && laddr->sdl_slen != 0))
1573*4eaa4710SRishi Srivatsavai 		goto eproto;
1574*4eaa4710SRishi Srivatsavai 
1575*4eaa4710SRishi Srivatsavai 	mutex_enter(&tsock->ts_socklock);
1576*4eaa4710SRishi Srivatsavai 	if (tsock->ts_state != TS_IDLE || tsock->ts_link == NULL) {
1577*4eaa4710SRishi Srivatsavai 		mutex_exit(&tsock->ts_socklock);
1578*4eaa4710SRishi Srivatsavai 		goto eproto;
1579*4eaa4710SRishi Srivatsavai 	}
1580*4eaa4710SRishi Srivatsavai 	atomic_inc_uint(&tsock->ts_sockthreadcount);
1581*4eaa4710SRishi Srivatsavai 	mutex_exit(&tsock->ts_socklock);
1582*4eaa4710SRishi Srivatsavai 
1583*4eaa4710SRishi Srivatsavai 	/*
1584*4eaa4710SRishi Srivatsavai 	 * Safe to dereference VLAN now, as we've checked the user's specified
1585*4eaa4710SRishi Srivatsavai 	 * values, and alignment is now guaranteed.
1586*4eaa4710SRishi Srivatsavai 	 */
1587*4eaa4710SRishi Srivatsavai 	if (laddr->sdl_slen == 0) {
1588*4eaa4710SRishi Srivatsavai 		tci = TRILL_NO_TCI;
1589*4eaa4710SRishi Srivatsavai 	} else {
1590*4eaa4710SRishi Srivatsavai 		/* LINTED: alignment */
1591*4eaa4710SRishi Srivatsavai 		tci = *(uint16_t *)(LLADDR(laddr) + ETHERADDRL);
1592*4eaa4710SRishi Srivatsavai 	}
1593*4eaa4710SRishi Srivatsavai 
1594*4eaa4710SRishi Srivatsavai 	mp = create_trill_header(tsock, mp, (const uchar_t *)LLADDR(laddr),
1595*4eaa4710SRishi Srivatsavai 	    B_TRUE, B_FALSE, tci, msgdsize(mp));
1596*4eaa4710SRishi Srivatsavai 	if (mp != NULL) {
1597*4eaa4710SRishi Srivatsavai 		mp = bridge_trill_output(tsock->ts_link, mp);
1598*4eaa4710SRishi Srivatsavai 		if (mp == NULL) {
1599*4eaa4710SRishi Srivatsavai 			KSPINCR(tks_sent);
1600*4eaa4710SRishi Srivatsavai 		} else {
1601*4eaa4710SRishi Srivatsavai 			freemsg(mp);
1602*4eaa4710SRishi Srivatsavai 			KSPINCR(tks_drops);
1603*4eaa4710SRishi Srivatsavai 		}
1604*4eaa4710SRishi Srivatsavai 	}
1605*4eaa4710SRishi Srivatsavai 
1606*4eaa4710SRishi Srivatsavai 	/* Wake up any threads blocking on us */
1607*4eaa4710SRishi Srivatsavai 	if (atomic_dec_uint_nv(&tsock->ts_sockthreadcount) == 0)
1608*4eaa4710SRishi Srivatsavai 		cv_broadcast(&tsock->ts_sockthreadwait);
1609*4eaa4710SRishi Srivatsavai 	return (0);
1610*4eaa4710SRishi Srivatsavai 
1611*4eaa4710SRishi Srivatsavai eproto:
1612*4eaa4710SRishi Srivatsavai 	freemsg(mp);
1613*4eaa4710SRishi Srivatsavai 	KSPINCR(tks_drops);
1614*4eaa4710SRishi Srivatsavai 	return (EPROTO);
1615*4eaa4710SRishi Srivatsavai }
1616*4eaa4710SRishi Srivatsavai 
1617*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1618*4eaa4710SRishi Srivatsavai static int
1619*4eaa4710SRishi Srivatsavai trill_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg,
1620*4eaa4710SRishi Srivatsavai     int mode, int32_t *rvalp, cred_t *cr)
1621*4eaa4710SRishi Srivatsavai {
1622*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
1623*4eaa4710SRishi Srivatsavai 	int rc;
1624*4eaa4710SRishi Srivatsavai 
1625*4eaa4710SRishi Srivatsavai 	switch (cmd) {
1626*4eaa4710SRishi Srivatsavai 	/* List of unprivileged TRILL ioctls */
1627*4eaa4710SRishi Srivatsavai 	case TRILL_GETNICK:
1628*4eaa4710SRishi Srivatsavai 	case TRILL_GETBRIDGE:
1629*4eaa4710SRishi Srivatsavai 	case TRILL_LISTNICK:
1630*4eaa4710SRishi Srivatsavai 		break;
1631*4eaa4710SRishi Srivatsavai 	default:
1632*4eaa4710SRishi Srivatsavai 		if (secpolicy_dl_config(cr) != 0)
1633*4eaa4710SRishi Srivatsavai 			return (EPERM);
1634*4eaa4710SRishi Srivatsavai 		break;
1635*4eaa4710SRishi Srivatsavai 	}
1636*4eaa4710SRishi Srivatsavai 
1637*4eaa4710SRishi Srivatsavai 	/* Lock ensures socket state is unchanged during ioctl handling */
1638*4eaa4710SRishi Srivatsavai 	mutex_enter(&tsock->ts_socklock);
1639*4eaa4710SRishi Srivatsavai 	rc = trill_do_ioctl(tsock, cmd, (void *)arg, mode);
1640*4eaa4710SRishi Srivatsavai 	mutex_exit(&tsock->ts_socklock);
1641*4eaa4710SRishi Srivatsavai 	return (rc);
1642*4eaa4710SRishi Srivatsavai }
1643*4eaa4710SRishi Srivatsavai 
1644*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1645*4eaa4710SRishi Srivatsavai static int
1646*4eaa4710SRishi Srivatsavai trill_accept(sock_lower_handle_t lproto_handle,
1647*4eaa4710SRishi Srivatsavai     sock_lower_handle_t eproto_handle, sock_upper_handle_t sock_handle,
1648*4eaa4710SRishi Srivatsavai     cred_t *cr)
1649*4eaa4710SRishi Srivatsavai {
1650*4eaa4710SRishi Srivatsavai 	return (EINVAL);
1651*4eaa4710SRishi Srivatsavai }
1652*4eaa4710SRishi Srivatsavai 
1653*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1654*4eaa4710SRishi Srivatsavai static int
1655*4eaa4710SRishi Srivatsavai trill_listen(sock_lower_handle_t proto_handle, int backlog, cred_t *cr)
1656*4eaa4710SRishi Srivatsavai {
1657*4eaa4710SRishi Srivatsavai 	return (EINVAL);
1658*4eaa4710SRishi Srivatsavai }
1659*4eaa4710SRishi Srivatsavai 
1660*4eaa4710SRishi Srivatsavai static void
1661*4eaa4710SRishi Srivatsavai trill_clr_flowctrl(sock_lower_handle_t proto_handle)
1662*4eaa4710SRishi Srivatsavai {
1663*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock = (trill_sock_t *)proto_handle;
1664*4eaa4710SRishi Srivatsavai 
1665*4eaa4710SRishi Srivatsavai 	mutex_enter(&tsock->ts_socklock);
1666*4eaa4710SRishi Srivatsavai 	tsock->ts_flow_ctrld = B_FALSE;
1667*4eaa4710SRishi Srivatsavai 	mutex_exit(&tsock->ts_socklock);
1668*4eaa4710SRishi Srivatsavai }
1669*4eaa4710SRishi Srivatsavai 
1670*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1671*4eaa4710SRishi Srivatsavai static int
1672*4eaa4710SRishi Srivatsavai trill_getsockname(sock_lower_handle_t proto_handle, struct sockaddr *addr,
1673*4eaa4710SRishi Srivatsavai     socklen_t *addrlen, cred_t *cr)
1674*4eaa4710SRishi Srivatsavai {
1675*4eaa4710SRishi Srivatsavai 	return (EOPNOTSUPP);
1676*4eaa4710SRishi Srivatsavai }
1677*4eaa4710SRishi Srivatsavai 
1678*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1679*4eaa4710SRishi Srivatsavai static int
1680*4eaa4710SRishi Srivatsavai trill_getpeername(sock_lower_handle_t proto_handle, struct sockaddr *addr,
1681*4eaa4710SRishi Srivatsavai     socklen_t *addrlen, cred_t *cr)
1682*4eaa4710SRishi Srivatsavai {
1683*4eaa4710SRishi Srivatsavai 	return (EOPNOTSUPP);
1684*4eaa4710SRishi Srivatsavai }
1685*4eaa4710SRishi Srivatsavai 
1686*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1687*4eaa4710SRishi Srivatsavai static int
1688*4eaa4710SRishi Srivatsavai trill_getsockopt(sock_lower_handle_t proto_handle, int level, int option_name,
1689*4eaa4710SRishi Srivatsavai     void *optvalp, socklen_t *optlen, cred_t *cr)
1690*4eaa4710SRishi Srivatsavai {
1691*4eaa4710SRishi Srivatsavai 	return (EOPNOTSUPP);
1692*4eaa4710SRishi Srivatsavai }
1693*4eaa4710SRishi Srivatsavai 
1694*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1695*4eaa4710SRishi Srivatsavai static int
1696*4eaa4710SRishi Srivatsavai trill_setsockopt(sock_lower_handle_t proto_handle, int level, int option_name,
1697*4eaa4710SRishi Srivatsavai     const void *optvalp, socklen_t optlen, cred_t *cr)
1698*4eaa4710SRishi Srivatsavai {
1699*4eaa4710SRishi Srivatsavai 	return (EOPNOTSUPP);
1700*4eaa4710SRishi Srivatsavai }
1701*4eaa4710SRishi Srivatsavai 
1702*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1703*4eaa4710SRishi Srivatsavai static int
1704*4eaa4710SRishi Srivatsavai trill_shutdown(sock_lower_handle_t proto_handle, int how, cred_t *cr)
1705*4eaa4710SRishi Srivatsavai {
1706*4eaa4710SRishi Srivatsavai 	return (EOPNOTSUPP);
1707*4eaa4710SRishi Srivatsavai }
1708*4eaa4710SRishi Srivatsavai 
1709*4eaa4710SRishi Srivatsavai static sock_downcalls_t sock_trill_downcalls = {
1710*4eaa4710SRishi Srivatsavai 	trill_activate,		/* sd_activate */
1711*4eaa4710SRishi Srivatsavai 	trill_accept,		/* sd_accept */
1712*4eaa4710SRishi Srivatsavai 	trill_bind,		/* sd_bind */
1713*4eaa4710SRishi Srivatsavai 	trill_listen,		/* sd_listen */
1714*4eaa4710SRishi Srivatsavai 	trill_connect,		/* sd_connect */
1715*4eaa4710SRishi Srivatsavai 	trill_getpeername,	/* sd_getpeername */
1716*4eaa4710SRishi Srivatsavai 	trill_getsockname,	/* sd_getsockname */
1717*4eaa4710SRishi Srivatsavai 	trill_getsockopt,	/* sd_getsockopt */
1718*4eaa4710SRishi Srivatsavai 	trill_setsockopt,	/* sd_setsockopt */
1719*4eaa4710SRishi Srivatsavai 	trill_send,		/* sd_send */
1720*4eaa4710SRishi Srivatsavai 	NULL,			/* sd_send_uio */
1721*4eaa4710SRishi Srivatsavai 	NULL,			/* sd_recv_uio */
1722*4eaa4710SRishi Srivatsavai 	NULL,			/* sd_poll */
1723*4eaa4710SRishi Srivatsavai 	trill_shutdown,		/* sd_shutdown */
1724*4eaa4710SRishi Srivatsavai 	trill_clr_flowctrl,	/* sd_setflowctrl */
1725*4eaa4710SRishi Srivatsavai 	trill_ioctl,		/* sd_ioctl */
1726*4eaa4710SRishi Srivatsavai 	trill_close		/* sd_close */
1727*4eaa4710SRishi Srivatsavai };
1728*4eaa4710SRishi Srivatsavai 
1729*4eaa4710SRishi Srivatsavai /* ARGSUSED */
1730*4eaa4710SRishi Srivatsavai static sock_lower_handle_t
1731*4eaa4710SRishi Srivatsavai trill_create(int family, int type, int proto, sock_downcalls_t **sock_downcalls,
1732*4eaa4710SRishi Srivatsavai     uint_t *smodep, int *errorp, int flags, cred_t *credp)
1733*4eaa4710SRishi Srivatsavai {
1734*4eaa4710SRishi Srivatsavai 	trill_sock_t *tsock;
1735*4eaa4710SRishi Srivatsavai 
1736*4eaa4710SRishi Srivatsavai 	if (family != AF_TRILL || type != SOCK_DGRAM || proto != 0) {
1737*4eaa4710SRishi Srivatsavai 		*errorp = EPROTONOSUPPORT;
1738*4eaa4710SRishi Srivatsavai 		return (NULL);
1739*4eaa4710SRishi Srivatsavai 	}
1740*4eaa4710SRishi Srivatsavai 
1741*4eaa4710SRishi Srivatsavai 	*sock_downcalls = &sock_trill_downcalls;
1742*4eaa4710SRishi Srivatsavai 	*smodep = SM_ATOMIC;
1743*4eaa4710SRishi Srivatsavai 	tsock = trill_do_open(flags);
1744*4eaa4710SRishi Srivatsavai 	*errorp = (tsock != NULL) ? 0:ENOMEM;
1745*4eaa4710SRishi Srivatsavai 	return ((sock_lower_handle_t)tsock);
1746*4eaa4710SRishi Srivatsavai }
1747