14eaa4710SRishi Srivatsavai /*
24eaa4710SRishi Srivatsavai * CDDL HEADER START
34eaa4710SRishi Srivatsavai *
44eaa4710SRishi Srivatsavai * The contents of this file are subject to the terms of the
54eaa4710SRishi Srivatsavai * Common Development and Distribution License (the "License").
64eaa4710SRishi Srivatsavai * You may not use this file except in compliance with the License.
74eaa4710SRishi Srivatsavai *
84eaa4710SRishi Srivatsavai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94eaa4710SRishi Srivatsavai * or http://www.opensolaris.org/os/licensing.
104eaa4710SRishi Srivatsavai * See the License for the specific language governing permissions
114eaa4710SRishi Srivatsavai * and limitations under the License.
124eaa4710SRishi Srivatsavai *
134eaa4710SRishi Srivatsavai * When distributing Covered Code, include this CDDL HEADER in each
144eaa4710SRishi Srivatsavai * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154eaa4710SRishi Srivatsavai * If applicable, add the following below this CDDL HEADER, with the
164eaa4710SRishi Srivatsavai * fields enclosed by brackets "[]" replaced with your own identifying
174eaa4710SRishi Srivatsavai * information: Portions Copyright [yyyy] [name of copyright owner]
184eaa4710SRishi Srivatsavai *
194eaa4710SRishi Srivatsavai * CDDL HEADER END
204eaa4710SRishi Srivatsavai */
214eaa4710SRishi Srivatsavai
224eaa4710SRishi Srivatsavai /*
236f40bf67SRishi Srivatsavai * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
244eaa4710SRishi Srivatsavai * Use is subject to license terms.
2548bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
26c61a1653SRyan Zezeski * Copyright 2019 Joyent, Inc.
274eaa4710SRishi Srivatsavai */
284eaa4710SRishi Srivatsavai
294eaa4710SRishi Srivatsavai /*
304eaa4710SRishi Srivatsavai * This module implements a STREAMS driver that provides layer-two (Ethernet)
314eaa4710SRishi Srivatsavai * bridging functionality. The STREAMS interface is used to provide
324eaa4710SRishi Srivatsavai * observability (snoop/wireshark) and control, but not for interface plumbing.
334eaa4710SRishi Srivatsavai */
344eaa4710SRishi Srivatsavai
354eaa4710SRishi Srivatsavai #include <sys/types.h>
364eaa4710SRishi Srivatsavai #include <sys/bitmap.h>
374eaa4710SRishi Srivatsavai #include <sys/cmn_err.h>
384eaa4710SRishi Srivatsavai #include <sys/conf.h>
394eaa4710SRishi Srivatsavai #include <sys/ddi.h>
404eaa4710SRishi Srivatsavai #include <sys/errno.h>
414eaa4710SRishi Srivatsavai #include <sys/kstat.h>
424eaa4710SRishi Srivatsavai #include <sys/modctl.h>
434eaa4710SRishi Srivatsavai #include <sys/note.h>
444eaa4710SRishi Srivatsavai #include <sys/param.h>
45c61a1653SRyan Zezeski #include <sys/pattr.h>
464eaa4710SRishi Srivatsavai #include <sys/policy.h>
474eaa4710SRishi Srivatsavai #include <sys/sdt.h>
484eaa4710SRishi Srivatsavai #include <sys/stat.h>
494eaa4710SRishi Srivatsavai #include <sys/stream.h>
504eaa4710SRishi Srivatsavai #include <sys/stropts.h>
514eaa4710SRishi Srivatsavai #include <sys/strsun.h>
524eaa4710SRishi Srivatsavai #include <sys/sunddi.h>
534eaa4710SRishi Srivatsavai #include <sys/sysmacros.h>
544eaa4710SRishi Srivatsavai #include <sys/systm.h>
554eaa4710SRishi Srivatsavai #include <sys/time.h>
564eaa4710SRishi Srivatsavai #include <sys/dlpi.h>
574eaa4710SRishi Srivatsavai #include <sys/dls.h>
584eaa4710SRishi Srivatsavai #include <sys/mac_ether.h>
594eaa4710SRishi Srivatsavai #include <sys/mac_provider.h>
604eaa4710SRishi Srivatsavai #include <sys/mac_client_priv.h>
614eaa4710SRishi Srivatsavai #include <sys/mac_impl.h>
624eaa4710SRishi Srivatsavai #include <sys/vlan.h>
634eaa4710SRishi Srivatsavai #include <net/bridge.h>
644eaa4710SRishi Srivatsavai #include <net/bridge_impl.h>
654eaa4710SRishi Srivatsavai #include <net/trill.h>
6656a3cd3dSRishi Srivatsavai #include <sys/dld_ioc.h>
674eaa4710SRishi Srivatsavai
684eaa4710SRishi Srivatsavai /*
694eaa4710SRishi Srivatsavai * Locks and reference counts: object lifetime and design.
704eaa4710SRishi Srivatsavai *
714eaa4710SRishi Srivatsavai * bridge_mac_t
724eaa4710SRishi Srivatsavai * Bridge mac (snoop) instances are in bmac_list, which is protected by
734eaa4710SRishi Srivatsavai * bmac_rwlock. They're allocated by bmac_alloc and freed by bridge_timer().
744eaa4710SRishi Srivatsavai * Every bridge_inst_t has a single bridge_mac_t, but when bridge_inst_t goes
754eaa4710SRishi Srivatsavai * away, the bridge_mac_t remains until either all of the users go away
764eaa4710SRishi Srivatsavai * (detected by a timer) or until the instance is picked up again by the same
774eaa4710SRishi Srivatsavai * bridge starting back up.
784eaa4710SRishi Srivatsavai *
794eaa4710SRishi Srivatsavai * bridge_inst_t
804eaa4710SRishi Srivatsavai * Bridge instances are in inst_list, which is protected by inst_lock.
814eaa4710SRishi Srivatsavai * They're allocated by inst_alloc() and freed by inst_free(). After
824eaa4710SRishi Srivatsavai * allocation, an instance is placed in inst_list, and the reference count is
834eaa4710SRishi Srivatsavai * incremented to represent this. That reference is decremented when the
844eaa4710SRishi Srivatsavai * BIF_SHUTDOWN flag is set, and no new increments may occur. When the last
854eaa4710SRishi Srivatsavai * reference is freed, the instance is removed from the list.
864eaa4710SRishi Srivatsavai *
874eaa4710SRishi Srivatsavai * Bridge instances have lists of links and an AVL tree of forwarding
884eaa4710SRishi Srivatsavai * entries. Each of these structures holds one reference on the bridge
894eaa4710SRishi Srivatsavai * instance. These lists and tree are protected by bi_rwlock.
904eaa4710SRishi Srivatsavai *
914eaa4710SRishi Srivatsavai * bridge_stream_t
924eaa4710SRishi Srivatsavai * Bridge streams are allocated by stream_alloc() and freed by stream_free().
934eaa4710SRishi Srivatsavai * These streams are created when "bridged" opens /dev/bridgectl, and are
944eaa4710SRishi Srivatsavai * used to create new bridge instances (via BRIOC_NEWBRIDGE) and control the
954eaa4710SRishi Srivatsavai * links on the bridge. When a stream closes, the bridge instance created is
964eaa4710SRishi Srivatsavai * destroyed. There's at most one bridge instance for a given control
974eaa4710SRishi Srivatsavai * stream.
984eaa4710SRishi Srivatsavai *
994eaa4710SRishi Srivatsavai * bridge_link_t
1004eaa4710SRishi Srivatsavai * Links are allocated by bridge_add_link() and freed by link_free(). The
1014eaa4710SRishi Srivatsavai * bi_links list holds a reference to the link. When the BLF_DELETED flag is
1024eaa4710SRishi Srivatsavai * set, that reference is dropped. The link isn't removed from the list
1034eaa4710SRishi Srivatsavai * until the last reference drops. Each forwarding entry that uses a given
1044eaa4710SRishi Srivatsavai * link holds a reference, as does each thread transmitting a packet via the
1054eaa4710SRishi Srivatsavai * link. The MAC layer calls in via bridge_ref_cb() to hold a reference on
1064eaa4710SRishi Srivatsavai * a link when transmitting.
1074eaa4710SRishi Srivatsavai *
1084eaa4710SRishi Srivatsavai * It's important that once BLF_DELETED is set, there's no way for the
1094eaa4710SRishi Srivatsavai * reference count to increase again. If it can, then the link may be
1104eaa4710SRishi Srivatsavai * double-freed. The BLF_FREED flag is intended for use with assertions to
1114eaa4710SRishi Srivatsavai * guard against this in testing.
1124eaa4710SRishi Srivatsavai *
1134eaa4710SRishi Srivatsavai * bridge_fwd_t
1144eaa4710SRishi Srivatsavai * Bridge forwarding entries are allocated by bridge_recv_cb() and freed by
1154eaa4710SRishi Srivatsavai * fwd_free(). The bi_fwd AVL tree holds one reference to the entry. Unlike
1164eaa4710SRishi Srivatsavai * other data structures, the reference is dropped when the entry is removed
1174eaa4710SRishi Srivatsavai * from the tree by fwd_delete(), and the BFF_INTREE flag is removed. Each
1184eaa4710SRishi Srivatsavai * thread that's forwarding a packet to a known destination holds a reference
1194eaa4710SRishi Srivatsavai * to a forwarding entry.
1204eaa4710SRishi Srivatsavai *
1214eaa4710SRishi Srivatsavai * TRILL notes:
1224eaa4710SRishi Srivatsavai *
1234eaa4710SRishi Srivatsavai * The TRILL module does all of its I/O through bridging. It uses references
1244eaa4710SRishi Srivatsavai * on the bridge_inst_t and bridge_link_t structures, and has seven entry
1254eaa4710SRishi Srivatsavai * points and four callbacks. One entry point is for setting the callbacks
1264eaa4710SRishi Srivatsavai * (bridge_trill_register_cb). There are four entry points for taking bridge
1274eaa4710SRishi Srivatsavai * and link references (bridge_trill_{br,ln}{ref,unref}). The final two
1284eaa4710SRishi Srivatsavai * entry points are for decapsulated packets from TRILL (bridge_trill_decaps)
1294eaa4710SRishi Srivatsavai * that need to be bridged locally, and for TRILL-encapsulated output packets
1304eaa4710SRishi Srivatsavai * (bridge_trill_output).
1314eaa4710SRishi Srivatsavai *
1324eaa4710SRishi Srivatsavai * The four callbacks comprise two notification functions for bridges and
1334eaa4710SRishi Srivatsavai * links being deleted, one function for raw received TRILL packets, and one
1344eaa4710SRishi Srivatsavai * for bridge output to non-local TRILL destinations (tunnel entry).
1354eaa4710SRishi Srivatsavai */
1364eaa4710SRishi Srivatsavai
1374eaa4710SRishi Srivatsavai /*
1384eaa4710SRishi Srivatsavai * Ethernet reserved multicast addresses for TRILL; used also in TRILL module.
1394eaa4710SRishi Srivatsavai */
1404eaa4710SRishi Srivatsavai const uint8_t all_isis_rbridges[] = ALL_ISIS_RBRIDGES;
1414eaa4710SRishi Srivatsavai static const uint8_t all_esadi_rbridges[] = ALL_ESADI_RBRIDGES;
1424eaa4710SRishi Srivatsavai const uint8_t bridge_group_address[] = BRIDGE_GROUP_ADDRESS;
1434eaa4710SRishi Srivatsavai
1444eaa4710SRishi Srivatsavai static const char *inst_kstats_list[] = { KSINST_NAMES };
1454eaa4710SRishi Srivatsavai static const char *link_kstats_list[] = { KSLINK_NAMES };
1464eaa4710SRishi Srivatsavai
1474eaa4710SRishi Srivatsavai #define KREF(p, m, vn) p->m.vn.value.ui64
1484eaa4710SRishi Srivatsavai #define KINCR(p, m, vn) ++KREF(p, m, vn)
1494eaa4710SRishi Srivatsavai #define KDECR(p, m, vn) --KREF(p, m, vn)
1504eaa4710SRishi Srivatsavai
1514eaa4710SRishi Srivatsavai #define KIPINCR(p, vn) KINCR(p, bi_kstats, vn)
1524eaa4710SRishi Srivatsavai #define KIPDECR(p, vn) KDECR(p, bi_kstats, vn)
1534eaa4710SRishi Srivatsavai #define KLPINCR(p, vn) KINCR(p, bl_kstats, vn)
1544eaa4710SRishi Srivatsavai
1554eaa4710SRishi Srivatsavai #define KIINCR(vn) KIPINCR(bip, vn)
1564eaa4710SRishi Srivatsavai #define KIDECR(vn) KIPDECR(bip, vn)
1574eaa4710SRishi Srivatsavai #define KLINCR(vn) KLPINCR(blp, vn)
1584eaa4710SRishi Srivatsavai
1594eaa4710SRishi Srivatsavai #define Dim(x) (sizeof (x) / sizeof (*(x)))
1604eaa4710SRishi Srivatsavai
1614eaa4710SRishi Srivatsavai /* Amount of overhead added when encapsulating with VLAN headers */
1624eaa4710SRishi Srivatsavai #define VLAN_INCR (sizeof (struct ether_vlan_header) - \
1634eaa4710SRishi Srivatsavai sizeof (struct ether_header))
1644eaa4710SRishi Srivatsavai
1654eaa4710SRishi Srivatsavai static dev_info_t *bridge_dev_info;
1664eaa4710SRishi Srivatsavai static major_t bridge_major;
1674eaa4710SRishi Srivatsavai static ddi_taskq_t *bridge_taskq;
1684eaa4710SRishi Srivatsavai
1694eaa4710SRishi Srivatsavai /*
1704eaa4710SRishi Srivatsavai * These are the bridge instance management data structures. The mutex lock
1714eaa4710SRishi Srivatsavai * protects the list of bridge instances. A reference count is then used on
1724eaa4710SRishi Srivatsavai * each instance to determine when to free it. We use mac_minor_hold() to
1734eaa4710SRishi Srivatsavai * allocate minor_t values, which are used both for self-cloning /dev/net/
1744eaa4710SRishi Srivatsavai * device nodes as well as client streams. Minor node 0 is reserved for the
1754eaa4710SRishi Srivatsavai * allocation control node.
1764eaa4710SRishi Srivatsavai */
1774eaa4710SRishi Srivatsavai static list_t inst_list;
1784eaa4710SRishi Srivatsavai static kcondvar_t inst_cv; /* Allows us to wait for shutdown */
1794eaa4710SRishi Srivatsavai static kmutex_t inst_lock;
1804eaa4710SRishi Srivatsavai
1814eaa4710SRishi Srivatsavai static krwlock_t bmac_rwlock;
1824eaa4710SRishi Srivatsavai static list_t bmac_list;
1834eaa4710SRishi Srivatsavai
1844eaa4710SRishi Srivatsavai /* Wait for taskq entries that use STREAMS */
1854eaa4710SRishi Srivatsavai static kcondvar_t stream_ref_cv;
1864eaa4710SRishi Srivatsavai static kmutex_t stream_ref_lock;
1874eaa4710SRishi Srivatsavai
1884eaa4710SRishi Srivatsavai static timeout_id_t bridge_timerid;
1894eaa4710SRishi Srivatsavai static clock_t bridge_scan_interval;
1904eaa4710SRishi Srivatsavai static clock_t bridge_fwd_age;
1914eaa4710SRishi Srivatsavai
1924eaa4710SRishi Srivatsavai static bridge_inst_t *bridge_find_name(const char *);
1934eaa4710SRishi Srivatsavai static void bridge_timer(void *);
1944eaa4710SRishi Srivatsavai static void bridge_unref(bridge_inst_t *);
1954eaa4710SRishi Srivatsavai
1964eaa4710SRishi Srivatsavai static const uint8_t zero_addr[ETHERADDRL] = { 0 };
1974eaa4710SRishi Srivatsavai
1984eaa4710SRishi Srivatsavai /* Global TRILL linkage */
1994eaa4710SRishi Srivatsavai static trill_recv_pkt_t trill_recv_fn;
2004eaa4710SRishi Srivatsavai static trill_encap_pkt_t trill_encap_fn;
2014eaa4710SRishi Srivatsavai static trill_br_dstr_t trill_brdstr_fn;
2024eaa4710SRishi Srivatsavai static trill_ln_dstr_t trill_lndstr_fn;
2034eaa4710SRishi Srivatsavai
2044eaa4710SRishi Srivatsavai /* special settings to accommodate DLD flow control; see dld_str.c */
2054eaa4710SRishi Srivatsavai static struct module_info bridge_dld_modinfo = {
2064eaa4710SRishi Srivatsavai 0, /* mi_idnum */
207f2905fb7SRishi Srivatsavai BRIDGE_DEV_NAME, /* mi_idname */
2084eaa4710SRishi Srivatsavai 0, /* mi_minpsz */
2094eaa4710SRishi Srivatsavai INFPSZ, /* mi_maxpsz */
2104eaa4710SRishi Srivatsavai 1, /* mi_hiwat */
2114eaa4710SRishi Srivatsavai 0 /* mi_lowat */
2124eaa4710SRishi Srivatsavai };
2134eaa4710SRishi Srivatsavai
2144eaa4710SRishi Srivatsavai static struct qinit bridge_dld_rinit = {
2154eaa4710SRishi Srivatsavai NULL, /* qi_putp */
2164eaa4710SRishi Srivatsavai NULL, /* qi_srvp */
2174eaa4710SRishi Srivatsavai dld_open, /* qi_qopen */
2184eaa4710SRishi Srivatsavai dld_close, /* qi_qclose */
2194eaa4710SRishi Srivatsavai NULL, /* qi_qadmin */
2204eaa4710SRishi Srivatsavai &bridge_dld_modinfo, /* qi_minfo */
2214eaa4710SRishi Srivatsavai NULL /* qi_mstat */
2224eaa4710SRishi Srivatsavai };
2234eaa4710SRishi Srivatsavai
2244eaa4710SRishi Srivatsavai static struct qinit bridge_dld_winit = {
225f1ccfd86SToomas Soome dld_wput, /* qi_putp */
226f1ccfd86SToomas Soome dld_wsrv, /* qi_srvp */
2274eaa4710SRishi Srivatsavai NULL, /* qi_qopen */
2284eaa4710SRishi Srivatsavai NULL, /* qi_qclose */
2294eaa4710SRishi Srivatsavai NULL, /* qi_qadmin */
2304eaa4710SRishi Srivatsavai &bridge_dld_modinfo, /* qi_minfo */
2314eaa4710SRishi Srivatsavai NULL /* qi_mstat */
2324eaa4710SRishi Srivatsavai };
2334eaa4710SRishi Srivatsavai
2344eaa4710SRishi Srivatsavai static int bridge_ioc_listfwd(void *, intptr_t, int, cred_t *, int *);
2354eaa4710SRishi Srivatsavai
2364eaa4710SRishi Srivatsavai /* GLDv3 control ioctls used by Bridging */
2374eaa4710SRishi Srivatsavai static dld_ioc_info_t bridge_ioc_list[] = {
2384eaa4710SRishi Srivatsavai {BRIDGE_IOC_LISTFWD, DLDCOPYINOUT, sizeof (bridge_listfwd_t),
2394eaa4710SRishi Srivatsavai bridge_ioc_listfwd, NULL},
2404eaa4710SRishi Srivatsavai };
2414eaa4710SRishi Srivatsavai
2424eaa4710SRishi Srivatsavai /*
2434eaa4710SRishi Srivatsavai * Given a bridge mac pointer, get a ref-held pointer to the corresponding
2444eaa4710SRishi Srivatsavai * bridge instance, if any. We must hold the global bmac_rwlock so that
2454eaa4710SRishi Srivatsavai * bm_inst doesn't slide out from under us.
2464eaa4710SRishi Srivatsavai */
2474eaa4710SRishi Srivatsavai static bridge_inst_t *
mac_to_inst(const bridge_mac_t * bmp)2484eaa4710SRishi Srivatsavai mac_to_inst(const bridge_mac_t *bmp)
2494eaa4710SRishi Srivatsavai {
2504eaa4710SRishi Srivatsavai bridge_inst_t *bip;
2514eaa4710SRishi Srivatsavai
2524eaa4710SRishi Srivatsavai rw_enter(&bmac_rwlock, RW_READER);
2534eaa4710SRishi Srivatsavai if ((bip = bmp->bm_inst) != NULL)
2544eaa4710SRishi Srivatsavai atomic_inc_uint(&bip->bi_refs);
2554eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock);
2564eaa4710SRishi Srivatsavai return (bip);
2574eaa4710SRishi Srivatsavai }
2584eaa4710SRishi Srivatsavai
2594eaa4710SRishi Srivatsavai static void
link_sdu_fail(bridge_link_t * blp,boolean_t failed,mblk_t ** mlist)2604eaa4710SRishi Srivatsavai link_sdu_fail(bridge_link_t *blp, boolean_t failed, mblk_t **mlist)
2614eaa4710SRishi Srivatsavai {
2624eaa4710SRishi Srivatsavai mblk_t *mp;
2634eaa4710SRishi Srivatsavai bridge_ctl_t *bcp;
2644eaa4710SRishi Srivatsavai bridge_link_t *blcmp;
2654eaa4710SRishi Srivatsavai bridge_inst_t *bip;
2664eaa4710SRishi Srivatsavai bridge_mac_t *bmp;
2674eaa4710SRishi Srivatsavai
2684eaa4710SRishi Srivatsavai if (failed) {
2694eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_SDUFAIL)
2704eaa4710SRishi Srivatsavai return;
2714eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_SDUFAIL;
2724eaa4710SRishi Srivatsavai } else {
2734eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_SDUFAIL))
2744eaa4710SRishi Srivatsavai return;
2754eaa4710SRishi Srivatsavai blp->bl_flags &= ~BLF_SDUFAIL;
2764eaa4710SRishi Srivatsavai }
2774eaa4710SRishi Srivatsavai
2784eaa4710SRishi Srivatsavai /*
2794eaa4710SRishi Srivatsavai * If this link is otherwise up, then check if there are any other
2804eaa4710SRishi Srivatsavai * non-failed non-down links. If not, then we control the state of the
2814eaa4710SRishi Srivatsavai * whole bridge.
2824eaa4710SRishi Srivatsavai */
2834eaa4710SRishi Srivatsavai bip = blp->bl_inst;
2844eaa4710SRishi Srivatsavai bmp = bip->bi_mac;
2854eaa4710SRishi Srivatsavai if (blp->bl_linkstate != LINK_STATE_DOWN) {
2864eaa4710SRishi Srivatsavai for (blcmp = list_head(&bip->bi_links); blcmp != NULL;
2874eaa4710SRishi Srivatsavai blcmp = list_next(&bip->bi_links, blcmp)) {
2884eaa4710SRishi Srivatsavai if (blp != blcmp &&
2894eaa4710SRishi Srivatsavai !(blcmp->bl_flags & (BLF_DELETED|BLF_SDUFAIL)) &&
2904eaa4710SRishi Srivatsavai blcmp->bl_linkstate != LINK_STATE_DOWN)
2914eaa4710SRishi Srivatsavai break;
2924eaa4710SRishi Srivatsavai }
2934eaa4710SRishi Srivatsavai if (blcmp == NULL) {
2944eaa4710SRishi Srivatsavai bmp->bm_linkstate = failed ? LINK_STATE_DOWN :
2954eaa4710SRishi Srivatsavai LINK_STATE_UP;
2964eaa4710SRishi Srivatsavai mac_link_redo(bmp->bm_mh, bmp->bm_linkstate);
2974eaa4710SRishi Srivatsavai }
2984eaa4710SRishi Srivatsavai }
2994eaa4710SRishi Srivatsavai
3004eaa4710SRishi Srivatsavai /*
3014eaa4710SRishi Srivatsavai * If we're becoming failed, then the link's current true state needs
3024eaa4710SRishi Srivatsavai * to be reflected upwards to this link's clients. If we're becoming
3034eaa4710SRishi Srivatsavai * unfailed, then we get the state of the bridge instead on all
3044eaa4710SRishi Srivatsavai * clients.
3054eaa4710SRishi Srivatsavai */
3064eaa4710SRishi Srivatsavai if (failed) {
3074eaa4710SRishi Srivatsavai if (bmp->bm_linkstate != blp->bl_linkstate)
3084eaa4710SRishi Srivatsavai mac_link_redo(blp->bl_mh, blp->bl_linkstate);
3094eaa4710SRishi Srivatsavai } else {
3104eaa4710SRishi Srivatsavai mac_link_redo(blp->bl_mh, bmp->bm_linkstate);
3114eaa4710SRishi Srivatsavai }
3124eaa4710SRishi Srivatsavai
3134eaa4710SRishi Srivatsavai /* get the current mblk we're going to send up */
3144eaa4710SRishi Srivatsavai if ((mp = blp->bl_lfailmp) == NULL &&
3154eaa4710SRishi Srivatsavai (mp = allocb(sizeof (bridge_ctl_t), BPRI_MED)) == NULL)
3164eaa4710SRishi Srivatsavai return;
3174eaa4710SRishi Srivatsavai
3184eaa4710SRishi Srivatsavai /* get a new one for next time */
3194eaa4710SRishi Srivatsavai blp->bl_lfailmp = allocb(sizeof (bridge_ctl_t), BPRI_MED);
3204eaa4710SRishi Srivatsavai
3214eaa4710SRishi Srivatsavai /* if none for next time, then report only failures */
3224eaa4710SRishi Srivatsavai if (blp->bl_lfailmp == NULL && !failed) {
3234eaa4710SRishi Srivatsavai blp->bl_lfailmp = mp;
3244eaa4710SRishi Srivatsavai return;
3254eaa4710SRishi Srivatsavai }
3264eaa4710SRishi Srivatsavai
3274eaa4710SRishi Srivatsavai /* LINTED: alignment */
3284eaa4710SRishi Srivatsavai bcp = (bridge_ctl_t *)mp->b_rptr;
3294eaa4710SRishi Srivatsavai bcp->bc_linkid = blp->bl_linkid;
3304eaa4710SRishi Srivatsavai bcp->bc_failed = failed;
3314eaa4710SRishi Srivatsavai mp->b_wptr = (uchar_t *)(bcp + 1);
3324eaa4710SRishi Srivatsavai mp->b_next = *mlist;
3334eaa4710SRishi Srivatsavai *mlist = mp;
3344eaa4710SRishi Srivatsavai }
3354eaa4710SRishi Srivatsavai
3364eaa4710SRishi Srivatsavai /*
3374eaa4710SRishi Srivatsavai * Send control messages (link SDU changes) using the stream to the
3384eaa4710SRishi Srivatsavai * bridge instance daemon.
3394eaa4710SRishi Srivatsavai */
3404eaa4710SRishi Srivatsavai static void
send_up_messages(bridge_inst_t * bip,mblk_t * mp)3414eaa4710SRishi Srivatsavai send_up_messages(bridge_inst_t *bip, mblk_t *mp)
3424eaa4710SRishi Srivatsavai {
3434eaa4710SRishi Srivatsavai mblk_t *mnext;
3444eaa4710SRishi Srivatsavai queue_t *rq;
3454eaa4710SRishi Srivatsavai
3464eaa4710SRishi Srivatsavai rq = bip->bi_control->bs_wq;
3474eaa4710SRishi Srivatsavai rq = OTHERQ(rq);
3484eaa4710SRishi Srivatsavai while (mp != NULL) {
3494eaa4710SRishi Srivatsavai mnext = mp->b_next;
3504eaa4710SRishi Srivatsavai mp->b_next = NULL;
3514eaa4710SRishi Srivatsavai putnext(rq, mp);
3524eaa4710SRishi Srivatsavai mp = mnext;
3534eaa4710SRishi Srivatsavai }
3544eaa4710SRishi Srivatsavai }
3554eaa4710SRishi Srivatsavai
3564eaa4710SRishi Srivatsavai /* ARGSUSED */
3574eaa4710SRishi Srivatsavai static int
bridge_m_getstat(void * arg,uint_t stat,uint64_t * val)3584eaa4710SRishi Srivatsavai bridge_m_getstat(void *arg, uint_t stat, uint64_t *val)
3594eaa4710SRishi Srivatsavai {
3604eaa4710SRishi Srivatsavai return (ENOTSUP);
3614eaa4710SRishi Srivatsavai }
3624eaa4710SRishi Srivatsavai
3634eaa4710SRishi Srivatsavai static int
bridge_m_start(void * arg)3644eaa4710SRishi Srivatsavai bridge_m_start(void *arg)
3654eaa4710SRishi Srivatsavai {
3664eaa4710SRishi Srivatsavai bridge_mac_t *bmp = arg;
3674eaa4710SRishi Srivatsavai
3684eaa4710SRishi Srivatsavai bmp->bm_flags |= BMF_STARTED;
3694eaa4710SRishi Srivatsavai return (0);
3704eaa4710SRishi Srivatsavai }
3714eaa4710SRishi Srivatsavai
3724eaa4710SRishi Srivatsavai static void
bridge_m_stop(void * arg)3734eaa4710SRishi Srivatsavai bridge_m_stop(void *arg)
3744eaa4710SRishi Srivatsavai {
3754eaa4710SRishi Srivatsavai bridge_mac_t *bmp = arg;
3764eaa4710SRishi Srivatsavai
3774eaa4710SRishi Srivatsavai bmp->bm_flags &= ~BMF_STARTED;
3784eaa4710SRishi Srivatsavai }
3794eaa4710SRishi Srivatsavai
3804eaa4710SRishi Srivatsavai /* ARGSUSED */
3814eaa4710SRishi Srivatsavai static int
bridge_m_setpromisc(void * arg,boolean_t on)3824eaa4710SRishi Srivatsavai bridge_m_setpromisc(void *arg, boolean_t on)
3834eaa4710SRishi Srivatsavai {
3844eaa4710SRishi Srivatsavai return (0);
3854eaa4710SRishi Srivatsavai }
3864eaa4710SRishi Srivatsavai
3874eaa4710SRishi Srivatsavai /* ARGSUSED */
3884eaa4710SRishi Srivatsavai static int
bridge_m_multicst(void * arg,boolean_t add,const uint8_t * mca)3894eaa4710SRishi Srivatsavai bridge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
3904eaa4710SRishi Srivatsavai {
3914eaa4710SRishi Srivatsavai return (0);
3924eaa4710SRishi Srivatsavai }
3934eaa4710SRishi Srivatsavai
3944eaa4710SRishi Srivatsavai /* ARGSUSED */
3954eaa4710SRishi Srivatsavai static int
bridge_m_unicst(void * arg,const uint8_t * macaddr)3964eaa4710SRishi Srivatsavai bridge_m_unicst(void *arg, const uint8_t *macaddr)
3974eaa4710SRishi Srivatsavai {
3984eaa4710SRishi Srivatsavai return (ENOTSUP);
3994eaa4710SRishi Srivatsavai }
4004eaa4710SRishi Srivatsavai
4014eaa4710SRishi Srivatsavai static mblk_t *
bridge_m_tx(void * arg,mblk_t * mp)4024eaa4710SRishi Srivatsavai bridge_m_tx(void *arg, mblk_t *mp)
4034eaa4710SRishi Srivatsavai {
4044eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(arg));
4054eaa4710SRishi Srivatsavai freemsgchain(mp);
4064eaa4710SRishi Srivatsavai return (NULL);
4074eaa4710SRishi Srivatsavai }
4084eaa4710SRishi Srivatsavai
4094eaa4710SRishi Srivatsavai /* ARGSUSED */
4104eaa4710SRishi Srivatsavai static int
bridge_ioc_listfwd(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)4114eaa4710SRishi Srivatsavai bridge_ioc_listfwd(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
4124eaa4710SRishi Srivatsavai {
4134eaa4710SRishi Srivatsavai bridge_listfwd_t *blf = karg;
4144eaa4710SRishi Srivatsavai bridge_inst_t *bip;
4154eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, match;
4164eaa4710SRishi Srivatsavai avl_index_t where;
4174eaa4710SRishi Srivatsavai
4184eaa4710SRishi Srivatsavai bip = bridge_find_name(blf->blf_name);
4194eaa4710SRishi Srivatsavai if (bip == NULL)
4204eaa4710SRishi Srivatsavai return (ENOENT);
4214eaa4710SRishi Srivatsavai
4224eaa4710SRishi Srivatsavai bcopy(blf->blf_dest, match.bf_dest, ETHERADDRL);
4234eaa4710SRishi Srivatsavai match.bf_flags |= BFF_VLANLOCAL;
4244eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER);
4254eaa4710SRishi Srivatsavai if ((bfp = avl_find(&bip->bi_fwd, &match, &where)) == NULL)
4264eaa4710SRishi Srivatsavai bfp = avl_nearest(&bip->bi_fwd, where, AVL_AFTER);
4274eaa4710SRishi Srivatsavai else
4284eaa4710SRishi Srivatsavai bfp = AVL_NEXT(&bip->bi_fwd, bfp);
4294eaa4710SRishi Srivatsavai if (bfp == NULL) {
4304eaa4710SRishi Srivatsavai bzero(blf, sizeof (*blf));
4314eaa4710SRishi Srivatsavai } else {
4324eaa4710SRishi Srivatsavai bcopy(bfp->bf_dest, blf->blf_dest, ETHERADDRL);
4334eaa4710SRishi Srivatsavai blf->blf_trill_nick = bfp->bf_trill_nick;
4344eaa4710SRishi Srivatsavai blf->blf_ms_age =
435d3d50737SRafael Vanoni drv_hztousec(ddi_get_lbolt() - bfp->bf_lastheard) / 1000;
4364eaa4710SRishi Srivatsavai blf->blf_is_local =
4374eaa4710SRishi Srivatsavai (bfp->bf_flags & BFF_LOCALADDR) != 0;
4384eaa4710SRishi Srivatsavai blf->blf_linkid = bfp->bf_links[0]->bl_linkid;
4394eaa4710SRishi Srivatsavai }
4404eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
4414eaa4710SRishi Srivatsavai bridge_unref(bip);
4424eaa4710SRishi Srivatsavai return (0);
4434eaa4710SRishi Srivatsavai }
4444eaa4710SRishi Srivatsavai
4454eaa4710SRishi Srivatsavai static int
bridge_m_setprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,const void * pr_val)4464eaa4710SRishi Srivatsavai bridge_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
4474eaa4710SRishi Srivatsavai uint_t pr_valsize, const void *pr_val)
4484eaa4710SRishi Srivatsavai {
4494eaa4710SRishi Srivatsavai bridge_mac_t *bmp = arg;
4504eaa4710SRishi Srivatsavai bridge_inst_t *bip;
4514eaa4710SRishi Srivatsavai bridge_link_t *blp;
4524eaa4710SRishi Srivatsavai int err;
4534eaa4710SRishi Srivatsavai uint_t maxsdu;
4544eaa4710SRishi Srivatsavai mblk_t *mlist;
4554eaa4710SRishi Srivatsavai
4564eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(pr_name));
4574eaa4710SRishi Srivatsavai switch (pr_num) {
4584eaa4710SRishi Srivatsavai case MAC_PROP_MTU:
4594eaa4710SRishi Srivatsavai if (pr_valsize < sizeof (bmp->bm_maxsdu)) {
4604eaa4710SRishi Srivatsavai err = EINVAL;
4614eaa4710SRishi Srivatsavai break;
4624eaa4710SRishi Srivatsavai }
4634eaa4710SRishi Srivatsavai (void) bcopy(pr_val, &maxsdu, sizeof (maxsdu));
4644eaa4710SRishi Srivatsavai if (maxsdu == bmp->bm_maxsdu) {
4654eaa4710SRishi Srivatsavai err = 0;
4664eaa4710SRishi Srivatsavai } else if ((bip = mac_to_inst(bmp)) == NULL) {
4674eaa4710SRishi Srivatsavai err = ENXIO;
4684eaa4710SRishi Srivatsavai } else {
4694eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
4704eaa4710SRishi Srivatsavai mlist = NULL;
4714eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL;
4724eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) {
4734eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_DELETED)
4744eaa4710SRishi Srivatsavai continue;
4754eaa4710SRishi Srivatsavai if (blp->bl_maxsdu == maxsdu)
4764eaa4710SRishi Srivatsavai link_sdu_fail(blp, B_FALSE, &mlist);
4774eaa4710SRishi Srivatsavai else if (blp->bl_maxsdu == bmp->bm_maxsdu)
4784eaa4710SRishi Srivatsavai link_sdu_fail(blp, B_TRUE, &mlist);
4794eaa4710SRishi Srivatsavai }
4804eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
4814eaa4710SRishi Srivatsavai bmp->bm_maxsdu = maxsdu;
4824eaa4710SRishi Srivatsavai (void) mac_maxsdu_update(bmp->bm_mh, maxsdu);
4834eaa4710SRishi Srivatsavai send_up_messages(bip, mlist);
4844eaa4710SRishi Srivatsavai bridge_unref(bip);
4854eaa4710SRishi Srivatsavai err = 0;
4864eaa4710SRishi Srivatsavai }
4874eaa4710SRishi Srivatsavai break;
4884eaa4710SRishi Srivatsavai
4894eaa4710SRishi Srivatsavai default:
4904eaa4710SRishi Srivatsavai err = ENOTSUP;
4914eaa4710SRishi Srivatsavai break;
4924eaa4710SRishi Srivatsavai }
4934eaa4710SRishi Srivatsavai return (err);
4944eaa4710SRishi Srivatsavai }
4954eaa4710SRishi Srivatsavai
4964eaa4710SRishi Srivatsavai static int
bridge_m_getprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)4974eaa4710SRishi Srivatsavai bridge_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
4980dc2366fSVenugopal Iyer uint_t pr_valsize, void *pr_val)
4994eaa4710SRishi Srivatsavai {
5004eaa4710SRishi Srivatsavai bridge_mac_t *bmp = arg;
5014eaa4710SRishi Srivatsavai int err = 0;
5024eaa4710SRishi Srivatsavai
5034eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(pr_name));
5044eaa4710SRishi Srivatsavai switch (pr_num) {
5054eaa4710SRishi Srivatsavai case MAC_PROP_STATUS:
5060dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (bmp->bm_linkstate));
507*ce17336eSAndy Fiddaman bcopy(&bmp->bm_linkstate, pr_val, sizeof (bmp->bm_linkstate));
5084eaa4710SRishi Srivatsavai break;
5094eaa4710SRishi Srivatsavai
5104eaa4710SRishi Srivatsavai default:
5114eaa4710SRishi Srivatsavai err = ENOTSUP;
5124eaa4710SRishi Srivatsavai break;
5134eaa4710SRishi Srivatsavai }
5144eaa4710SRishi Srivatsavai return (err);
5154eaa4710SRishi Srivatsavai }
5164eaa4710SRishi Srivatsavai
5170dc2366fSVenugopal Iyer static void
bridge_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)5180dc2366fSVenugopal Iyer bridge_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
5190dc2366fSVenugopal Iyer mac_prop_info_handle_t prh)
5200dc2366fSVenugopal Iyer {
5210dc2366fSVenugopal Iyer bridge_mac_t *bmp = arg;
5220dc2366fSVenugopal Iyer
5230dc2366fSVenugopal Iyer _NOTE(ARGUNUSED(pr_name));
5240dc2366fSVenugopal Iyer
5250dc2366fSVenugopal Iyer switch (pr_num) {
5260dc2366fSVenugopal Iyer case MAC_PROP_MTU:
5270dc2366fSVenugopal Iyer mac_prop_info_set_range_uint32(prh, bmp->bm_maxsdu,
5280dc2366fSVenugopal Iyer bmp->bm_maxsdu);
5290dc2366fSVenugopal Iyer break;
5300dc2366fSVenugopal Iyer case MAC_PROP_STATUS:
5310dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
5320dc2366fSVenugopal Iyer break;
5330dc2366fSVenugopal Iyer }
5340dc2366fSVenugopal Iyer }
5350dc2366fSVenugopal Iyer
5364eaa4710SRishi Srivatsavai static mac_callbacks_t bridge_m_callbacks = {
5370dc2366fSVenugopal Iyer MC_SETPROP | MC_GETPROP | MC_PROPINFO,
5384eaa4710SRishi Srivatsavai bridge_m_getstat,
5394eaa4710SRishi Srivatsavai bridge_m_start,
5404eaa4710SRishi Srivatsavai bridge_m_stop,
5414eaa4710SRishi Srivatsavai bridge_m_setpromisc,
5424eaa4710SRishi Srivatsavai bridge_m_multicst,
5434eaa4710SRishi Srivatsavai bridge_m_unicst,
5444eaa4710SRishi Srivatsavai bridge_m_tx,
5450dc2366fSVenugopal Iyer NULL, /* reserved */
5464eaa4710SRishi Srivatsavai NULL, /* ioctl */
5474eaa4710SRishi Srivatsavai NULL, /* getcapab */
5484eaa4710SRishi Srivatsavai NULL, /* open */
5494eaa4710SRishi Srivatsavai NULL, /* close */
5504eaa4710SRishi Srivatsavai bridge_m_setprop,
5510dc2366fSVenugopal Iyer bridge_m_getprop,
5520dc2366fSVenugopal Iyer bridge_m_propinfo
5534eaa4710SRishi Srivatsavai };
5544eaa4710SRishi Srivatsavai
5554eaa4710SRishi Srivatsavai /*
5564eaa4710SRishi Srivatsavai * Create kstats from a list.
5574eaa4710SRishi Srivatsavai */
5584eaa4710SRishi Srivatsavai static kstat_t *
kstat_setup(kstat_named_t * knt,const char ** names,int nstat,const char * unitname)5594eaa4710SRishi Srivatsavai kstat_setup(kstat_named_t *knt, const char **names, int nstat,
5604eaa4710SRishi Srivatsavai const char *unitname)
5614eaa4710SRishi Srivatsavai {
5624eaa4710SRishi Srivatsavai kstat_t *ksp;
5634eaa4710SRishi Srivatsavai int i;
5644eaa4710SRishi Srivatsavai
5654eaa4710SRishi Srivatsavai for (i = 0; i < nstat; i++)
5664eaa4710SRishi Srivatsavai kstat_named_init(&knt[i], names[i], KSTAT_DATA_UINT64);
5674eaa4710SRishi Srivatsavai
568f2905fb7SRishi Srivatsavai ksp = kstat_create_zone(BRIDGE_DEV_NAME, 0, unitname, "net",
5694eaa4710SRishi Srivatsavai KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_VIRTUAL, GLOBAL_ZONEID);
5704eaa4710SRishi Srivatsavai if (ksp != NULL) {
5714eaa4710SRishi Srivatsavai ksp->ks_data = knt;
5724eaa4710SRishi Srivatsavai kstat_install(ksp);
5734eaa4710SRishi Srivatsavai }
5744eaa4710SRishi Srivatsavai return (ksp);
5754eaa4710SRishi Srivatsavai }
5764eaa4710SRishi Srivatsavai
5774eaa4710SRishi Srivatsavai /*
5784eaa4710SRishi Srivatsavai * Find an existing bridge_mac_t structure or allocate a new one for the given
5794eaa4710SRishi Srivatsavai * bridge instance. This creates the mac driver instance that snoop can use.
5804eaa4710SRishi Srivatsavai */
5814eaa4710SRishi Srivatsavai static int
bmac_alloc(bridge_inst_t * bip,bridge_mac_t ** bmacp)5824eaa4710SRishi Srivatsavai bmac_alloc(bridge_inst_t *bip, bridge_mac_t **bmacp)
5834eaa4710SRishi Srivatsavai {
5844eaa4710SRishi Srivatsavai bridge_mac_t *bmp, *bnew;
5854eaa4710SRishi Srivatsavai mac_register_t *mac;
5864eaa4710SRishi Srivatsavai int err;
5874eaa4710SRishi Srivatsavai
5884eaa4710SRishi Srivatsavai *bmacp = NULL;
5894eaa4710SRishi Srivatsavai if ((mac = mac_alloc(MAC_VERSION)) == NULL)
5904eaa4710SRishi Srivatsavai return (EINVAL);
5914eaa4710SRishi Srivatsavai
5924eaa4710SRishi Srivatsavai bnew = kmem_zalloc(sizeof (*bnew), KM_SLEEP);
5934eaa4710SRishi Srivatsavai
5944eaa4710SRishi Srivatsavai rw_enter(&bmac_rwlock, RW_WRITER);
5954eaa4710SRishi Srivatsavai for (bmp = list_head(&bmac_list); bmp != NULL;
5964eaa4710SRishi Srivatsavai bmp = list_next(&bmac_list, bmp)) {
5974eaa4710SRishi Srivatsavai if (strcmp(bip->bi_name, bmp->bm_name) == 0) {
5984eaa4710SRishi Srivatsavai ASSERT(bmp->bm_inst == NULL);
5994eaa4710SRishi Srivatsavai bmp->bm_inst = bip;
6004eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock);
6014eaa4710SRishi Srivatsavai kmem_free(bnew, sizeof (*bnew));
6024eaa4710SRishi Srivatsavai mac_free(mac);
6034eaa4710SRishi Srivatsavai *bmacp = bmp;
6044eaa4710SRishi Srivatsavai return (0);
6054eaa4710SRishi Srivatsavai }
6064eaa4710SRishi Srivatsavai }
6074eaa4710SRishi Srivatsavai
6084eaa4710SRishi Srivatsavai mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
6094eaa4710SRishi Srivatsavai mac->m_driver = bnew;
6104eaa4710SRishi Srivatsavai mac->m_dip = bridge_dev_info;
6114eaa4710SRishi Srivatsavai mac->m_instance = (uint_t)-1;
6124eaa4710SRishi Srivatsavai mac->m_src_addr = (uint8_t *)zero_addr;
6134eaa4710SRishi Srivatsavai mac->m_callbacks = &bridge_m_callbacks;
6144eaa4710SRishi Srivatsavai
6154eaa4710SRishi Srivatsavai /*
6164eaa4710SRishi Srivatsavai * Note that the SDU limits are irrelevant, as nobody transmits on the
6174eaa4710SRishi Srivatsavai * bridge node itself. It's mainly for monitoring but we allow
6184eaa4710SRishi Srivatsavai * setting the bridge MTU for quick transition of all links part of the
6194eaa4710SRishi Srivatsavai * bridge to a new MTU.
6204eaa4710SRishi Srivatsavai */
6214eaa4710SRishi Srivatsavai mac->m_min_sdu = 1;
6224eaa4710SRishi Srivatsavai mac->m_max_sdu = 1500;
6234eaa4710SRishi Srivatsavai err = mac_register(mac, &bnew->bm_mh);
6244eaa4710SRishi Srivatsavai mac_free(mac);
6254eaa4710SRishi Srivatsavai if (err != 0) {
6264eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock);
6274eaa4710SRishi Srivatsavai kmem_free(bnew, sizeof (*bnew));
6284eaa4710SRishi Srivatsavai return (err);
6294eaa4710SRishi Srivatsavai }
6304eaa4710SRishi Srivatsavai
6314eaa4710SRishi Srivatsavai bnew->bm_inst = bip;
6324eaa4710SRishi Srivatsavai (void) strcpy(bnew->bm_name, bip->bi_name);
6334eaa4710SRishi Srivatsavai if (list_is_empty(&bmac_list)) {
6344eaa4710SRishi Srivatsavai bridge_timerid = timeout(bridge_timer, NULL,
6354eaa4710SRishi Srivatsavai bridge_scan_interval);
6364eaa4710SRishi Srivatsavai }
6374eaa4710SRishi Srivatsavai list_insert_tail(&bmac_list, bnew);
6384eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock);
6394eaa4710SRishi Srivatsavai
6404eaa4710SRishi Srivatsavai /*
6414eaa4710SRishi Srivatsavai * Mark the MAC as unable to go "active" so that only passive clients
6424eaa4710SRishi Srivatsavai * (such as snoop) can bind to it.
6434eaa4710SRishi Srivatsavai */
6444eaa4710SRishi Srivatsavai mac_no_active(bnew->bm_mh);
6454eaa4710SRishi Srivatsavai *bmacp = bnew;
6464eaa4710SRishi Srivatsavai return (0);
6474eaa4710SRishi Srivatsavai }
6484eaa4710SRishi Srivatsavai
6494eaa4710SRishi Srivatsavai /*
6504eaa4710SRishi Srivatsavai * Disconnect the given bridge_mac_t from its bridge instance. The bridge
6514eaa4710SRishi Srivatsavai * instance is going away. The mac instance can't go away until the clients
6524eaa4710SRishi Srivatsavai * are gone (see bridge_timer).
6534eaa4710SRishi Srivatsavai */
6544eaa4710SRishi Srivatsavai static void
bmac_disconnect(bridge_mac_t * bmp)6554eaa4710SRishi Srivatsavai bmac_disconnect(bridge_mac_t *bmp)
6564eaa4710SRishi Srivatsavai {
6574eaa4710SRishi Srivatsavai bridge_inst_t *bip;
6584eaa4710SRishi Srivatsavai
6594eaa4710SRishi Srivatsavai bmp->bm_linkstate = LINK_STATE_DOWN;
6604eaa4710SRishi Srivatsavai mac_link_redo(bmp->bm_mh, LINK_STATE_DOWN);
6614eaa4710SRishi Srivatsavai
6624eaa4710SRishi Srivatsavai rw_enter(&bmac_rwlock, RW_READER);
6634eaa4710SRishi Srivatsavai bip = bmp->bm_inst;
6644eaa4710SRishi Srivatsavai bip->bi_mac = NULL;
6654eaa4710SRishi Srivatsavai bmp->bm_inst = NULL;
6664eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock);
6674eaa4710SRishi Srivatsavai }
6684eaa4710SRishi Srivatsavai
6694eaa4710SRishi Srivatsavai /* This is used by the avl trees to sort forwarding table entries */
6704eaa4710SRishi Srivatsavai static int
fwd_compare(const void * addr1,const void * addr2)6714eaa4710SRishi Srivatsavai fwd_compare(const void *addr1, const void *addr2)
6724eaa4710SRishi Srivatsavai {
6734eaa4710SRishi Srivatsavai const bridge_fwd_t *fwd1 = addr1;
6744eaa4710SRishi Srivatsavai const bridge_fwd_t *fwd2 = addr2;
6754eaa4710SRishi Srivatsavai int diff = memcmp(fwd1->bf_dest, fwd2->bf_dest, ETHERADDRL);
6764eaa4710SRishi Srivatsavai
6774eaa4710SRishi Srivatsavai if (diff != 0)
6784eaa4710SRishi Srivatsavai return (diff > 0 ? 1 : -1);
6794eaa4710SRishi Srivatsavai
6804eaa4710SRishi Srivatsavai if ((fwd1->bf_flags ^ fwd2->bf_flags) & BFF_VLANLOCAL) {
6814eaa4710SRishi Srivatsavai if (fwd1->bf_vlanid > fwd2->bf_vlanid)
6824eaa4710SRishi Srivatsavai return (1);
6834eaa4710SRishi Srivatsavai else if (fwd1->bf_vlanid < fwd2->bf_vlanid)
6844eaa4710SRishi Srivatsavai return (-1);
6854eaa4710SRishi Srivatsavai }
6864eaa4710SRishi Srivatsavai return (0);
6874eaa4710SRishi Srivatsavai }
6884eaa4710SRishi Srivatsavai
6894eaa4710SRishi Srivatsavai static void
inst_free(bridge_inst_t * bip)6904eaa4710SRishi Srivatsavai inst_free(bridge_inst_t *bip)
6914eaa4710SRishi Srivatsavai {
6924eaa4710SRishi Srivatsavai ASSERT(bip->bi_mac == NULL);
6934eaa4710SRishi Srivatsavai rw_destroy(&bip->bi_rwlock);
6944eaa4710SRishi Srivatsavai list_destroy(&bip->bi_links);
6954eaa4710SRishi Srivatsavai cv_destroy(&bip->bi_linkwait);
6964eaa4710SRishi Srivatsavai avl_destroy(&bip->bi_fwd);
6974eaa4710SRishi Srivatsavai if (bip->bi_ksp != NULL)
6984eaa4710SRishi Srivatsavai kstat_delete(bip->bi_ksp);
6994eaa4710SRishi Srivatsavai kmem_free(bip, sizeof (*bip));
7004eaa4710SRishi Srivatsavai }
7014eaa4710SRishi Srivatsavai
7024eaa4710SRishi Srivatsavai static bridge_inst_t *
inst_alloc(const char * bridge)7034eaa4710SRishi Srivatsavai inst_alloc(const char *bridge)
7044eaa4710SRishi Srivatsavai {
7054eaa4710SRishi Srivatsavai bridge_inst_t *bip;
7064eaa4710SRishi Srivatsavai
7074eaa4710SRishi Srivatsavai bip = kmem_zalloc(sizeof (*bip), KM_SLEEP);
7084eaa4710SRishi Srivatsavai bip->bi_refs = 1;
7094eaa4710SRishi Srivatsavai (void) strcpy(bip->bi_name, bridge);
7104eaa4710SRishi Srivatsavai rw_init(&bip->bi_rwlock, NULL, RW_DRIVER, NULL);
7114eaa4710SRishi Srivatsavai list_create(&bip->bi_links, sizeof (bridge_link_t),
7124eaa4710SRishi Srivatsavai offsetof(bridge_link_t, bl_node));
7134eaa4710SRishi Srivatsavai cv_init(&bip->bi_linkwait, NULL, CV_DRIVER, NULL);
7144eaa4710SRishi Srivatsavai avl_create(&bip->bi_fwd, fwd_compare, sizeof (bridge_fwd_t),
7154eaa4710SRishi Srivatsavai offsetof(bridge_fwd_t, bf_node));
7164eaa4710SRishi Srivatsavai return (bip);
7174eaa4710SRishi Srivatsavai }
7184eaa4710SRishi Srivatsavai
7194eaa4710SRishi Srivatsavai static bridge_inst_t *
bridge_find_name(const char * bridge)7204eaa4710SRishi Srivatsavai bridge_find_name(const char *bridge)
7214eaa4710SRishi Srivatsavai {
7224eaa4710SRishi Srivatsavai bridge_inst_t *bip;
7234eaa4710SRishi Srivatsavai
7244eaa4710SRishi Srivatsavai mutex_enter(&inst_lock);
7254eaa4710SRishi Srivatsavai for (bip = list_head(&inst_list); bip != NULL;
7264eaa4710SRishi Srivatsavai bip = list_next(&inst_list, bip)) {
7274eaa4710SRishi Srivatsavai if (!(bip->bi_flags & BIF_SHUTDOWN) &&
7284eaa4710SRishi Srivatsavai strcmp(bridge, bip->bi_name) == 0) {
7294eaa4710SRishi Srivatsavai atomic_inc_uint(&bip->bi_refs);
7304eaa4710SRishi Srivatsavai break;
7314eaa4710SRishi Srivatsavai }
7324eaa4710SRishi Srivatsavai }
7334eaa4710SRishi Srivatsavai mutex_exit(&inst_lock);
7344eaa4710SRishi Srivatsavai
7354eaa4710SRishi Srivatsavai return (bip);
7364eaa4710SRishi Srivatsavai }
7374eaa4710SRishi Srivatsavai
7384eaa4710SRishi Srivatsavai static int
bridge_create(datalink_id_t linkid,const char * bridge,bridge_inst_t ** bipc,cred_t * cred)7392b24ab6bSSebastien Roy bridge_create(datalink_id_t linkid, const char *bridge, bridge_inst_t **bipc,
7402b24ab6bSSebastien Roy cred_t *cred)
7414eaa4710SRishi Srivatsavai {
7424eaa4710SRishi Srivatsavai bridge_inst_t *bip, *bipnew;
7434eaa4710SRishi Srivatsavai bridge_mac_t *bmp = NULL;
7444eaa4710SRishi Srivatsavai int err;
7454eaa4710SRishi Srivatsavai
7464eaa4710SRishi Srivatsavai *bipc = NULL;
7474eaa4710SRishi Srivatsavai bipnew = inst_alloc(bridge);
7484eaa4710SRishi Srivatsavai
7494eaa4710SRishi Srivatsavai mutex_enter(&inst_lock);
7504eaa4710SRishi Srivatsavai lookup_retry:
7514eaa4710SRishi Srivatsavai for (bip = list_head(&inst_list); bip != NULL;
7524eaa4710SRishi Srivatsavai bip = list_next(&inst_list, bip)) {
7534eaa4710SRishi Srivatsavai if (strcmp(bridge, bip->bi_name) == 0)
7544eaa4710SRishi Srivatsavai break;
7554eaa4710SRishi Srivatsavai }
7564eaa4710SRishi Srivatsavai
7574eaa4710SRishi Srivatsavai /* This should not take long; if it does, we've got a design problem */
7584eaa4710SRishi Srivatsavai if (bip != NULL && (bip->bi_flags & BIF_SHUTDOWN)) {
7594eaa4710SRishi Srivatsavai cv_wait(&inst_cv, &inst_lock);
7604eaa4710SRishi Srivatsavai goto lookup_retry;
7614eaa4710SRishi Srivatsavai }
7624eaa4710SRishi Srivatsavai
763f2905fb7SRishi Srivatsavai if (bip == NULL) {
7644eaa4710SRishi Srivatsavai bip = bipnew;
7654eaa4710SRishi Srivatsavai bipnew = NULL;
7664eaa4710SRishi Srivatsavai list_insert_tail(&inst_list, bip);
7674eaa4710SRishi Srivatsavai }
7684eaa4710SRishi Srivatsavai
7694eaa4710SRishi Srivatsavai mutex_exit(&inst_lock);
770f2905fb7SRishi Srivatsavai if (bipnew != NULL) {
771f2905fb7SRishi Srivatsavai inst_free(bipnew);
772f2905fb7SRishi Srivatsavai return (EEXIST);
773f2905fb7SRishi Srivatsavai }
7744eaa4710SRishi Srivatsavai
7754eaa4710SRishi Srivatsavai bip->bi_ksp = kstat_setup((kstat_named_t *)&bip->bi_kstats,
7764eaa4710SRishi Srivatsavai inst_kstats_list, Dim(inst_kstats_list), bip->bi_name);
7774eaa4710SRishi Srivatsavai
7784eaa4710SRishi Srivatsavai err = bmac_alloc(bip, &bmp);
7794eaa4710SRishi Srivatsavai if ((bip->bi_mac = bmp) == NULL)
7804eaa4710SRishi Srivatsavai goto fail_create;
7814eaa4710SRishi Srivatsavai
7824eaa4710SRishi Srivatsavai /*
7834eaa4710SRishi Srivatsavai * bm_inst is set, so the timer cannot yank the DLS rug from under us.
7844eaa4710SRishi Srivatsavai * No extra locking is needed here.
7854eaa4710SRishi Srivatsavai */
7864eaa4710SRishi Srivatsavai if (!(bmp->bm_flags & BMF_DLS)) {
7872b24ab6bSSebastien Roy err = dls_devnet_create(bmp->bm_mh, linkid, crgetzoneid(cred));
7882b24ab6bSSebastien Roy if (err != 0)
7894eaa4710SRishi Srivatsavai goto fail_create;
7904eaa4710SRishi Srivatsavai bmp->bm_flags |= BMF_DLS;
7914eaa4710SRishi Srivatsavai }
7924eaa4710SRishi Srivatsavai
7934eaa4710SRishi Srivatsavai bip->bi_dev = makedevice(bridge_major, mac_minor(bmp->bm_mh));
7944eaa4710SRishi Srivatsavai *bipc = bip;
7954eaa4710SRishi Srivatsavai return (0);
7964eaa4710SRishi Srivatsavai
7974eaa4710SRishi Srivatsavai fail_create:
798f2905fb7SRishi Srivatsavai ASSERT(bip->bi_trilldata == NULL);
799f2905fb7SRishi Srivatsavai bip->bi_flags |= BIF_SHUTDOWN;
800f2905fb7SRishi Srivatsavai bridge_unref(bip);
8014eaa4710SRishi Srivatsavai return (err);
8024eaa4710SRishi Srivatsavai }
8034eaa4710SRishi Srivatsavai
8044eaa4710SRishi Srivatsavai static void
bridge_unref(bridge_inst_t * bip)8054eaa4710SRishi Srivatsavai bridge_unref(bridge_inst_t *bip)
8064eaa4710SRishi Srivatsavai {
8074eaa4710SRishi Srivatsavai if (atomic_dec_uint_nv(&bip->bi_refs) == 0) {
8084eaa4710SRishi Srivatsavai ASSERT(bip->bi_flags & BIF_SHUTDOWN);
8094eaa4710SRishi Srivatsavai /* free up mac for reuse before leaving global list */
8104eaa4710SRishi Srivatsavai if (bip->bi_mac != NULL)
8114eaa4710SRishi Srivatsavai bmac_disconnect(bip->bi_mac);
8124eaa4710SRishi Srivatsavai mutex_enter(&inst_lock);
8134eaa4710SRishi Srivatsavai list_remove(&inst_list, bip);
8144eaa4710SRishi Srivatsavai cv_broadcast(&inst_cv);
8154eaa4710SRishi Srivatsavai mutex_exit(&inst_lock);
8164eaa4710SRishi Srivatsavai inst_free(bip);
8174eaa4710SRishi Srivatsavai }
8184eaa4710SRishi Srivatsavai }
8194eaa4710SRishi Srivatsavai
8204eaa4710SRishi Srivatsavai /*
8214eaa4710SRishi Srivatsavai * Stream instances are used only for allocating bridges and serving as a
8224eaa4710SRishi Srivatsavai * control node. They serve no data-handling function.
8234eaa4710SRishi Srivatsavai */
8244eaa4710SRishi Srivatsavai static bridge_stream_t *
stream_alloc(void)8254eaa4710SRishi Srivatsavai stream_alloc(void)
8264eaa4710SRishi Srivatsavai {
8274eaa4710SRishi Srivatsavai bridge_stream_t *bsp;
8284eaa4710SRishi Srivatsavai minor_t mn;
8294eaa4710SRishi Srivatsavai
8304eaa4710SRishi Srivatsavai if ((mn = mac_minor_hold(B_FALSE)) == 0)
8314eaa4710SRishi Srivatsavai return (NULL);
8324eaa4710SRishi Srivatsavai bsp = kmem_zalloc(sizeof (*bsp), KM_SLEEP);
8334eaa4710SRishi Srivatsavai bsp->bs_minor = mn;
8344eaa4710SRishi Srivatsavai return (bsp);
8354eaa4710SRishi Srivatsavai }
8364eaa4710SRishi Srivatsavai
8374eaa4710SRishi Srivatsavai static void
stream_free(bridge_stream_t * bsp)8384eaa4710SRishi Srivatsavai stream_free(bridge_stream_t *bsp)
8394eaa4710SRishi Srivatsavai {
8404eaa4710SRishi Srivatsavai mac_minor_rele(bsp->bs_minor);
8414eaa4710SRishi Srivatsavai kmem_free(bsp, sizeof (*bsp));
8424eaa4710SRishi Srivatsavai }
8434eaa4710SRishi Srivatsavai
8444eaa4710SRishi Srivatsavai /* Reference hold/release functions for STREAMS-related taskq */
8454eaa4710SRishi Srivatsavai static void
stream_ref(bridge_stream_t * bsp)8464eaa4710SRishi Srivatsavai stream_ref(bridge_stream_t *bsp)
8474eaa4710SRishi Srivatsavai {
8484eaa4710SRishi Srivatsavai mutex_enter(&stream_ref_lock);
8494eaa4710SRishi Srivatsavai bsp->bs_taskq_cnt++;
8504eaa4710SRishi Srivatsavai mutex_exit(&stream_ref_lock);
8514eaa4710SRishi Srivatsavai }
8524eaa4710SRishi Srivatsavai
8534eaa4710SRishi Srivatsavai static void
stream_unref(bridge_stream_t * bsp)8544eaa4710SRishi Srivatsavai stream_unref(bridge_stream_t *bsp)
8554eaa4710SRishi Srivatsavai {
8564eaa4710SRishi Srivatsavai mutex_enter(&stream_ref_lock);
8574eaa4710SRishi Srivatsavai if (--bsp->bs_taskq_cnt == 0)
8584eaa4710SRishi Srivatsavai cv_broadcast(&stream_ref_cv);
8594eaa4710SRishi Srivatsavai mutex_exit(&stream_ref_lock);
8604eaa4710SRishi Srivatsavai }
8614eaa4710SRishi Srivatsavai
8624eaa4710SRishi Srivatsavai static void
link_free(bridge_link_t * blp)8634eaa4710SRishi Srivatsavai link_free(bridge_link_t *blp)
8644eaa4710SRishi Srivatsavai {
8654eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst;
8664eaa4710SRishi Srivatsavai
8674eaa4710SRishi Srivatsavai ASSERT(!(blp->bl_flags & BLF_FREED));
8684eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_FREED;
8694eaa4710SRishi Srivatsavai if (blp->bl_ksp != NULL)
8704eaa4710SRishi Srivatsavai kstat_delete(blp->bl_ksp);
8714eaa4710SRishi Srivatsavai if (blp->bl_lfailmp != NULL)
8724eaa4710SRishi Srivatsavai freeb(blp->bl_lfailmp);
8734eaa4710SRishi Srivatsavai cv_destroy(&blp->bl_trillwait);
8744eaa4710SRishi Srivatsavai mutex_destroy(&blp->bl_trilllock);
8754eaa4710SRishi Srivatsavai kmem_free(blp, sizeof (*blp));
8764eaa4710SRishi Srivatsavai /* Don't unreference the bridge until the MAC is closed */
8774eaa4710SRishi Srivatsavai bridge_unref(bip);
8784eaa4710SRishi Srivatsavai }
8794eaa4710SRishi Srivatsavai
8804eaa4710SRishi Srivatsavai static void
link_unref(bridge_link_t * blp)8814eaa4710SRishi Srivatsavai link_unref(bridge_link_t *blp)
8824eaa4710SRishi Srivatsavai {
8834eaa4710SRishi Srivatsavai if (atomic_dec_uint_nv(&blp->bl_refs) == 0) {
8844eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst;
8854eaa4710SRishi Srivatsavai
8864eaa4710SRishi Srivatsavai ASSERT(blp->bl_flags & BLF_DELETED);
8874eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
8886f40bf67SRishi Srivatsavai if (blp->bl_flags & BLF_LINK_ADDED)
8894eaa4710SRishi Srivatsavai list_remove(&bip->bi_links, blp);
8904eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
8914eaa4710SRishi Srivatsavai if (bip->bi_trilldata != NULL && list_is_empty(&bip->bi_links))
8924eaa4710SRishi Srivatsavai cv_broadcast(&bip->bi_linkwait);
8934eaa4710SRishi Srivatsavai link_free(blp);
8944eaa4710SRishi Srivatsavai }
8954eaa4710SRishi Srivatsavai }
8964eaa4710SRishi Srivatsavai
8974eaa4710SRishi Srivatsavai static bridge_fwd_t *
fwd_alloc(const uint8_t * addr,uint_t nlinks,uint16_t nick)8984eaa4710SRishi Srivatsavai fwd_alloc(const uint8_t *addr, uint_t nlinks, uint16_t nick)
8994eaa4710SRishi Srivatsavai {
9004eaa4710SRishi Srivatsavai bridge_fwd_t *bfp;
9014eaa4710SRishi Srivatsavai
9024eaa4710SRishi Srivatsavai bfp = kmem_zalloc(sizeof (*bfp) + (nlinks * sizeof (bridge_link_t *)),
9034eaa4710SRishi Srivatsavai KM_NOSLEEP);
9044eaa4710SRishi Srivatsavai if (bfp != NULL) {
9054eaa4710SRishi Srivatsavai bcopy(addr, bfp->bf_dest, ETHERADDRL);
906d3d50737SRafael Vanoni bfp->bf_lastheard = ddi_get_lbolt();
9074eaa4710SRishi Srivatsavai bfp->bf_maxlinks = nlinks;
9084eaa4710SRishi Srivatsavai bfp->bf_links = (bridge_link_t **)(bfp + 1);
9094eaa4710SRishi Srivatsavai bfp->bf_trill_nick = nick;
9104eaa4710SRishi Srivatsavai }
9114eaa4710SRishi Srivatsavai return (bfp);
9124eaa4710SRishi Srivatsavai }
9134eaa4710SRishi Srivatsavai
9144eaa4710SRishi Srivatsavai static bridge_fwd_t *
fwd_find(bridge_inst_t * bip,const uint8_t * addr,uint16_t vlanid)9154eaa4710SRishi Srivatsavai fwd_find(bridge_inst_t *bip, const uint8_t *addr, uint16_t vlanid)
9164eaa4710SRishi Srivatsavai {
9174eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *vbfp;
9184eaa4710SRishi Srivatsavai bridge_fwd_t match;
9194eaa4710SRishi Srivatsavai
9204eaa4710SRishi Srivatsavai bcopy(addr, match.bf_dest, ETHERADDRL);
9214eaa4710SRishi Srivatsavai match.bf_flags = 0;
9224eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER);
9234eaa4710SRishi Srivatsavai if ((bfp = avl_find(&bip->bi_fwd, &match, NULL)) != NULL) {
9244eaa4710SRishi Srivatsavai if (bfp->bf_vlanid != vlanid && bfp->bf_vcnt > 0) {
9254eaa4710SRishi Srivatsavai match.bf_vlanid = vlanid;
9264eaa4710SRishi Srivatsavai match.bf_flags = BFF_VLANLOCAL;
9274eaa4710SRishi Srivatsavai vbfp = avl_find(&bip->bi_fwd, &match, NULL);
9284eaa4710SRishi Srivatsavai if (vbfp != NULL)
9294eaa4710SRishi Srivatsavai bfp = vbfp;
9304eaa4710SRishi Srivatsavai }
9314eaa4710SRishi Srivatsavai atomic_inc_uint(&bfp->bf_refs);
9324eaa4710SRishi Srivatsavai }
9334eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
9344eaa4710SRishi Srivatsavai return (bfp);
9354eaa4710SRishi Srivatsavai }
9364eaa4710SRishi Srivatsavai
9374eaa4710SRishi Srivatsavai static void
fwd_free(bridge_fwd_t * bfp)9384eaa4710SRishi Srivatsavai fwd_free(bridge_fwd_t *bfp)
9394eaa4710SRishi Srivatsavai {
9404eaa4710SRishi Srivatsavai uint_t i;
9414eaa4710SRishi Srivatsavai bridge_inst_t *bip = bfp->bf_links[0]->bl_inst;
9424eaa4710SRishi Srivatsavai
9434eaa4710SRishi Srivatsavai KIDECR(bki_count);
9444eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++)
9454eaa4710SRishi Srivatsavai link_unref(bfp->bf_links[i]);
9464eaa4710SRishi Srivatsavai kmem_free(bfp,
9474eaa4710SRishi Srivatsavai sizeof (*bfp) + bfp->bf_maxlinks * sizeof (bridge_link_t *));
9484eaa4710SRishi Srivatsavai }
9494eaa4710SRishi Srivatsavai
9504eaa4710SRishi Srivatsavai static void
fwd_unref(bridge_fwd_t * bfp)9514eaa4710SRishi Srivatsavai fwd_unref(bridge_fwd_t *bfp)
9524eaa4710SRishi Srivatsavai {
9534eaa4710SRishi Srivatsavai if (atomic_dec_uint_nv(&bfp->bf_refs) == 0) {
9544eaa4710SRishi Srivatsavai ASSERT(!(bfp->bf_flags & BFF_INTREE));
9554eaa4710SRishi Srivatsavai fwd_free(bfp);
9564eaa4710SRishi Srivatsavai }
9574eaa4710SRishi Srivatsavai }
9584eaa4710SRishi Srivatsavai
9594eaa4710SRishi Srivatsavai static void
fwd_delete(bridge_fwd_t * bfp)9604eaa4710SRishi Srivatsavai fwd_delete(bridge_fwd_t *bfp)
9614eaa4710SRishi Srivatsavai {
9624eaa4710SRishi Srivatsavai bridge_inst_t *bip;
9634eaa4710SRishi Srivatsavai bridge_fwd_t *bfpzero;
9644eaa4710SRishi Srivatsavai
9654eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_INTREE) {
9664eaa4710SRishi Srivatsavai ASSERT(bfp->bf_nlinks > 0);
9674eaa4710SRishi Srivatsavai bip = bfp->bf_links[0]->bl_inst;
9684eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
9694eaa4710SRishi Srivatsavai /* Another thread could beat us to this */
9704eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_INTREE) {
9714eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp);
9724eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE;
9734eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_VLANLOCAL) {
9744eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_VLANLOCAL;
9754eaa4710SRishi Srivatsavai bfpzero = avl_find(&bip->bi_fwd, bfp, NULL);
9764eaa4710SRishi Srivatsavai if (bfpzero != NULL && bfpzero->bf_vcnt > 0)
9774eaa4710SRishi Srivatsavai bfpzero->bf_vcnt--;
9784eaa4710SRishi Srivatsavai }
9794eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
9804eaa4710SRishi Srivatsavai fwd_unref(bfp); /* no longer in avl tree */
9814eaa4710SRishi Srivatsavai } else {
9824eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
9834eaa4710SRishi Srivatsavai }
9844eaa4710SRishi Srivatsavai }
9854eaa4710SRishi Srivatsavai }
9864eaa4710SRishi Srivatsavai
9874eaa4710SRishi Srivatsavai static boolean_t
fwd_insert(bridge_inst_t * bip,bridge_fwd_t * bfp)9884eaa4710SRishi Srivatsavai fwd_insert(bridge_inst_t *bip, bridge_fwd_t *bfp)
9894eaa4710SRishi Srivatsavai {
9904eaa4710SRishi Srivatsavai avl_index_t idx;
9914eaa4710SRishi Srivatsavai boolean_t retv;
9924eaa4710SRishi Srivatsavai
9934eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
9944eaa4710SRishi Srivatsavai if (!(bip->bi_flags & BIF_SHUTDOWN) &&
9954eaa4710SRishi Srivatsavai avl_numnodes(&bip->bi_fwd) < bip->bi_tablemax &&
9964eaa4710SRishi Srivatsavai avl_find(&bip->bi_fwd, bfp, &idx) == NULL) {
9974eaa4710SRishi Srivatsavai avl_insert(&bip->bi_fwd, bfp, idx);
9984eaa4710SRishi Srivatsavai bfp->bf_flags |= BFF_INTREE;
9994eaa4710SRishi Srivatsavai atomic_inc_uint(&bfp->bf_refs); /* avl entry */
10004eaa4710SRishi Srivatsavai retv = B_TRUE;
10014eaa4710SRishi Srivatsavai } else {
10024eaa4710SRishi Srivatsavai retv = B_FALSE;
10034eaa4710SRishi Srivatsavai }
10044eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
10054eaa4710SRishi Srivatsavai return (retv);
10064eaa4710SRishi Srivatsavai }
10074eaa4710SRishi Srivatsavai
10084eaa4710SRishi Srivatsavai static void
fwd_update_local(bridge_link_t * blp,const uint8_t * oldaddr,const uint8_t * newaddr)10094eaa4710SRishi Srivatsavai fwd_update_local(bridge_link_t *blp, const uint8_t *oldaddr,
10104eaa4710SRishi Srivatsavai const uint8_t *newaddr)
10114eaa4710SRishi Srivatsavai {
10124eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst;
10134eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfnew;
10144eaa4710SRishi Srivatsavai bridge_fwd_t match;
10154eaa4710SRishi Srivatsavai avl_index_t idx;
10164eaa4710SRishi Srivatsavai boolean_t drop_ref = B_FALSE;
10174eaa4710SRishi Srivatsavai
10184eaa4710SRishi Srivatsavai if (bcmp(oldaddr, newaddr, ETHERADDRL) == 0)
10194eaa4710SRishi Srivatsavai return;
10204eaa4710SRishi Srivatsavai
10214eaa4710SRishi Srivatsavai if (bcmp(oldaddr, zero_addr, ETHERADDRL) == 0)
10224eaa4710SRishi Srivatsavai goto no_old_addr;
10234eaa4710SRishi Srivatsavai
10244eaa4710SRishi Srivatsavai /*
10254eaa4710SRishi Srivatsavai * Find the previous entry, and remove our link from it.
10264eaa4710SRishi Srivatsavai */
10274eaa4710SRishi Srivatsavai bcopy(oldaddr, match.bf_dest, ETHERADDRL);
10284eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
10294eaa4710SRishi Srivatsavai if ((bfp = avl_find(&bip->bi_fwd, &match, NULL)) != NULL) {
10304eaa4710SRishi Srivatsavai int i;
10314eaa4710SRishi Srivatsavai
10324eaa4710SRishi Srivatsavai /*
10334eaa4710SRishi Srivatsavai * See if we're in the list, and remove if so.
10344eaa4710SRishi Srivatsavai */
10354eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++) {
10364eaa4710SRishi Srivatsavai if (bfp->bf_links[i] == blp) {
10374eaa4710SRishi Srivatsavai /*
10384eaa4710SRishi Srivatsavai * We assume writes are atomic, so no special
10394eaa4710SRishi Srivatsavai * MT handling is needed. The list length is
10404eaa4710SRishi Srivatsavai * decremented first, and then we remove
10414eaa4710SRishi Srivatsavai * entries.
10424eaa4710SRishi Srivatsavai */
10434eaa4710SRishi Srivatsavai bfp->bf_nlinks--;
10444eaa4710SRishi Srivatsavai for (; i < bfp->bf_nlinks; i++)
10454eaa4710SRishi Srivatsavai bfp->bf_links[i] = bfp->bf_links[i + 1];
10464eaa4710SRishi Srivatsavai drop_ref = B_TRUE;
10474eaa4710SRishi Srivatsavai break;
10484eaa4710SRishi Srivatsavai }
10494eaa4710SRishi Srivatsavai }
10504eaa4710SRishi Srivatsavai /* If no more links, then remove and free up */
10514eaa4710SRishi Srivatsavai if (bfp->bf_nlinks == 0) {
10524eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp);
10534eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE;
10544eaa4710SRishi Srivatsavai } else {
10554eaa4710SRishi Srivatsavai bfp = NULL;
10564eaa4710SRishi Srivatsavai }
10574eaa4710SRishi Srivatsavai }
10584eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
10594eaa4710SRishi Srivatsavai if (bfp != NULL)
10604eaa4710SRishi Srivatsavai fwd_unref(bfp); /* no longer in avl tree */
10614eaa4710SRishi Srivatsavai
10624eaa4710SRishi Srivatsavai /*
10634eaa4710SRishi Srivatsavai * Now get the new link address and add this link to the list. The
10644eaa4710SRishi Srivatsavai * list should be of length 1 unless the user has configured multiple
10654eaa4710SRishi Srivatsavai * NICs with the same address. (That's an incorrect configuration, but
10664eaa4710SRishi Srivatsavai * we support it anyway.)
10674eaa4710SRishi Srivatsavai */
10684eaa4710SRishi Srivatsavai no_old_addr:
10694eaa4710SRishi Srivatsavai bfp = NULL;
10704eaa4710SRishi Srivatsavai if ((bip->bi_flags & BIF_SHUTDOWN) ||
10714eaa4710SRishi Srivatsavai bcmp(newaddr, zero_addr, ETHERADDRL) == 0)
10724eaa4710SRishi Srivatsavai goto no_new_addr;
10734eaa4710SRishi Srivatsavai
10744eaa4710SRishi Srivatsavai bcopy(newaddr, match.bf_dest, ETHERADDRL);
10754eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
10764eaa4710SRishi Srivatsavai if ((bfp = avl_find(&bip->bi_fwd, &match, &idx)) == NULL) {
10774eaa4710SRishi Srivatsavai bfnew = fwd_alloc(newaddr, 1, RBRIDGE_NICKNAME_NONE);
10784eaa4710SRishi Srivatsavai if (bfnew != NULL)
10794eaa4710SRishi Srivatsavai KIINCR(bki_count);
10804eaa4710SRishi Srivatsavai } else if (bfp->bf_nlinks < bfp->bf_maxlinks) {
10814eaa4710SRishi Srivatsavai /* special case: link fits in existing entry */
10824eaa4710SRishi Srivatsavai bfnew = bfp;
10834eaa4710SRishi Srivatsavai } else {
10844eaa4710SRishi Srivatsavai bfnew = fwd_alloc(newaddr, bfp->bf_nlinks + 1,
10854eaa4710SRishi Srivatsavai RBRIDGE_NICKNAME_NONE);
10864eaa4710SRishi Srivatsavai if (bfnew != NULL) {
10874eaa4710SRishi Srivatsavai KIINCR(bki_count);
10884eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp);
10894eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE;
10904eaa4710SRishi Srivatsavai bfnew->bf_nlinks = bfp->bf_nlinks;
10914eaa4710SRishi Srivatsavai bcopy(bfp->bf_links, bfnew->bf_links,
10924eaa4710SRishi Srivatsavai bfp->bf_nlinks * sizeof (bfp));
10934eaa4710SRishi Srivatsavai /* reset the idx value due to removal above */
10944eaa4710SRishi Srivatsavai (void) avl_find(&bip->bi_fwd, &match, &idx);
10954eaa4710SRishi Srivatsavai }
10964eaa4710SRishi Srivatsavai }
10974eaa4710SRishi Srivatsavai
10984eaa4710SRishi Srivatsavai if (bfnew != NULL) {
10994eaa4710SRishi Srivatsavai bfnew->bf_links[bfnew->bf_nlinks++] = blp;
11004eaa4710SRishi Srivatsavai if (drop_ref)
11014eaa4710SRishi Srivatsavai drop_ref = B_FALSE;
11024eaa4710SRishi Srivatsavai else
11034eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_refs); /* bf_links entry */
11044eaa4710SRishi Srivatsavai
11054eaa4710SRishi Srivatsavai if (bfnew != bfp) {
11064eaa4710SRishi Srivatsavai /* local addresses are not subject to table limits */
11074eaa4710SRishi Srivatsavai avl_insert(&bip->bi_fwd, bfnew, idx);
11084eaa4710SRishi Srivatsavai bfnew->bf_flags |= (BFF_INTREE | BFF_LOCALADDR);
11094eaa4710SRishi Srivatsavai atomic_inc_uint(&bfnew->bf_refs); /* avl entry */
11104eaa4710SRishi Srivatsavai }
11114eaa4710SRishi Srivatsavai }
11124eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
11134eaa4710SRishi Srivatsavai
11144eaa4710SRishi Srivatsavai no_new_addr:
11154eaa4710SRishi Srivatsavai /*
11164eaa4710SRishi Srivatsavai * If we found an existing entry and we replaced it with a new one,
11174eaa4710SRishi Srivatsavai * then drop the table reference from the old one. We removed it from
11184eaa4710SRishi Srivatsavai * the AVL tree above.
11194eaa4710SRishi Srivatsavai */
11204eaa4710SRishi Srivatsavai if (bfnew != NULL && bfp != NULL && bfnew != bfp)
11214eaa4710SRishi Srivatsavai fwd_unref(bfp);
11224eaa4710SRishi Srivatsavai
11234eaa4710SRishi Srivatsavai /* Account for removed entry. */
11244eaa4710SRishi Srivatsavai if (drop_ref)
11254eaa4710SRishi Srivatsavai link_unref(blp);
11264eaa4710SRishi Srivatsavai }
11274eaa4710SRishi Srivatsavai
11284eaa4710SRishi Srivatsavai static void
bridge_new_unicst(bridge_link_t * blp)11294eaa4710SRishi Srivatsavai bridge_new_unicst(bridge_link_t *blp)
11304eaa4710SRishi Srivatsavai {
11314eaa4710SRishi Srivatsavai uint8_t new_mac[ETHERADDRL];
11324eaa4710SRishi Srivatsavai
11334eaa4710SRishi Srivatsavai mac_unicast_primary_get(blp->bl_mh, new_mac);
11344eaa4710SRishi Srivatsavai fwd_update_local(blp, blp->bl_local_mac, new_mac);
11354eaa4710SRishi Srivatsavai bcopy(new_mac, blp->bl_local_mac, ETHERADDRL);
11364eaa4710SRishi Srivatsavai }
11374eaa4710SRishi Srivatsavai
11384eaa4710SRishi Srivatsavai /*
11394eaa4710SRishi Srivatsavai * We must shut down a link prior to freeing it, and doing that requires
11404eaa4710SRishi Srivatsavai * blocking to wait for running MAC threads while holding a reference. This is
11414eaa4710SRishi Srivatsavai * run from a taskq to accomplish proper link shutdown followed by reference
11424eaa4710SRishi Srivatsavai * drop.
11434eaa4710SRishi Srivatsavai */
11444eaa4710SRishi Srivatsavai static void
link_shutdown(void * arg)11454eaa4710SRishi Srivatsavai link_shutdown(void *arg)
11464eaa4710SRishi Srivatsavai {
11474eaa4710SRishi Srivatsavai bridge_link_t *blp = arg;
11484eaa4710SRishi Srivatsavai mac_handle_t mh = blp->bl_mh;
11494eaa4710SRishi Srivatsavai bridge_inst_t *bip;
11504eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfnext;
11514eaa4710SRishi Srivatsavai avl_tree_t fwd_scavenge;
11524eaa4710SRishi Srivatsavai int i;
11534eaa4710SRishi Srivatsavai
11544eaa4710SRishi Srivatsavai /*
11554eaa4710SRishi Srivatsavai * This link is being destroyed. Notify TRILL now that it's no longer
11564eaa4710SRishi Srivatsavai * possible to send packets. Data packets may still arrive until TRILL
11574eaa4710SRishi Srivatsavai * calls bridge_trill_lnunref.
11584eaa4710SRishi Srivatsavai */
11594eaa4710SRishi Srivatsavai if (blp->bl_trilldata != NULL)
11604eaa4710SRishi Srivatsavai trill_lndstr_fn(blp->bl_trilldata, blp);
11614eaa4710SRishi Srivatsavai
11624eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_PROM_ADDED)
11634eaa4710SRishi Srivatsavai (void) mac_promisc_remove(blp->bl_mphp);
11644eaa4710SRishi Srivatsavai
11654eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_SET_BRIDGE)
11664eaa4710SRishi Srivatsavai mac_bridge_clear(mh, (mac_handle_t)blp);
11674eaa4710SRishi Srivatsavai
11684eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_MARGIN_ADDED) {
11694249d844SRishi Srivatsavai (void) mac_notify_remove(blp->bl_mnh, B_TRUE);
11704eaa4710SRishi Srivatsavai (void) mac_margin_remove(mh, blp->bl_margin);
11714eaa4710SRishi Srivatsavai }
11724eaa4710SRishi Srivatsavai
11734eaa4710SRishi Srivatsavai /* Tell the clients the real link state when we leave */
11744eaa4710SRishi Srivatsavai mac_link_redo(blp->bl_mh,
11754eaa4710SRishi Srivatsavai mac_stat_get(blp->bl_mh, MAC_STAT_LOWLINK_STATE));
11764eaa4710SRishi Srivatsavai
11774eaa4710SRishi Srivatsavai /* Destroy all of the forwarding entries related to this link */
11784eaa4710SRishi Srivatsavai avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t),
11794eaa4710SRishi Srivatsavai offsetof(bridge_fwd_t, bf_node));
11804eaa4710SRishi Srivatsavai bip = blp->bl_inst;
11814eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
11824eaa4710SRishi Srivatsavai bfnext = avl_first(&bip->bi_fwd);
11834eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) {
11844eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&bip->bi_fwd, bfp);
11854eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++) {
11864eaa4710SRishi Srivatsavai if (bfp->bf_links[i] == blp)
11874eaa4710SRishi Srivatsavai break;
11884eaa4710SRishi Srivatsavai }
11894eaa4710SRishi Srivatsavai if (i >= bfp->bf_nlinks)
11904eaa4710SRishi Srivatsavai continue;
11914eaa4710SRishi Srivatsavai if (bfp->bf_nlinks > 1) {
11924eaa4710SRishi Srivatsavai /* note that this can't be the last reference */
11934eaa4710SRishi Srivatsavai link_unref(blp);
11944eaa4710SRishi Srivatsavai bfp->bf_nlinks--;
11954eaa4710SRishi Srivatsavai for (; i < bfp->bf_nlinks; i++)
11964eaa4710SRishi Srivatsavai bfp->bf_links[i] = bfp->bf_links[i + 1];
11974eaa4710SRishi Srivatsavai } else {
11984eaa4710SRishi Srivatsavai ASSERT(bfp->bf_flags & BFF_INTREE);
11994eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp);
12004eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE;
12014eaa4710SRishi Srivatsavai avl_add(&fwd_scavenge, bfp);
12024eaa4710SRishi Srivatsavai }
12034eaa4710SRishi Srivatsavai }
12044eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
12054eaa4710SRishi Srivatsavai bfnext = avl_first(&fwd_scavenge);
12064eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) {
12074eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&fwd_scavenge, bfp);
12084eaa4710SRishi Srivatsavai avl_remove(&fwd_scavenge, bfp);
12094eaa4710SRishi Srivatsavai fwd_unref(bfp);
12104eaa4710SRishi Srivatsavai }
12114eaa4710SRishi Srivatsavai avl_destroy(&fwd_scavenge);
12124eaa4710SRishi Srivatsavai
12134eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_CLIENT_OPEN)
12144eaa4710SRishi Srivatsavai mac_client_close(blp->bl_mch, 0);
12154eaa4710SRishi Srivatsavai
12164eaa4710SRishi Srivatsavai mac_close(mh);
12174eaa4710SRishi Srivatsavai
12184eaa4710SRishi Srivatsavai /*
12194eaa4710SRishi Srivatsavai * We are now completely removed from the active list, so drop the
12204eaa4710SRishi Srivatsavai * reference (see bridge_add_link).
12214eaa4710SRishi Srivatsavai */
12224eaa4710SRishi Srivatsavai link_unref(blp);
12234eaa4710SRishi Srivatsavai }
12244eaa4710SRishi Srivatsavai
12254eaa4710SRishi Srivatsavai static void
shutdown_inst(bridge_inst_t * bip)12264eaa4710SRishi Srivatsavai shutdown_inst(bridge_inst_t *bip)
12274eaa4710SRishi Srivatsavai {
12284eaa4710SRishi Srivatsavai bridge_link_t *blp, *blnext;
12294eaa4710SRishi Srivatsavai bridge_fwd_t *bfp;
12304eaa4710SRishi Srivatsavai
12314eaa4710SRishi Srivatsavai mutex_enter(&inst_lock);
12324eaa4710SRishi Srivatsavai if (bip->bi_flags & BIF_SHUTDOWN) {
12334eaa4710SRishi Srivatsavai mutex_exit(&inst_lock);
12344eaa4710SRishi Srivatsavai return;
12354eaa4710SRishi Srivatsavai }
12364eaa4710SRishi Srivatsavai
12374eaa4710SRishi Srivatsavai /*
12384eaa4710SRishi Srivatsavai * Once on the inst_list, the bridge instance must not leave that list
12394eaa4710SRishi Srivatsavai * without having the shutdown flag set first. When the shutdown flag
12404eaa4710SRishi Srivatsavai * is set, we own the list reference, so we must drop it before
12414eaa4710SRishi Srivatsavai * returning.
12424eaa4710SRishi Srivatsavai */
12434eaa4710SRishi Srivatsavai bip->bi_flags |= BIF_SHUTDOWN;
12444eaa4710SRishi Srivatsavai mutex_exit(&inst_lock);
12454eaa4710SRishi Srivatsavai
12464eaa4710SRishi Srivatsavai bip->bi_control = NULL;
12474eaa4710SRishi Srivatsavai
12484eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER);
12494eaa4710SRishi Srivatsavai blnext = list_head(&bip->bi_links);
12504eaa4710SRishi Srivatsavai while ((blp = blnext) != NULL) {
12514eaa4710SRishi Srivatsavai blnext = list_next(&bip->bi_links, blp);
12524eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_DELETED)) {
12534eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_DELETED;
12544eaa4710SRishi Srivatsavai (void) ddi_taskq_dispatch(bridge_taskq, link_shutdown,
12554eaa4710SRishi Srivatsavai blp, DDI_SLEEP);
12564eaa4710SRishi Srivatsavai }
12574eaa4710SRishi Srivatsavai }
12584eaa4710SRishi Srivatsavai while ((bfp = avl_first(&bip->bi_fwd)) != NULL) {
12594eaa4710SRishi Srivatsavai atomic_inc_uint(&bfp->bf_refs);
12604eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
12614eaa4710SRishi Srivatsavai fwd_delete(bfp);
12624eaa4710SRishi Srivatsavai fwd_unref(bfp);
12634eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER);
12644eaa4710SRishi Srivatsavai }
12654eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
12664eaa4710SRishi Srivatsavai
12674eaa4710SRishi Srivatsavai /*
12684eaa4710SRishi Srivatsavai * This bridge is being destroyed. Notify TRILL once all of the
12694eaa4710SRishi Srivatsavai * links are all gone.
12704eaa4710SRishi Srivatsavai */
12714eaa4710SRishi Srivatsavai mutex_enter(&inst_lock);
12724eaa4710SRishi Srivatsavai while (bip->bi_trilldata != NULL && !list_is_empty(&bip->bi_links))
12734eaa4710SRishi Srivatsavai cv_wait(&bip->bi_linkwait, &inst_lock);
12744eaa4710SRishi Srivatsavai mutex_exit(&inst_lock);
12754eaa4710SRishi Srivatsavai if (bip->bi_trilldata != NULL)
12764eaa4710SRishi Srivatsavai trill_brdstr_fn(bip->bi_trilldata, bip);
12774eaa4710SRishi Srivatsavai
12784eaa4710SRishi Srivatsavai bridge_unref(bip);
12794eaa4710SRishi Srivatsavai }
12804eaa4710SRishi Srivatsavai
12814eaa4710SRishi Srivatsavai /*
12824eaa4710SRishi Srivatsavai * This is called once by the TRILL module when it starts up. It just sets the
12834eaa4710SRishi Srivatsavai * global TRILL callback function pointers -- data transmit/receive and bridge
12844eaa4710SRishi Srivatsavai * and link destroy notification. There's only one TRILL module, so only one
12854eaa4710SRishi Srivatsavai * registration is needed.
12864eaa4710SRishi Srivatsavai *
12874eaa4710SRishi Srivatsavai * TRILL should call this function with NULL pointers before unloading. It
12884eaa4710SRishi Srivatsavai * must not do so before dropping all references to bridges and links. We
12894eaa4710SRishi Srivatsavai * assert that this is true on debug builds.
12904eaa4710SRishi Srivatsavai */
12914eaa4710SRishi Srivatsavai void
bridge_trill_register_cb(trill_recv_pkt_t recv_fn,trill_encap_pkt_t encap_fn,trill_br_dstr_t brdstr_fn,trill_ln_dstr_t lndstr_fn)12924eaa4710SRishi Srivatsavai bridge_trill_register_cb(trill_recv_pkt_t recv_fn, trill_encap_pkt_t encap_fn,
12934eaa4710SRishi Srivatsavai trill_br_dstr_t brdstr_fn, trill_ln_dstr_t lndstr_fn)
12944eaa4710SRishi Srivatsavai {
12954eaa4710SRishi Srivatsavai #ifdef DEBUG
12964eaa4710SRishi Srivatsavai if (recv_fn == NULL && trill_recv_fn != NULL) {
12974eaa4710SRishi Srivatsavai bridge_inst_t *bip;
12984eaa4710SRishi Srivatsavai bridge_link_t *blp;
12994eaa4710SRishi Srivatsavai
13004eaa4710SRishi Srivatsavai mutex_enter(&inst_lock);
13014eaa4710SRishi Srivatsavai for (bip = list_head(&inst_list); bip != NULL;
13024eaa4710SRishi Srivatsavai bip = list_next(&inst_list, bip)) {
13034eaa4710SRishi Srivatsavai ASSERT(bip->bi_trilldata == NULL);
13044eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER);
13054eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL;
13064eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) {
13074eaa4710SRishi Srivatsavai ASSERT(blp->bl_trilldata == NULL);
13084eaa4710SRishi Srivatsavai }
13094eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
13104eaa4710SRishi Srivatsavai }
13114eaa4710SRishi Srivatsavai mutex_exit(&inst_lock);
13124eaa4710SRishi Srivatsavai }
13134eaa4710SRishi Srivatsavai #endif
13144eaa4710SRishi Srivatsavai trill_recv_fn = recv_fn;
13154eaa4710SRishi Srivatsavai trill_encap_fn = encap_fn;
13164eaa4710SRishi Srivatsavai trill_brdstr_fn = brdstr_fn;
13174eaa4710SRishi Srivatsavai trill_lndstr_fn = lndstr_fn;
13184eaa4710SRishi Srivatsavai }
13194eaa4710SRishi Srivatsavai
13204eaa4710SRishi Srivatsavai /*
13214eaa4710SRishi Srivatsavai * This registers the TRILL instance pointer with a bridge. Before this
13224eaa4710SRishi Srivatsavai * pointer is set, the forwarding, TRILL receive, and bridge destructor
13234eaa4710SRishi Srivatsavai * functions won't be called.
13244eaa4710SRishi Srivatsavai *
13254eaa4710SRishi Srivatsavai * TRILL holds a reference on a bridge with this call. It must free the
13264eaa4710SRishi Srivatsavai * reference by calling the unregister function below.
13274eaa4710SRishi Srivatsavai */
13284eaa4710SRishi Srivatsavai bridge_inst_t *
bridge_trill_brref(const char * bname,void * ptr)13294eaa4710SRishi Srivatsavai bridge_trill_brref(const char *bname, void *ptr)
13304eaa4710SRishi Srivatsavai {
13314eaa4710SRishi Srivatsavai char bridge[MAXLINKNAMELEN];
13324eaa4710SRishi Srivatsavai bridge_inst_t *bip;
13334eaa4710SRishi Srivatsavai
13344eaa4710SRishi Srivatsavai (void) snprintf(bridge, MAXLINKNAMELEN, "%s0", bname);
13354eaa4710SRishi Srivatsavai bip = bridge_find_name(bridge);
13364eaa4710SRishi Srivatsavai if (bip != NULL) {
13374eaa4710SRishi Srivatsavai ASSERT(bip->bi_trilldata == NULL && ptr != NULL);
13384eaa4710SRishi Srivatsavai bip->bi_trilldata = ptr;
13394eaa4710SRishi Srivatsavai }
13404eaa4710SRishi Srivatsavai return (bip);
13414eaa4710SRishi Srivatsavai }
13424eaa4710SRishi Srivatsavai
13434eaa4710SRishi Srivatsavai void
bridge_trill_brunref(bridge_inst_t * bip)13444eaa4710SRishi Srivatsavai bridge_trill_brunref(bridge_inst_t *bip)
13454eaa4710SRishi Srivatsavai {
13464eaa4710SRishi Srivatsavai ASSERT(bip->bi_trilldata != NULL);
13474eaa4710SRishi Srivatsavai bip->bi_trilldata = NULL;
13484eaa4710SRishi Srivatsavai bridge_unref(bip);
13494eaa4710SRishi Srivatsavai }
13504eaa4710SRishi Srivatsavai
13514eaa4710SRishi Srivatsavai /*
13524eaa4710SRishi Srivatsavai * TRILL calls this function when referencing a particular link on a bridge.
13534eaa4710SRishi Srivatsavai *
13544eaa4710SRishi Srivatsavai * It holds a reference on the link, so TRILL must clear out the reference when
13554eaa4710SRishi Srivatsavai * it's done with the link (on unbinding).
13564eaa4710SRishi Srivatsavai */
13574eaa4710SRishi Srivatsavai bridge_link_t *
bridge_trill_lnref(bridge_inst_t * bip,datalink_id_t linkid,void * ptr)13584eaa4710SRishi Srivatsavai bridge_trill_lnref(bridge_inst_t *bip, datalink_id_t linkid, void *ptr)
13594eaa4710SRishi Srivatsavai {
13604eaa4710SRishi Srivatsavai bridge_link_t *blp;
13614eaa4710SRishi Srivatsavai
13624eaa4710SRishi Srivatsavai ASSERT(ptr != NULL);
13634eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER);
13644eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL;
13654eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) {
13664eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_DELETED) &&
13674eaa4710SRishi Srivatsavai blp->bl_linkid == linkid && blp->bl_trilldata == NULL) {
13684eaa4710SRishi Srivatsavai blp->bl_trilldata = ptr;
13694eaa4710SRishi Srivatsavai blp->bl_flags &= ~BLF_TRILLACTIVE;
13704eaa4710SRishi Srivatsavai (void) memset(blp->bl_afs, 0, sizeof (blp->bl_afs));
13714eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_refs);
13724eaa4710SRishi Srivatsavai break;
13734eaa4710SRishi Srivatsavai }
13744eaa4710SRishi Srivatsavai }
13754eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
13764eaa4710SRishi Srivatsavai return (blp);
13774eaa4710SRishi Srivatsavai }
13784eaa4710SRishi Srivatsavai
13794eaa4710SRishi Srivatsavai void
bridge_trill_lnunref(bridge_link_t * blp)13804eaa4710SRishi Srivatsavai bridge_trill_lnunref(bridge_link_t *blp)
13814eaa4710SRishi Srivatsavai {
13824eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock);
13834eaa4710SRishi Srivatsavai ASSERT(blp->bl_trilldata != NULL);
13844eaa4710SRishi Srivatsavai blp->bl_trilldata = NULL;
13854eaa4710SRishi Srivatsavai blp->bl_flags &= ~BLF_TRILLACTIVE;
13864eaa4710SRishi Srivatsavai while (blp->bl_trillthreads > 0)
13874eaa4710SRishi Srivatsavai cv_wait(&blp->bl_trillwait, &blp->bl_trilllock);
13884eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock);
13894eaa4710SRishi Srivatsavai (void) memset(blp->bl_afs, 0xff, sizeof (blp->bl_afs));
13904eaa4710SRishi Srivatsavai link_unref(blp);
13914eaa4710SRishi Srivatsavai }
13924eaa4710SRishi Srivatsavai
13934eaa4710SRishi Srivatsavai /*
13944eaa4710SRishi Srivatsavai * This periodic timer performs three functions:
13954eaa4710SRishi Srivatsavai * 1. It scans the list of learned forwarding entries, and removes ones that
13964eaa4710SRishi Srivatsavai * haven't been heard from in a while. The time limit is backed down if
13974eaa4710SRishi Srivatsavai * we're above the configured table limit.
13984eaa4710SRishi Srivatsavai * 2. It walks the links and decays away the bl_learns counter.
13994eaa4710SRishi Srivatsavai * 3. It scans the observability node entries looking for ones that can be
14004eaa4710SRishi Srivatsavai * freed up.
14014eaa4710SRishi Srivatsavai */
14024eaa4710SRishi Srivatsavai /* ARGSUSED */
14034eaa4710SRishi Srivatsavai static void
bridge_timer(void * arg)14044eaa4710SRishi Srivatsavai bridge_timer(void *arg)
14054eaa4710SRishi Srivatsavai {
14064eaa4710SRishi Srivatsavai bridge_inst_t *bip;
14074eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfnext;
14084eaa4710SRishi Srivatsavai bridge_mac_t *bmp, *bmnext;
14094eaa4710SRishi Srivatsavai bridge_link_t *blp;
14104eaa4710SRishi Srivatsavai int err;
14114eaa4710SRishi Srivatsavai datalink_id_t tmpid;
14124eaa4710SRishi Srivatsavai avl_tree_t fwd_scavenge;
14134eaa4710SRishi Srivatsavai clock_t age_limit;
14144eaa4710SRishi Srivatsavai uint32_t ldecay;
14154eaa4710SRishi Srivatsavai
14164eaa4710SRishi Srivatsavai avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t),
14174eaa4710SRishi Srivatsavai offsetof(bridge_fwd_t, bf_node));
14184eaa4710SRishi Srivatsavai mutex_enter(&inst_lock);
14194eaa4710SRishi Srivatsavai for (bip = list_head(&inst_list); bip != NULL;
14204eaa4710SRishi Srivatsavai bip = list_next(&inst_list, bip)) {
14214eaa4710SRishi Srivatsavai if (bip->bi_flags & BIF_SHUTDOWN)
14224eaa4710SRishi Srivatsavai continue;
14234eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
14244eaa4710SRishi Srivatsavai /* compute scaled maximum age based on table limit */
14254eaa4710SRishi Srivatsavai if (avl_numnodes(&bip->bi_fwd) > bip->bi_tablemax)
14264eaa4710SRishi Srivatsavai bip->bi_tshift++;
14274eaa4710SRishi Srivatsavai else
14284eaa4710SRishi Srivatsavai bip->bi_tshift = 0;
14294eaa4710SRishi Srivatsavai if ((age_limit = bridge_fwd_age >> bip->bi_tshift) == 0) {
14304eaa4710SRishi Srivatsavai if (bip->bi_tshift != 0)
14314eaa4710SRishi Srivatsavai bip->bi_tshift--;
14324eaa4710SRishi Srivatsavai age_limit = 1;
14334eaa4710SRishi Srivatsavai }
14344eaa4710SRishi Srivatsavai bfnext = avl_first(&bip->bi_fwd);
14354eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) {
14364eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&bip->bi_fwd, bfp);
14374eaa4710SRishi Srivatsavai if (!(bfp->bf_flags & BFF_LOCALADDR) &&
1438d3d50737SRafael Vanoni (ddi_get_lbolt() - bfp->bf_lastheard) > age_limit) {
14394eaa4710SRishi Srivatsavai ASSERT(bfp->bf_flags & BFF_INTREE);
14404eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp);
14414eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE;
14424eaa4710SRishi Srivatsavai avl_add(&fwd_scavenge, bfp);
14434eaa4710SRishi Srivatsavai }
14444eaa4710SRishi Srivatsavai }
14454eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL;
14464eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) {
14474eaa4710SRishi Srivatsavai ldecay = mac_get_ldecay(blp->bl_mh);
14484eaa4710SRishi Srivatsavai if (ldecay >= blp->bl_learns)
14494eaa4710SRishi Srivatsavai blp->bl_learns = 0;
14504eaa4710SRishi Srivatsavai else
14514eaa4710SRishi Srivatsavai atomic_add_int(&blp->bl_learns, -(int)ldecay);
14524eaa4710SRishi Srivatsavai }
14534eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
14544eaa4710SRishi Srivatsavai bfnext = avl_first(&fwd_scavenge);
14554eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) {
14564eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&fwd_scavenge, bfp);
14574eaa4710SRishi Srivatsavai avl_remove(&fwd_scavenge, bfp);
14584eaa4710SRishi Srivatsavai KIINCR(bki_expire);
14594eaa4710SRishi Srivatsavai fwd_unref(bfp); /* drop tree reference */
14604eaa4710SRishi Srivatsavai }
14614eaa4710SRishi Srivatsavai }
14624eaa4710SRishi Srivatsavai mutex_exit(&inst_lock);
14634eaa4710SRishi Srivatsavai avl_destroy(&fwd_scavenge);
14644eaa4710SRishi Srivatsavai
14654eaa4710SRishi Srivatsavai /*
14664eaa4710SRishi Srivatsavai * Scan the bridge_mac_t entries and try to free up the ones that are
14674eaa4710SRishi Srivatsavai * no longer active. This must be done by polling, as neither DLS nor
14684eaa4710SRishi Srivatsavai * MAC provides a driver any sort of positive control over clients.
14694eaa4710SRishi Srivatsavai */
14704eaa4710SRishi Srivatsavai rw_enter(&bmac_rwlock, RW_WRITER);
14714eaa4710SRishi Srivatsavai bmnext = list_head(&bmac_list);
14724eaa4710SRishi Srivatsavai while ((bmp = bmnext) != NULL) {
14734eaa4710SRishi Srivatsavai bmnext = list_next(&bmac_list, bmp);
14744eaa4710SRishi Srivatsavai
14754eaa4710SRishi Srivatsavai /* ignore active bridges */
14764eaa4710SRishi Srivatsavai if (bmp->bm_inst != NULL)
14774eaa4710SRishi Srivatsavai continue;
14784eaa4710SRishi Srivatsavai
14794eaa4710SRishi Srivatsavai if (bmp->bm_flags & BMF_DLS) {
14804eaa4710SRishi Srivatsavai err = dls_devnet_destroy(bmp->bm_mh, &tmpid, B_FALSE);
14814eaa4710SRishi Srivatsavai ASSERT(err == 0 || err == EBUSY);
14824eaa4710SRishi Srivatsavai if (err == 0)
14834eaa4710SRishi Srivatsavai bmp->bm_flags &= ~BMF_DLS;
14844eaa4710SRishi Srivatsavai }
14854eaa4710SRishi Srivatsavai
14864eaa4710SRishi Srivatsavai if (!(bmp->bm_flags & BMF_DLS)) {
14874eaa4710SRishi Srivatsavai err = mac_unregister(bmp->bm_mh);
14884eaa4710SRishi Srivatsavai ASSERT(err == 0 || err == EBUSY);
14894eaa4710SRishi Srivatsavai if (err == 0) {
14904eaa4710SRishi Srivatsavai list_remove(&bmac_list, bmp);
14914eaa4710SRishi Srivatsavai kmem_free(bmp, sizeof (*bmp));
14924eaa4710SRishi Srivatsavai }
14934eaa4710SRishi Srivatsavai }
14944eaa4710SRishi Srivatsavai }
14954eaa4710SRishi Srivatsavai if (list_is_empty(&bmac_list)) {
14964eaa4710SRishi Srivatsavai bridge_timerid = 0;
14974eaa4710SRishi Srivatsavai } else {
14984eaa4710SRishi Srivatsavai bridge_timerid = timeout(bridge_timer, NULL,
14994eaa4710SRishi Srivatsavai bridge_scan_interval);
15004eaa4710SRishi Srivatsavai }
15014eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock);
15024eaa4710SRishi Srivatsavai }
15034eaa4710SRishi Srivatsavai
15044eaa4710SRishi Srivatsavai static int
bridge_open(queue_t * rq,dev_t * devp,int oflag,int sflag,cred_t * credp)15054eaa4710SRishi Srivatsavai bridge_open(queue_t *rq, dev_t *devp, int oflag, int sflag, cred_t *credp)
15064eaa4710SRishi Srivatsavai {
15074eaa4710SRishi Srivatsavai bridge_stream_t *bsp;
15084eaa4710SRishi Srivatsavai
15094eaa4710SRishi Srivatsavai if (rq->q_ptr != NULL)
15104eaa4710SRishi Srivatsavai return (0);
15114eaa4710SRishi Srivatsavai
15124eaa4710SRishi Srivatsavai if (sflag & MODOPEN)
15134eaa4710SRishi Srivatsavai return (EINVAL);
15144eaa4710SRishi Srivatsavai
15154eaa4710SRishi Srivatsavai /*
15164eaa4710SRishi Srivatsavai * Check the minor node number being opened. This tells us which
15174eaa4710SRishi Srivatsavai * bridge instance the user wants.
15184eaa4710SRishi Srivatsavai */
15194eaa4710SRishi Srivatsavai if (getminor(*devp) != 0) {
15204eaa4710SRishi Srivatsavai /*
15214eaa4710SRishi Srivatsavai * This is a regular DLPI stream for snoop or the like.
15224eaa4710SRishi Srivatsavai * Redirect it through DLD.
15234eaa4710SRishi Srivatsavai */
15244eaa4710SRishi Srivatsavai rq->q_qinfo = &bridge_dld_rinit;
15254eaa4710SRishi Srivatsavai OTHERQ(rq)->q_qinfo = &bridge_dld_winit;
15264eaa4710SRishi Srivatsavai return (dld_open(rq, devp, oflag, sflag, credp));
15274eaa4710SRishi Srivatsavai } else {
15284eaa4710SRishi Srivatsavai /*
15294eaa4710SRishi Srivatsavai * Allocate the bridge control stream structure.
15304eaa4710SRishi Srivatsavai */
15314eaa4710SRishi Srivatsavai if ((bsp = stream_alloc()) == NULL)
15324eaa4710SRishi Srivatsavai return (ENOSR);
15334eaa4710SRishi Srivatsavai rq->q_ptr = WR(rq)->q_ptr = (caddr_t)bsp;
15344eaa4710SRishi Srivatsavai bsp->bs_wq = WR(rq);
15354eaa4710SRishi Srivatsavai *devp = makedevice(getmajor(*devp), bsp->bs_minor);
15364eaa4710SRishi Srivatsavai qprocson(rq);
15374eaa4710SRishi Srivatsavai return (0);
15384eaa4710SRishi Srivatsavai }
15394eaa4710SRishi Srivatsavai }
15404eaa4710SRishi Srivatsavai
15414eaa4710SRishi Srivatsavai /*
15424eaa4710SRishi Srivatsavai * This is used only for bridge control streams. DLPI goes through dld
15434eaa4710SRishi Srivatsavai * instead.
15444eaa4710SRishi Srivatsavai */
15455e1743f0SToomas Soome /* ARGSUSED */
15464eaa4710SRishi Srivatsavai static int
bridge_close(queue_t * rq,int flags __unused,cred_t * credp __unused)15475e1743f0SToomas Soome bridge_close(queue_t *rq, int flags __unused, cred_t *credp __unused)
15484eaa4710SRishi Srivatsavai {
15494eaa4710SRishi Srivatsavai bridge_stream_t *bsp = rq->q_ptr;
15504eaa4710SRishi Srivatsavai bridge_inst_t *bip;
15514eaa4710SRishi Srivatsavai
15524eaa4710SRishi Srivatsavai /*
15534eaa4710SRishi Srivatsavai * Wait for any stray taskq (add/delete link) entries related to this
15544eaa4710SRishi Srivatsavai * stream to leave the system.
15554eaa4710SRishi Srivatsavai */
15564eaa4710SRishi Srivatsavai mutex_enter(&stream_ref_lock);
15574eaa4710SRishi Srivatsavai while (bsp->bs_taskq_cnt != 0)
15584eaa4710SRishi Srivatsavai cv_wait(&stream_ref_cv, &stream_ref_lock);
15594eaa4710SRishi Srivatsavai mutex_exit(&stream_ref_lock);
15604eaa4710SRishi Srivatsavai
15614eaa4710SRishi Srivatsavai qprocsoff(rq);
15624eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) != NULL)
15634eaa4710SRishi Srivatsavai shutdown_inst(bip);
15644eaa4710SRishi Srivatsavai rq->q_ptr = WR(rq)->q_ptr = NULL;
15654eaa4710SRishi Srivatsavai stream_free(bsp);
15664eaa4710SRishi Srivatsavai if (bip != NULL)
15674eaa4710SRishi Srivatsavai bridge_unref(bip);
15684eaa4710SRishi Srivatsavai
15694eaa4710SRishi Srivatsavai return (0);
15704eaa4710SRishi Srivatsavai }
15714eaa4710SRishi Srivatsavai
15724eaa4710SRishi Srivatsavai static void
bridge_learn(bridge_link_t * blp,const uint8_t * saddr,uint16_t ingress_nick,uint16_t vlanid)15734eaa4710SRishi Srivatsavai bridge_learn(bridge_link_t *blp, const uint8_t *saddr, uint16_t ingress_nick,
15744eaa4710SRishi Srivatsavai uint16_t vlanid)
15754eaa4710SRishi Srivatsavai {
15764eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst;
15774eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfpnew;
15784eaa4710SRishi Srivatsavai int i;
15794eaa4710SRishi Srivatsavai boolean_t replaced = B_FALSE;
15804eaa4710SRishi Srivatsavai
15814eaa4710SRishi Srivatsavai /* Ignore multi-destination address used as source; it's nonsense. */
15824eaa4710SRishi Srivatsavai if (*saddr & 1)
15834eaa4710SRishi Srivatsavai return;
15844eaa4710SRishi Srivatsavai
15854eaa4710SRishi Srivatsavai /*
15864eaa4710SRishi Srivatsavai * If the source is known, then check whether it belongs on this link.
15874eaa4710SRishi Srivatsavai * If not, and this isn't a fixed local address, then we've detected a
15884eaa4710SRishi Srivatsavai * move. If it's not known, learn it.
15894eaa4710SRishi Srivatsavai */
15904eaa4710SRishi Srivatsavai if ((bfp = fwd_find(bip, saddr, vlanid)) != NULL) {
15914eaa4710SRishi Srivatsavai /*
15924eaa4710SRishi Srivatsavai * If the packet has a fixed local source address, then there's
15934eaa4710SRishi Srivatsavai * nothing we can learn. We must quit. If this was a received
15944eaa4710SRishi Srivatsavai * packet, then the sender has stolen our address, but there's
15954eaa4710SRishi Srivatsavai * nothing we can do. If it's a transmitted packet, then
15964eaa4710SRishi Srivatsavai * that's the normal case.
15974eaa4710SRishi Srivatsavai */
15984eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_LOCALADDR) {
15994eaa4710SRishi Srivatsavai fwd_unref(bfp);
16004eaa4710SRishi Srivatsavai return;
16014eaa4710SRishi Srivatsavai }
16024eaa4710SRishi Srivatsavai
16034eaa4710SRishi Srivatsavai /*
16044eaa4710SRishi Srivatsavai * Check if the link (and TRILL sender, if any) being used is
16054eaa4710SRishi Srivatsavai * among the ones registered for this address. If so, then
16064eaa4710SRishi Srivatsavai * this is information that we already know.
16074eaa4710SRishi Srivatsavai */
16084eaa4710SRishi Srivatsavai if (bfp->bf_trill_nick == ingress_nick) {
16094eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++) {
16104eaa4710SRishi Srivatsavai if (bfp->bf_links[i] == blp) {
1611d3d50737SRafael Vanoni bfp->bf_lastheard = ddi_get_lbolt();
16124eaa4710SRishi Srivatsavai fwd_unref(bfp);
16134eaa4710SRishi Srivatsavai return;
16144eaa4710SRishi Srivatsavai }
16154eaa4710SRishi Srivatsavai }
16164eaa4710SRishi Srivatsavai }
16174eaa4710SRishi Srivatsavai }
16184eaa4710SRishi Srivatsavai
16194eaa4710SRishi Srivatsavai /*
16204eaa4710SRishi Srivatsavai * Note that we intentionally "unlearn" things that appear to be under
16214eaa4710SRishi Srivatsavai * attack on this link. The forwarding cache is a negative thing for
16224eaa4710SRishi Srivatsavai * security -- it disables reachability as a performance optimization
16234eaa4710SRishi Srivatsavai * -- so leaving out entries optimizes for success and defends against
16244eaa4710SRishi Srivatsavai * the attack. Thus, the bare increment without a check in the delete
16254eaa4710SRishi Srivatsavai * code above is right. (And it's ok if we skid over the limit a
16264eaa4710SRishi Srivatsavai * little, so there's no syncronization needed on the test.)
16274eaa4710SRishi Srivatsavai */
16284eaa4710SRishi Srivatsavai if (blp->bl_learns >= mac_get_llimit(blp->bl_mh)) {
16294eaa4710SRishi Srivatsavai if (bfp != NULL) {
16304eaa4710SRishi Srivatsavai if (bfp->bf_vcnt == 0)
16314eaa4710SRishi Srivatsavai fwd_delete(bfp);
16324eaa4710SRishi Srivatsavai fwd_unref(bfp);
16334eaa4710SRishi Srivatsavai }
16344eaa4710SRishi Srivatsavai return;
16354eaa4710SRishi Srivatsavai }
16364eaa4710SRishi Srivatsavai
16374eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_learns);
16384eaa4710SRishi Srivatsavai
16394eaa4710SRishi Srivatsavai if ((bfpnew = fwd_alloc(saddr, 1, ingress_nick)) == NULL) {
16404eaa4710SRishi Srivatsavai if (bfp != NULL)
16414eaa4710SRishi Srivatsavai fwd_unref(bfp);
16424eaa4710SRishi Srivatsavai return;
16434eaa4710SRishi Srivatsavai }
16444eaa4710SRishi Srivatsavai KIINCR(bki_count);
16454eaa4710SRishi Srivatsavai
16464eaa4710SRishi Srivatsavai if (bfp != NULL) {
16474eaa4710SRishi Srivatsavai /*
16484eaa4710SRishi Srivatsavai * If this is a new destination for the same VLAN, then delete
16494eaa4710SRishi Srivatsavai * so that we can update. If it's a different VLAN, then we're
16504eaa4710SRishi Srivatsavai * not going to delete the original. Split off instead into an
16514eaa4710SRishi Srivatsavai * IVL entry.
16524eaa4710SRishi Srivatsavai */
16534eaa4710SRishi Srivatsavai if (bfp->bf_vlanid == vlanid) {
16544eaa4710SRishi Srivatsavai /* save the count of IVL duplicates */
16554eaa4710SRishi Srivatsavai bfpnew->bf_vcnt = bfp->bf_vcnt;
16564eaa4710SRishi Srivatsavai
16574eaa4710SRishi Srivatsavai /* entry deletes count as learning events */
16584eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_learns);
16594eaa4710SRishi Srivatsavai
16604eaa4710SRishi Srivatsavai /* destroy and create anew; node moved */
16614eaa4710SRishi Srivatsavai fwd_delete(bfp);
16624eaa4710SRishi Srivatsavai replaced = B_TRUE;
16634eaa4710SRishi Srivatsavai KIINCR(bki_moved);
16644eaa4710SRishi Srivatsavai } else {
16654eaa4710SRishi Srivatsavai bfp->bf_vcnt++;
16664eaa4710SRishi Srivatsavai bfpnew->bf_flags |= BFF_VLANLOCAL;
16674eaa4710SRishi Srivatsavai }
16684eaa4710SRishi Srivatsavai fwd_unref(bfp);
16694eaa4710SRishi Srivatsavai }
16704eaa4710SRishi Srivatsavai bfpnew->bf_links[0] = blp;
16714eaa4710SRishi Srivatsavai bfpnew->bf_nlinks = 1;
16724eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_refs); /* bf_links entry */
16734eaa4710SRishi Srivatsavai if (!fwd_insert(bip, bfpnew))
16744eaa4710SRishi Srivatsavai fwd_free(bfpnew);
16754eaa4710SRishi Srivatsavai else if (!replaced)
16764eaa4710SRishi Srivatsavai KIINCR(bki_source);
16774eaa4710SRishi Srivatsavai }
16784eaa4710SRishi Srivatsavai
16794eaa4710SRishi Srivatsavai /*
16804eaa4710SRishi Srivatsavai * Process the VLAN headers for output on a given link. There are several
16814eaa4710SRishi Srivatsavai * cases (noting that we don't map VLANs):
16824eaa4710SRishi Srivatsavai * 1. The input packet is good as it is; either
16834eaa4710SRishi Srivatsavai * a. It has no tag, and output has same PVID
16844eaa4710SRishi Srivatsavai * b. It has a non-zero priority-only tag for PVID, and b_band is same
16854eaa4710SRishi Srivatsavai * c. It has a tag with VLAN different from PVID, and b_band is same
16864eaa4710SRishi Srivatsavai * 2. The tag must change: non-zero b_band is different from tag priority
16874eaa4710SRishi Srivatsavai * 3. The packet has a tag and should not (VLAN same as PVID, b_band zero)
16884eaa4710SRishi Srivatsavai * 4. The packet has no tag and needs one:
16894eaa4710SRishi Srivatsavai * a. VLAN ID same as PVID, but b_band is non-zero
16904eaa4710SRishi Srivatsavai * b. VLAN ID different from PVID
16914eaa4710SRishi Srivatsavai * We exclude case 1 first, then modify the packet. Note that output packets
16924eaa4710SRishi Srivatsavai * get a priority set by the mblk, not by the header, because QoS in bridging
16934eaa4710SRishi Srivatsavai * requires priority recalculation at each node.
16944eaa4710SRishi Srivatsavai *
16954eaa4710SRishi Srivatsavai * The passed-in tci is the "impossible" value 0xFFFF when no tag is present.
16964eaa4710SRishi Srivatsavai */
16974eaa4710SRishi Srivatsavai static mblk_t *
reform_vlan_header(mblk_t * mp,uint16_t vlanid,uint16_t tci,uint16_t pvid)16984eaa4710SRishi Srivatsavai reform_vlan_header(mblk_t *mp, uint16_t vlanid, uint16_t tci, uint16_t pvid)
16994eaa4710SRishi Srivatsavai {
17004eaa4710SRishi Srivatsavai boolean_t source_has_tag = (tci != 0xFFFF);
17014eaa4710SRishi Srivatsavai mblk_t *mpcopy;
17024eaa4710SRishi Srivatsavai size_t mlen, minlen;
17034eaa4710SRishi Srivatsavai struct ether_vlan_header *evh;
17044eaa4710SRishi Srivatsavai int pri;
17054eaa4710SRishi Srivatsavai
17064eaa4710SRishi Srivatsavai /* This helps centralize error handling in the caller. */
17074eaa4710SRishi Srivatsavai if (mp == NULL)
17084eaa4710SRishi Srivatsavai return (mp);
17094eaa4710SRishi Srivatsavai
1710c61a1653SRyan Zezeski /*
1711c61a1653SRyan Zezeski * A forwarded packet cannot have hardware offloads enabled
1712c61a1653SRyan Zezeski * because we don't know if the destination can handle them.
1713c61a1653SRyan Zezeski * By this point, any hardware offloads present should have
1714c61a1653SRyan Zezeski * been emulated.
1715c61a1653SRyan Zezeski */
17164eaa4710SRishi Srivatsavai DB_CKSUMFLAGS(mp) = 0;
17174eaa4710SRishi Srivatsavai
17184eaa4710SRishi Srivatsavai /* Get the no-modification cases out of the way first */
17194eaa4710SRishi Srivatsavai if (!source_has_tag && vlanid == pvid) /* 1a */
17204eaa4710SRishi Srivatsavai return (mp);
17214eaa4710SRishi Srivatsavai
17224eaa4710SRishi Srivatsavai pri = VLAN_PRI(tci);
17234eaa4710SRishi Srivatsavai if (source_has_tag && mp->b_band == pri) {
17244eaa4710SRishi Srivatsavai if (vlanid != pvid) /* 1c */
17254eaa4710SRishi Srivatsavai return (mp);
17264eaa4710SRishi Srivatsavai if (pri != 0 && VLAN_ID(tci) == 0) /* 1b */
17274eaa4710SRishi Srivatsavai return (mp);
17284eaa4710SRishi Srivatsavai }
17294eaa4710SRishi Srivatsavai
17304eaa4710SRishi Srivatsavai /*
17314eaa4710SRishi Srivatsavai * We now know that we must modify the packet. Prepare for that. Note
17324eaa4710SRishi Srivatsavai * that if a tag is present, the caller has already done a pullup for
17334eaa4710SRishi Srivatsavai * the VLAN header, so we're good to go.
17344eaa4710SRishi Srivatsavai */
17354eaa4710SRishi Srivatsavai if (MBLKL(mp) < sizeof (struct ether_header)) {
17364eaa4710SRishi Srivatsavai mpcopy = msgpullup(mp, sizeof (struct ether_header));
17374eaa4710SRishi Srivatsavai if (mpcopy == NULL) {
17384eaa4710SRishi Srivatsavai freemsg(mp);
17394eaa4710SRishi Srivatsavai return (NULL);
17404eaa4710SRishi Srivatsavai }
17414eaa4710SRishi Srivatsavai mp = mpcopy;
17424eaa4710SRishi Srivatsavai }
17434eaa4710SRishi Srivatsavai if (DB_REF(mp) > 1 || !IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)) ||
17444eaa4710SRishi Srivatsavai (!source_has_tag && MBLKTAIL(mp) < VLAN_INCR)) {
17454eaa4710SRishi Srivatsavai minlen = mlen = MBLKL(mp);
17464eaa4710SRishi Srivatsavai if (!source_has_tag)
17474eaa4710SRishi Srivatsavai minlen += VLAN_INCR;
17484eaa4710SRishi Srivatsavai ASSERT(minlen >= sizeof (struct ether_vlan_header));
17494eaa4710SRishi Srivatsavai /*
17504eaa4710SRishi Srivatsavai * We're willing to copy some data to avoid fragmentation, but
17514eaa4710SRishi Srivatsavai * not a lot.
17524eaa4710SRishi Srivatsavai */
17534eaa4710SRishi Srivatsavai if (minlen > 256)
17544eaa4710SRishi Srivatsavai minlen = sizeof (struct ether_vlan_header);
17554eaa4710SRishi Srivatsavai mpcopy = allocb(minlen, BPRI_MED);
17564eaa4710SRishi Srivatsavai if (mpcopy == NULL) {
17574eaa4710SRishi Srivatsavai freemsg(mp);
17584eaa4710SRishi Srivatsavai return (NULL);
17594eaa4710SRishi Srivatsavai }
17604eaa4710SRishi Srivatsavai if (mlen <= minlen) {
17614eaa4710SRishi Srivatsavai /* We toss the first mblk when we can. */
17624eaa4710SRishi Srivatsavai bcopy(mp->b_rptr, mpcopy->b_rptr, mlen);
17634eaa4710SRishi Srivatsavai mpcopy->b_wptr += mlen;
17644eaa4710SRishi Srivatsavai mpcopy->b_cont = mp->b_cont;
17654eaa4710SRishi Srivatsavai freeb(mp);
17664eaa4710SRishi Srivatsavai } else {
17674eaa4710SRishi Srivatsavai /* If not, then just copy what we need */
17684eaa4710SRishi Srivatsavai if (!source_has_tag)
17694eaa4710SRishi Srivatsavai minlen = sizeof (struct ether_header);
17704eaa4710SRishi Srivatsavai bcopy(mp->b_rptr, mpcopy->b_rptr, minlen);
17714eaa4710SRishi Srivatsavai mpcopy->b_wptr += minlen;
17724eaa4710SRishi Srivatsavai mpcopy->b_cont = mp;
17734eaa4710SRishi Srivatsavai mp->b_rptr += minlen;
17744eaa4710SRishi Srivatsavai }
17754eaa4710SRishi Srivatsavai mp = mpcopy;
17764eaa4710SRishi Srivatsavai }
17774eaa4710SRishi Srivatsavai
17784eaa4710SRishi Srivatsavai /* LINTED: pointer alignment */
17794eaa4710SRishi Srivatsavai evh = (struct ether_vlan_header *)mp->b_rptr;
17804eaa4710SRishi Srivatsavai if (source_has_tag) {
17814eaa4710SRishi Srivatsavai if (mp->b_band == 0 && vlanid == pvid) { /* 3 */
17824eaa4710SRishi Srivatsavai evh->ether_tpid = evh->ether_type;
17834eaa4710SRishi Srivatsavai mlen = MBLKL(mp);
17844eaa4710SRishi Srivatsavai if (mlen > sizeof (struct ether_vlan_header))
17854eaa4710SRishi Srivatsavai ovbcopy(mp->b_rptr +
17864eaa4710SRishi Srivatsavai sizeof (struct ether_vlan_header),
17874eaa4710SRishi Srivatsavai mp->b_rptr + sizeof (struct ether_header),
17884eaa4710SRishi Srivatsavai mlen - sizeof (struct ether_vlan_header));
17894eaa4710SRishi Srivatsavai mp->b_wptr -= VLAN_INCR;
17904eaa4710SRishi Srivatsavai } else { /* 2 */
17914eaa4710SRishi Srivatsavai if (vlanid == pvid)
17924eaa4710SRishi Srivatsavai vlanid = VLAN_ID_NONE;
17934eaa4710SRishi Srivatsavai tci = VLAN_TCI(mp->b_band, ETHER_CFI, vlanid);
17944eaa4710SRishi Srivatsavai evh->ether_tci = htons(tci);
17954eaa4710SRishi Srivatsavai }
17964eaa4710SRishi Srivatsavai } else {
17974eaa4710SRishi Srivatsavai /* case 4: no header present, but one is needed */
17984eaa4710SRishi Srivatsavai mlen = MBLKL(mp);
17994eaa4710SRishi Srivatsavai if (mlen > sizeof (struct ether_header))
18004eaa4710SRishi Srivatsavai ovbcopy(mp->b_rptr + sizeof (struct ether_header),
18014eaa4710SRishi Srivatsavai mp->b_rptr + sizeof (struct ether_vlan_header),
18024eaa4710SRishi Srivatsavai mlen - sizeof (struct ether_header));
18034eaa4710SRishi Srivatsavai mp->b_wptr += VLAN_INCR;
18044eaa4710SRishi Srivatsavai ASSERT(mp->b_wptr <= DB_LIM(mp));
18054eaa4710SRishi Srivatsavai if (vlanid == pvid)
18064eaa4710SRishi Srivatsavai vlanid = VLAN_ID_NONE;
18074eaa4710SRishi Srivatsavai tci = VLAN_TCI(mp->b_band, ETHER_CFI, vlanid);
18084eaa4710SRishi Srivatsavai evh->ether_type = evh->ether_tpid;
18094eaa4710SRishi Srivatsavai evh->ether_tpid = htons(ETHERTYPE_VLAN);
18104eaa4710SRishi Srivatsavai evh->ether_tci = htons(tci);
18114eaa4710SRishi Srivatsavai }
18124eaa4710SRishi Srivatsavai return (mp);
18134eaa4710SRishi Srivatsavai }
18144eaa4710SRishi Srivatsavai
18154eaa4710SRishi Srivatsavai /* Record VLAN information and strip header if requested . */
18164eaa4710SRishi Srivatsavai static void
update_header(mblk_t * mp,mac_header_info_t * hdr_info,boolean_t striphdr)18174eaa4710SRishi Srivatsavai update_header(mblk_t *mp, mac_header_info_t *hdr_info, boolean_t striphdr)
18184eaa4710SRishi Srivatsavai {
18194eaa4710SRishi Srivatsavai if (hdr_info->mhi_bindsap == ETHERTYPE_VLAN) {
18204eaa4710SRishi Srivatsavai struct ether_vlan_header *evhp;
18214eaa4710SRishi Srivatsavai uint16_t ether_type;
18224eaa4710SRishi Srivatsavai
18234eaa4710SRishi Srivatsavai /* LINTED: alignment */
18244eaa4710SRishi Srivatsavai evhp = (struct ether_vlan_header *)mp->b_rptr;
18254eaa4710SRishi Srivatsavai hdr_info->mhi_istagged = B_TRUE;
18264eaa4710SRishi Srivatsavai hdr_info->mhi_tci = ntohs(evhp->ether_tci);
18274eaa4710SRishi Srivatsavai if (striphdr) {
18284eaa4710SRishi Srivatsavai /*
18294eaa4710SRishi Srivatsavai * For VLAN tagged frames update the ether_type
18304eaa4710SRishi Srivatsavai * in hdr_info before stripping the header.
18314eaa4710SRishi Srivatsavai */
18324eaa4710SRishi Srivatsavai ether_type = ntohs(evhp->ether_type);
18334eaa4710SRishi Srivatsavai hdr_info->mhi_origsap = ether_type;
18344eaa4710SRishi Srivatsavai hdr_info->mhi_bindsap = (ether_type > ETHERMTU) ?
18354eaa4710SRishi Srivatsavai ether_type : DLS_SAP_LLC;
18364eaa4710SRishi Srivatsavai mp->b_rptr = (uchar_t *)(evhp + 1);
18374eaa4710SRishi Srivatsavai }
18384eaa4710SRishi Srivatsavai } else {
18394eaa4710SRishi Srivatsavai hdr_info->mhi_istagged = B_FALSE;
18404eaa4710SRishi Srivatsavai hdr_info->mhi_tci = VLAN_ID_NONE;
18414eaa4710SRishi Srivatsavai if (striphdr)
18424eaa4710SRishi Srivatsavai mp->b_rptr += sizeof (struct ether_header);
18434eaa4710SRishi Srivatsavai }
18444eaa4710SRishi Srivatsavai }
18454eaa4710SRishi Srivatsavai
18464eaa4710SRishi Srivatsavai /*
18474eaa4710SRishi Srivatsavai * Return B_TRUE if we're allowed to send on this link with the given VLAN ID.
18484eaa4710SRishi Srivatsavai */
18494eaa4710SRishi Srivatsavai static boolean_t
bridge_can_send(bridge_link_t * blp,uint16_t vlanid)18504eaa4710SRishi Srivatsavai bridge_can_send(bridge_link_t *blp, uint16_t vlanid)
18514eaa4710SRishi Srivatsavai {
18524eaa4710SRishi Srivatsavai ASSERT(vlanid != VLAN_ID_NONE);
18534eaa4710SRishi Srivatsavai if (blp->bl_flags & BLF_DELETED)
18544eaa4710SRishi Srivatsavai return (B_FALSE);
18554eaa4710SRishi Srivatsavai if (blp->bl_trilldata == NULL && blp->bl_state != BLS_FORWARDING)
18564eaa4710SRishi Srivatsavai return (B_FALSE);
18574eaa4710SRishi Srivatsavai return (BRIDGE_VLAN_ISSET(blp, vlanid) && BRIDGE_AF_ISSET(blp, vlanid));
18584eaa4710SRishi Srivatsavai }
18594eaa4710SRishi Srivatsavai
18604eaa4710SRishi Srivatsavai /*
18614eaa4710SRishi Srivatsavai * This function scans the bridge forwarding tables in order to forward a given
18624eaa4710SRishi Srivatsavai * packet. If the packet either doesn't need forwarding (the current link is
18634eaa4710SRishi Srivatsavai * correct) or the current link needs a copy as well, then the packet is
18644eaa4710SRishi Srivatsavai * returned to the caller.
18654eaa4710SRishi Srivatsavai *
18664eaa4710SRishi Srivatsavai * If a packet has been decapsulated from TRILL, then it must *NOT* reenter a
18674eaa4710SRishi Srivatsavai * TRILL tunnel. If the destination points there, then drop instead.
18684eaa4710SRishi Srivatsavai */
18694eaa4710SRishi Srivatsavai static mblk_t *
bridge_forward(bridge_link_t * blp,mac_header_info_t * hdr_info,mblk_t * mp,uint16_t vlanid,uint16_t tci,boolean_t from_trill,boolean_t is_xmit)18704eaa4710SRishi Srivatsavai bridge_forward(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp,
18714eaa4710SRishi Srivatsavai uint16_t vlanid, uint16_t tci, boolean_t from_trill, boolean_t is_xmit)
18724eaa4710SRishi Srivatsavai {
18734eaa4710SRishi Srivatsavai mblk_t *mpsend, *mpcopy;
18744eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst;
18754eaa4710SRishi Srivatsavai bridge_link_t *blpsend, *blpnext;
18764eaa4710SRishi Srivatsavai bridge_fwd_t *bfp;
18774eaa4710SRishi Srivatsavai uint_t i;
18784eaa4710SRishi Srivatsavai boolean_t selfseen = B_FALSE;
18794eaa4710SRishi Srivatsavai void *tdp;
18804eaa4710SRishi Srivatsavai const uint8_t *daddr = hdr_info->mhi_daddr;
18814eaa4710SRishi Srivatsavai
18824eaa4710SRishi Srivatsavai /*
18834eaa4710SRishi Srivatsavai * Check for the IEEE "reserved" multicast addresses. Messages sent to
18844eaa4710SRishi Srivatsavai * these addresses are used for link-local control (STP and pause), and
18854eaa4710SRishi Srivatsavai * are never forwarded or redirected.
18864eaa4710SRishi Srivatsavai */
18874eaa4710SRishi Srivatsavai if (daddr[0] == 1 && daddr[1] == 0x80 && daddr[2] == 0xc2 &&
18884eaa4710SRishi Srivatsavai daddr[3] == 0 && daddr[4] == 0 && (daddr[5] & 0xf0) == 0) {
18894eaa4710SRishi Srivatsavai if (from_trill) {
18904eaa4710SRishi Srivatsavai freemsg(mp);
18914eaa4710SRishi Srivatsavai mp = NULL;
18924eaa4710SRishi Srivatsavai }
18934eaa4710SRishi Srivatsavai return (mp);
18944eaa4710SRishi Srivatsavai }
18954eaa4710SRishi Srivatsavai
18964eaa4710SRishi Srivatsavai if ((bfp = fwd_find(bip, daddr, vlanid)) != NULL) {
18974eaa4710SRishi Srivatsavai
18984eaa4710SRishi Srivatsavai /*
18994eaa4710SRishi Srivatsavai * If trill indicates a destination for this node, then it's
19004eaa4710SRishi Srivatsavai * clearly not intended for local delivery. We must tell TRILL
19014eaa4710SRishi Srivatsavai * to encapsulate, as long as we didn't just decapsulate it.
19024eaa4710SRishi Srivatsavai */
19034eaa4710SRishi Srivatsavai if (bfp->bf_trill_nick != RBRIDGE_NICKNAME_NONE) {
19044eaa4710SRishi Srivatsavai /*
19054eaa4710SRishi Srivatsavai * Error case: can't reencapsulate if the protocols are
19064eaa4710SRishi Srivatsavai * working correctly.
19074eaa4710SRishi Srivatsavai */
19084eaa4710SRishi Srivatsavai if (from_trill) {
19094eaa4710SRishi Srivatsavai freemsg(mp);
19104eaa4710SRishi Srivatsavai return (NULL);
19114eaa4710SRishi Srivatsavai }
19124eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock);
19134eaa4710SRishi Srivatsavai if ((tdp = blp->bl_trilldata) != NULL) {
19144eaa4710SRishi Srivatsavai blp->bl_trillthreads++;
19154eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock);
19164eaa4710SRishi Srivatsavai update_header(mp, hdr_info, B_FALSE);
1917c61a1653SRyan Zezeski
1918c61a1653SRyan Zezeski /*
1919c61a1653SRyan Zezeski * All trill data frames have
1920c61a1653SRyan Zezeski * Inner.VLAN.
1921c61a1653SRyan Zezeski */
19224eaa4710SRishi Srivatsavai mp = reform_vlan_header(mp, vlanid, tci, 0);
1923c61a1653SRyan Zezeski
19244eaa4710SRishi Srivatsavai if (mp == NULL) {
19254eaa4710SRishi Srivatsavai KIINCR(bki_drops);
1926c61a1653SRyan Zezeski goto done;
19274eaa4710SRishi Srivatsavai }
1928c61a1653SRyan Zezeski
19294eaa4710SRishi Srivatsavai trill_encap_fn(tdp, blp, hdr_info, mp,
19304eaa4710SRishi Srivatsavai bfp->bf_trill_nick);
1931c61a1653SRyan Zezeski
1932c61a1653SRyan Zezeski done:
19334eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock);
19344eaa4710SRishi Srivatsavai if (--blp->bl_trillthreads == 0 &&
19354eaa4710SRishi Srivatsavai blp->bl_trilldata == NULL)
19364eaa4710SRishi Srivatsavai cv_broadcast(&blp->bl_trillwait);
19374eaa4710SRishi Srivatsavai }
19384eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock);
19394eaa4710SRishi Srivatsavai
19404eaa4710SRishi Srivatsavai /* if TRILL has been disabled, then kill this stray */
19414eaa4710SRishi Srivatsavai if (tdp == NULL) {
19424eaa4710SRishi Srivatsavai freemsg(mp);
19434eaa4710SRishi Srivatsavai fwd_delete(bfp);
19444eaa4710SRishi Srivatsavai }
19454eaa4710SRishi Srivatsavai fwd_unref(bfp);
19464eaa4710SRishi Srivatsavai return (NULL);
19474eaa4710SRishi Srivatsavai }
19484eaa4710SRishi Srivatsavai
19494eaa4710SRishi Srivatsavai /* find first link we can send on */
19504eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++) {
19514eaa4710SRishi Srivatsavai blpsend = bfp->bf_links[i];
19524eaa4710SRishi Srivatsavai if (blpsend == blp)
19534eaa4710SRishi Srivatsavai selfseen = B_TRUE;
19544eaa4710SRishi Srivatsavai else if (bridge_can_send(blpsend, vlanid))
19554eaa4710SRishi Srivatsavai break;
19564eaa4710SRishi Srivatsavai }
19574eaa4710SRishi Srivatsavai
19584eaa4710SRishi Srivatsavai while (i < bfp->bf_nlinks) {
19594eaa4710SRishi Srivatsavai blpsend = bfp->bf_links[i];
19604eaa4710SRishi Srivatsavai for (i++; i < bfp->bf_nlinks; i++) {
19614eaa4710SRishi Srivatsavai blpnext = bfp->bf_links[i];
19624eaa4710SRishi Srivatsavai if (blpnext == blp)
19634eaa4710SRishi Srivatsavai selfseen = B_TRUE;
19644eaa4710SRishi Srivatsavai else if (bridge_can_send(blpnext, vlanid))
19654eaa4710SRishi Srivatsavai break;
19664eaa4710SRishi Srivatsavai }
19674eaa4710SRishi Srivatsavai if (i == bfp->bf_nlinks && !selfseen) {
19684eaa4710SRishi Srivatsavai mpsend = mp;
19694eaa4710SRishi Srivatsavai mp = NULL;
19704eaa4710SRishi Srivatsavai } else {
19714eaa4710SRishi Srivatsavai mpsend = copymsg(mp);
19724eaa4710SRishi Srivatsavai }
19734eaa4710SRishi Srivatsavai
19744eaa4710SRishi Srivatsavai mpsend = reform_vlan_header(mpsend, vlanid, tci,
19754eaa4710SRishi Srivatsavai blpsend->bl_pvid);
1976c61a1653SRyan Zezeski
19774eaa4710SRishi Srivatsavai if (mpsend == NULL) {
19784eaa4710SRishi Srivatsavai KIINCR(bki_drops);
19794eaa4710SRishi Srivatsavai continue;
19804eaa4710SRishi Srivatsavai }
19814eaa4710SRishi Srivatsavai
19824eaa4710SRishi Srivatsavai KIINCR(bki_forwards);
1983c61a1653SRyan Zezeski
19844eaa4710SRishi Srivatsavai /*
19854eaa4710SRishi Srivatsavai * No need to bump up the link reference count, as
19864eaa4710SRishi Srivatsavai * the forwarding entry itself holds a reference to
19874eaa4710SRishi Srivatsavai * the link.
19884eaa4710SRishi Srivatsavai */
19894eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_LOCALADDR) {
19904eaa4710SRishi Srivatsavai mac_rx_common(blpsend->bl_mh, NULL, mpsend);
19914eaa4710SRishi Srivatsavai } else {
19924eaa4710SRishi Srivatsavai KLPINCR(blpsend, bkl_xmit);
1993c61a1653SRyan Zezeski mpsend = mac_ring_tx(blpsend->bl_mh, NULL,
19944eaa4710SRishi Srivatsavai mpsend);
19954eaa4710SRishi Srivatsavai freemsg(mpsend);
19964eaa4710SRishi Srivatsavai }
19974eaa4710SRishi Srivatsavai }
1998c61a1653SRyan Zezeski
19994eaa4710SRishi Srivatsavai /*
20004eaa4710SRishi Srivatsavai * Handle a special case: if we're transmitting to the original
20014eaa4710SRishi Srivatsavai * link, then check whether the localaddr flag is set. If it
20024eaa4710SRishi Srivatsavai * is, then receive instead. This doesn't happen with ordinary
20034eaa4710SRishi Srivatsavai * bridging, but does happen often with TRILL decapsulation.
20044eaa4710SRishi Srivatsavai */
20054eaa4710SRishi Srivatsavai if (mp != NULL && is_xmit && (bfp->bf_flags & BFF_LOCALADDR)) {
20064eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, NULL, mp);
20074eaa4710SRishi Srivatsavai mp = NULL;
20084eaa4710SRishi Srivatsavai }
20094eaa4710SRishi Srivatsavai fwd_unref(bfp);
20104eaa4710SRishi Srivatsavai } else {
20114eaa4710SRishi Srivatsavai /*
20124eaa4710SRishi Srivatsavai * TRILL has two cases to handle. If the packet is off the
20134eaa4710SRishi Srivatsavai * wire (not from TRILL), then we need to send up into the
20144eaa4710SRishi Srivatsavai * TRILL module to have the distribution tree computed. If the
20154eaa4710SRishi Srivatsavai * packet is from TRILL (decapsulated), then we're part of the
20164eaa4710SRishi Srivatsavai * distribution tree, and we need to copy the packet on member
20174eaa4710SRishi Srivatsavai * interfaces.
20184eaa4710SRishi Srivatsavai *
20194eaa4710SRishi Srivatsavai * Thus, the from TRILL case is identical to the STP case.
20204eaa4710SRishi Srivatsavai */
20214eaa4710SRishi Srivatsavai if (!from_trill && blp->bl_trilldata != NULL) {
20224eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock);
20234eaa4710SRishi Srivatsavai if ((tdp = blp->bl_trilldata) != NULL) {
20244eaa4710SRishi Srivatsavai blp->bl_trillthreads++;
20254eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock);
20264eaa4710SRishi Srivatsavai if ((mpsend = copymsg(mp)) != NULL) {
20274eaa4710SRishi Srivatsavai update_header(mpsend,
20284eaa4710SRishi Srivatsavai hdr_info, B_FALSE);
20294eaa4710SRishi Srivatsavai /*
20304eaa4710SRishi Srivatsavai * all trill data frames have
20314eaa4710SRishi Srivatsavai * Inner.VLAN
20324eaa4710SRishi Srivatsavai */
20334eaa4710SRishi Srivatsavai mpsend = reform_vlan_header(mpsend,
20344eaa4710SRishi Srivatsavai vlanid, tci, 0);
20354eaa4710SRishi Srivatsavai if (mpsend == NULL) {
20364eaa4710SRishi Srivatsavai KIINCR(bki_drops);
20374eaa4710SRishi Srivatsavai } else {
20384eaa4710SRishi Srivatsavai trill_encap_fn(tdp, blp,
20394eaa4710SRishi Srivatsavai hdr_info, mpsend,
20404eaa4710SRishi Srivatsavai RBRIDGE_NICKNAME_NONE);
20414eaa4710SRishi Srivatsavai }
20424eaa4710SRishi Srivatsavai }
20434eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock);
20444eaa4710SRishi Srivatsavai if (--blp->bl_trillthreads == 0 &&
20454eaa4710SRishi Srivatsavai blp->bl_trilldata == NULL)
20464eaa4710SRishi Srivatsavai cv_broadcast(&blp->bl_trillwait);
20474eaa4710SRishi Srivatsavai }
20484eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock);
20494eaa4710SRishi Srivatsavai }
20504eaa4710SRishi Srivatsavai
20514eaa4710SRishi Srivatsavai /*
20524eaa4710SRishi Srivatsavai * This is an unknown destination, so flood.
20534eaa4710SRishi Srivatsavai */
20544eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER);
20554eaa4710SRishi Srivatsavai for (blpnext = list_head(&bip->bi_links); blpnext != NULL;
20564eaa4710SRishi Srivatsavai blpnext = list_next(&bip->bi_links, blpnext)) {
20574eaa4710SRishi Srivatsavai if (blpnext == blp)
20584eaa4710SRishi Srivatsavai selfseen = B_TRUE;
20594eaa4710SRishi Srivatsavai else if (bridge_can_send(blpnext, vlanid))
20604eaa4710SRishi Srivatsavai break;
20614eaa4710SRishi Srivatsavai }
20624eaa4710SRishi Srivatsavai if (blpnext != NULL)
20634eaa4710SRishi Srivatsavai atomic_inc_uint(&blpnext->bl_refs);
20644eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
20654eaa4710SRishi Srivatsavai while ((blpsend = blpnext) != NULL) {
20664eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER);
20674eaa4710SRishi Srivatsavai for (blpnext = list_next(&bip->bi_links, blpsend);
20684eaa4710SRishi Srivatsavai blpnext != NULL;
20694eaa4710SRishi Srivatsavai blpnext = list_next(&bip->bi_links, blpnext)) {
20704eaa4710SRishi Srivatsavai if (blpnext == blp)
20714eaa4710SRishi Srivatsavai selfseen = B_TRUE;
20724eaa4710SRishi Srivatsavai else if (bridge_can_send(blpnext, vlanid))
20734eaa4710SRishi Srivatsavai break;
20744eaa4710SRishi Srivatsavai }
20754eaa4710SRishi Srivatsavai if (blpnext != NULL)
20764eaa4710SRishi Srivatsavai atomic_inc_uint(&blpnext->bl_refs);
20774eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
20784eaa4710SRishi Srivatsavai if (blpnext == NULL && !selfseen) {
20794eaa4710SRishi Srivatsavai mpsend = mp;
20804eaa4710SRishi Srivatsavai mp = NULL;
20814eaa4710SRishi Srivatsavai } else {
20824eaa4710SRishi Srivatsavai mpsend = copymsg(mp);
20834eaa4710SRishi Srivatsavai }
20844eaa4710SRishi Srivatsavai
20854eaa4710SRishi Srivatsavai mpsend = reform_vlan_header(mpsend, vlanid, tci,
20864eaa4710SRishi Srivatsavai blpsend->bl_pvid);
2087c61a1653SRyan Zezeski
20884eaa4710SRishi Srivatsavai if (mpsend == NULL) {
20894eaa4710SRishi Srivatsavai KIINCR(bki_drops);
20904eaa4710SRishi Srivatsavai continue;
20914eaa4710SRishi Srivatsavai }
20924eaa4710SRishi Srivatsavai
20934eaa4710SRishi Srivatsavai if (hdr_info->mhi_dsttype == MAC_ADDRTYPE_UNICAST)
20944eaa4710SRishi Srivatsavai KIINCR(bki_unknown);
20954eaa4710SRishi Srivatsavai else
20964eaa4710SRishi Srivatsavai KIINCR(bki_mbcast);
2097c61a1653SRyan Zezeski
20984eaa4710SRishi Srivatsavai KLPINCR(blpsend, bkl_xmit);
2099c61a1653SRyan Zezeski if ((mpcopy = copymsg(mpsend)) != NULL) {
21004eaa4710SRishi Srivatsavai mac_rx_common(blpsend->bl_mh, NULL, mpcopy);
2101c61a1653SRyan Zezeski }
2102c61a1653SRyan Zezeski
2103c61a1653SRyan Zezeski mpsend = mac_ring_tx(blpsend->bl_mh, NULL, mpsend);
21044eaa4710SRishi Srivatsavai freemsg(mpsend);
21054eaa4710SRishi Srivatsavai link_unref(blpsend);
21064eaa4710SRishi Srivatsavai }
21074eaa4710SRishi Srivatsavai }
21084eaa4710SRishi Srivatsavai
21094eaa4710SRishi Srivatsavai /*
21104eaa4710SRishi Srivatsavai * At this point, if np is non-NULL, it means that the caller needs to
21114eaa4710SRishi Srivatsavai * continue on the selected link.
21124eaa4710SRishi Srivatsavai */
21134eaa4710SRishi Srivatsavai return (mp);
21144eaa4710SRishi Srivatsavai }
21154eaa4710SRishi Srivatsavai
21164eaa4710SRishi Srivatsavai /*
21174eaa4710SRishi Srivatsavai * Extract and validate the VLAN information for a given packet. This checks
21184eaa4710SRishi Srivatsavai * conformance with the rules for use of the PVID on the link, and for the
21194eaa4710SRishi Srivatsavai * allowed (configured) VLAN set.
21204eaa4710SRishi Srivatsavai *
21214eaa4710SRishi Srivatsavai * Returns B_TRUE if the packet passes, B_FALSE if it fails.
21224eaa4710SRishi Srivatsavai */
21234eaa4710SRishi Srivatsavai static boolean_t
bridge_get_vlan(bridge_link_t * blp,mac_header_info_t * hdr_info,mblk_t * mp,uint16_t * vlanidp,uint16_t * tcip)21244eaa4710SRishi Srivatsavai bridge_get_vlan(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp,
21254eaa4710SRishi Srivatsavai uint16_t *vlanidp, uint16_t *tcip)
21264eaa4710SRishi Srivatsavai {
21274eaa4710SRishi Srivatsavai uint16_t tci, vlanid;
21284eaa4710SRishi Srivatsavai
21294eaa4710SRishi Srivatsavai if (hdr_info->mhi_bindsap == ETHERTYPE_VLAN) {
21304eaa4710SRishi Srivatsavai ptrdiff_t tpos = offsetof(struct ether_vlan_header, ether_tci);
21314eaa4710SRishi Srivatsavai ptrdiff_t mlen;
21324eaa4710SRishi Srivatsavai
21334eaa4710SRishi Srivatsavai /*
21344eaa4710SRishi Srivatsavai * Extract the VLAN ID information, regardless of alignment,
21354eaa4710SRishi Srivatsavai * and without a pullup. This isn't attractive, but we do this
21364eaa4710SRishi Srivatsavai * to avoid having to deal with the pointers stashed in
21374eaa4710SRishi Srivatsavai * hdr_info moving around or having the caller deal with a new
21384eaa4710SRishi Srivatsavai * mblk_t pointer.
21394eaa4710SRishi Srivatsavai */
21404eaa4710SRishi Srivatsavai while (mp != NULL) {
21414eaa4710SRishi Srivatsavai mlen = MBLKL(mp);
21424eaa4710SRishi Srivatsavai if (mlen > tpos && mlen > 0)
21434eaa4710SRishi Srivatsavai break;
21444eaa4710SRishi Srivatsavai tpos -= mlen;
21454eaa4710SRishi Srivatsavai mp = mp->b_cont;
21464eaa4710SRishi Srivatsavai }
21474eaa4710SRishi Srivatsavai if (mp == NULL)
21484eaa4710SRishi Srivatsavai return (B_FALSE);
21494eaa4710SRishi Srivatsavai tci = mp->b_rptr[tpos] << 8;
21504eaa4710SRishi Srivatsavai if (++tpos >= mlen) {
21514eaa4710SRishi Srivatsavai do {
21524eaa4710SRishi Srivatsavai mp = mp->b_cont;
21534eaa4710SRishi Srivatsavai } while (mp != NULL && MBLKL(mp) == 0);
21544eaa4710SRishi Srivatsavai if (mp == NULL)
21554eaa4710SRishi Srivatsavai return (B_FALSE);
21564eaa4710SRishi Srivatsavai tpos = 0;
21574eaa4710SRishi Srivatsavai }
21584eaa4710SRishi Srivatsavai tci |= mp->b_rptr[tpos];
21594eaa4710SRishi Srivatsavai
21604eaa4710SRishi Srivatsavai vlanid = VLAN_ID(tci);
21614eaa4710SRishi Srivatsavai if (VLAN_CFI(tci) != ETHER_CFI || vlanid > VLAN_ID_MAX)
21624eaa4710SRishi Srivatsavai return (B_FALSE);
21634eaa4710SRishi Srivatsavai if (vlanid == VLAN_ID_NONE || vlanid == blp->bl_pvid)
21644eaa4710SRishi Srivatsavai goto input_no_vlan;
21654eaa4710SRishi Srivatsavai if (!BRIDGE_VLAN_ISSET(blp, vlanid))
21664eaa4710SRishi Srivatsavai return (B_FALSE);
21674eaa4710SRishi Srivatsavai } else {
21684eaa4710SRishi Srivatsavai tci = 0xFFFF;
21694eaa4710SRishi Srivatsavai input_no_vlan:
21704eaa4710SRishi Srivatsavai /*
21714eaa4710SRishi Srivatsavai * If PVID is set to zero, then untagged traffic is not
21724eaa4710SRishi Srivatsavai * supported here. Do not learn or forward.
21734eaa4710SRishi Srivatsavai */
21744eaa4710SRishi Srivatsavai if ((vlanid = blp->bl_pvid) == VLAN_ID_NONE)
21754eaa4710SRishi Srivatsavai return (B_FALSE);
21764eaa4710SRishi Srivatsavai }
21774eaa4710SRishi Srivatsavai
21784eaa4710SRishi Srivatsavai *tcip = tci;
21794eaa4710SRishi Srivatsavai *vlanidp = vlanid;
21804eaa4710SRishi Srivatsavai return (B_TRUE);
21814eaa4710SRishi Srivatsavai }
21824eaa4710SRishi Srivatsavai
21834eaa4710SRishi Srivatsavai /*
21844eaa4710SRishi Srivatsavai * Handle MAC notifications.
21854eaa4710SRishi Srivatsavai */
21864eaa4710SRishi Srivatsavai static void
bridge_notify_cb(void * arg,mac_notify_type_t note_type)21874eaa4710SRishi Srivatsavai bridge_notify_cb(void *arg, mac_notify_type_t note_type)
21884eaa4710SRishi Srivatsavai {
21894eaa4710SRishi Srivatsavai bridge_link_t *blp = arg;
21904eaa4710SRishi Srivatsavai
21914eaa4710SRishi Srivatsavai switch (note_type) {
21924eaa4710SRishi Srivatsavai case MAC_NOTE_UNICST:
21934eaa4710SRishi Srivatsavai bridge_new_unicst(blp);
21944eaa4710SRishi Srivatsavai break;
21954eaa4710SRishi Srivatsavai
21964eaa4710SRishi Srivatsavai case MAC_NOTE_SDU_SIZE: {
21974eaa4710SRishi Srivatsavai uint_t maxsdu;
21984eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst;
21994eaa4710SRishi Srivatsavai bridge_mac_t *bmp = bip->bi_mac;
22004eaa4710SRishi Srivatsavai boolean_t notify = B_FALSE;
22014eaa4710SRishi Srivatsavai mblk_t *mlist = NULL;
22024eaa4710SRishi Srivatsavai
22034eaa4710SRishi Srivatsavai mac_sdu_get(blp->bl_mh, NULL, &maxsdu);
22044eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER);
22054eaa4710SRishi Srivatsavai if (list_prev(&bip->bi_links, blp) == NULL &&
22064eaa4710SRishi Srivatsavai list_next(&bip->bi_links, blp) == NULL) {
22074eaa4710SRishi Srivatsavai notify = (maxsdu != bmp->bm_maxsdu);
22084eaa4710SRishi Srivatsavai bmp->bm_maxsdu = maxsdu;
22094eaa4710SRishi Srivatsavai }
22104eaa4710SRishi Srivatsavai blp->bl_maxsdu = maxsdu;
22114eaa4710SRishi Srivatsavai if (maxsdu != bmp->bm_maxsdu)
22124eaa4710SRishi Srivatsavai link_sdu_fail(blp, B_TRUE, &mlist);
22134eaa4710SRishi Srivatsavai else if (notify)
22144eaa4710SRishi Srivatsavai (void) mac_maxsdu_update(bmp->bm_mh, maxsdu);
22154eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
22164eaa4710SRishi Srivatsavai send_up_messages(bip, mlist);
22174eaa4710SRishi Srivatsavai break;
22184eaa4710SRishi Srivatsavai }
22194eaa4710SRishi Srivatsavai }
22204eaa4710SRishi Srivatsavai }
22214eaa4710SRishi Srivatsavai
22224eaa4710SRishi Srivatsavai /*
22234eaa4710SRishi Srivatsavai * This is called by the MAC layer. As with the transmit side, we're right in
22244eaa4710SRishi Srivatsavai * the data path for all I/O on this port, so if we don't need to forward this
22254eaa4710SRishi Srivatsavai * packet anywhere, we have to send it upwards via mac_rx_common.
22264eaa4710SRishi Srivatsavai */
22274eaa4710SRishi Srivatsavai static void
bridge_recv_cb(mac_handle_t mh,mac_resource_handle_t rsrc,mblk_t * mpnext)22284eaa4710SRishi Srivatsavai bridge_recv_cb(mac_handle_t mh, mac_resource_handle_t rsrc, mblk_t *mpnext)
22294eaa4710SRishi Srivatsavai {
22304eaa4710SRishi Srivatsavai mblk_t *mp, *mpcopy;
22314eaa4710SRishi Srivatsavai bridge_link_t *blp = (bridge_link_t *)mh;
22324eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst;
22334eaa4710SRishi Srivatsavai bridge_mac_t *bmp = bip->bi_mac;
22344eaa4710SRishi Srivatsavai mac_header_info_t hdr_info;
22354eaa4710SRishi Srivatsavai uint16_t vlanid, tci;
22364eaa4710SRishi Srivatsavai boolean_t trillmode = B_FALSE;
22374eaa4710SRishi Srivatsavai
22384eaa4710SRishi Srivatsavai KIINCR(bki_recv);
22394eaa4710SRishi Srivatsavai KLINCR(bkl_recv);
22404eaa4710SRishi Srivatsavai
22414eaa4710SRishi Srivatsavai /*
22424eaa4710SRishi Srivatsavai * Regardless of state, check for inbound TRILL packets when TRILL is
22434eaa4710SRishi Srivatsavai * active. These are pulled out of band and sent for TRILL handling.
22444eaa4710SRishi Srivatsavai */
22454eaa4710SRishi Srivatsavai if (blp->bl_trilldata != NULL) {
22464eaa4710SRishi Srivatsavai void *tdp;
22474eaa4710SRishi Srivatsavai mblk_t *newhead;
22484eaa4710SRishi Srivatsavai mblk_t *tail = NULL;
22494eaa4710SRishi Srivatsavai
22504eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock);
22514eaa4710SRishi Srivatsavai if ((tdp = blp->bl_trilldata) != NULL) {
22524eaa4710SRishi Srivatsavai blp->bl_trillthreads++;
22534eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock);
22544eaa4710SRishi Srivatsavai trillmode = B_TRUE;
22554eaa4710SRishi Srivatsavai newhead = mpnext;
22564eaa4710SRishi Srivatsavai while ((mp = mpnext) != NULL) {
22574eaa4710SRishi Srivatsavai boolean_t raw_isis, bridge_group;
22584eaa4710SRishi Srivatsavai
22594eaa4710SRishi Srivatsavai mpnext = mp->b_next;
22604eaa4710SRishi Srivatsavai
22614eaa4710SRishi Srivatsavai /*
22624eaa4710SRishi Srivatsavai * If the header isn't readable, then leave on
22634eaa4710SRishi Srivatsavai * the list and continue.
22644eaa4710SRishi Srivatsavai */
22654eaa4710SRishi Srivatsavai if (mac_header_info(blp->bl_mh, mp,
22664eaa4710SRishi Srivatsavai &hdr_info) != 0) {
22674eaa4710SRishi Srivatsavai tail = mp;
22684eaa4710SRishi Srivatsavai continue;
22694eaa4710SRishi Srivatsavai }
22704eaa4710SRishi Srivatsavai
22714eaa4710SRishi Srivatsavai /*
22724eaa4710SRishi Srivatsavai * The TRILL document specifies that, on
22734eaa4710SRishi Srivatsavai * Ethernet alone, IS-IS packets arrive with
22744eaa4710SRishi Srivatsavai * LLC rather than Ethertype, and using a
22754eaa4710SRishi Srivatsavai * specific destination address. We must check
22764eaa4710SRishi Srivatsavai * for that here. Also, we need to give BPDUs
22774eaa4710SRishi Srivatsavai * to TRILL for processing.
22784eaa4710SRishi Srivatsavai */
22794eaa4710SRishi Srivatsavai raw_isis = bridge_group = B_FALSE;
22804eaa4710SRishi Srivatsavai if (hdr_info.mhi_dsttype ==
22814eaa4710SRishi Srivatsavai MAC_ADDRTYPE_MULTICAST) {
22824eaa4710SRishi Srivatsavai if (memcmp(hdr_info.mhi_daddr,
22834eaa4710SRishi Srivatsavai all_isis_rbridges, ETHERADDRL) == 0)
22844eaa4710SRishi Srivatsavai raw_isis = B_TRUE;
22854eaa4710SRishi Srivatsavai else if (memcmp(hdr_info.mhi_daddr,
22864eaa4710SRishi Srivatsavai bridge_group_address, ETHERADDRL) ==
22874eaa4710SRishi Srivatsavai 0)
22884eaa4710SRishi Srivatsavai bridge_group = B_TRUE;
22894eaa4710SRishi Srivatsavai }
22904eaa4710SRishi Srivatsavai if (!raw_isis && !bridge_group &&
22914eaa4710SRishi Srivatsavai hdr_info.mhi_bindsap != ETHERTYPE_TRILL &&
22924eaa4710SRishi Srivatsavai (hdr_info.mhi_bindsap != ETHERTYPE_VLAN ||
22934eaa4710SRishi Srivatsavai /* LINTED: alignment */
22944eaa4710SRishi Srivatsavai ((struct ether_vlan_header *)mp->b_rptr)->
22954eaa4710SRishi Srivatsavai ether_type != htons(ETHERTYPE_TRILL))) {
22964eaa4710SRishi Srivatsavai tail = mp;
22974eaa4710SRishi Srivatsavai continue;
22984eaa4710SRishi Srivatsavai }
22994eaa4710SRishi Srivatsavai
23004eaa4710SRishi Srivatsavai /*
23014eaa4710SRishi Srivatsavai * We've got TRILL input. Remove from the list
23024eaa4710SRishi Srivatsavai * and send up through the TRILL module. (Send
23034eaa4710SRishi Srivatsavai * a copy through promiscuous receive just to
23044eaa4710SRishi Srivatsavai * support snooping on TRILL. Order isn't
23054eaa4710SRishi Srivatsavai * preserved strictly, but that doesn't matter
23064eaa4710SRishi Srivatsavai * here.)
23074eaa4710SRishi Srivatsavai */
23084eaa4710SRishi Srivatsavai if (tail != NULL)
23094eaa4710SRishi Srivatsavai tail->b_next = mpnext;
23104eaa4710SRishi Srivatsavai mp->b_next = NULL;
23114eaa4710SRishi Srivatsavai if (mp == newhead)
23124eaa4710SRishi Srivatsavai newhead = mpnext;
23134eaa4710SRishi Srivatsavai mac_trill_snoop(blp->bl_mh, mp);
23144eaa4710SRishi Srivatsavai update_header(mp, &hdr_info, B_TRUE);
23154eaa4710SRishi Srivatsavai /*
23164eaa4710SRishi Srivatsavai * On raw IS-IS and BPDU frames, we have to
23174eaa4710SRishi Srivatsavai * make sure that the length is trimmed
23184eaa4710SRishi Srivatsavai * properly. We use origsap in order to cope
23194eaa4710SRishi Srivatsavai * with jumbograms for IS-IS. (Regular mac
23204eaa4710SRishi Srivatsavai * can't.)
23214eaa4710SRishi Srivatsavai */
23224eaa4710SRishi Srivatsavai if (raw_isis || bridge_group) {
23234eaa4710SRishi Srivatsavai size_t msglen = msgdsize(mp);
23244eaa4710SRishi Srivatsavai
23254eaa4710SRishi Srivatsavai if (msglen > hdr_info.mhi_origsap) {
23264eaa4710SRishi Srivatsavai (void) adjmsg(mp,
23274eaa4710SRishi Srivatsavai hdr_info.mhi_origsap -
23284eaa4710SRishi Srivatsavai msglen);
23294eaa4710SRishi Srivatsavai } else if (msglen <
23304eaa4710SRishi Srivatsavai hdr_info.mhi_origsap) {
23314eaa4710SRishi Srivatsavai freemsg(mp);
23324eaa4710SRishi Srivatsavai continue;
23334eaa4710SRishi Srivatsavai }
23344eaa4710SRishi Srivatsavai }
23354eaa4710SRishi Srivatsavai trill_recv_fn(tdp, blp, rsrc, mp, &hdr_info);
23364eaa4710SRishi Srivatsavai }
23374eaa4710SRishi Srivatsavai mpnext = newhead;
23384eaa4710SRishi Srivatsavai mutex_enter(&blp->bl_trilllock);
23394eaa4710SRishi Srivatsavai if (--blp->bl_trillthreads == 0 &&
23404eaa4710SRishi Srivatsavai blp->bl_trilldata == NULL)
23414eaa4710SRishi Srivatsavai cv_broadcast(&blp->bl_trillwait);
23424eaa4710SRishi Srivatsavai }
23434eaa4710SRishi Srivatsavai mutex_exit(&blp->bl_trilllock);
23444eaa4710SRishi Srivatsavai if (mpnext == NULL)
23454eaa4710SRishi Srivatsavai return;
23464eaa4710SRishi Srivatsavai }
23474eaa4710SRishi Srivatsavai
23484eaa4710SRishi Srivatsavai /*
23494eaa4710SRishi Srivatsavai * If this is a TRILL RBridge, then just check whether this link is
23504eaa4710SRishi Srivatsavai * used at all for forwarding. If not, then we're done.
23514eaa4710SRishi Srivatsavai */
23524eaa4710SRishi Srivatsavai if (trillmode) {
23534eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_TRILLACTIVE) ||
23544eaa4710SRishi Srivatsavai (blp->bl_flags & BLF_SDUFAIL)) {
23554eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mpnext);
23564eaa4710SRishi Srivatsavai return;
23574eaa4710SRishi Srivatsavai }
23584eaa4710SRishi Srivatsavai } else {
23594eaa4710SRishi Srivatsavai /*
23604eaa4710SRishi Srivatsavai * For regular (STP) bridges, if we're in blocking or listening
23614eaa4710SRishi Srivatsavai * state, then do nothing. We don't learn or forward until
23624eaa4710SRishi Srivatsavai * told to do so.
23634eaa4710SRishi Srivatsavai */
23644eaa4710SRishi Srivatsavai if (blp->bl_state == BLS_BLOCKLISTEN) {
23654eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mpnext);
23664eaa4710SRishi Srivatsavai return;
23674eaa4710SRishi Srivatsavai }
23684eaa4710SRishi Srivatsavai }
23694eaa4710SRishi Srivatsavai
23704eaa4710SRishi Srivatsavai /*
23714eaa4710SRishi Srivatsavai * Send a copy of the message chain up to the observability node users.
23724eaa4710SRishi Srivatsavai * For TRILL, we must obey the VLAN AF rules, so we go packet-by-
23734eaa4710SRishi Srivatsavai * packet.
23744eaa4710SRishi Srivatsavai */
23754eaa4710SRishi Srivatsavai if (!trillmode && blp->bl_state == BLS_FORWARDING &&
23764eaa4710SRishi Srivatsavai (bmp->bm_flags & BMF_STARTED) &&
23774eaa4710SRishi Srivatsavai (mp = copymsgchain(mpnext)) != NULL) {
23784eaa4710SRishi Srivatsavai mac_rx(bmp->bm_mh, NULL, mp);
23794eaa4710SRishi Srivatsavai }
23804eaa4710SRishi Srivatsavai
23814eaa4710SRishi Srivatsavai /*
23824eaa4710SRishi Srivatsavai * We must be in learning or forwarding state, or using TRILL on a link
23834eaa4710SRishi Srivatsavai * with one or more VLANs active. For each packet in the list, process
23844eaa4710SRishi Srivatsavai * the source address, and then attempt to forward.
23854eaa4710SRishi Srivatsavai */
23864eaa4710SRishi Srivatsavai while ((mp = mpnext) != NULL) {
23874eaa4710SRishi Srivatsavai mpnext = mp->b_next;
23884eaa4710SRishi Srivatsavai mp->b_next = NULL;
23894eaa4710SRishi Srivatsavai
23904eaa4710SRishi Srivatsavai /*
23914eaa4710SRishi Srivatsavai * If we can't decode the header or if the header specifies a
23924eaa4710SRishi Srivatsavai * multicast source address (impossible!), then don't bother
23934eaa4710SRishi Srivatsavai * learning or forwarding, but go ahead and forward up the
23944eaa4710SRishi Srivatsavai * stack for subsequent processing.
23954eaa4710SRishi Srivatsavai */
23964eaa4710SRishi Srivatsavai if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0 ||
23974eaa4710SRishi Srivatsavai (hdr_info.mhi_saddr[0] & 1) != 0) {
23984eaa4710SRishi Srivatsavai KIINCR(bki_drops);
23994eaa4710SRishi Srivatsavai KLINCR(bkl_drops);
24004eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mp);
24014eaa4710SRishi Srivatsavai continue;
24024eaa4710SRishi Srivatsavai }
24034eaa4710SRishi Srivatsavai
24044eaa4710SRishi Srivatsavai /*
24054eaa4710SRishi Srivatsavai * Extract and validate the VLAN ID for this packet.
24064eaa4710SRishi Srivatsavai */
24074eaa4710SRishi Srivatsavai if (!bridge_get_vlan(blp, &hdr_info, mp, &vlanid, &tci) ||
24084eaa4710SRishi Srivatsavai !BRIDGE_AF_ISSET(blp, vlanid)) {
24094eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mp);
24104eaa4710SRishi Srivatsavai continue;
24114eaa4710SRishi Srivatsavai }
24124eaa4710SRishi Srivatsavai
24134eaa4710SRishi Srivatsavai if (trillmode) {
24144eaa4710SRishi Srivatsavai /*
24154eaa4710SRishi Srivatsavai * Special test required by TRILL document: must
24164eaa4710SRishi Srivatsavai * discard frames with outer address set to ESADI.
24174eaa4710SRishi Srivatsavai */
24184eaa4710SRishi Srivatsavai if (memcmp(hdr_info.mhi_daddr, all_esadi_rbridges,
24194eaa4710SRishi Srivatsavai ETHERADDRL) == 0) {
24204eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mp);
24214eaa4710SRishi Srivatsavai continue;
24224eaa4710SRishi Srivatsavai }
24234eaa4710SRishi Srivatsavai
24244eaa4710SRishi Srivatsavai /*
24254eaa4710SRishi Srivatsavai * If we're in TRILL mode, then the call above to get
24264eaa4710SRishi Srivatsavai * the VLAN ID has also checked that we're the
24274eaa4710SRishi Srivatsavai * appointed forwarder, so report that we're handling
24284eaa4710SRishi Srivatsavai * this packet to any observability node users.
24294eaa4710SRishi Srivatsavai */
24304eaa4710SRishi Srivatsavai if ((bmp->bm_flags & BMF_STARTED) &&
24314eaa4710SRishi Srivatsavai (mpcopy = copymsg(mp)) != NULL)
24324eaa4710SRishi Srivatsavai mac_rx(bmp->bm_mh, NULL, mpcopy);
24334eaa4710SRishi Srivatsavai }
24344eaa4710SRishi Srivatsavai
24354eaa4710SRishi Srivatsavai /*
24364eaa4710SRishi Srivatsavai * First process the source address and learn from it. For
24374eaa4710SRishi Srivatsavai * TRILL, we learn only if we're the appointed forwarder.
24384eaa4710SRishi Srivatsavai */
24394eaa4710SRishi Srivatsavai bridge_learn(blp, hdr_info.mhi_saddr, RBRIDGE_NICKNAME_NONE,
24404eaa4710SRishi Srivatsavai vlanid);
24414eaa4710SRishi Srivatsavai
24424eaa4710SRishi Srivatsavai /*
24434eaa4710SRishi Srivatsavai * Now check whether we're forwarding and look up the
24444eaa4710SRishi Srivatsavai * destination. If we can forward, do so.
24454eaa4710SRishi Srivatsavai */
24464eaa4710SRishi Srivatsavai if (trillmode || blp->bl_state == BLS_FORWARDING) {
24474eaa4710SRishi Srivatsavai mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci,
24484eaa4710SRishi Srivatsavai B_FALSE, B_FALSE);
24494eaa4710SRishi Srivatsavai }
24504eaa4710SRishi Srivatsavai if (mp != NULL)
24514eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, rsrc, mp);
24524eaa4710SRishi Srivatsavai }
24534eaa4710SRishi Srivatsavai }
24544eaa4710SRishi Srivatsavai
24554eaa4710SRishi Srivatsavai
24564eaa4710SRishi Srivatsavai /* ARGSUSED */
24574eaa4710SRishi Srivatsavai static mblk_t *
bridge_xmit_cb(mac_handle_t mh,mac_ring_handle_t rh,mblk_t * mpnext)24584eaa4710SRishi Srivatsavai bridge_xmit_cb(mac_handle_t mh, mac_ring_handle_t rh, mblk_t *mpnext)
24594eaa4710SRishi Srivatsavai {
24604eaa4710SRishi Srivatsavai bridge_link_t *blp = (bridge_link_t *)mh;
24614eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst;
24624eaa4710SRishi Srivatsavai bridge_mac_t *bmp = bip->bi_mac;
24634eaa4710SRishi Srivatsavai mac_header_info_t hdr_info;
24644eaa4710SRishi Srivatsavai uint16_t vlanid, tci;
24654eaa4710SRishi Srivatsavai mblk_t *mp, *mpcopy;
24664eaa4710SRishi Srivatsavai boolean_t trillmode;
24674eaa4710SRishi Srivatsavai
24684eaa4710SRishi Srivatsavai trillmode = blp->bl_trilldata != NULL;
24694eaa4710SRishi Srivatsavai
24704eaa4710SRishi Srivatsavai /*
24714eaa4710SRishi Srivatsavai * If we're using STP and we're in blocking or listening state, or if
24724eaa4710SRishi Srivatsavai * we're using TRILL and no VLANs are active, then behave as though the
24734eaa4710SRishi Srivatsavai * bridge isn't here at all, and send on the local link alone.
24744eaa4710SRishi Srivatsavai */
24754eaa4710SRishi Srivatsavai if ((!trillmode && blp->bl_state == BLS_BLOCKLISTEN) ||
24764eaa4710SRishi Srivatsavai (trillmode &&
24774eaa4710SRishi Srivatsavai (!(blp->bl_flags & BLF_TRILLACTIVE) ||
24784eaa4710SRishi Srivatsavai (blp->bl_flags & BLF_SDUFAIL)))) {
24794eaa4710SRishi Srivatsavai KIINCR(bki_sent);
24804eaa4710SRishi Srivatsavai KLINCR(bkl_xmit);
2481c61a1653SRyan Zezeski mp = mac_ring_tx(blp->bl_mh, rh, mpnext);
24824eaa4710SRishi Srivatsavai return (mp);
24834eaa4710SRishi Srivatsavai }
24844eaa4710SRishi Srivatsavai
24854eaa4710SRishi Srivatsavai /*
24864eaa4710SRishi Srivatsavai * Send a copy of the message up to the observability node users.
24874eaa4710SRishi Srivatsavai * TRILL needs to check on a packet-by-packet basis.
24884eaa4710SRishi Srivatsavai */
24894eaa4710SRishi Srivatsavai if (!trillmode && blp->bl_state == BLS_FORWARDING &&
24904eaa4710SRishi Srivatsavai (bmp->bm_flags & BMF_STARTED) &&
24914eaa4710SRishi Srivatsavai (mp = copymsgchain(mpnext)) != NULL) {
24924eaa4710SRishi Srivatsavai mac_rx(bmp->bm_mh, NULL, mp);
24934eaa4710SRishi Srivatsavai }
24944eaa4710SRishi Srivatsavai
24954eaa4710SRishi Srivatsavai while ((mp = mpnext) != NULL) {
24964eaa4710SRishi Srivatsavai mpnext = mp->b_next;
24974eaa4710SRishi Srivatsavai mp->b_next = NULL;
24984eaa4710SRishi Srivatsavai
24994eaa4710SRishi Srivatsavai if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0) {
25004eaa4710SRishi Srivatsavai freemsg(mp);
25014eaa4710SRishi Srivatsavai continue;
25024eaa4710SRishi Srivatsavai }
25034eaa4710SRishi Srivatsavai
25044eaa4710SRishi Srivatsavai /*
25054eaa4710SRishi Srivatsavai * Extract and validate the VLAN ID for this packet.
25064eaa4710SRishi Srivatsavai */
25074eaa4710SRishi Srivatsavai if (!bridge_get_vlan(blp, &hdr_info, mp, &vlanid, &tci) ||
25084eaa4710SRishi Srivatsavai !BRIDGE_AF_ISSET(blp, vlanid)) {
25094eaa4710SRishi Srivatsavai freemsg(mp);
25104eaa4710SRishi Srivatsavai continue;
25114eaa4710SRishi Srivatsavai }
25124eaa4710SRishi Srivatsavai
25134eaa4710SRishi Srivatsavai /*
25144eaa4710SRishi Srivatsavai * If we're using TRILL, then we've now validated that we're
25154eaa4710SRishi Srivatsavai * the forwarder for this VLAN, so go ahead and let
25164eaa4710SRishi Srivatsavai * observability node users know about the packet.
25174eaa4710SRishi Srivatsavai */
25184eaa4710SRishi Srivatsavai if (trillmode && (bmp->bm_flags & BMF_STARTED) &&
25194eaa4710SRishi Srivatsavai (mpcopy = copymsg(mp)) != NULL) {
25204eaa4710SRishi Srivatsavai mac_rx(bmp->bm_mh, NULL, mpcopy);
25214eaa4710SRishi Srivatsavai }
25224eaa4710SRishi Srivatsavai
25234eaa4710SRishi Srivatsavai /*
25244eaa4710SRishi Srivatsavai * We have to learn from our own transmitted packets, because
252548bbca81SDaniel Hoffman * there may be a Solaris DLPI raw sender (which can specify its
25264eaa4710SRishi Srivatsavai * own source address) using promiscuous mode for receive. The
25274eaa4710SRishi Srivatsavai * mac layer information won't (and can't) tell us everything
25284eaa4710SRishi Srivatsavai * we need to know.
25294eaa4710SRishi Srivatsavai */
25304eaa4710SRishi Srivatsavai bridge_learn(blp, hdr_info.mhi_saddr, RBRIDGE_NICKNAME_NONE,
25314eaa4710SRishi Srivatsavai vlanid);
25324eaa4710SRishi Srivatsavai
25334eaa4710SRishi Srivatsavai /* attempt forwarding */
25344eaa4710SRishi Srivatsavai if (trillmode || blp->bl_state == BLS_FORWARDING) {
25354eaa4710SRishi Srivatsavai mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci,
25364eaa4710SRishi Srivatsavai B_FALSE, B_TRUE);
25374eaa4710SRishi Srivatsavai }
25384eaa4710SRishi Srivatsavai if (mp != NULL) {
2539c61a1653SRyan Zezeski mp = mac_ring_tx(blp->bl_mh, rh, mp);
25404eaa4710SRishi Srivatsavai if (mp == NULL) {
25414eaa4710SRishi Srivatsavai KIINCR(bki_sent);
25424eaa4710SRishi Srivatsavai KLINCR(bkl_xmit);
25434eaa4710SRishi Srivatsavai }
25444eaa4710SRishi Srivatsavai }
25454eaa4710SRishi Srivatsavai /*
25464eaa4710SRishi Srivatsavai * If we get stuck, then stop. Don't let the user's output
25474eaa4710SRishi Srivatsavai * packets get out of order. (More importantly: don't try to
25484eaa4710SRishi Srivatsavai * bridge the same packet multiple times if flow control is
25494eaa4710SRishi Srivatsavai * asserted.)
25504eaa4710SRishi Srivatsavai */
25514eaa4710SRishi Srivatsavai if (mp != NULL) {
25524eaa4710SRishi Srivatsavai mp->b_next = mpnext;
25534eaa4710SRishi Srivatsavai break;
25544eaa4710SRishi Srivatsavai }
25554eaa4710SRishi Srivatsavai }
25564eaa4710SRishi Srivatsavai return (mp);
25574eaa4710SRishi Srivatsavai }
25584eaa4710SRishi Srivatsavai
25594eaa4710SRishi Srivatsavai /*
25604eaa4710SRishi Srivatsavai * This is called by TRILL when it decapsulates an packet, and we must forward
25614eaa4710SRishi Srivatsavai * locally. On failure, we just drop.
25624eaa4710SRishi Srivatsavai *
25634eaa4710SRishi Srivatsavai * Note that the ingress_nick reported by TRILL must not represent this local
25644eaa4710SRishi Srivatsavai * node.
25654eaa4710SRishi Srivatsavai */
25664eaa4710SRishi Srivatsavai void
bridge_trill_decaps(bridge_link_t * blp,mblk_t * mp,uint16_t ingress_nick)25674eaa4710SRishi Srivatsavai bridge_trill_decaps(bridge_link_t *blp, mblk_t *mp, uint16_t ingress_nick)
25684eaa4710SRishi Srivatsavai {
25694eaa4710SRishi Srivatsavai mac_header_info_t hdr_info;
25704eaa4710SRishi Srivatsavai uint16_t vlanid, tci;
25714eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; /* used by macros */
25724eaa4710SRishi Srivatsavai mblk_t *mpcopy;
25734eaa4710SRishi Srivatsavai
25744eaa4710SRishi Srivatsavai if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0) {
25754eaa4710SRishi Srivatsavai freemsg(mp);
25764eaa4710SRishi Srivatsavai return;
25774eaa4710SRishi Srivatsavai }
25784eaa4710SRishi Srivatsavai
25794eaa4710SRishi Srivatsavai /* Extract VLAN ID for this packet. */
25804eaa4710SRishi Srivatsavai if (hdr_info.mhi_bindsap == ETHERTYPE_VLAN) {
25814eaa4710SRishi Srivatsavai struct ether_vlan_header *evhp;
25824eaa4710SRishi Srivatsavai
25834eaa4710SRishi Srivatsavai /* LINTED: alignment */
25844eaa4710SRishi Srivatsavai evhp = (struct ether_vlan_header *)mp->b_rptr;
25854eaa4710SRishi Srivatsavai tci = ntohs(evhp->ether_tci);
25864eaa4710SRishi Srivatsavai vlanid = VLAN_ID(tci);
25874eaa4710SRishi Srivatsavai } else {
25884eaa4710SRishi Srivatsavai /* Inner VLAN headers are required in TRILL data packets */
25894eaa4710SRishi Srivatsavai DTRACE_PROBE3(bridge__trill__decaps__novlan, bridge_link_t *,
25904eaa4710SRishi Srivatsavai blp, mblk_t *, mp, uint16_t, ingress_nick);
25914eaa4710SRishi Srivatsavai freemsg(mp);
25924eaa4710SRishi Srivatsavai return;
25934eaa4710SRishi Srivatsavai }
25944eaa4710SRishi Srivatsavai
25954eaa4710SRishi Srivatsavai /* Learn the location of this sender in the RBridge network */
25964eaa4710SRishi Srivatsavai bridge_learn(blp, hdr_info.mhi_saddr, ingress_nick, vlanid);
25974eaa4710SRishi Srivatsavai
25984eaa4710SRishi Srivatsavai /* attempt forwarding */
25994eaa4710SRishi Srivatsavai mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci, B_TRUE, B_TRUE);
26004eaa4710SRishi Srivatsavai if (mp != NULL) {
26014eaa4710SRishi Srivatsavai if (bridge_can_send(blp, vlanid)) {
26024eaa4710SRishi Srivatsavai /* Deliver a copy locally as well */
26034eaa4710SRishi Srivatsavai if ((mpcopy = copymsg(mp)) != NULL)
26044eaa4710SRishi Srivatsavai mac_rx_common(blp->bl_mh, NULL, mpcopy);
2605c61a1653SRyan Zezeski mp = mac_ring_tx(blp->bl_mh, NULL, mp);
26064eaa4710SRishi Srivatsavai }
26074eaa4710SRishi Srivatsavai if (mp == NULL) {
26084eaa4710SRishi Srivatsavai KIINCR(bki_sent);
26094eaa4710SRishi Srivatsavai KLINCR(bkl_xmit);
26104eaa4710SRishi Srivatsavai } else {
26114eaa4710SRishi Srivatsavai freemsg(mp);
26124eaa4710SRishi Srivatsavai }
26134eaa4710SRishi Srivatsavai }
26144eaa4710SRishi Srivatsavai }
26154eaa4710SRishi Srivatsavai
26164eaa4710SRishi Srivatsavai /*
26174eaa4710SRishi Srivatsavai * This function is used by TRILL _only_ to transmit TRILL-encapsulated
26184eaa4710SRishi Srivatsavai * packets. It sends on a single underlying link and does not bridge.
26194eaa4710SRishi Srivatsavai */
26204eaa4710SRishi Srivatsavai mblk_t *
bridge_trill_output(bridge_link_t * blp,mblk_t * mp)26214eaa4710SRishi Srivatsavai bridge_trill_output(bridge_link_t *blp, mblk_t *mp)
26224eaa4710SRishi Srivatsavai {
26234eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst; /* used by macros */
26244eaa4710SRishi Srivatsavai
26254eaa4710SRishi Srivatsavai mac_trill_snoop(blp->bl_mh, mp);
2626c61a1653SRyan Zezeski mp = mac_ring_tx(blp->bl_mh, NULL, mp);
26274eaa4710SRishi Srivatsavai if (mp == NULL) {
26284eaa4710SRishi Srivatsavai KIINCR(bki_sent);
26294eaa4710SRishi Srivatsavai KLINCR(bkl_xmit);
26304eaa4710SRishi Srivatsavai }
26314eaa4710SRishi Srivatsavai return (mp);
26324eaa4710SRishi Srivatsavai }
26334eaa4710SRishi Srivatsavai
26344eaa4710SRishi Srivatsavai /*
26354eaa4710SRishi Srivatsavai * Set the "appointed forwarder" flag array for this link. TRILL controls
26364eaa4710SRishi Srivatsavai * forwarding on a VLAN basis. The "trillactive" flag is an optimization for
26374eaa4710SRishi Srivatsavai * the forwarder.
26384eaa4710SRishi Srivatsavai */
26394eaa4710SRishi Srivatsavai void
bridge_trill_setvlans(bridge_link_t * blp,const uint8_t * arr)26404eaa4710SRishi Srivatsavai bridge_trill_setvlans(bridge_link_t *blp, const uint8_t *arr)
26414eaa4710SRishi Srivatsavai {
26424eaa4710SRishi Srivatsavai int i;
26434eaa4710SRishi Srivatsavai uint_t newflags = 0;
26444eaa4710SRishi Srivatsavai
26454eaa4710SRishi Srivatsavai for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) {
26464eaa4710SRishi Srivatsavai if ((blp->bl_afs[i] = arr[i]) != 0)
26474eaa4710SRishi Srivatsavai newflags = BLF_TRILLACTIVE;
26484eaa4710SRishi Srivatsavai }
26494eaa4710SRishi Srivatsavai blp->bl_flags = (blp->bl_flags & ~BLF_TRILLACTIVE) | newflags;
26504eaa4710SRishi Srivatsavai }
26514eaa4710SRishi Srivatsavai
26524eaa4710SRishi Srivatsavai void
bridge_trill_flush(bridge_link_t * blp,uint16_t vlan,boolean_t dotrill)26534eaa4710SRishi Srivatsavai bridge_trill_flush(bridge_link_t *blp, uint16_t vlan, boolean_t dotrill)
26544eaa4710SRishi Srivatsavai {
26554eaa4710SRishi Srivatsavai bridge_inst_t *bip = blp->bl_inst;
26564eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfnext;
26574eaa4710SRishi Srivatsavai avl_tree_t fwd_scavenge;
26584eaa4710SRishi Srivatsavai int i;
26594eaa4710SRishi Srivatsavai
26604eaa4710SRishi Srivatsavai _NOTE(ARGUNUSED(vlan));
26614eaa4710SRishi Srivatsavai
26624eaa4710SRishi Srivatsavai avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t),
26634eaa4710SRishi Srivatsavai offsetof(bridge_fwd_t, bf_node));
26644eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
26654eaa4710SRishi Srivatsavai bfnext = avl_first(&bip->bi_fwd);
26664eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) {
26674eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&bip->bi_fwd, bfp);
26684eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_LOCALADDR)
26694eaa4710SRishi Srivatsavai continue;
26704eaa4710SRishi Srivatsavai if (dotrill) {
26714eaa4710SRishi Srivatsavai /* port doesn't matter if we're flushing TRILL */
26724eaa4710SRishi Srivatsavai if (bfp->bf_trill_nick == RBRIDGE_NICKNAME_NONE)
26734eaa4710SRishi Srivatsavai continue;
26744eaa4710SRishi Srivatsavai } else {
26754eaa4710SRishi Srivatsavai if (bfp->bf_trill_nick != RBRIDGE_NICKNAME_NONE)
26764eaa4710SRishi Srivatsavai continue;
26774eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_nlinks; i++) {
26784eaa4710SRishi Srivatsavai if (bfp->bf_links[i] == blp)
26794eaa4710SRishi Srivatsavai break;
26804eaa4710SRishi Srivatsavai }
26814eaa4710SRishi Srivatsavai if (i >= bfp->bf_nlinks)
26824eaa4710SRishi Srivatsavai continue;
26834eaa4710SRishi Srivatsavai }
26844eaa4710SRishi Srivatsavai ASSERT(bfp->bf_flags & BFF_INTREE);
26854eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp);
26864eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE;
26874eaa4710SRishi Srivatsavai avl_add(&fwd_scavenge, bfp);
26884eaa4710SRishi Srivatsavai }
26894eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
26904eaa4710SRishi Srivatsavai bfnext = avl_first(&fwd_scavenge);
26914eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) {
26924eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&fwd_scavenge, bfp);
26934eaa4710SRishi Srivatsavai avl_remove(&fwd_scavenge, bfp);
26944eaa4710SRishi Srivatsavai fwd_unref(bfp);
26954eaa4710SRishi Srivatsavai }
26964eaa4710SRishi Srivatsavai avl_destroy(&fwd_scavenge);
26974eaa4710SRishi Srivatsavai }
26984eaa4710SRishi Srivatsavai
26994eaa4710SRishi Srivatsavai /*
27004eaa4710SRishi Srivatsavai * Let the mac module take or drop a reference to a bridge link. When this is
27014eaa4710SRishi Srivatsavai * called, the mac module is holding the mi_bridge_lock, so the link cannot be
27024eaa4710SRishi Srivatsavai * in the process of entering or leaving a bridge.
27034eaa4710SRishi Srivatsavai */
27044eaa4710SRishi Srivatsavai static void
bridge_ref_cb(mac_handle_t mh,boolean_t hold)27054eaa4710SRishi Srivatsavai bridge_ref_cb(mac_handle_t mh, boolean_t hold)
27064eaa4710SRishi Srivatsavai {
27074eaa4710SRishi Srivatsavai bridge_link_t *blp = (bridge_link_t *)mh;
27084eaa4710SRishi Srivatsavai
27094eaa4710SRishi Srivatsavai if (hold)
27104eaa4710SRishi Srivatsavai atomic_inc_uint(&blp->bl_refs);
27114eaa4710SRishi Srivatsavai else
27124eaa4710SRishi Srivatsavai link_unref(blp);
27134eaa4710SRishi Srivatsavai }
27144eaa4710SRishi Srivatsavai
27154eaa4710SRishi Srivatsavai /*
27164eaa4710SRishi Srivatsavai * Handle link state changes reported by the mac layer. This acts as a filter
27174eaa4710SRishi Srivatsavai * for link state changes: if a link is reporting down, but there are other
27184eaa4710SRishi Srivatsavai * links still up on the bridge, then the state is changed to "up." When the
27194eaa4710SRishi Srivatsavai * last link goes down, all are marked down, and when the first link goes up,
27204eaa4710SRishi Srivatsavai * all are marked up. (Recursion is avoided by the use of the "redo" function.)
27214eaa4710SRishi Srivatsavai *
27224eaa4710SRishi Srivatsavai * We treat unknown as equivalent to "up."
27234eaa4710SRishi Srivatsavai */
27244eaa4710SRishi Srivatsavai static link_state_t
bridge_ls_cb(mac_handle_t mh,link_state_t newls)27254eaa4710SRishi Srivatsavai bridge_ls_cb(mac_handle_t mh, link_state_t newls)
27264eaa4710SRishi Srivatsavai {
27274eaa4710SRishi Srivatsavai bridge_link_t *blp = (bridge_link_t *)mh;
27284eaa4710SRishi Srivatsavai bridge_link_t *blcmp;
27294eaa4710SRishi Srivatsavai bridge_inst_t *bip;
27304eaa4710SRishi Srivatsavai bridge_mac_t *bmp;
27314eaa4710SRishi Srivatsavai
27324eaa4710SRishi Srivatsavai if (newls != LINK_STATE_DOWN && blp->bl_linkstate != LINK_STATE_DOWN ||
27334eaa4710SRishi Srivatsavai (blp->bl_flags & (BLF_DELETED|BLF_SDUFAIL))) {
27344eaa4710SRishi Srivatsavai blp->bl_linkstate = newls;
27354eaa4710SRishi Srivatsavai return (newls);
27364eaa4710SRishi Srivatsavai }
27374eaa4710SRishi Srivatsavai
27384eaa4710SRishi Srivatsavai /*
27394eaa4710SRishi Srivatsavai * Scan first to see if there are any other non-down links. If there
27404eaa4710SRishi Srivatsavai * are, then we're done. Otherwise, if all others are down, then the
27414eaa4710SRishi Srivatsavai * state of this link is the state of the bridge.
27424eaa4710SRishi Srivatsavai */
27434eaa4710SRishi Srivatsavai bip = blp->bl_inst;
27444eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
27454eaa4710SRishi Srivatsavai for (blcmp = list_head(&bip->bi_links); blcmp != NULL;
27464eaa4710SRishi Srivatsavai blcmp = list_next(&bip->bi_links, blcmp)) {
27474eaa4710SRishi Srivatsavai if (blcmp != blp &&
27484eaa4710SRishi Srivatsavai !(blcmp->bl_flags & (BLF_DELETED|BLF_SDUFAIL)) &&
27494eaa4710SRishi Srivatsavai blcmp->bl_linkstate != LINK_STATE_DOWN)
27504eaa4710SRishi Srivatsavai break;
27514eaa4710SRishi Srivatsavai }
27524eaa4710SRishi Srivatsavai
27534eaa4710SRishi Srivatsavai if (blcmp != NULL) {
27544eaa4710SRishi Srivatsavai /*
27554eaa4710SRishi Srivatsavai * If there are other links that are considered up, then tell
27564eaa4710SRishi Srivatsavai * the caller that the link is actually still up, regardless of
27574eaa4710SRishi Srivatsavai * this link's underlying state.
27584eaa4710SRishi Srivatsavai */
27594eaa4710SRishi Srivatsavai blp->bl_linkstate = newls;
27604eaa4710SRishi Srivatsavai newls = LINK_STATE_UP;
27614eaa4710SRishi Srivatsavai } else if (blp->bl_linkstate != newls) {
27624eaa4710SRishi Srivatsavai /*
27634eaa4710SRishi Srivatsavai * If we've found no other 'up' links, and this link has
27644eaa4710SRishi Srivatsavai * changed state, then report the new state of the bridge to
27654eaa4710SRishi Srivatsavai * all other clients.
27664eaa4710SRishi Srivatsavai */
27674eaa4710SRishi Srivatsavai blp->bl_linkstate = newls;
27684eaa4710SRishi Srivatsavai for (blcmp = list_head(&bip->bi_links); blcmp != NULL;
27694eaa4710SRishi Srivatsavai blcmp = list_next(&bip->bi_links, blcmp)) {
27704eaa4710SRishi Srivatsavai if (blcmp != blp && !(blcmp->bl_flags & BLF_DELETED))
27714eaa4710SRishi Srivatsavai mac_link_redo(blcmp->bl_mh, newls);
27724eaa4710SRishi Srivatsavai }
27734eaa4710SRishi Srivatsavai bmp = bip->bi_mac;
27744eaa4710SRishi Srivatsavai if ((bmp->bm_linkstate = newls) != LINK_STATE_DOWN)
27754eaa4710SRishi Srivatsavai bmp->bm_linkstate = LINK_STATE_UP;
27764eaa4710SRishi Srivatsavai mac_link_redo(bmp->bm_mh, bmp->bm_linkstate);
27774eaa4710SRishi Srivatsavai }
27784eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
27794eaa4710SRishi Srivatsavai return (newls);
27804eaa4710SRishi Srivatsavai }
27814eaa4710SRishi Srivatsavai
27824eaa4710SRishi Srivatsavai static void
bridge_add_link(void * arg)27834eaa4710SRishi Srivatsavai bridge_add_link(void *arg)
27844eaa4710SRishi Srivatsavai {
27854eaa4710SRishi Srivatsavai mblk_t *mp = arg;
27864eaa4710SRishi Srivatsavai bridge_stream_t *bsp;
27874eaa4710SRishi Srivatsavai bridge_inst_t *bip, *bipt;
27884eaa4710SRishi Srivatsavai bridge_mac_t *bmp;
27894eaa4710SRishi Srivatsavai datalink_id_t linkid;
27904eaa4710SRishi Srivatsavai int err;
27914eaa4710SRishi Srivatsavai mac_handle_t mh;
27924eaa4710SRishi Srivatsavai uint_t maxsdu;
27934eaa4710SRishi Srivatsavai bridge_link_t *blp = NULL, *blpt;
27944eaa4710SRishi Srivatsavai const mac_info_t *mip;
27954eaa4710SRishi Srivatsavai boolean_t macopen = B_FALSE;
27964eaa4710SRishi Srivatsavai char linkname[MAXLINKNAMELEN];
27974eaa4710SRishi Srivatsavai char kstatname[KSTAT_STRLEN];
27984eaa4710SRishi Srivatsavai int i;
27994eaa4710SRishi Srivatsavai link_state_t linkstate;
28004eaa4710SRishi Srivatsavai mblk_t *mlist;
28014eaa4710SRishi Srivatsavai
28024eaa4710SRishi Srivatsavai bsp = (bridge_stream_t *)mp->b_next;
28034eaa4710SRishi Srivatsavai mp->b_next = NULL;
28044eaa4710SRishi Srivatsavai bip = bsp->bs_inst;
28054eaa4710SRishi Srivatsavai /* LINTED: alignment */
28064eaa4710SRishi Srivatsavai linkid = *(datalink_id_t *)mp->b_cont->b_rptr;
28074eaa4710SRishi Srivatsavai
28084eaa4710SRishi Srivatsavai /*
28094eaa4710SRishi Srivatsavai * First make sure that there is no other bridge that has this link.
28104eaa4710SRishi Srivatsavai * We don't want to overlap operations from two bridges; the MAC layer
28114eaa4710SRishi Srivatsavai * supports only one bridge on a given MAC at a time.
28124eaa4710SRishi Srivatsavai *
28134eaa4710SRishi Srivatsavai * We rely on the fact that there's just one taskq thread for the
28144eaa4710SRishi Srivatsavai * bridging module: once we've checked for a duplicate, we can drop the
28154eaa4710SRishi Srivatsavai * lock, because no other thread could possibly be adding another link
28164eaa4710SRishi Srivatsavai * until we're done.
28174eaa4710SRishi Srivatsavai */
28184eaa4710SRishi Srivatsavai mutex_enter(&inst_lock);
28194eaa4710SRishi Srivatsavai for (bipt = list_head(&inst_list); bipt != NULL;
28204eaa4710SRishi Srivatsavai bipt = list_next(&inst_list, bipt)) {
28214eaa4710SRishi Srivatsavai rw_enter(&bipt->bi_rwlock, RW_READER);
28224eaa4710SRishi Srivatsavai for (blpt = list_head(&bipt->bi_links); blpt != NULL;
28234eaa4710SRishi Srivatsavai blpt = list_next(&bipt->bi_links, blpt)) {
28244eaa4710SRishi Srivatsavai if (linkid == blpt->bl_linkid)
28254eaa4710SRishi Srivatsavai break;
28264eaa4710SRishi Srivatsavai }
28274eaa4710SRishi Srivatsavai rw_exit(&bipt->bi_rwlock);
28284eaa4710SRishi Srivatsavai if (blpt != NULL)
28294eaa4710SRishi Srivatsavai break;
28304eaa4710SRishi Srivatsavai }
28314eaa4710SRishi Srivatsavai mutex_exit(&inst_lock);
28324eaa4710SRishi Srivatsavai if (bipt != NULL) {
28334eaa4710SRishi Srivatsavai err = EBUSY;
28344eaa4710SRishi Srivatsavai goto fail;
28354eaa4710SRishi Srivatsavai }
28364eaa4710SRishi Srivatsavai
28374eaa4710SRishi Srivatsavai if ((err = mac_open_by_linkid(linkid, &mh)) != 0)
28384eaa4710SRishi Srivatsavai goto fail;
28394eaa4710SRishi Srivatsavai macopen = B_TRUE;
28404eaa4710SRishi Srivatsavai
28414eaa4710SRishi Srivatsavai /* we bridge only Ethernet */
28424eaa4710SRishi Srivatsavai mip = mac_info(mh);
28434eaa4710SRishi Srivatsavai if (mip->mi_media != DL_ETHER) {
28444eaa4710SRishi Srivatsavai err = ENOTSUP;
28454eaa4710SRishi Srivatsavai goto fail;
28464eaa4710SRishi Srivatsavai }
28474eaa4710SRishi Srivatsavai
28484eaa4710SRishi Srivatsavai /*
28494eaa4710SRishi Srivatsavai * Get the current maximum SDU on this interface. If there are other
28504eaa4710SRishi Srivatsavai * links on the bridge, then this one must match, or it errors out.
28514eaa4710SRishi Srivatsavai * Otherwise, the first link becomes the standard for the new bridge.
28524eaa4710SRishi Srivatsavai */
28534eaa4710SRishi Srivatsavai mac_sdu_get(mh, NULL, &maxsdu);
28544eaa4710SRishi Srivatsavai bmp = bip->bi_mac;
28554eaa4710SRishi Srivatsavai if (list_is_empty(&bip->bi_links)) {
28564eaa4710SRishi Srivatsavai bmp->bm_maxsdu = maxsdu;
28574eaa4710SRishi Srivatsavai (void) mac_maxsdu_update(bmp->bm_mh, maxsdu);
28584eaa4710SRishi Srivatsavai }
28594eaa4710SRishi Srivatsavai
28604eaa4710SRishi Srivatsavai /* figure the kstat name; also used as the mac client name */
28614eaa4710SRishi Srivatsavai i = MBLKL(mp->b_cont) - sizeof (datalink_id_t);
28624eaa4710SRishi Srivatsavai if (i < 0 || i >= MAXLINKNAMELEN)
28634eaa4710SRishi Srivatsavai i = MAXLINKNAMELEN - 1;
28644eaa4710SRishi Srivatsavai bcopy(mp->b_cont->b_rptr + sizeof (datalink_id_t), linkname, i);
28654eaa4710SRishi Srivatsavai linkname[i] = '\0';
28664eaa4710SRishi Srivatsavai (void) snprintf(kstatname, sizeof (kstatname), "%s-%s", bip->bi_name,
28674eaa4710SRishi Srivatsavai linkname);
28684eaa4710SRishi Srivatsavai
28694eaa4710SRishi Srivatsavai if ((blp = kmem_zalloc(sizeof (*blp), KM_NOSLEEP)) == NULL) {
28704eaa4710SRishi Srivatsavai err = ENOMEM;
28714eaa4710SRishi Srivatsavai goto fail;
28724eaa4710SRishi Srivatsavai }
28734eaa4710SRishi Srivatsavai blp->bl_lfailmp = allocb(sizeof (bridge_ctl_t), BPRI_MED);
28744eaa4710SRishi Srivatsavai if (blp->bl_lfailmp == NULL) {
28754eaa4710SRishi Srivatsavai kmem_free(blp, sizeof (*blp));
28766f40bf67SRishi Srivatsavai blp = NULL;
28774eaa4710SRishi Srivatsavai err = ENOMEM;
28784eaa4710SRishi Srivatsavai goto fail;
28794eaa4710SRishi Srivatsavai }
28804eaa4710SRishi Srivatsavai
28816f40bf67SRishi Srivatsavai blp->bl_refs = 1;
28824eaa4710SRishi Srivatsavai atomic_inc_uint(&bip->bi_refs);
28834eaa4710SRishi Srivatsavai blp->bl_inst = bip;
28844eaa4710SRishi Srivatsavai blp->bl_mh = mh;
28854eaa4710SRishi Srivatsavai blp->bl_linkid = linkid;
28864eaa4710SRishi Srivatsavai blp->bl_maxsdu = maxsdu;
28874eaa4710SRishi Srivatsavai cv_init(&blp->bl_trillwait, NULL, CV_DRIVER, NULL);
28884eaa4710SRishi Srivatsavai mutex_init(&blp->bl_trilllock, NULL, MUTEX_DRIVER, NULL);
28894eaa4710SRishi Srivatsavai (void) memset(blp->bl_afs, 0xff, sizeof (blp->bl_afs));
28904eaa4710SRishi Srivatsavai
28914eaa4710SRishi Srivatsavai err = mac_client_open(mh, &blp->bl_mch, kstatname, 0);
28924eaa4710SRishi Srivatsavai if (err != 0)
28934eaa4710SRishi Srivatsavai goto fail;
28944eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_CLIENT_OPEN;
28954eaa4710SRishi Srivatsavai
28964eaa4710SRishi Srivatsavai err = mac_margin_add(mh, &blp->bl_margin, B_TRUE);
28974eaa4710SRishi Srivatsavai if (err != 0)
28984eaa4710SRishi Srivatsavai goto fail;
28994eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_MARGIN_ADDED;
29004eaa4710SRishi Srivatsavai
29014eaa4710SRishi Srivatsavai blp->bl_mnh = mac_notify_add(mh, bridge_notify_cb, blp);
29024eaa4710SRishi Srivatsavai
29036f40bf67SRishi Srivatsavai /* Enable Bridging on the link */
29044eaa4710SRishi Srivatsavai err = mac_bridge_set(mh, (mac_handle_t)blp);
29054eaa4710SRishi Srivatsavai if (err != 0)
29064eaa4710SRishi Srivatsavai goto fail;
29074eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_SET_BRIDGE;
29084eaa4710SRishi Srivatsavai
29094eaa4710SRishi Srivatsavai err = mac_promisc_add(blp->bl_mch, MAC_CLIENT_PROMISC_ALL, NULL,
29104eaa4710SRishi Srivatsavai blp, &blp->bl_mphp, MAC_PROMISC_FLAGS_NO_TX_LOOP);
29114eaa4710SRishi Srivatsavai if (err != 0)
29124eaa4710SRishi Srivatsavai goto fail;
29134eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_PROM_ADDED;
29144eaa4710SRishi Srivatsavai
29154eaa4710SRishi Srivatsavai bridge_new_unicst(blp);
29164eaa4710SRishi Srivatsavai
29174eaa4710SRishi Srivatsavai blp->bl_ksp = kstat_setup((kstat_named_t *)&blp->bl_kstats,
29184eaa4710SRishi Srivatsavai link_kstats_list, Dim(link_kstats_list), kstatname);
29194eaa4710SRishi Srivatsavai
29204eaa4710SRishi Srivatsavai /*
29214eaa4710SRishi Srivatsavai * The link holds a reference to the bridge instance, so that the
29224eaa4710SRishi Srivatsavai * instance can't go away before the link is freed. The insertion into
29236f40bf67SRishi Srivatsavai * bi_links holds a reference on the link (reference set to 1 above).
29246f40bf67SRishi Srivatsavai * When marking as removed from bi_links (BLF_DELETED), drop the
29256f40bf67SRishi Srivatsavai * reference on the link. When freeing the link, drop the reference on
29266f40bf67SRishi Srivatsavai * the instance. BLF_LINK_ADDED tracks link insertion in bi_links list.
29274eaa4710SRishi Srivatsavai */
29284eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
29294eaa4710SRishi Srivatsavai list_insert_tail(&bip->bi_links, blp);
29306f40bf67SRishi Srivatsavai blp->bl_flags |= BLF_LINK_ADDED;
29314eaa4710SRishi Srivatsavai
29324eaa4710SRishi Srivatsavai /*
29334eaa4710SRishi Srivatsavai * If the new link is no good on this bridge, then let the daemon know
29344eaa4710SRishi Srivatsavai * about the problem.
29354eaa4710SRishi Srivatsavai */
29364eaa4710SRishi Srivatsavai mlist = NULL;
29374eaa4710SRishi Srivatsavai if (maxsdu != bmp->bm_maxsdu)
29384eaa4710SRishi Srivatsavai link_sdu_fail(blp, B_TRUE, &mlist);
29394eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
29404eaa4710SRishi Srivatsavai send_up_messages(bip, mlist);
29414eaa4710SRishi Srivatsavai
29424eaa4710SRishi Srivatsavai /*
29434eaa4710SRishi Srivatsavai * Trigger a link state update so that if this link is the first one
29444eaa4710SRishi Srivatsavai * "up" in the bridge, then we notify everyone. This triggers a trip
29454eaa4710SRishi Srivatsavai * through bridge_ls_cb.
29464eaa4710SRishi Srivatsavai */
29474eaa4710SRishi Srivatsavai linkstate = mac_stat_get(mh, MAC_STAT_LOWLINK_STATE);
29484eaa4710SRishi Srivatsavai blp->bl_linkstate = LINK_STATE_DOWN;
29494eaa4710SRishi Srivatsavai mac_link_update(mh, linkstate);
29504eaa4710SRishi Srivatsavai
29514eaa4710SRishi Srivatsavai /*
29524eaa4710SRishi Srivatsavai * We now need to report back to the stream that invoked us, and then
29534eaa4710SRishi Srivatsavai * drop the reference on the stream that we're holding.
29544eaa4710SRishi Srivatsavai */
29554eaa4710SRishi Srivatsavai miocack(bsp->bs_wq, mp, 0, 0);
29564eaa4710SRishi Srivatsavai stream_unref(bsp);
29574eaa4710SRishi Srivatsavai return;
29584eaa4710SRishi Srivatsavai
29594eaa4710SRishi Srivatsavai fail:
29604eaa4710SRishi Srivatsavai if (blp == NULL) {
29614eaa4710SRishi Srivatsavai if (macopen)
29624eaa4710SRishi Srivatsavai mac_close(mh);
29634eaa4710SRishi Srivatsavai } else {
29644eaa4710SRishi Srivatsavai link_shutdown(blp);
29654eaa4710SRishi Srivatsavai }
29664eaa4710SRishi Srivatsavai miocnak(bsp->bs_wq, mp, 0, err);
29674eaa4710SRishi Srivatsavai stream_unref(bsp);
29684eaa4710SRishi Srivatsavai }
29694eaa4710SRishi Srivatsavai
29704eaa4710SRishi Srivatsavai static void
bridge_rem_link(void * arg)29714eaa4710SRishi Srivatsavai bridge_rem_link(void *arg)
29724eaa4710SRishi Srivatsavai {
29734eaa4710SRishi Srivatsavai mblk_t *mp = arg;
29744eaa4710SRishi Srivatsavai bridge_stream_t *bsp;
29754eaa4710SRishi Srivatsavai bridge_inst_t *bip;
29764eaa4710SRishi Srivatsavai bridge_mac_t *bmp;
29774eaa4710SRishi Srivatsavai datalink_id_t linkid;
29784eaa4710SRishi Srivatsavai bridge_link_t *blp, *blsave;
29794eaa4710SRishi Srivatsavai boolean_t found;
29804eaa4710SRishi Srivatsavai mblk_t *mlist;
29814eaa4710SRishi Srivatsavai
29824eaa4710SRishi Srivatsavai bsp = (bridge_stream_t *)mp->b_next;
29834eaa4710SRishi Srivatsavai mp->b_next = NULL;
29844eaa4710SRishi Srivatsavai bip = bsp->bs_inst;
29854eaa4710SRishi Srivatsavai /* LINTED: alignment */
29864eaa4710SRishi Srivatsavai linkid = *(datalink_id_t *)mp->b_cont->b_rptr;
29874eaa4710SRishi Srivatsavai
29884eaa4710SRishi Srivatsavai /*
29894eaa4710SRishi Srivatsavai * We become reader here so that we can loop over the other links and
29904eaa4710SRishi Srivatsavai * deliver link up/down notification.
29914eaa4710SRishi Srivatsavai */
29924eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER);
29934eaa4710SRishi Srivatsavai found = B_FALSE;
29944eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL;
29954eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) {
29964eaa4710SRishi Srivatsavai if (blp->bl_linkid == linkid &&
29974eaa4710SRishi Srivatsavai !(blp->bl_flags & BLF_DELETED)) {
29984eaa4710SRishi Srivatsavai blp->bl_flags |= BLF_DELETED;
29994eaa4710SRishi Srivatsavai (void) ddi_taskq_dispatch(bridge_taskq, link_shutdown,
30004eaa4710SRishi Srivatsavai blp, DDI_SLEEP);
30014eaa4710SRishi Srivatsavai found = B_TRUE;
30024eaa4710SRishi Srivatsavai break;
30034eaa4710SRishi Srivatsavai }
30044eaa4710SRishi Srivatsavai }
30054eaa4710SRishi Srivatsavai
30064eaa4710SRishi Srivatsavai /*
30074eaa4710SRishi Srivatsavai * Check if this link is up and the remainder of the links are all
30084eaa4710SRishi Srivatsavai * down.
30094eaa4710SRishi Srivatsavai */
30104eaa4710SRishi Srivatsavai if (blp != NULL && blp->bl_linkstate != LINK_STATE_DOWN) {
30114eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL;
30124eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) {
30134eaa4710SRishi Srivatsavai if (blp->bl_linkstate != LINK_STATE_DOWN &&
30144eaa4710SRishi Srivatsavai !(blp->bl_flags & (BLF_DELETED|BLF_SDUFAIL)))
30154eaa4710SRishi Srivatsavai break;
30164eaa4710SRishi Srivatsavai }
30174eaa4710SRishi Srivatsavai if (blp == NULL) {
30184eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL;
30194eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) {
30204eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_DELETED))
30214eaa4710SRishi Srivatsavai mac_link_redo(blp->bl_mh,
30224eaa4710SRishi Srivatsavai LINK_STATE_DOWN);
30234eaa4710SRishi Srivatsavai }
30244eaa4710SRishi Srivatsavai bmp = bip->bi_mac;
30254eaa4710SRishi Srivatsavai bmp->bm_linkstate = LINK_STATE_DOWN;
30264eaa4710SRishi Srivatsavai mac_link_redo(bmp->bm_mh, LINK_STATE_DOWN);
30274eaa4710SRishi Srivatsavai }
30284eaa4710SRishi Srivatsavai }
30294eaa4710SRishi Srivatsavai
30304eaa4710SRishi Srivatsavai /*
30314eaa4710SRishi Srivatsavai * Check if there's just one working link left on the bridge. If so,
30324eaa4710SRishi Srivatsavai * then that link is now authoritative for bridge MTU.
30334eaa4710SRishi Srivatsavai */
30344eaa4710SRishi Srivatsavai blsave = NULL;
30354eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL;
30364eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) {
30374eaa4710SRishi Srivatsavai if (!(blp->bl_flags & BLF_DELETED)) {
30384eaa4710SRishi Srivatsavai if (blsave == NULL)
30394eaa4710SRishi Srivatsavai blsave = blp;
30404eaa4710SRishi Srivatsavai else
30414eaa4710SRishi Srivatsavai break;
30424eaa4710SRishi Srivatsavai }
30434eaa4710SRishi Srivatsavai }
30444eaa4710SRishi Srivatsavai mlist = NULL;
30454eaa4710SRishi Srivatsavai bmp = bip->bi_mac;
30464eaa4710SRishi Srivatsavai if (blsave != NULL && blp == NULL &&
30474eaa4710SRishi Srivatsavai blsave->bl_maxsdu != bmp->bm_maxsdu) {
30484eaa4710SRishi Srivatsavai bmp->bm_maxsdu = blsave->bl_maxsdu;
30494eaa4710SRishi Srivatsavai (void) mac_maxsdu_update(bmp->bm_mh, blsave->bl_maxsdu);
30504eaa4710SRishi Srivatsavai link_sdu_fail(blsave, B_FALSE, &mlist);
30514eaa4710SRishi Srivatsavai }
30524eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
30534eaa4710SRishi Srivatsavai send_up_messages(bip, mlist);
30544eaa4710SRishi Srivatsavai
30554eaa4710SRishi Srivatsavai if (found)
30564eaa4710SRishi Srivatsavai miocack(bsp->bs_wq, mp, 0, 0);
30574eaa4710SRishi Srivatsavai else
30584eaa4710SRishi Srivatsavai miocnak(bsp->bs_wq, mp, 0, ENOENT);
30594eaa4710SRishi Srivatsavai stream_unref(bsp);
30604eaa4710SRishi Srivatsavai }
30614eaa4710SRishi Srivatsavai
30624eaa4710SRishi Srivatsavai /*
30634eaa4710SRishi Srivatsavai * This function intentionally returns with bi_rwlock held; it is intended for
30644eaa4710SRishi Srivatsavai * quick checks and updates.
30654eaa4710SRishi Srivatsavai */
30664eaa4710SRishi Srivatsavai static bridge_link_t *
enter_link(bridge_inst_t * bip,datalink_id_t linkid)30674eaa4710SRishi Srivatsavai enter_link(bridge_inst_t *bip, datalink_id_t linkid)
30684eaa4710SRishi Srivatsavai {
30694eaa4710SRishi Srivatsavai bridge_link_t *blp;
30704eaa4710SRishi Srivatsavai
30714eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_READER);
30724eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL;
30734eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) {
30744eaa4710SRishi Srivatsavai if (blp->bl_linkid == linkid && !(blp->bl_flags & BLF_DELETED))
30754eaa4710SRishi Srivatsavai break;
30764eaa4710SRishi Srivatsavai }
30774eaa4710SRishi Srivatsavai return (blp);
30784eaa4710SRishi Srivatsavai }
30794eaa4710SRishi Srivatsavai
30804eaa4710SRishi Srivatsavai static void
bridge_ioctl(queue_t * wq,mblk_t * mp)30814eaa4710SRishi Srivatsavai bridge_ioctl(queue_t *wq, mblk_t *mp)
30824eaa4710SRishi Srivatsavai {
30834eaa4710SRishi Srivatsavai bridge_stream_t *bsp = wq->q_ptr;
30844eaa4710SRishi Srivatsavai bridge_inst_t *bip;
30854eaa4710SRishi Srivatsavai struct iocblk *iop;
30864eaa4710SRishi Srivatsavai int rc = EINVAL;
30874eaa4710SRishi Srivatsavai int len = 0;
30884eaa4710SRishi Srivatsavai bridge_link_t *blp;
30894eaa4710SRishi Srivatsavai cred_t *cr;
30904eaa4710SRishi Srivatsavai
30914eaa4710SRishi Srivatsavai /* LINTED: alignment */
30924eaa4710SRishi Srivatsavai iop = (struct iocblk *)mp->b_rptr;
30934eaa4710SRishi Srivatsavai
30944eaa4710SRishi Srivatsavai /*
30954eaa4710SRishi Srivatsavai * For now, all of the bridge ioctls are privileged.
30964eaa4710SRishi Srivatsavai */
30974eaa4710SRishi Srivatsavai if ((cr = msg_getcred(mp, NULL)) == NULL)
30984eaa4710SRishi Srivatsavai cr = iop->ioc_cr;
30994eaa4710SRishi Srivatsavai if (cr != NULL && secpolicy_net_config(cr, B_FALSE) != 0) {
31004eaa4710SRishi Srivatsavai miocnak(wq, mp, 0, EPERM);
31014eaa4710SRishi Srivatsavai return;
31024eaa4710SRishi Srivatsavai }
31034eaa4710SRishi Srivatsavai
31044eaa4710SRishi Srivatsavai switch (iop->ioc_cmd) {
31054eaa4710SRishi Srivatsavai case BRIOC_NEWBRIDGE: {
31064eaa4710SRishi Srivatsavai bridge_newbridge_t *bnb;
31074eaa4710SRishi Srivatsavai
31084eaa4710SRishi Srivatsavai if (bsp->bs_inst != NULL ||
31094eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (bridge_newbridge_t))) != 0)
31104eaa4710SRishi Srivatsavai break;
31114eaa4710SRishi Srivatsavai /* LINTED: alignment */
31124eaa4710SRishi Srivatsavai bnb = (bridge_newbridge_t *)mp->b_cont->b_rptr;
31134eaa4710SRishi Srivatsavai bnb->bnb_name[MAXNAMELEN-1] = '\0';
31142b24ab6bSSebastien Roy rc = bridge_create(bnb->bnb_linkid, bnb->bnb_name, &bip, cr);
31152b24ab6bSSebastien Roy if (rc != 0)
31164eaa4710SRishi Srivatsavai break;
31174eaa4710SRishi Srivatsavai
31184eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
31194eaa4710SRishi Srivatsavai if (bip->bi_control != NULL) {
31204eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
31214eaa4710SRishi Srivatsavai bridge_unref(bip);
31224eaa4710SRishi Srivatsavai rc = EBUSY;
31234eaa4710SRishi Srivatsavai } else {
31244eaa4710SRishi Srivatsavai atomic_inc_uint(&bip->bi_refs);
31254eaa4710SRishi Srivatsavai bsp->bs_inst = bip; /* stream holds reference */
31264eaa4710SRishi Srivatsavai bip->bi_control = bsp;
31274eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
31284eaa4710SRishi Srivatsavai rc = 0;
31294eaa4710SRishi Srivatsavai }
31304eaa4710SRishi Srivatsavai break;
31314eaa4710SRishi Srivatsavai }
31324eaa4710SRishi Srivatsavai
31334eaa4710SRishi Srivatsavai case BRIOC_ADDLINK:
31344eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL ||
31354eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (datalink_id_t))) != 0)
31364eaa4710SRishi Srivatsavai break;
31374eaa4710SRishi Srivatsavai /*
31384eaa4710SRishi Srivatsavai * We cannot perform the action in this thread, because we're
31394eaa4710SRishi Srivatsavai * not in process context, and we may already be holding
31404eaa4710SRishi Srivatsavai * MAC-related locks. Place the request on taskq.
31414eaa4710SRishi Srivatsavai */
31424eaa4710SRishi Srivatsavai mp->b_next = (mblk_t *)bsp;
31434eaa4710SRishi Srivatsavai stream_ref(bsp);
31444eaa4710SRishi Srivatsavai (void) ddi_taskq_dispatch(bridge_taskq, bridge_add_link, mp,
31454eaa4710SRishi Srivatsavai DDI_SLEEP);
31464eaa4710SRishi Srivatsavai return;
31474eaa4710SRishi Srivatsavai
31484eaa4710SRishi Srivatsavai case BRIOC_REMLINK:
31494eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL ||
31504eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (datalink_id_t))) != 0)
31514eaa4710SRishi Srivatsavai break;
31524eaa4710SRishi Srivatsavai /*
31534eaa4710SRishi Srivatsavai * We cannot perform the action in this thread, because we're
31544eaa4710SRishi Srivatsavai * not in process context, and we may already be holding
31554eaa4710SRishi Srivatsavai * MAC-related locks. Place the request on taskq.
31564eaa4710SRishi Srivatsavai */
31574eaa4710SRishi Srivatsavai mp->b_next = (mblk_t *)bsp;
31584eaa4710SRishi Srivatsavai stream_ref(bsp);
31594eaa4710SRishi Srivatsavai (void) ddi_taskq_dispatch(bridge_taskq, bridge_rem_link, mp,
31604eaa4710SRishi Srivatsavai DDI_SLEEP);
31614eaa4710SRishi Srivatsavai return;
31624eaa4710SRishi Srivatsavai
31634eaa4710SRishi Srivatsavai case BRIOC_SETSTATE: {
31644eaa4710SRishi Srivatsavai bridge_setstate_t *bss;
31654eaa4710SRishi Srivatsavai
31664eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL ||
31674eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (*bss))) != 0)
31684eaa4710SRishi Srivatsavai break;
31694eaa4710SRishi Srivatsavai /* LINTED: alignment */
31704eaa4710SRishi Srivatsavai bss = (bridge_setstate_t *)mp->b_cont->b_rptr;
31714eaa4710SRishi Srivatsavai if ((blp = enter_link(bip, bss->bss_linkid)) == NULL) {
31724eaa4710SRishi Srivatsavai rc = ENOENT;
31734eaa4710SRishi Srivatsavai } else {
31744eaa4710SRishi Srivatsavai rc = 0;
31754eaa4710SRishi Srivatsavai blp->bl_state = bss->bss_state;
31764eaa4710SRishi Srivatsavai }
31774eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
31784eaa4710SRishi Srivatsavai break;
31794eaa4710SRishi Srivatsavai }
31804eaa4710SRishi Srivatsavai
31814eaa4710SRishi Srivatsavai case BRIOC_SETPVID: {
31824eaa4710SRishi Srivatsavai bridge_setpvid_t *bsv;
31834eaa4710SRishi Srivatsavai
31844eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL ||
31854eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (*bsv))) != 0)
31864eaa4710SRishi Srivatsavai break;
31874eaa4710SRishi Srivatsavai /* LINTED: alignment */
31884eaa4710SRishi Srivatsavai bsv = (bridge_setpvid_t *)mp->b_cont->b_rptr;
31894eaa4710SRishi Srivatsavai if (bsv->bsv_vlan > VLAN_ID_MAX)
31904eaa4710SRishi Srivatsavai break;
31914eaa4710SRishi Srivatsavai if ((blp = enter_link(bip, bsv->bsv_linkid)) == NULL) {
31924eaa4710SRishi Srivatsavai rc = ENOENT;
31934eaa4710SRishi Srivatsavai } else if (blp->bl_pvid == bsv->bsv_vlan) {
31944eaa4710SRishi Srivatsavai rc = 0;
31954eaa4710SRishi Srivatsavai } else {
31964eaa4710SRishi Srivatsavai rc = 0;
31974eaa4710SRishi Srivatsavai BRIDGE_VLAN_CLR(blp, blp->bl_pvid);
31984eaa4710SRishi Srivatsavai blp->bl_pvid = bsv->bsv_vlan;
31994eaa4710SRishi Srivatsavai if (blp->bl_pvid != 0)
32004eaa4710SRishi Srivatsavai BRIDGE_VLAN_SET(blp, blp->bl_pvid);
32014eaa4710SRishi Srivatsavai }
32024eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
32034eaa4710SRishi Srivatsavai break;
32044eaa4710SRishi Srivatsavai }
32054eaa4710SRishi Srivatsavai
32064eaa4710SRishi Srivatsavai case BRIOC_VLANENAB: {
32074eaa4710SRishi Srivatsavai bridge_vlanenab_t *bve;
32084eaa4710SRishi Srivatsavai
32094eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL ||
32104eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (*bve))) != 0)
32114eaa4710SRishi Srivatsavai break;
32124eaa4710SRishi Srivatsavai /* LINTED: alignment */
32134eaa4710SRishi Srivatsavai bve = (bridge_vlanenab_t *)mp->b_cont->b_rptr;
32144eaa4710SRishi Srivatsavai if (bve->bve_vlan > VLAN_ID_MAX)
32154eaa4710SRishi Srivatsavai break;
32164eaa4710SRishi Srivatsavai if ((blp = enter_link(bip, bve->bve_linkid)) == NULL) {
32174eaa4710SRishi Srivatsavai rc = ENOENT;
32184eaa4710SRishi Srivatsavai } else {
32194eaa4710SRishi Srivatsavai rc = 0;
32204eaa4710SRishi Srivatsavai /* special case: vlan 0 means "all" */
32214eaa4710SRishi Srivatsavai if (bve->bve_vlan == 0) {
32224eaa4710SRishi Srivatsavai (void) memset(blp->bl_vlans,
32234eaa4710SRishi Srivatsavai bve->bve_onoff ? ~0 : 0,
32244eaa4710SRishi Srivatsavai sizeof (blp->bl_vlans));
32254eaa4710SRishi Srivatsavai BRIDGE_VLAN_CLR(blp, 0);
32264eaa4710SRishi Srivatsavai if (blp->bl_pvid != 0)
32274eaa4710SRishi Srivatsavai BRIDGE_VLAN_SET(blp, blp->bl_pvid);
32284eaa4710SRishi Srivatsavai } else if (bve->bve_vlan == blp->bl_pvid) {
32294eaa4710SRishi Srivatsavai rc = EINVAL;
32304eaa4710SRishi Srivatsavai } else if (bve->bve_onoff) {
32314eaa4710SRishi Srivatsavai BRIDGE_VLAN_SET(blp, bve->bve_vlan);
32324eaa4710SRishi Srivatsavai } else {
32334eaa4710SRishi Srivatsavai BRIDGE_VLAN_CLR(blp, bve->bve_vlan);
32344eaa4710SRishi Srivatsavai }
32354eaa4710SRishi Srivatsavai }
32364eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
32374eaa4710SRishi Srivatsavai break;
32384eaa4710SRishi Srivatsavai }
32394eaa4710SRishi Srivatsavai
32404eaa4710SRishi Srivatsavai case BRIOC_FLUSHFWD: {
32414eaa4710SRishi Srivatsavai bridge_flushfwd_t *bff;
32424eaa4710SRishi Srivatsavai bridge_fwd_t *bfp, *bfnext;
32434eaa4710SRishi Srivatsavai avl_tree_t fwd_scavenge;
32444eaa4710SRishi Srivatsavai int i;
32454eaa4710SRishi Srivatsavai
32464eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL ||
32474eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (*bff))) != 0)
32484eaa4710SRishi Srivatsavai break;
32494eaa4710SRishi Srivatsavai /* LINTED: alignment */
32504eaa4710SRishi Srivatsavai bff = (bridge_flushfwd_t *)mp->b_cont->b_rptr;
32514eaa4710SRishi Srivatsavai rw_enter(&bip->bi_rwlock, RW_WRITER);
32524eaa4710SRishi Srivatsavai /* This case means "all" */
32534eaa4710SRishi Srivatsavai if (bff->bff_linkid == DATALINK_INVALID_LINKID) {
32544eaa4710SRishi Srivatsavai blp = NULL;
32554eaa4710SRishi Srivatsavai } else {
32564eaa4710SRishi Srivatsavai for (blp = list_head(&bip->bi_links); blp != NULL;
32574eaa4710SRishi Srivatsavai blp = list_next(&bip->bi_links, blp)) {
32584eaa4710SRishi Srivatsavai if (blp->bl_linkid == bff->bff_linkid &&
32594eaa4710SRishi Srivatsavai !(blp->bl_flags & BLF_DELETED))
32604eaa4710SRishi Srivatsavai break;
32614eaa4710SRishi Srivatsavai }
32624eaa4710SRishi Srivatsavai if (blp == NULL) {
32634eaa4710SRishi Srivatsavai rc = ENOENT;
32644eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
32654eaa4710SRishi Srivatsavai break;
32664eaa4710SRishi Srivatsavai }
32674eaa4710SRishi Srivatsavai }
32684eaa4710SRishi Srivatsavai avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t),
32694eaa4710SRishi Srivatsavai offsetof(bridge_fwd_t, bf_node));
32704eaa4710SRishi Srivatsavai bfnext = avl_first(&bip->bi_fwd);
32714eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) {
32724eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&bip->bi_fwd, bfp);
32734eaa4710SRishi Srivatsavai if (bfp->bf_flags & BFF_LOCALADDR)
32744eaa4710SRishi Srivatsavai continue;
32754eaa4710SRishi Srivatsavai if (blp != NULL) {
32764eaa4710SRishi Srivatsavai for (i = 0; i < bfp->bf_maxlinks; i++) {
32774eaa4710SRishi Srivatsavai if (bfp->bf_links[i] == blp)
32784eaa4710SRishi Srivatsavai break;
32794eaa4710SRishi Srivatsavai }
32804eaa4710SRishi Srivatsavai /*
32814eaa4710SRishi Srivatsavai * If the link is there and we're excluding,
32824eaa4710SRishi Srivatsavai * then skip. If the link is not there and
32834eaa4710SRishi Srivatsavai * we're doing only that link, then skip.
32844eaa4710SRishi Srivatsavai */
32854eaa4710SRishi Srivatsavai if ((i < bfp->bf_maxlinks) == bff->bff_exclude)
32864eaa4710SRishi Srivatsavai continue;
32874eaa4710SRishi Srivatsavai }
32884eaa4710SRishi Srivatsavai ASSERT(bfp->bf_flags & BFF_INTREE);
32894eaa4710SRishi Srivatsavai avl_remove(&bip->bi_fwd, bfp);
32904eaa4710SRishi Srivatsavai bfp->bf_flags &= ~BFF_INTREE;
32914eaa4710SRishi Srivatsavai avl_add(&fwd_scavenge, bfp);
32924eaa4710SRishi Srivatsavai }
32934eaa4710SRishi Srivatsavai rw_exit(&bip->bi_rwlock);
32944eaa4710SRishi Srivatsavai bfnext = avl_first(&fwd_scavenge);
32954eaa4710SRishi Srivatsavai while ((bfp = bfnext) != NULL) {
32964eaa4710SRishi Srivatsavai bfnext = AVL_NEXT(&fwd_scavenge, bfp);
32974eaa4710SRishi Srivatsavai avl_remove(&fwd_scavenge, bfp);
32984eaa4710SRishi Srivatsavai fwd_unref(bfp); /* drop tree reference */
32994eaa4710SRishi Srivatsavai }
33004eaa4710SRishi Srivatsavai avl_destroy(&fwd_scavenge);
33014eaa4710SRishi Srivatsavai break;
33024eaa4710SRishi Srivatsavai }
33034eaa4710SRishi Srivatsavai
33044eaa4710SRishi Srivatsavai case BRIOC_TABLEMAX:
33054eaa4710SRishi Srivatsavai if ((bip = bsp->bs_inst) == NULL ||
33064eaa4710SRishi Srivatsavai (rc = miocpullup(mp, sizeof (uint32_t))) != 0)
33074eaa4710SRishi Srivatsavai break;
33084eaa4710SRishi Srivatsavai /* LINTED: alignment */
33094eaa4710SRishi Srivatsavai bip->bi_tablemax = *(uint32_t *)mp->b_cont->b_rptr;
33104eaa4710SRishi Srivatsavai break;
33114eaa4710SRishi Srivatsavai }
33124eaa4710SRishi Srivatsavai
33134eaa4710SRishi Srivatsavai if (rc == 0)
33144eaa4710SRishi Srivatsavai miocack(wq, mp, len, 0);
33154eaa4710SRishi Srivatsavai else
33164eaa4710SRishi Srivatsavai miocnak(wq, mp, 0, rc);
33174eaa4710SRishi Srivatsavai }
33184eaa4710SRishi Srivatsavai
3319f1ccfd86SToomas Soome static int
bridge_wput(queue_t * wq,mblk_t * mp)33204eaa4710SRishi Srivatsavai bridge_wput(queue_t *wq, mblk_t *mp)
33214eaa4710SRishi Srivatsavai {
33224eaa4710SRishi Srivatsavai switch (DB_TYPE(mp)) {
33234eaa4710SRishi Srivatsavai case M_IOCTL:
33244eaa4710SRishi Srivatsavai bridge_ioctl(wq, mp);
33254eaa4710SRishi Srivatsavai break;
33264eaa4710SRishi Srivatsavai case M_FLUSH:
33274eaa4710SRishi Srivatsavai if (*mp->b_rptr & FLUSHW)
33284eaa4710SRishi Srivatsavai *mp->b_rptr &= ~FLUSHW;
33294eaa4710SRishi Srivatsavai if (*mp->b_rptr & FLUSHR)
33304eaa4710SRishi Srivatsavai qreply(wq, mp);
33314eaa4710SRishi Srivatsavai else
33324eaa4710SRishi Srivatsavai freemsg(mp);
33334eaa4710SRishi Srivatsavai break;
33344eaa4710SRishi Srivatsavai default:
33354eaa4710SRishi Srivatsavai freemsg(mp);
33364eaa4710SRishi Srivatsavai break;
33374eaa4710SRishi Srivatsavai }
3338f1ccfd86SToomas Soome return (0);
33394eaa4710SRishi Srivatsavai }
33404eaa4710SRishi Srivatsavai
33414eaa4710SRishi Srivatsavai /*
33424eaa4710SRishi Srivatsavai * This function allocates the main data structures for the bridge driver and
33434eaa4710SRishi Srivatsavai * connects us into devfs.
33444eaa4710SRishi Srivatsavai */
33454eaa4710SRishi Srivatsavai static void
bridge_inst_init(void)33464eaa4710SRishi Srivatsavai bridge_inst_init(void)
33474eaa4710SRishi Srivatsavai {
33484eaa4710SRishi Srivatsavai bridge_scan_interval = 5 * drv_usectohz(1000000);
33494eaa4710SRishi Srivatsavai bridge_fwd_age = 25 * drv_usectohz(1000000);
33504eaa4710SRishi Srivatsavai
33514eaa4710SRishi Srivatsavai rw_init(&bmac_rwlock, NULL, RW_DRIVER, NULL);
33524eaa4710SRishi Srivatsavai list_create(&bmac_list, sizeof (bridge_mac_t),
33534eaa4710SRishi Srivatsavai offsetof(bridge_mac_t, bm_node));
33544eaa4710SRishi Srivatsavai list_create(&inst_list, sizeof (bridge_inst_t),
33554eaa4710SRishi Srivatsavai offsetof(bridge_inst_t, bi_node));
33564eaa4710SRishi Srivatsavai cv_init(&inst_cv, NULL, CV_DRIVER, NULL);
33574eaa4710SRishi Srivatsavai mutex_init(&inst_lock, NULL, MUTEX_DRIVER, NULL);
33584eaa4710SRishi Srivatsavai cv_init(&stream_ref_cv, NULL, CV_DRIVER, NULL);
33594eaa4710SRishi Srivatsavai mutex_init(&stream_ref_lock, NULL, MUTEX_DRIVER, NULL);
33604eaa4710SRishi Srivatsavai
33614eaa4710SRishi Srivatsavai mac_bridge_vectors(bridge_xmit_cb, bridge_recv_cb, bridge_ref_cb,
33624eaa4710SRishi Srivatsavai bridge_ls_cb);
33634eaa4710SRishi Srivatsavai }
33644eaa4710SRishi Srivatsavai
33654eaa4710SRishi Srivatsavai /*
33664eaa4710SRishi Srivatsavai * This function disconnects from devfs and destroys all data structures in
33674eaa4710SRishi Srivatsavai * preparation for unload. It's assumed that there are no active bridge
33684eaa4710SRishi Srivatsavai * references left at this point.
33694eaa4710SRishi Srivatsavai */
33704eaa4710SRishi Srivatsavai static void
bridge_inst_fini(void)33714eaa4710SRishi Srivatsavai bridge_inst_fini(void)
33724eaa4710SRishi Srivatsavai {
33734eaa4710SRishi Srivatsavai mac_bridge_vectors(NULL, NULL, NULL, NULL);
33744eaa4710SRishi Srivatsavai if (bridge_timerid != 0)
33754eaa4710SRishi Srivatsavai (void) untimeout(bridge_timerid);
33764eaa4710SRishi Srivatsavai rw_destroy(&bmac_rwlock);
33774eaa4710SRishi Srivatsavai list_destroy(&bmac_list);
33784eaa4710SRishi Srivatsavai list_destroy(&inst_list);
33794eaa4710SRishi Srivatsavai cv_destroy(&inst_cv);
33804eaa4710SRishi Srivatsavai mutex_destroy(&inst_lock);
33814eaa4710SRishi Srivatsavai cv_destroy(&stream_ref_cv);
33824eaa4710SRishi Srivatsavai mutex_destroy(&stream_ref_lock);
33834eaa4710SRishi Srivatsavai }
33844eaa4710SRishi Srivatsavai
33854eaa4710SRishi Srivatsavai /*
33864eaa4710SRishi Srivatsavai * bridge_attach()
33874eaa4710SRishi Srivatsavai *
33884eaa4710SRishi Srivatsavai * Description:
33894eaa4710SRishi Srivatsavai * Attach bridge driver to the system.
33904eaa4710SRishi Srivatsavai */
33914eaa4710SRishi Srivatsavai static int
bridge_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)33924eaa4710SRishi Srivatsavai bridge_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
33934eaa4710SRishi Srivatsavai {
33944eaa4710SRishi Srivatsavai if (cmd != DDI_ATTACH)
33954eaa4710SRishi Srivatsavai return (DDI_FAILURE);
33964eaa4710SRishi Srivatsavai
33974eaa4710SRishi Srivatsavai if (ddi_create_minor_node(dip, BRIDGE_CTL, S_IFCHR, 0, DDI_PSEUDO,
33984eaa4710SRishi Srivatsavai CLONE_DEV) == DDI_FAILURE) {
33994eaa4710SRishi Srivatsavai return (DDI_FAILURE);
34004eaa4710SRishi Srivatsavai }
34014eaa4710SRishi Srivatsavai
34024eaa4710SRishi Srivatsavai if (dld_ioc_register(BRIDGE_IOC, bridge_ioc_list,
34034eaa4710SRishi Srivatsavai DLDIOCCNT(bridge_ioc_list)) != 0) {
34044eaa4710SRishi Srivatsavai ddi_remove_minor_node(dip, BRIDGE_CTL);
34054eaa4710SRishi Srivatsavai return (DDI_FAILURE);
34064eaa4710SRishi Srivatsavai }
34074eaa4710SRishi Srivatsavai
34084eaa4710SRishi Srivatsavai bridge_dev_info = dip;
34094eaa4710SRishi Srivatsavai bridge_major = ddi_driver_major(dip);
3410f2905fb7SRishi Srivatsavai bridge_taskq = ddi_taskq_create(dip, BRIDGE_DEV_NAME, 1,
3411f2905fb7SRishi Srivatsavai TASKQ_DEFAULTPRI, 0);
34124eaa4710SRishi Srivatsavai return (DDI_SUCCESS);
34134eaa4710SRishi Srivatsavai }
34144eaa4710SRishi Srivatsavai
34154eaa4710SRishi Srivatsavai /*
34164eaa4710SRishi Srivatsavai * bridge_detach()
34174eaa4710SRishi Srivatsavai *
34184eaa4710SRishi Srivatsavai * Description:
34194eaa4710SRishi Srivatsavai * Detach an interface to the system.
34204eaa4710SRishi Srivatsavai */
34214eaa4710SRishi Srivatsavai static int
bridge_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)34224eaa4710SRishi Srivatsavai bridge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
34234eaa4710SRishi Srivatsavai {
34244eaa4710SRishi Srivatsavai if (cmd != DDI_DETACH)
34254eaa4710SRishi Srivatsavai return (DDI_FAILURE);
34264eaa4710SRishi Srivatsavai
34274eaa4710SRishi Srivatsavai ddi_remove_minor_node(dip, NULL);
34284eaa4710SRishi Srivatsavai ddi_taskq_destroy(bridge_taskq);
34294eaa4710SRishi Srivatsavai bridge_dev_info = NULL;
34304eaa4710SRishi Srivatsavai return (DDI_SUCCESS);
34314eaa4710SRishi Srivatsavai }
34324eaa4710SRishi Srivatsavai
34334eaa4710SRishi Srivatsavai /*
34344eaa4710SRishi Srivatsavai * bridge_info()
34354eaa4710SRishi Srivatsavai *
34364eaa4710SRishi Srivatsavai * Description:
34374eaa4710SRishi Srivatsavai * Translate "dev_t" to a pointer to the associated "dev_info_t".
34384eaa4710SRishi Srivatsavai */
34394eaa4710SRishi Srivatsavai /* ARGSUSED */
34404eaa4710SRishi Srivatsavai static int
bridge_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)34414eaa4710SRishi Srivatsavai bridge_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
34424eaa4710SRishi Srivatsavai void **result)
34434eaa4710SRishi Srivatsavai {
34444eaa4710SRishi Srivatsavai int rc;
34454eaa4710SRishi Srivatsavai
34464eaa4710SRishi Srivatsavai switch (infocmd) {
34474eaa4710SRishi Srivatsavai case DDI_INFO_DEVT2DEVINFO:
34484eaa4710SRishi Srivatsavai if (bridge_dev_info == NULL) {
34494eaa4710SRishi Srivatsavai rc = DDI_FAILURE;
34504eaa4710SRishi Srivatsavai } else {
34514eaa4710SRishi Srivatsavai *result = (void *)bridge_dev_info;
34524eaa4710SRishi Srivatsavai rc = DDI_SUCCESS;
34534eaa4710SRishi Srivatsavai }
34544eaa4710SRishi Srivatsavai break;
34554eaa4710SRishi Srivatsavai case DDI_INFO_DEVT2INSTANCE:
34564eaa4710SRishi Srivatsavai *result = NULL;
34574eaa4710SRishi Srivatsavai rc = DDI_SUCCESS;
34584eaa4710SRishi Srivatsavai break;
34594eaa4710SRishi Srivatsavai default:
34604eaa4710SRishi Srivatsavai rc = DDI_FAILURE;
34614eaa4710SRishi Srivatsavai break;
34624eaa4710SRishi Srivatsavai }
34634eaa4710SRishi Srivatsavai return (rc);
34644eaa4710SRishi Srivatsavai }
34654eaa4710SRishi Srivatsavai
34664eaa4710SRishi Srivatsavai static struct module_info bridge_modinfo = {
34674eaa4710SRishi Srivatsavai 2105, /* mi_idnum */
3468f2905fb7SRishi Srivatsavai BRIDGE_DEV_NAME, /* mi_idname */
34694eaa4710SRishi Srivatsavai 0, /* mi_minpsz */
34704eaa4710SRishi Srivatsavai 16384, /* mi_maxpsz */
34714eaa4710SRishi Srivatsavai 65536, /* mi_hiwat */
34724eaa4710SRishi Srivatsavai 128 /* mi_lowat */
34734eaa4710SRishi Srivatsavai };
34744eaa4710SRishi Srivatsavai
34754eaa4710SRishi Srivatsavai static struct qinit bridge_rinit = {
34764eaa4710SRishi Srivatsavai NULL, /* qi_putp */
34774eaa4710SRishi Srivatsavai NULL, /* qi_srvp */
34784eaa4710SRishi Srivatsavai bridge_open, /* qi_qopen */
34794eaa4710SRishi Srivatsavai bridge_close, /* qi_qclose */
34804eaa4710SRishi Srivatsavai NULL, /* qi_qadmin */
34814eaa4710SRishi Srivatsavai &bridge_modinfo, /* qi_minfo */
34824eaa4710SRishi Srivatsavai NULL /* qi_mstat */
34834eaa4710SRishi Srivatsavai };
34844eaa4710SRishi Srivatsavai
34854eaa4710SRishi Srivatsavai static struct qinit bridge_winit = {
34864eaa4710SRishi Srivatsavai (int (*)())bridge_wput, /* qi_putp */
34874eaa4710SRishi Srivatsavai NULL, /* qi_srvp */
34884eaa4710SRishi Srivatsavai NULL, /* qi_qopen */
34894eaa4710SRishi Srivatsavai NULL, /* qi_qclose */
34904eaa4710SRishi Srivatsavai NULL, /* qi_qadmin */
34914eaa4710SRishi Srivatsavai &bridge_modinfo, /* qi_minfo */
34924eaa4710SRishi Srivatsavai NULL /* qi_mstat */
34934eaa4710SRishi Srivatsavai };
34944eaa4710SRishi Srivatsavai
34954eaa4710SRishi Srivatsavai static struct streamtab bridge_tab = {
34964eaa4710SRishi Srivatsavai &bridge_rinit, /* st_rdinit */
34974eaa4710SRishi Srivatsavai &bridge_winit /* st_wrinit */
34984eaa4710SRishi Srivatsavai };
34994eaa4710SRishi Srivatsavai
35004eaa4710SRishi Srivatsavai /* No STREAMS perimeters; we do all our own locking */
35014eaa4710SRishi Srivatsavai DDI_DEFINE_STREAM_OPS(bridge_ops, nulldev, nulldev, bridge_attach,
35024eaa4710SRishi Srivatsavai bridge_detach, nodev, bridge_info, D_NEW | D_MP, &bridge_tab,
35034eaa4710SRishi Srivatsavai ddi_quiesce_not_supported);
35044eaa4710SRishi Srivatsavai
35054eaa4710SRishi Srivatsavai static struct modldrv modldrv = {
35064eaa4710SRishi Srivatsavai &mod_driverops,
35074eaa4710SRishi Srivatsavai "bridging driver",
35084eaa4710SRishi Srivatsavai &bridge_ops
35094eaa4710SRishi Srivatsavai };
35104eaa4710SRishi Srivatsavai
35114eaa4710SRishi Srivatsavai static struct modlinkage modlinkage = {
35124eaa4710SRishi Srivatsavai MODREV_1,
35134eaa4710SRishi Srivatsavai (void *)&modldrv,
35144eaa4710SRishi Srivatsavai NULL
35154eaa4710SRishi Srivatsavai };
35164eaa4710SRishi Srivatsavai
35174eaa4710SRishi Srivatsavai int
_init(void)35184eaa4710SRishi Srivatsavai _init(void)
35194eaa4710SRishi Srivatsavai {
35204eaa4710SRishi Srivatsavai int retv;
35214eaa4710SRishi Srivatsavai
3522f2905fb7SRishi Srivatsavai mac_init_ops(NULL, BRIDGE_DEV_NAME);
35234eaa4710SRishi Srivatsavai bridge_inst_init();
35244eaa4710SRishi Srivatsavai if ((retv = mod_install(&modlinkage)) != 0)
35254eaa4710SRishi Srivatsavai bridge_inst_fini();
35264eaa4710SRishi Srivatsavai return (retv);
35274eaa4710SRishi Srivatsavai }
35284eaa4710SRishi Srivatsavai
35294eaa4710SRishi Srivatsavai int
_fini(void)35304eaa4710SRishi Srivatsavai _fini(void)
35314eaa4710SRishi Srivatsavai {
35324eaa4710SRishi Srivatsavai int retv;
35334eaa4710SRishi Srivatsavai
35344eaa4710SRishi Srivatsavai rw_enter(&bmac_rwlock, RW_READER);
35354eaa4710SRishi Srivatsavai retv = list_is_empty(&bmac_list) ? 0 : EBUSY;
35364eaa4710SRishi Srivatsavai rw_exit(&bmac_rwlock);
35374eaa4710SRishi Srivatsavai if (retv == 0 &&
35384eaa4710SRishi Srivatsavai (retv = mod_remove(&modlinkage)) == 0)
35394eaa4710SRishi Srivatsavai bridge_inst_fini();
35404eaa4710SRishi Srivatsavai return (retv);
35414eaa4710SRishi Srivatsavai }
35424eaa4710SRishi Srivatsavai
35434eaa4710SRishi Srivatsavai int
_info(struct modinfo * modinfop)35444eaa4710SRishi Srivatsavai _info(struct modinfo *modinfop)
35454eaa4710SRishi Srivatsavai {
35464eaa4710SRishi Srivatsavai return (mod_info(&modlinkage, modinfop));
35474eaa4710SRishi Srivatsavai }
3548