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