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