110491SRishi.Srivatsavai@Sun.COM /* 210491SRishi.Srivatsavai@Sun.COM * CDDL HEADER START 310491SRishi.Srivatsavai@Sun.COM * 410491SRishi.Srivatsavai@Sun.COM * The contents of this file are subject to the terms of the 510491SRishi.Srivatsavai@Sun.COM * Common Development and Distribution License (the "License"). 610491SRishi.Srivatsavai@Sun.COM * You may not use this file except in compliance with the License. 710491SRishi.Srivatsavai@Sun.COM * 810491SRishi.Srivatsavai@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 910491SRishi.Srivatsavai@Sun.COM * or http://www.opensolaris.org/os/licensing. 1010491SRishi.Srivatsavai@Sun.COM * See the License for the specific language governing permissions 1110491SRishi.Srivatsavai@Sun.COM * and limitations under the License. 1210491SRishi.Srivatsavai@Sun.COM * 1310491SRishi.Srivatsavai@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1410491SRishi.Srivatsavai@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1510491SRishi.Srivatsavai@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1610491SRishi.Srivatsavai@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1710491SRishi.Srivatsavai@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1810491SRishi.Srivatsavai@Sun.COM * 1910491SRishi.Srivatsavai@Sun.COM * CDDL HEADER END 2010491SRishi.Srivatsavai@Sun.COM */ 2110491SRishi.Srivatsavai@Sun.COM 2210491SRishi.Srivatsavai@Sun.COM /* 23*11483SRishi.Srivatsavai@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 2410491SRishi.Srivatsavai@Sun.COM * Use is subject to license terms. 2510491SRishi.Srivatsavai@Sun.COM */ 2610491SRishi.Srivatsavai@Sun.COM 2710491SRishi.Srivatsavai@Sun.COM /* 2810491SRishi.Srivatsavai@Sun.COM * This module implements a STREAMS driver that provides layer-two (Ethernet) 2910491SRishi.Srivatsavai@Sun.COM * bridging functionality. The STREAMS interface is used to provide 3010491SRishi.Srivatsavai@Sun.COM * observability (snoop/wireshark) and control, but not for interface plumbing. 3110491SRishi.Srivatsavai@Sun.COM */ 3210491SRishi.Srivatsavai@Sun.COM 3310491SRishi.Srivatsavai@Sun.COM #include <sys/types.h> 3410491SRishi.Srivatsavai@Sun.COM #include <sys/bitmap.h> 3510491SRishi.Srivatsavai@Sun.COM #include <sys/cmn_err.h> 3610491SRishi.Srivatsavai@Sun.COM #include <sys/conf.h> 3710491SRishi.Srivatsavai@Sun.COM #include <sys/ddi.h> 3810491SRishi.Srivatsavai@Sun.COM #include <sys/errno.h> 3910491SRishi.Srivatsavai@Sun.COM #include <sys/kstat.h> 4010491SRishi.Srivatsavai@Sun.COM #include <sys/modctl.h> 4110491SRishi.Srivatsavai@Sun.COM #include <sys/note.h> 4210491SRishi.Srivatsavai@Sun.COM #include <sys/param.h> 4310491SRishi.Srivatsavai@Sun.COM #include <sys/policy.h> 4410491SRishi.Srivatsavai@Sun.COM #include <sys/sdt.h> 4510491SRishi.Srivatsavai@Sun.COM #include <sys/stat.h> 4610491SRishi.Srivatsavai@Sun.COM #include <sys/stream.h> 4710491SRishi.Srivatsavai@Sun.COM #include <sys/stropts.h> 4810491SRishi.Srivatsavai@Sun.COM #include <sys/strsun.h> 4910491SRishi.Srivatsavai@Sun.COM #include <sys/sunddi.h> 5010491SRishi.Srivatsavai@Sun.COM #include <sys/sysmacros.h> 5110491SRishi.Srivatsavai@Sun.COM #include <sys/systm.h> 5210491SRishi.Srivatsavai@Sun.COM #include <sys/time.h> 5310491SRishi.Srivatsavai@Sun.COM #include <sys/dlpi.h> 5410491SRishi.Srivatsavai@Sun.COM #include <sys/dls.h> 5510491SRishi.Srivatsavai@Sun.COM #include <sys/mac_ether.h> 5610491SRishi.Srivatsavai@Sun.COM #include <sys/mac_provider.h> 5710491SRishi.Srivatsavai@Sun.COM #include <sys/mac_client_priv.h> 5810491SRishi.Srivatsavai@Sun.COM #include <sys/mac_impl.h> 5910491SRishi.Srivatsavai@Sun.COM #include <sys/vlan.h> 6010491SRishi.Srivatsavai@Sun.COM #include <net/bridge.h> 6110491SRishi.Srivatsavai@Sun.COM #include <net/bridge_impl.h> 6210491SRishi.Srivatsavai@Sun.COM #include <net/trill.h> 6310530SRishi.Srivatsavai@Sun.COM #include <sys/dld_ioc.h> 6410491SRishi.Srivatsavai@Sun.COM 6510491SRishi.Srivatsavai@Sun.COM /* 6610491SRishi.Srivatsavai@Sun.COM * Locks and reference counts: object lifetime and design. 6710491SRishi.Srivatsavai@Sun.COM * 6810491SRishi.Srivatsavai@Sun.COM * bridge_mac_t 6910491SRishi.Srivatsavai@Sun.COM * Bridge mac (snoop) instances are in bmac_list, which is protected by 7010491SRishi.Srivatsavai@Sun.COM * bmac_rwlock. They're allocated by bmac_alloc and freed by bridge_timer(). 7110491SRishi.Srivatsavai@Sun.COM * Every bridge_inst_t has a single bridge_mac_t, but when bridge_inst_t goes 7210491SRishi.Srivatsavai@Sun.COM * away, the bridge_mac_t remains until either all of the users go away 7310491SRishi.Srivatsavai@Sun.COM * (detected by a timer) or until the instance is picked up again by the same 7410491SRishi.Srivatsavai@Sun.COM * bridge starting back up. 7510491SRishi.Srivatsavai@Sun.COM * 7610491SRishi.Srivatsavai@Sun.COM * bridge_inst_t 7710491SRishi.Srivatsavai@Sun.COM * Bridge instances are in inst_list, which is protected by inst_lock. 7810491SRishi.Srivatsavai@Sun.COM * They're allocated by inst_alloc() and freed by inst_free(). After 7910491SRishi.Srivatsavai@Sun.COM * allocation, an instance is placed in inst_list, and the reference count is 8010491SRishi.Srivatsavai@Sun.COM * incremented to represent this. That reference is decremented when the 8110491SRishi.Srivatsavai@Sun.COM * BIF_SHUTDOWN flag is set, and no new increments may occur. When the last 8210491SRishi.Srivatsavai@Sun.COM * reference is freed, the instance is removed from the list. 8310491SRishi.Srivatsavai@Sun.COM * 8410491SRishi.Srivatsavai@Sun.COM * Bridge instances have lists of links and an AVL tree of forwarding 8510491SRishi.Srivatsavai@Sun.COM * entries. Each of these structures holds one reference on the bridge 8610491SRishi.Srivatsavai@Sun.COM * instance. These lists and tree are protected by bi_rwlock. 8710491SRishi.Srivatsavai@Sun.COM * 8810491SRishi.Srivatsavai@Sun.COM * bridge_stream_t 8910491SRishi.Srivatsavai@Sun.COM * Bridge streams are allocated by stream_alloc() and freed by stream_free(). 9010491SRishi.Srivatsavai@Sun.COM * These streams are created when "bridged" opens /dev/bridgectl, and are 9110491SRishi.Srivatsavai@Sun.COM * used to create new bridge instances (via BRIOC_NEWBRIDGE) and control the 9210491SRishi.Srivatsavai@Sun.COM * links on the bridge. When a stream closes, the bridge instance created is 9310491SRishi.Srivatsavai@Sun.COM * destroyed. There's at most one bridge instance for a given control 9410491SRishi.Srivatsavai@Sun.COM * stream. 9510491SRishi.Srivatsavai@Sun.COM * 9610491SRishi.Srivatsavai@Sun.COM * bridge_link_t 9710491SRishi.Srivatsavai@Sun.COM * Links are allocated by bridge_add_link() and freed by link_free(). The 9810491SRishi.Srivatsavai@Sun.COM * bi_links list holds a reference to the link. When the BLF_DELETED flag is 9910491SRishi.Srivatsavai@Sun.COM * set, that reference is dropped. The link isn't removed from the list 10010491SRishi.Srivatsavai@Sun.COM * until the last reference drops. Each forwarding entry that uses a given 10110491SRishi.Srivatsavai@Sun.COM * link holds a reference, as does each thread transmitting a packet via the 10210491SRishi.Srivatsavai@Sun.COM * link. The MAC layer calls in via bridge_ref_cb() to hold a reference on 10310491SRishi.Srivatsavai@Sun.COM * a link when transmitting. 10410491SRishi.Srivatsavai@Sun.COM * 10510491SRishi.Srivatsavai@Sun.COM * It's important that once BLF_DELETED is set, there's no way for the 10610491SRishi.Srivatsavai@Sun.COM * reference count to increase again. If it can, then the link may be 10710491SRishi.Srivatsavai@Sun.COM * double-freed. The BLF_FREED flag is intended for use with assertions to 10810491SRishi.Srivatsavai@Sun.COM * guard against this in testing. 10910491SRishi.Srivatsavai@Sun.COM * 11010491SRishi.Srivatsavai@Sun.COM * bridge_fwd_t 11110491SRishi.Srivatsavai@Sun.COM * Bridge forwarding entries are allocated by bridge_recv_cb() and freed by 11210491SRishi.Srivatsavai@Sun.COM * fwd_free(). The bi_fwd AVL tree holds one reference to the entry. Unlike 11310491SRishi.Srivatsavai@Sun.COM * other data structures, the reference is dropped when the entry is removed 11410491SRishi.Srivatsavai@Sun.COM * from the tree by fwd_delete(), and the BFF_INTREE flag is removed. Each 11510491SRishi.Srivatsavai@Sun.COM * thread that's forwarding a packet to a known destination holds a reference 11610491SRishi.Srivatsavai@Sun.COM * to a forwarding entry. 11710491SRishi.Srivatsavai@Sun.COM * 11810491SRishi.Srivatsavai@Sun.COM * TRILL notes: 11910491SRishi.Srivatsavai@Sun.COM * 12010491SRishi.Srivatsavai@Sun.COM * The TRILL module does all of its I/O through bridging. It uses references 12110491SRishi.Srivatsavai@Sun.COM * on the bridge_inst_t and bridge_link_t structures, and has seven entry 12210491SRishi.Srivatsavai@Sun.COM * points and four callbacks. One entry point is for setting the callbacks 12310491SRishi.Srivatsavai@Sun.COM * (bridge_trill_register_cb). There are four entry points for taking bridge 12410491SRishi.Srivatsavai@Sun.COM * and link references (bridge_trill_{br,ln}{ref,unref}). The final two 12510491SRishi.Srivatsavai@Sun.COM * entry points are for decapsulated packets from TRILL (bridge_trill_decaps) 12610491SRishi.Srivatsavai@Sun.COM * that need to be bridged locally, and for TRILL-encapsulated output packets 12710491SRishi.Srivatsavai@Sun.COM * (bridge_trill_output). 12810491SRishi.Srivatsavai@Sun.COM * 12910491SRishi.Srivatsavai@Sun.COM * The four callbacks comprise two notification functions for bridges and 13010491SRishi.Srivatsavai@Sun.COM * links being deleted, one function for raw received TRILL packets, and one 13110491SRishi.Srivatsavai@Sun.COM * for bridge output to non-local TRILL destinations (tunnel entry). 13210491SRishi.Srivatsavai@Sun.COM */ 13310491SRishi.Srivatsavai@Sun.COM 13410491SRishi.Srivatsavai@Sun.COM /* 13510491SRishi.Srivatsavai@Sun.COM * Ethernet reserved multicast addresses for TRILL; used also in TRILL module. 13610491SRishi.Srivatsavai@Sun.COM */ 13710491SRishi.Srivatsavai@Sun.COM const uint8_t all_isis_rbridges[] = ALL_ISIS_RBRIDGES; 13810491SRishi.Srivatsavai@Sun.COM static const uint8_t all_esadi_rbridges[] = ALL_ESADI_RBRIDGES; 13910491SRishi.Srivatsavai@Sun.COM const uint8_t bridge_group_address[] = BRIDGE_GROUP_ADDRESS; 14010491SRishi.Srivatsavai@Sun.COM 14110491SRishi.Srivatsavai@Sun.COM static const char *inst_kstats_list[] = { KSINST_NAMES }; 14210491SRishi.Srivatsavai@Sun.COM static const char *link_kstats_list[] = { KSLINK_NAMES }; 14310491SRishi.Srivatsavai@Sun.COM 14410491SRishi.Srivatsavai@Sun.COM #define KREF(p, m, vn) p->m.vn.value.ui64 14510491SRishi.Srivatsavai@Sun.COM #define KINCR(p, m, vn) ++KREF(p, m, vn) 14610491SRishi.Srivatsavai@Sun.COM #define KDECR(p, m, vn) --KREF(p, m, vn) 14710491SRishi.Srivatsavai@Sun.COM 14810491SRishi.Srivatsavai@Sun.COM #define KIPINCR(p, vn) KINCR(p, bi_kstats, vn) 14910491SRishi.Srivatsavai@Sun.COM #define KIPDECR(p, vn) KDECR(p, bi_kstats, vn) 15010491SRishi.Srivatsavai@Sun.COM #define KLPINCR(p, vn) KINCR(p, bl_kstats, vn) 15110491SRishi.Srivatsavai@Sun.COM 15210491SRishi.Srivatsavai@Sun.COM #define KIINCR(vn) KIPINCR(bip, vn) 15310491SRishi.Srivatsavai@Sun.COM #define KIDECR(vn) KIPDECR(bip, vn) 15410491SRishi.Srivatsavai@Sun.COM #define KLINCR(vn) KLPINCR(blp, vn) 15510491SRishi.Srivatsavai@Sun.COM 15610491SRishi.Srivatsavai@Sun.COM #define Dim(x) (sizeof (x) / sizeof (*(x))) 15710491SRishi.Srivatsavai@Sun.COM 15810491SRishi.Srivatsavai@Sun.COM /* Amount of overhead added when encapsulating with VLAN headers */ 15910491SRishi.Srivatsavai@Sun.COM #define VLAN_INCR (sizeof (struct ether_vlan_header) - \ 16010491SRishi.Srivatsavai@Sun.COM sizeof (struct ether_header)) 16110491SRishi.Srivatsavai@Sun.COM 16210491SRishi.Srivatsavai@Sun.COM static dev_info_t *bridge_dev_info; 16310491SRishi.Srivatsavai@Sun.COM static major_t bridge_major; 16410491SRishi.Srivatsavai@Sun.COM static ddi_taskq_t *bridge_taskq; 16510491SRishi.Srivatsavai@Sun.COM 16610491SRishi.Srivatsavai@Sun.COM /* 16710491SRishi.Srivatsavai@Sun.COM * These are the bridge instance management data structures. The mutex lock 16810491SRishi.Srivatsavai@Sun.COM * protects the list of bridge instances. A reference count is then used on 16910491SRishi.Srivatsavai@Sun.COM * each instance to determine when to free it. We use mac_minor_hold() to 17010491SRishi.Srivatsavai@Sun.COM * allocate minor_t values, which are used both for self-cloning /dev/net/ 17110491SRishi.Srivatsavai@Sun.COM * device nodes as well as client streams. Minor node 0 is reserved for the 17210491SRishi.Srivatsavai@Sun.COM * allocation control node. 17310491SRishi.Srivatsavai@Sun.COM */ 17410491SRishi.Srivatsavai@Sun.COM static list_t inst_list; 17510491SRishi.Srivatsavai@Sun.COM static kcondvar_t inst_cv; /* Allows us to wait for shutdown */ 17610491SRishi.Srivatsavai@Sun.COM static kmutex_t inst_lock; 17710491SRishi.Srivatsavai@Sun.COM 17810491SRishi.Srivatsavai@Sun.COM static krwlock_t bmac_rwlock; 17910491SRishi.Srivatsavai@Sun.COM static list_t bmac_list; 18010491SRishi.Srivatsavai@Sun.COM 18110491SRishi.Srivatsavai@Sun.COM /* Wait for taskq entries that use STREAMS */ 18210491SRishi.Srivatsavai@Sun.COM static kcondvar_t stream_ref_cv; 18310491SRishi.Srivatsavai@Sun.COM static kmutex_t stream_ref_lock; 18410491SRishi.Srivatsavai@Sun.COM 18510491SRishi.Srivatsavai@Sun.COM static timeout_id_t bridge_timerid; 18610491SRishi.Srivatsavai@Sun.COM static clock_t bridge_scan_interval; 18710491SRishi.Srivatsavai@Sun.COM static clock_t bridge_fwd_age; 18810491SRishi.Srivatsavai@Sun.COM 18910491SRishi.Srivatsavai@Sun.COM static bridge_inst_t *bridge_find_name(const char *); 19010491SRishi.Srivatsavai@Sun.COM static void bridge_timer(void *); 19110491SRishi.Srivatsavai@Sun.COM static void bridge_unref(bridge_inst_t *); 19210491SRishi.Srivatsavai@Sun.COM 19310491SRishi.Srivatsavai@Sun.COM static const uint8_t zero_addr[ETHERADDRL] = { 0 }; 19410491SRishi.Srivatsavai@Sun.COM 19510491SRishi.Srivatsavai@Sun.COM /* Global TRILL linkage */ 19610491SRishi.Srivatsavai@Sun.COM static trill_recv_pkt_t trill_recv_fn; 19710491SRishi.Srivatsavai@Sun.COM static trill_encap_pkt_t trill_encap_fn; 19810491SRishi.Srivatsavai@Sun.COM static trill_br_dstr_t trill_brdstr_fn; 19910491SRishi.Srivatsavai@Sun.COM static trill_ln_dstr_t trill_lndstr_fn; 20010491SRishi.Srivatsavai@Sun.COM 20110491SRishi.Srivatsavai@Sun.COM /* special settings to accommodate DLD flow control; see dld_str.c */ 20210491SRishi.Srivatsavai@Sun.COM static struct module_info bridge_dld_modinfo = { 20310491SRishi.Srivatsavai@Sun.COM 0, /* mi_idnum */ 20411109SRishi.Srivatsavai@Sun.COM BRIDGE_DEV_NAME, /* mi_idname */ 20510491SRishi.Srivatsavai@Sun.COM 0, /* mi_minpsz */ 20610491SRishi.Srivatsavai@Sun.COM INFPSZ, /* mi_maxpsz */ 20710491SRishi.Srivatsavai@Sun.COM 1, /* mi_hiwat */ 20810491SRishi.Srivatsavai@Sun.COM 0 /* mi_lowat */ 20910491SRishi.Srivatsavai@Sun.COM }; 21010491SRishi.Srivatsavai@Sun.COM 21110491SRishi.Srivatsavai@Sun.COM static struct qinit bridge_dld_rinit = { 21210491SRishi.Srivatsavai@Sun.COM NULL, /* qi_putp */ 21310491SRishi.Srivatsavai@Sun.COM NULL, /* qi_srvp */ 21410491SRishi.Srivatsavai@Sun.COM dld_open, /* qi_qopen */ 21510491SRishi.Srivatsavai@Sun.COM dld_close, /* qi_qclose */ 21610491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qadmin */ 21710491SRishi.Srivatsavai@Sun.COM &bridge_dld_modinfo, /* qi_minfo */ 21810491SRishi.Srivatsavai@Sun.COM NULL /* qi_mstat */ 21910491SRishi.Srivatsavai@Sun.COM }; 22010491SRishi.Srivatsavai@Sun.COM 22110491SRishi.Srivatsavai@Sun.COM static struct qinit bridge_dld_winit = { 22210491SRishi.Srivatsavai@Sun.COM (int (*)())dld_wput, /* qi_putp */ 22310491SRishi.Srivatsavai@Sun.COM (int (*)())dld_wsrv, /* qi_srvp */ 22410491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qopen */ 22510491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qclose */ 22610491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qadmin */ 22710491SRishi.Srivatsavai@Sun.COM &bridge_dld_modinfo, /* qi_minfo */ 22810491SRishi.Srivatsavai@Sun.COM NULL /* qi_mstat */ 22910491SRishi.Srivatsavai@Sun.COM }; 23010491SRishi.Srivatsavai@Sun.COM 23110491SRishi.Srivatsavai@Sun.COM static int bridge_ioc_listfwd(void *, intptr_t, int, cred_t *, int *); 23210491SRishi.Srivatsavai@Sun.COM 23310491SRishi.Srivatsavai@Sun.COM /* GLDv3 control ioctls used by Bridging */ 23410491SRishi.Srivatsavai@Sun.COM static dld_ioc_info_t bridge_ioc_list[] = { 23510491SRishi.Srivatsavai@Sun.COM {BRIDGE_IOC_LISTFWD, DLDCOPYINOUT, sizeof (bridge_listfwd_t), 23610491SRishi.Srivatsavai@Sun.COM bridge_ioc_listfwd, NULL}, 23710491SRishi.Srivatsavai@Sun.COM }; 23810491SRishi.Srivatsavai@Sun.COM 23910491SRishi.Srivatsavai@Sun.COM /* 24010491SRishi.Srivatsavai@Sun.COM * Given a bridge mac pointer, get a ref-held pointer to the corresponding 24110491SRishi.Srivatsavai@Sun.COM * bridge instance, if any. We must hold the global bmac_rwlock so that 24210491SRishi.Srivatsavai@Sun.COM * bm_inst doesn't slide out from under us. 24310491SRishi.Srivatsavai@Sun.COM */ 24410491SRishi.Srivatsavai@Sun.COM static bridge_inst_t * 24510491SRishi.Srivatsavai@Sun.COM mac_to_inst(const bridge_mac_t *bmp) 24610491SRishi.Srivatsavai@Sun.COM { 24710491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 24810491SRishi.Srivatsavai@Sun.COM 24910491SRishi.Srivatsavai@Sun.COM rw_enter(&bmac_rwlock, RW_READER); 25010491SRishi.Srivatsavai@Sun.COM if ((bip = bmp->bm_inst) != NULL) 25110491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bip->bi_refs); 25210491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 25310491SRishi.Srivatsavai@Sun.COM return (bip); 25410491SRishi.Srivatsavai@Sun.COM } 25510491SRishi.Srivatsavai@Sun.COM 25610491SRishi.Srivatsavai@Sun.COM static void 25710491SRishi.Srivatsavai@Sun.COM link_sdu_fail(bridge_link_t *blp, boolean_t failed, mblk_t **mlist) 25810491SRishi.Srivatsavai@Sun.COM { 25910491SRishi.Srivatsavai@Sun.COM mblk_t *mp; 26010491SRishi.Srivatsavai@Sun.COM bridge_ctl_t *bcp; 26110491SRishi.Srivatsavai@Sun.COM bridge_link_t *blcmp; 26210491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 26310491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp; 26410491SRishi.Srivatsavai@Sun.COM 26510491SRishi.Srivatsavai@Sun.COM if (failed) { 26610491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_SDUFAIL) 26710491SRishi.Srivatsavai@Sun.COM return; 26810491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_SDUFAIL; 26910491SRishi.Srivatsavai@Sun.COM } else { 27010491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_SDUFAIL)) 27110491SRishi.Srivatsavai@Sun.COM return; 27210491SRishi.Srivatsavai@Sun.COM blp->bl_flags &= ~BLF_SDUFAIL; 27310491SRishi.Srivatsavai@Sun.COM } 27410491SRishi.Srivatsavai@Sun.COM 27510491SRishi.Srivatsavai@Sun.COM /* 27610491SRishi.Srivatsavai@Sun.COM * If this link is otherwise up, then check if there are any other 27710491SRishi.Srivatsavai@Sun.COM * non-failed non-down links. If not, then we control the state of the 27810491SRishi.Srivatsavai@Sun.COM * whole bridge. 27910491SRishi.Srivatsavai@Sun.COM */ 28010491SRishi.Srivatsavai@Sun.COM bip = blp->bl_inst; 28110491SRishi.Srivatsavai@Sun.COM bmp = bip->bi_mac; 28210491SRishi.Srivatsavai@Sun.COM if (blp->bl_linkstate != LINK_STATE_DOWN) { 28310491SRishi.Srivatsavai@Sun.COM for (blcmp = list_head(&bip->bi_links); blcmp != NULL; 28410491SRishi.Srivatsavai@Sun.COM blcmp = list_next(&bip->bi_links, blcmp)) { 28510491SRishi.Srivatsavai@Sun.COM if (blp != blcmp && 28610491SRishi.Srivatsavai@Sun.COM !(blcmp->bl_flags & (BLF_DELETED|BLF_SDUFAIL)) && 28710491SRishi.Srivatsavai@Sun.COM blcmp->bl_linkstate != LINK_STATE_DOWN) 28810491SRishi.Srivatsavai@Sun.COM break; 28910491SRishi.Srivatsavai@Sun.COM } 29010491SRishi.Srivatsavai@Sun.COM if (blcmp == NULL) { 29110491SRishi.Srivatsavai@Sun.COM bmp->bm_linkstate = failed ? LINK_STATE_DOWN : 29210491SRishi.Srivatsavai@Sun.COM LINK_STATE_UP; 29310491SRishi.Srivatsavai@Sun.COM mac_link_redo(bmp->bm_mh, bmp->bm_linkstate); 29410491SRishi.Srivatsavai@Sun.COM } 29510491SRishi.Srivatsavai@Sun.COM } 29610491SRishi.Srivatsavai@Sun.COM 29710491SRishi.Srivatsavai@Sun.COM /* 29810491SRishi.Srivatsavai@Sun.COM * If we're becoming failed, then the link's current true state needs 29910491SRishi.Srivatsavai@Sun.COM * to be reflected upwards to this link's clients. If we're becoming 30010491SRishi.Srivatsavai@Sun.COM * unfailed, then we get the state of the bridge instead on all 30110491SRishi.Srivatsavai@Sun.COM * clients. 30210491SRishi.Srivatsavai@Sun.COM */ 30310491SRishi.Srivatsavai@Sun.COM if (failed) { 30410491SRishi.Srivatsavai@Sun.COM if (bmp->bm_linkstate != blp->bl_linkstate) 30510491SRishi.Srivatsavai@Sun.COM mac_link_redo(blp->bl_mh, blp->bl_linkstate); 30610491SRishi.Srivatsavai@Sun.COM } else { 30710491SRishi.Srivatsavai@Sun.COM mac_link_redo(blp->bl_mh, bmp->bm_linkstate); 30810491SRishi.Srivatsavai@Sun.COM } 30910491SRishi.Srivatsavai@Sun.COM 31010491SRishi.Srivatsavai@Sun.COM /* get the current mblk we're going to send up */ 31110491SRishi.Srivatsavai@Sun.COM if ((mp = blp->bl_lfailmp) == NULL && 31210491SRishi.Srivatsavai@Sun.COM (mp = allocb(sizeof (bridge_ctl_t), BPRI_MED)) == NULL) 31310491SRishi.Srivatsavai@Sun.COM return; 31410491SRishi.Srivatsavai@Sun.COM 31510491SRishi.Srivatsavai@Sun.COM /* get a new one for next time */ 31610491SRishi.Srivatsavai@Sun.COM blp->bl_lfailmp = allocb(sizeof (bridge_ctl_t), BPRI_MED); 31710491SRishi.Srivatsavai@Sun.COM 31810491SRishi.Srivatsavai@Sun.COM /* if none for next time, then report only failures */ 31910491SRishi.Srivatsavai@Sun.COM if (blp->bl_lfailmp == NULL && !failed) { 32010491SRishi.Srivatsavai@Sun.COM blp->bl_lfailmp = mp; 32110491SRishi.Srivatsavai@Sun.COM return; 32210491SRishi.Srivatsavai@Sun.COM } 32310491SRishi.Srivatsavai@Sun.COM 32410491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 32510491SRishi.Srivatsavai@Sun.COM bcp = (bridge_ctl_t *)mp->b_rptr; 32610491SRishi.Srivatsavai@Sun.COM bcp->bc_linkid = blp->bl_linkid; 32710491SRishi.Srivatsavai@Sun.COM bcp->bc_failed = failed; 32810491SRishi.Srivatsavai@Sun.COM mp->b_wptr = (uchar_t *)(bcp + 1); 32910491SRishi.Srivatsavai@Sun.COM mp->b_next = *mlist; 33010491SRishi.Srivatsavai@Sun.COM *mlist = mp; 33110491SRishi.Srivatsavai@Sun.COM } 33210491SRishi.Srivatsavai@Sun.COM 33310491SRishi.Srivatsavai@Sun.COM /* 33410491SRishi.Srivatsavai@Sun.COM * Send control messages (link SDU changes) using the stream to the 33510491SRishi.Srivatsavai@Sun.COM * bridge instance daemon. 33610491SRishi.Srivatsavai@Sun.COM */ 33710491SRishi.Srivatsavai@Sun.COM static void 33810491SRishi.Srivatsavai@Sun.COM send_up_messages(bridge_inst_t *bip, mblk_t *mp) 33910491SRishi.Srivatsavai@Sun.COM { 34010491SRishi.Srivatsavai@Sun.COM mblk_t *mnext; 34110491SRishi.Srivatsavai@Sun.COM queue_t *rq; 34210491SRishi.Srivatsavai@Sun.COM 34310491SRishi.Srivatsavai@Sun.COM rq = bip->bi_control->bs_wq; 34410491SRishi.Srivatsavai@Sun.COM rq = OTHERQ(rq); 34510491SRishi.Srivatsavai@Sun.COM while (mp != NULL) { 34610491SRishi.Srivatsavai@Sun.COM mnext = mp->b_next; 34710491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 34810491SRishi.Srivatsavai@Sun.COM putnext(rq, mp); 34910491SRishi.Srivatsavai@Sun.COM mp = mnext; 35010491SRishi.Srivatsavai@Sun.COM } 35110491SRishi.Srivatsavai@Sun.COM } 35210491SRishi.Srivatsavai@Sun.COM 35310491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 35410491SRishi.Srivatsavai@Sun.COM static int 35510491SRishi.Srivatsavai@Sun.COM bridge_m_getstat(void *arg, uint_t stat, uint64_t *val) 35610491SRishi.Srivatsavai@Sun.COM { 35710491SRishi.Srivatsavai@Sun.COM return (ENOTSUP); 35810491SRishi.Srivatsavai@Sun.COM } 35910491SRishi.Srivatsavai@Sun.COM 36010491SRishi.Srivatsavai@Sun.COM static int 36110491SRishi.Srivatsavai@Sun.COM bridge_m_start(void *arg) 36210491SRishi.Srivatsavai@Sun.COM { 36310491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = arg; 36410491SRishi.Srivatsavai@Sun.COM 36510491SRishi.Srivatsavai@Sun.COM bmp->bm_flags |= BMF_STARTED; 36610491SRishi.Srivatsavai@Sun.COM return (0); 36710491SRishi.Srivatsavai@Sun.COM } 36810491SRishi.Srivatsavai@Sun.COM 36910491SRishi.Srivatsavai@Sun.COM static void 37010491SRishi.Srivatsavai@Sun.COM bridge_m_stop(void *arg) 37110491SRishi.Srivatsavai@Sun.COM { 37210491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = arg; 37310491SRishi.Srivatsavai@Sun.COM 37410491SRishi.Srivatsavai@Sun.COM bmp->bm_flags &= ~BMF_STARTED; 37510491SRishi.Srivatsavai@Sun.COM } 37610491SRishi.Srivatsavai@Sun.COM 37710491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 37810491SRishi.Srivatsavai@Sun.COM static int 37910491SRishi.Srivatsavai@Sun.COM bridge_m_setpromisc(void *arg, boolean_t on) 38010491SRishi.Srivatsavai@Sun.COM { 38110491SRishi.Srivatsavai@Sun.COM return (0); 38210491SRishi.Srivatsavai@Sun.COM } 38310491SRishi.Srivatsavai@Sun.COM 38410491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 38510491SRishi.Srivatsavai@Sun.COM static int 38610491SRishi.Srivatsavai@Sun.COM bridge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 38710491SRishi.Srivatsavai@Sun.COM { 38810491SRishi.Srivatsavai@Sun.COM return (0); 38910491SRishi.Srivatsavai@Sun.COM } 39010491SRishi.Srivatsavai@Sun.COM 39110491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 39210491SRishi.Srivatsavai@Sun.COM static int 39310491SRishi.Srivatsavai@Sun.COM bridge_m_unicst(void *arg, const uint8_t *macaddr) 39410491SRishi.Srivatsavai@Sun.COM { 39510491SRishi.Srivatsavai@Sun.COM return (ENOTSUP); 39610491SRishi.Srivatsavai@Sun.COM } 39710491SRishi.Srivatsavai@Sun.COM 39810491SRishi.Srivatsavai@Sun.COM static mblk_t * 39910491SRishi.Srivatsavai@Sun.COM bridge_m_tx(void *arg, mblk_t *mp) 40010491SRishi.Srivatsavai@Sun.COM { 40110491SRishi.Srivatsavai@Sun.COM _NOTE(ARGUNUSED(arg)); 40210491SRishi.Srivatsavai@Sun.COM freemsgchain(mp); 40310491SRishi.Srivatsavai@Sun.COM return (NULL); 40410491SRishi.Srivatsavai@Sun.COM } 40510491SRishi.Srivatsavai@Sun.COM 40610491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 40710491SRishi.Srivatsavai@Sun.COM static int 40810491SRishi.Srivatsavai@Sun.COM bridge_ioc_listfwd(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 40910491SRishi.Srivatsavai@Sun.COM { 41010491SRishi.Srivatsavai@Sun.COM bridge_listfwd_t *blf = karg; 41110491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 41210491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, match; 41310491SRishi.Srivatsavai@Sun.COM avl_index_t where; 41410491SRishi.Srivatsavai@Sun.COM 41510491SRishi.Srivatsavai@Sun.COM bip = bridge_find_name(blf->blf_name); 41610491SRishi.Srivatsavai@Sun.COM if (bip == NULL) 41710491SRishi.Srivatsavai@Sun.COM return (ENOENT); 41810491SRishi.Srivatsavai@Sun.COM 41910491SRishi.Srivatsavai@Sun.COM bcopy(blf->blf_dest, match.bf_dest, ETHERADDRL); 42010491SRishi.Srivatsavai@Sun.COM match.bf_flags |= BFF_VLANLOCAL; 42110491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 42210491SRishi.Srivatsavai@Sun.COM if ((bfp = avl_find(&bip->bi_fwd, &match, &where)) == NULL) 42310491SRishi.Srivatsavai@Sun.COM bfp = avl_nearest(&bip->bi_fwd, where, AVL_AFTER); 42410491SRishi.Srivatsavai@Sun.COM else 42510491SRishi.Srivatsavai@Sun.COM bfp = AVL_NEXT(&bip->bi_fwd, bfp); 42610491SRishi.Srivatsavai@Sun.COM if (bfp == NULL) { 42710491SRishi.Srivatsavai@Sun.COM bzero(blf, sizeof (*blf)); 42810491SRishi.Srivatsavai@Sun.COM } else { 42910491SRishi.Srivatsavai@Sun.COM bcopy(bfp->bf_dest, blf->blf_dest, ETHERADDRL); 43010491SRishi.Srivatsavai@Sun.COM blf->blf_trill_nick = bfp->bf_trill_nick; 43110491SRishi.Srivatsavai@Sun.COM blf->blf_ms_age = 43211066Srafael.vanoni@sun.com drv_hztousec(ddi_get_lbolt() - bfp->bf_lastheard) / 1000; 43310491SRishi.Srivatsavai@Sun.COM blf->blf_is_local = 43410491SRishi.Srivatsavai@Sun.COM (bfp->bf_flags & BFF_LOCALADDR) != 0; 43510491SRishi.Srivatsavai@Sun.COM blf->blf_linkid = bfp->bf_links[0]->bl_linkid; 43610491SRishi.Srivatsavai@Sun.COM } 43710491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 43810491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 43910491SRishi.Srivatsavai@Sun.COM return (0); 44010491SRishi.Srivatsavai@Sun.COM } 44110491SRishi.Srivatsavai@Sun.COM 44210491SRishi.Srivatsavai@Sun.COM static int 44310491SRishi.Srivatsavai@Sun.COM bridge_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 44410491SRishi.Srivatsavai@Sun.COM uint_t pr_valsize, const void *pr_val) 44510491SRishi.Srivatsavai@Sun.COM { 44610491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = arg; 44710491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 44810491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 44910491SRishi.Srivatsavai@Sun.COM int err; 45010491SRishi.Srivatsavai@Sun.COM uint_t maxsdu; 45110491SRishi.Srivatsavai@Sun.COM mblk_t *mlist; 45210491SRishi.Srivatsavai@Sun.COM 45310491SRishi.Srivatsavai@Sun.COM _NOTE(ARGUNUSED(pr_name)); 45410491SRishi.Srivatsavai@Sun.COM switch (pr_num) { 45510491SRishi.Srivatsavai@Sun.COM case MAC_PROP_MTU: 45610491SRishi.Srivatsavai@Sun.COM if (pr_valsize < sizeof (bmp->bm_maxsdu)) { 45710491SRishi.Srivatsavai@Sun.COM err = EINVAL; 45810491SRishi.Srivatsavai@Sun.COM break; 45910491SRishi.Srivatsavai@Sun.COM } 46010491SRishi.Srivatsavai@Sun.COM (void) bcopy(pr_val, &maxsdu, sizeof (maxsdu)); 46110491SRishi.Srivatsavai@Sun.COM if (maxsdu == bmp->bm_maxsdu) { 46210491SRishi.Srivatsavai@Sun.COM err = 0; 46310491SRishi.Srivatsavai@Sun.COM } else if ((bip = mac_to_inst(bmp)) == NULL) { 46410491SRishi.Srivatsavai@Sun.COM err = ENXIO; 46510491SRishi.Srivatsavai@Sun.COM } else { 46610491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 46710491SRishi.Srivatsavai@Sun.COM mlist = NULL; 46810491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 46910491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 47010491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_DELETED) 47110491SRishi.Srivatsavai@Sun.COM continue; 47210491SRishi.Srivatsavai@Sun.COM if (blp->bl_maxsdu == maxsdu) 47310491SRishi.Srivatsavai@Sun.COM link_sdu_fail(blp, B_FALSE, &mlist); 47410491SRishi.Srivatsavai@Sun.COM else if (blp->bl_maxsdu == bmp->bm_maxsdu) 47510491SRishi.Srivatsavai@Sun.COM link_sdu_fail(blp, B_TRUE, &mlist); 47610491SRishi.Srivatsavai@Sun.COM } 47710491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 47810491SRishi.Srivatsavai@Sun.COM bmp->bm_maxsdu = maxsdu; 47910491SRishi.Srivatsavai@Sun.COM (void) mac_maxsdu_update(bmp->bm_mh, maxsdu); 48010491SRishi.Srivatsavai@Sun.COM send_up_messages(bip, mlist); 48110491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 48210491SRishi.Srivatsavai@Sun.COM err = 0; 48310491SRishi.Srivatsavai@Sun.COM } 48410491SRishi.Srivatsavai@Sun.COM break; 48510491SRishi.Srivatsavai@Sun.COM 48610491SRishi.Srivatsavai@Sun.COM default: 48710491SRishi.Srivatsavai@Sun.COM err = ENOTSUP; 48810491SRishi.Srivatsavai@Sun.COM break; 48910491SRishi.Srivatsavai@Sun.COM } 49010491SRishi.Srivatsavai@Sun.COM return (err); 49110491SRishi.Srivatsavai@Sun.COM } 49210491SRishi.Srivatsavai@Sun.COM 49310491SRishi.Srivatsavai@Sun.COM static int 49410491SRishi.Srivatsavai@Sun.COM bridge_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 49510491SRishi.Srivatsavai@Sun.COM uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm) 49610491SRishi.Srivatsavai@Sun.COM { 49710491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = arg; 49810491SRishi.Srivatsavai@Sun.COM int err = 0; 49910491SRishi.Srivatsavai@Sun.COM 50010491SRishi.Srivatsavai@Sun.COM _NOTE(ARGUNUSED(pr_name)); 50110491SRishi.Srivatsavai@Sun.COM switch (pr_num) { 50210491SRishi.Srivatsavai@Sun.COM case MAC_PROP_MTU: { 50310491SRishi.Srivatsavai@Sun.COM mac_propval_range_t range; 50410491SRishi.Srivatsavai@Sun.COM 50510491SRishi.Srivatsavai@Sun.COM if (!(pr_flags & MAC_PROP_POSSIBLE)) 50610491SRishi.Srivatsavai@Sun.COM return (ENOTSUP); 50710491SRishi.Srivatsavai@Sun.COM if (pr_valsize < sizeof (mac_propval_range_t)) 50810491SRishi.Srivatsavai@Sun.COM return (EINVAL); 50910491SRishi.Srivatsavai@Sun.COM range.mpr_count = 1; 51010491SRishi.Srivatsavai@Sun.COM range.mpr_type = MAC_PROPVAL_UINT32; 51110491SRishi.Srivatsavai@Sun.COM range.range_uint32[0].mpur_min = 51210491SRishi.Srivatsavai@Sun.COM range.range_uint32[0].mpur_max = bmp->bm_maxsdu; 51310491SRishi.Srivatsavai@Sun.COM bcopy(&range, pr_val, sizeof (range)); 51410491SRishi.Srivatsavai@Sun.COM *perm = MAC_PROP_PERM_RW; 51510491SRishi.Srivatsavai@Sun.COM break; 51610491SRishi.Srivatsavai@Sun.COM } 51710491SRishi.Srivatsavai@Sun.COM case MAC_PROP_STATUS: 51810491SRishi.Srivatsavai@Sun.COM if (pr_valsize < sizeof (bmp->bm_linkstate)) { 51910491SRishi.Srivatsavai@Sun.COM err = EINVAL; 52010491SRishi.Srivatsavai@Sun.COM } else { 52110491SRishi.Srivatsavai@Sun.COM bcopy(&bmp->bm_linkstate, pr_val, 52210491SRishi.Srivatsavai@Sun.COM sizeof (&bmp->bm_linkstate)); 52310491SRishi.Srivatsavai@Sun.COM *perm = MAC_PROP_PERM_READ; 52410491SRishi.Srivatsavai@Sun.COM } 52510491SRishi.Srivatsavai@Sun.COM break; 52610491SRishi.Srivatsavai@Sun.COM 52710491SRishi.Srivatsavai@Sun.COM default: 52810491SRishi.Srivatsavai@Sun.COM err = ENOTSUP; 52910491SRishi.Srivatsavai@Sun.COM break; 53010491SRishi.Srivatsavai@Sun.COM } 53110491SRishi.Srivatsavai@Sun.COM return (err); 53210491SRishi.Srivatsavai@Sun.COM } 53310491SRishi.Srivatsavai@Sun.COM 53410491SRishi.Srivatsavai@Sun.COM static mac_callbacks_t bridge_m_callbacks = { 53510491SRishi.Srivatsavai@Sun.COM MC_SETPROP | MC_GETPROP, 53610491SRishi.Srivatsavai@Sun.COM bridge_m_getstat, 53710491SRishi.Srivatsavai@Sun.COM bridge_m_start, 53810491SRishi.Srivatsavai@Sun.COM bridge_m_stop, 53910491SRishi.Srivatsavai@Sun.COM bridge_m_setpromisc, 54010491SRishi.Srivatsavai@Sun.COM bridge_m_multicst, 54110491SRishi.Srivatsavai@Sun.COM bridge_m_unicst, 54210491SRishi.Srivatsavai@Sun.COM bridge_m_tx, 54310491SRishi.Srivatsavai@Sun.COM NULL, /* ioctl */ 54410491SRishi.Srivatsavai@Sun.COM NULL, /* getcapab */ 54510491SRishi.Srivatsavai@Sun.COM NULL, /* open */ 54610491SRishi.Srivatsavai@Sun.COM NULL, /* close */ 54710491SRishi.Srivatsavai@Sun.COM bridge_m_setprop, 54810491SRishi.Srivatsavai@Sun.COM bridge_m_getprop 54910491SRishi.Srivatsavai@Sun.COM }; 55010491SRishi.Srivatsavai@Sun.COM 55110491SRishi.Srivatsavai@Sun.COM /* 55210491SRishi.Srivatsavai@Sun.COM * Create kstats from a list. 55310491SRishi.Srivatsavai@Sun.COM */ 55410491SRishi.Srivatsavai@Sun.COM static kstat_t * 55510491SRishi.Srivatsavai@Sun.COM kstat_setup(kstat_named_t *knt, const char **names, int nstat, 55610491SRishi.Srivatsavai@Sun.COM const char *unitname) 55710491SRishi.Srivatsavai@Sun.COM { 55810491SRishi.Srivatsavai@Sun.COM kstat_t *ksp; 55910491SRishi.Srivatsavai@Sun.COM int i; 56010491SRishi.Srivatsavai@Sun.COM 56110491SRishi.Srivatsavai@Sun.COM for (i = 0; i < nstat; i++) 56210491SRishi.Srivatsavai@Sun.COM kstat_named_init(&knt[i], names[i], KSTAT_DATA_UINT64); 56310491SRishi.Srivatsavai@Sun.COM 56411109SRishi.Srivatsavai@Sun.COM ksp = kstat_create_zone(BRIDGE_DEV_NAME, 0, unitname, "net", 56510491SRishi.Srivatsavai@Sun.COM KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_VIRTUAL, GLOBAL_ZONEID); 56610491SRishi.Srivatsavai@Sun.COM if (ksp != NULL) { 56710491SRishi.Srivatsavai@Sun.COM ksp->ks_data = knt; 56810491SRishi.Srivatsavai@Sun.COM kstat_install(ksp); 56910491SRishi.Srivatsavai@Sun.COM } 57010491SRishi.Srivatsavai@Sun.COM return (ksp); 57110491SRishi.Srivatsavai@Sun.COM } 57210491SRishi.Srivatsavai@Sun.COM 57310491SRishi.Srivatsavai@Sun.COM /* 57410491SRishi.Srivatsavai@Sun.COM * Find an existing bridge_mac_t structure or allocate a new one for the given 57510491SRishi.Srivatsavai@Sun.COM * bridge instance. This creates the mac driver instance that snoop can use. 57610491SRishi.Srivatsavai@Sun.COM */ 57710491SRishi.Srivatsavai@Sun.COM static int 57810491SRishi.Srivatsavai@Sun.COM bmac_alloc(bridge_inst_t *bip, bridge_mac_t **bmacp) 57910491SRishi.Srivatsavai@Sun.COM { 58010491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp, *bnew; 58110491SRishi.Srivatsavai@Sun.COM mac_register_t *mac; 58210491SRishi.Srivatsavai@Sun.COM int err; 58310491SRishi.Srivatsavai@Sun.COM 58410491SRishi.Srivatsavai@Sun.COM *bmacp = NULL; 58510491SRishi.Srivatsavai@Sun.COM if ((mac = mac_alloc(MAC_VERSION)) == NULL) 58610491SRishi.Srivatsavai@Sun.COM return (EINVAL); 58710491SRishi.Srivatsavai@Sun.COM 58810491SRishi.Srivatsavai@Sun.COM bnew = kmem_zalloc(sizeof (*bnew), KM_SLEEP); 58910491SRishi.Srivatsavai@Sun.COM 59010491SRishi.Srivatsavai@Sun.COM rw_enter(&bmac_rwlock, RW_WRITER); 59110491SRishi.Srivatsavai@Sun.COM for (bmp = list_head(&bmac_list); bmp != NULL; 59210491SRishi.Srivatsavai@Sun.COM bmp = list_next(&bmac_list, bmp)) { 59310491SRishi.Srivatsavai@Sun.COM if (strcmp(bip->bi_name, bmp->bm_name) == 0) { 59410491SRishi.Srivatsavai@Sun.COM ASSERT(bmp->bm_inst == NULL); 59510491SRishi.Srivatsavai@Sun.COM bmp->bm_inst = bip; 59610491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 59710491SRishi.Srivatsavai@Sun.COM kmem_free(bnew, sizeof (*bnew)); 59810491SRishi.Srivatsavai@Sun.COM mac_free(mac); 59910491SRishi.Srivatsavai@Sun.COM *bmacp = bmp; 60010491SRishi.Srivatsavai@Sun.COM return (0); 60110491SRishi.Srivatsavai@Sun.COM } 60210491SRishi.Srivatsavai@Sun.COM } 60310491SRishi.Srivatsavai@Sun.COM 60410491SRishi.Srivatsavai@Sun.COM mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 60510491SRishi.Srivatsavai@Sun.COM mac->m_driver = bnew; 60610491SRishi.Srivatsavai@Sun.COM mac->m_dip = bridge_dev_info; 60710491SRishi.Srivatsavai@Sun.COM mac->m_instance = (uint_t)-1; 60810491SRishi.Srivatsavai@Sun.COM mac->m_src_addr = (uint8_t *)zero_addr; 60910491SRishi.Srivatsavai@Sun.COM mac->m_callbacks = &bridge_m_callbacks; 61010491SRishi.Srivatsavai@Sun.COM 61110491SRishi.Srivatsavai@Sun.COM /* 61210491SRishi.Srivatsavai@Sun.COM * Note that the SDU limits are irrelevant, as nobody transmits on the 61310491SRishi.Srivatsavai@Sun.COM * bridge node itself. It's mainly for monitoring but we allow 61410491SRishi.Srivatsavai@Sun.COM * setting the bridge MTU for quick transition of all links part of the 61510491SRishi.Srivatsavai@Sun.COM * bridge to a new MTU. 61610491SRishi.Srivatsavai@Sun.COM */ 61710491SRishi.Srivatsavai@Sun.COM mac->m_min_sdu = 1; 61810491SRishi.Srivatsavai@Sun.COM mac->m_max_sdu = 1500; 61910491SRishi.Srivatsavai@Sun.COM err = mac_register(mac, &bnew->bm_mh); 62010491SRishi.Srivatsavai@Sun.COM mac_free(mac); 62110491SRishi.Srivatsavai@Sun.COM if (err != 0) { 62210491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 62310491SRishi.Srivatsavai@Sun.COM kmem_free(bnew, sizeof (*bnew)); 62410491SRishi.Srivatsavai@Sun.COM return (err); 62510491SRishi.Srivatsavai@Sun.COM } 62610491SRishi.Srivatsavai@Sun.COM 62710491SRishi.Srivatsavai@Sun.COM bnew->bm_inst = bip; 62810491SRishi.Srivatsavai@Sun.COM (void) strcpy(bnew->bm_name, bip->bi_name); 62910491SRishi.Srivatsavai@Sun.COM if (list_is_empty(&bmac_list)) { 63010491SRishi.Srivatsavai@Sun.COM bridge_timerid = timeout(bridge_timer, NULL, 63110491SRishi.Srivatsavai@Sun.COM bridge_scan_interval); 63210491SRishi.Srivatsavai@Sun.COM } 63310491SRishi.Srivatsavai@Sun.COM list_insert_tail(&bmac_list, bnew); 63410491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 63510491SRishi.Srivatsavai@Sun.COM 63610491SRishi.Srivatsavai@Sun.COM /* 63710491SRishi.Srivatsavai@Sun.COM * Mark the MAC as unable to go "active" so that only passive clients 63810491SRishi.Srivatsavai@Sun.COM * (such as snoop) can bind to it. 63910491SRishi.Srivatsavai@Sun.COM */ 64010491SRishi.Srivatsavai@Sun.COM mac_no_active(bnew->bm_mh); 64110491SRishi.Srivatsavai@Sun.COM *bmacp = bnew; 64210491SRishi.Srivatsavai@Sun.COM return (0); 64310491SRishi.Srivatsavai@Sun.COM } 64410491SRishi.Srivatsavai@Sun.COM 64510491SRishi.Srivatsavai@Sun.COM /* 64610491SRishi.Srivatsavai@Sun.COM * Disconnect the given bridge_mac_t from its bridge instance. The bridge 64710491SRishi.Srivatsavai@Sun.COM * instance is going away. The mac instance can't go away until the clients 64810491SRishi.Srivatsavai@Sun.COM * are gone (see bridge_timer). 64910491SRishi.Srivatsavai@Sun.COM */ 65010491SRishi.Srivatsavai@Sun.COM static void 65110491SRishi.Srivatsavai@Sun.COM bmac_disconnect(bridge_mac_t *bmp) 65210491SRishi.Srivatsavai@Sun.COM { 65310491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 65410491SRishi.Srivatsavai@Sun.COM 65510491SRishi.Srivatsavai@Sun.COM bmp->bm_linkstate = LINK_STATE_DOWN; 65610491SRishi.Srivatsavai@Sun.COM mac_link_redo(bmp->bm_mh, LINK_STATE_DOWN); 65710491SRishi.Srivatsavai@Sun.COM 65810491SRishi.Srivatsavai@Sun.COM rw_enter(&bmac_rwlock, RW_READER); 65910491SRishi.Srivatsavai@Sun.COM bip = bmp->bm_inst; 66010491SRishi.Srivatsavai@Sun.COM bip->bi_mac = NULL; 66110491SRishi.Srivatsavai@Sun.COM bmp->bm_inst = NULL; 66210491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 66310491SRishi.Srivatsavai@Sun.COM } 66410491SRishi.Srivatsavai@Sun.COM 66510491SRishi.Srivatsavai@Sun.COM /* This is used by the avl trees to sort forwarding table entries */ 66610491SRishi.Srivatsavai@Sun.COM static int 66710491SRishi.Srivatsavai@Sun.COM fwd_compare(const void *addr1, const void *addr2) 66810491SRishi.Srivatsavai@Sun.COM { 66910491SRishi.Srivatsavai@Sun.COM const bridge_fwd_t *fwd1 = addr1; 67010491SRishi.Srivatsavai@Sun.COM const bridge_fwd_t *fwd2 = addr2; 67110491SRishi.Srivatsavai@Sun.COM int diff = memcmp(fwd1->bf_dest, fwd2->bf_dest, ETHERADDRL); 67210491SRishi.Srivatsavai@Sun.COM 67310491SRishi.Srivatsavai@Sun.COM if (diff != 0) 67410491SRishi.Srivatsavai@Sun.COM return (diff > 0 ? 1 : -1); 67510491SRishi.Srivatsavai@Sun.COM 67610491SRishi.Srivatsavai@Sun.COM if ((fwd1->bf_flags ^ fwd2->bf_flags) & BFF_VLANLOCAL) { 67710491SRishi.Srivatsavai@Sun.COM if (fwd1->bf_vlanid > fwd2->bf_vlanid) 67810491SRishi.Srivatsavai@Sun.COM return (1); 67910491SRishi.Srivatsavai@Sun.COM else if (fwd1->bf_vlanid < fwd2->bf_vlanid) 68010491SRishi.Srivatsavai@Sun.COM return (-1); 68110491SRishi.Srivatsavai@Sun.COM } 68210491SRishi.Srivatsavai@Sun.COM return (0); 68310491SRishi.Srivatsavai@Sun.COM } 68410491SRishi.Srivatsavai@Sun.COM 68510491SRishi.Srivatsavai@Sun.COM static void 68610491SRishi.Srivatsavai@Sun.COM inst_free(bridge_inst_t *bip) 68710491SRishi.Srivatsavai@Sun.COM { 68810491SRishi.Srivatsavai@Sun.COM ASSERT(bip->bi_mac == NULL); 68910491SRishi.Srivatsavai@Sun.COM rw_destroy(&bip->bi_rwlock); 69010491SRishi.Srivatsavai@Sun.COM list_destroy(&bip->bi_links); 69110491SRishi.Srivatsavai@Sun.COM cv_destroy(&bip->bi_linkwait); 69210491SRishi.Srivatsavai@Sun.COM avl_destroy(&bip->bi_fwd); 69310491SRishi.Srivatsavai@Sun.COM if (bip->bi_ksp != NULL) 69410491SRishi.Srivatsavai@Sun.COM kstat_delete(bip->bi_ksp); 69510491SRishi.Srivatsavai@Sun.COM kmem_free(bip, sizeof (*bip)); 69610491SRishi.Srivatsavai@Sun.COM } 69710491SRishi.Srivatsavai@Sun.COM 69810491SRishi.Srivatsavai@Sun.COM static bridge_inst_t * 69910491SRishi.Srivatsavai@Sun.COM inst_alloc(const char *bridge) 70010491SRishi.Srivatsavai@Sun.COM { 70110491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 70210491SRishi.Srivatsavai@Sun.COM 70310491SRishi.Srivatsavai@Sun.COM bip = kmem_zalloc(sizeof (*bip), KM_SLEEP); 70410491SRishi.Srivatsavai@Sun.COM bip->bi_refs = 1; 70510491SRishi.Srivatsavai@Sun.COM (void) strcpy(bip->bi_name, bridge); 70610491SRishi.Srivatsavai@Sun.COM rw_init(&bip->bi_rwlock, NULL, RW_DRIVER, NULL); 70710491SRishi.Srivatsavai@Sun.COM list_create(&bip->bi_links, sizeof (bridge_link_t), 70810491SRishi.Srivatsavai@Sun.COM offsetof(bridge_link_t, bl_node)); 70910491SRishi.Srivatsavai@Sun.COM cv_init(&bip->bi_linkwait, NULL, CV_DRIVER, NULL); 71010491SRishi.Srivatsavai@Sun.COM avl_create(&bip->bi_fwd, fwd_compare, sizeof (bridge_fwd_t), 71110491SRishi.Srivatsavai@Sun.COM offsetof(bridge_fwd_t, bf_node)); 71210491SRishi.Srivatsavai@Sun.COM return (bip); 71310491SRishi.Srivatsavai@Sun.COM } 71410491SRishi.Srivatsavai@Sun.COM 71510491SRishi.Srivatsavai@Sun.COM static bridge_inst_t * 71610491SRishi.Srivatsavai@Sun.COM bridge_find_name(const char *bridge) 71710491SRishi.Srivatsavai@Sun.COM { 71810491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 71910491SRishi.Srivatsavai@Sun.COM 72010491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 72110491SRishi.Srivatsavai@Sun.COM for (bip = list_head(&inst_list); bip != NULL; 72210491SRishi.Srivatsavai@Sun.COM bip = list_next(&inst_list, bip)) { 72310491SRishi.Srivatsavai@Sun.COM if (!(bip->bi_flags & BIF_SHUTDOWN) && 72410491SRishi.Srivatsavai@Sun.COM strcmp(bridge, bip->bi_name) == 0) { 72510491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bip->bi_refs); 72610491SRishi.Srivatsavai@Sun.COM break; 72710491SRishi.Srivatsavai@Sun.COM } 72810491SRishi.Srivatsavai@Sun.COM } 72910491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 73010491SRishi.Srivatsavai@Sun.COM 73110491SRishi.Srivatsavai@Sun.COM return (bip); 73210491SRishi.Srivatsavai@Sun.COM } 73310491SRishi.Srivatsavai@Sun.COM 73410491SRishi.Srivatsavai@Sun.COM static int 73510616SSebastien.Roy@Sun.COM bridge_create(datalink_id_t linkid, const char *bridge, bridge_inst_t **bipc, 73610616SSebastien.Roy@Sun.COM cred_t *cred) 73710491SRishi.Srivatsavai@Sun.COM { 73810491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip, *bipnew; 73910491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = NULL; 74010491SRishi.Srivatsavai@Sun.COM int err; 74110491SRishi.Srivatsavai@Sun.COM 74210491SRishi.Srivatsavai@Sun.COM *bipc = NULL; 74310491SRishi.Srivatsavai@Sun.COM bipnew = inst_alloc(bridge); 74410491SRishi.Srivatsavai@Sun.COM 74510491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 74610491SRishi.Srivatsavai@Sun.COM lookup_retry: 74710491SRishi.Srivatsavai@Sun.COM for (bip = list_head(&inst_list); bip != NULL; 74810491SRishi.Srivatsavai@Sun.COM bip = list_next(&inst_list, bip)) { 74910491SRishi.Srivatsavai@Sun.COM if (strcmp(bridge, bip->bi_name) == 0) 75010491SRishi.Srivatsavai@Sun.COM break; 75110491SRishi.Srivatsavai@Sun.COM } 75210491SRishi.Srivatsavai@Sun.COM 75310491SRishi.Srivatsavai@Sun.COM /* This should not take long; if it does, we've got a design problem */ 75410491SRishi.Srivatsavai@Sun.COM if (bip != NULL && (bip->bi_flags & BIF_SHUTDOWN)) { 75510491SRishi.Srivatsavai@Sun.COM cv_wait(&inst_cv, &inst_lock); 75610491SRishi.Srivatsavai@Sun.COM goto lookup_retry; 75710491SRishi.Srivatsavai@Sun.COM } 75810491SRishi.Srivatsavai@Sun.COM 75911109SRishi.Srivatsavai@Sun.COM if (bip == NULL) { 76010491SRishi.Srivatsavai@Sun.COM bip = bipnew; 76110491SRishi.Srivatsavai@Sun.COM bipnew = NULL; 76210491SRishi.Srivatsavai@Sun.COM list_insert_tail(&inst_list, bip); 76310491SRishi.Srivatsavai@Sun.COM } 76410491SRishi.Srivatsavai@Sun.COM 76510491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 76611109SRishi.Srivatsavai@Sun.COM if (bipnew != NULL) { 76711109SRishi.Srivatsavai@Sun.COM inst_free(bipnew); 76811109SRishi.Srivatsavai@Sun.COM return (EEXIST); 76911109SRishi.Srivatsavai@Sun.COM } 77010491SRishi.Srivatsavai@Sun.COM 77110491SRishi.Srivatsavai@Sun.COM bip->bi_ksp = kstat_setup((kstat_named_t *)&bip->bi_kstats, 77210491SRishi.Srivatsavai@Sun.COM inst_kstats_list, Dim(inst_kstats_list), bip->bi_name); 77310491SRishi.Srivatsavai@Sun.COM 77410491SRishi.Srivatsavai@Sun.COM err = bmac_alloc(bip, &bmp); 77510491SRishi.Srivatsavai@Sun.COM if ((bip->bi_mac = bmp) == NULL) 77610491SRishi.Srivatsavai@Sun.COM goto fail_create; 77710491SRishi.Srivatsavai@Sun.COM 77810491SRishi.Srivatsavai@Sun.COM /* 77910491SRishi.Srivatsavai@Sun.COM * bm_inst is set, so the timer cannot yank the DLS rug from under us. 78010491SRishi.Srivatsavai@Sun.COM * No extra locking is needed here. 78110491SRishi.Srivatsavai@Sun.COM */ 78210491SRishi.Srivatsavai@Sun.COM if (!(bmp->bm_flags & BMF_DLS)) { 78310616SSebastien.Roy@Sun.COM err = dls_devnet_create(bmp->bm_mh, linkid, crgetzoneid(cred)); 78410616SSebastien.Roy@Sun.COM if (err != 0) 78510491SRishi.Srivatsavai@Sun.COM goto fail_create; 78610491SRishi.Srivatsavai@Sun.COM bmp->bm_flags |= BMF_DLS; 78710491SRishi.Srivatsavai@Sun.COM } 78810491SRishi.Srivatsavai@Sun.COM 78910491SRishi.Srivatsavai@Sun.COM bip->bi_dev = makedevice(bridge_major, mac_minor(bmp->bm_mh)); 79010491SRishi.Srivatsavai@Sun.COM *bipc = bip; 79110491SRishi.Srivatsavai@Sun.COM return (0); 79210491SRishi.Srivatsavai@Sun.COM 79310491SRishi.Srivatsavai@Sun.COM fail_create: 79411109SRishi.Srivatsavai@Sun.COM ASSERT(bip->bi_trilldata == NULL); 79511109SRishi.Srivatsavai@Sun.COM bip->bi_flags |= BIF_SHUTDOWN; 79611109SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 79710491SRishi.Srivatsavai@Sun.COM return (err); 79810491SRishi.Srivatsavai@Sun.COM } 79910491SRishi.Srivatsavai@Sun.COM 80010491SRishi.Srivatsavai@Sun.COM static void 80110491SRishi.Srivatsavai@Sun.COM bridge_unref(bridge_inst_t *bip) 80210491SRishi.Srivatsavai@Sun.COM { 80310491SRishi.Srivatsavai@Sun.COM if (atomic_dec_uint_nv(&bip->bi_refs) == 0) { 80410491SRishi.Srivatsavai@Sun.COM ASSERT(bip->bi_flags & BIF_SHUTDOWN); 80510491SRishi.Srivatsavai@Sun.COM /* free up mac for reuse before leaving global list */ 80610491SRishi.Srivatsavai@Sun.COM if (bip->bi_mac != NULL) 80710491SRishi.Srivatsavai@Sun.COM bmac_disconnect(bip->bi_mac); 80810491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 80910491SRishi.Srivatsavai@Sun.COM list_remove(&inst_list, bip); 81010491SRishi.Srivatsavai@Sun.COM cv_broadcast(&inst_cv); 81110491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 81210491SRishi.Srivatsavai@Sun.COM inst_free(bip); 81310491SRishi.Srivatsavai@Sun.COM } 81410491SRishi.Srivatsavai@Sun.COM } 81510491SRishi.Srivatsavai@Sun.COM 81610491SRishi.Srivatsavai@Sun.COM /* 81710491SRishi.Srivatsavai@Sun.COM * Stream instances are used only for allocating bridges and serving as a 81810491SRishi.Srivatsavai@Sun.COM * control node. They serve no data-handling function. 81910491SRishi.Srivatsavai@Sun.COM */ 82010491SRishi.Srivatsavai@Sun.COM static bridge_stream_t * 82110491SRishi.Srivatsavai@Sun.COM stream_alloc(void) 82210491SRishi.Srivatsavai@Sun.COM { 82310491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp; 82410491SRishi.Srivatsavai@Sun.COM minor_t mn; 82510491SRishi.Srivatsavai@Sun.COM 82610491SRishi.Srivatsavai@Sun.COM if ((mn = mac_minor_hold(B_FALSE)) == 0) 82710491SRishi.Srivatsavai@Sun.COM return (NULL); 82810491SRishi.Srivatsavai@Sun.COM bsp = kmem_zalloc(sizeof (*bsp), KM_SLEEP); 82910491SRishi.Srivatsavai@Sun.COM bsp->bs_minor = mn; 83010491SRishi.Srivatsavai@Sun.COM return (bsp); 83110491SRishi.Srivatsavai@Sun.COM } 83210491SRishi.Srivatsavai@Sun.COM 83310491SRishi.Srivatsavai@Sun.COM static void 83410491SRishi.Srivatsavai@Sun.COM stream_free(bridge_stream_t *bsp) 83510491SRishi.Srivatsavai@Sun.COM { 83610491SRishi.Srivatsavai@Sun.COM mac_minor_rele(bsp->bs_minor); 83710491SRishi.Srivatsavai@Sun.COM kmem_free(bsp, sizeof (*bsp)); 83810491SRishi.Srivatsavai@Sun.COM } 83910491SRishi.Srivatsavai@Sun.COM 84010491SRishi.Srivatsavai@Sun.COM /* Reference hold/release functions for STREAMS-related taskq */ 84110491SRishi.Srivatsavai@Sun.COM static void 84210491SRishi.Srivatsavai@Sun.COM stream_ref(bridge_stream_t *bsp) 84310491SRishi.Srivatsavai@Sun.COM { 84410491SRishi.Srivatsavai@Sun.COM mutex_enter(&stream_ref_lock); 84510491SRishi.Srivatsavai@Sun.COM bsp->bs_taskq_cnt++; 84610491SRishi.Srivatsavai@Sun.COM mutex_exit(&stream_ref_lock); 84710491SRishi.Srivatsavai@Sun.COM } 84810491SRishi.Srivatsavai@Sun.COM 84910491SRishi.Srivatsavai@Sun.COM static void 85010491SRishi.Srivatsavai@Sun.COM stream_unref(bridge_stream_t *bsp) 85110491SRishi.Srivatsavai@Sun.COM { 85210491SRishi.Srivatsavai@Sun.COM mutex_enter(&stream_ref_lock); 85310491SRishi.Srivatsavai@Sun.COM if (--bsp->bs_taskq_cnt == 0) 85410491SRishi.Srivatsavai@Sun.COM cv_broadcast(&stream_ref_cv); 85510491SRishi.Srivatsavai@Sun.COM mutex_exit(&stream_ref_lock); 85610491SRishi.Srivatsavai@Sun.COM } 85710491SRishi.Srivatsavai@Sun.COM 85810491SRishi.Srivatsavai@Sun.COM static void 85910491SRishi.Srivatsavai@Sun.COM link_free(bridge_link_t *blp) 86010491SRishi.Srivatsavai@Sun.COM { 86110491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 86210491SRishi.Srivatsavai@Sun.COM 86310491SRishi.Srivatsavai@Sun.COM ASSERT(!(blp->bl_flags & BLF_FREED)); 86410491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_FREED; 86510491SRishi.Srivatsavai@Sun.COM if (blp->bl_ksp != NULL) 86610491SRishi.Srivatsavai@Sun.COM kstat_delete(blp->bl_ksp); 86710491SRishi.Srivatsavai@Sun.COM if (blp->bl_lfailmp != NULL) 86810491SRishi.Srivatsavai@Sun.COM freeb(blp->bl_lfailmp); 86910491SRishi.Srivatsavai@Sun.COM cv_destroy(&blp->bl_trillwait); 87010491SRishi.Srivatsavai@Sun.COM mutex_destroy(&blp->bl_trilllock); 87110491SRishi.Srivatsavai@Sun.COM kmem_free(blp, sizeof (*blp)); 87210491SRishi.Srivatsavai@Sun.COM /* Don't unreference the bridge until the MAC is closed */ 87310491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 87410491SRishi.Srivatsavai@Sun.COM } 87510491SRishi.Srivatsavai@Sun.COM 87610491SRishi.Srivatsavai@Sun.COM static void 87710491SRishi.Srivatsavai@Sun.COM link_unref(bridge_link_t *blp) 87810491SRishi.Srivatsavai@Sun.COM { 87910491SRishi.Srivatsavai@Sun.COM if (atomic_dec_uint_nv(&blp->bl_refs) == 0) { 88010491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 88110491SRishi.Srivatsavai@Sun.COM 88210491SRishi.Srivatsavai@Sun.COM ASSERT(blp->bl_flags & BLF_DELETED); 88310491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 884*11483SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_LINK_ADDED) 885*11483SRishi.Srivatsavai@Sun.COM list_remove(&bip->bi_links, blp); 88610491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 88710491SRishi.Srivatsavai@Sun.COM if (bip->bi_trilldata != NULL && list_is_empty(&bip->bi_links)) 88810491SRishi.Srivatsavai@Sun.COM cv_broadcast(&bip->bi_linkwait); 88910491SRishi.Srivatsavai@Sun.COM link_free(blp); 89010491SRishi.Srivatsavai@Sun.COM } 89110491SRishi.Srivatsavai@Sun.COM } 89210491SRishi.Srivatsavai@Sun.COM 89310491SRishi.Srivatsavai@Sun.COM static bridge_fwd_t * 89410491SRishi.Srivatsavai@Sun.COM fwd_alloc(const uint8_t *addr, uint_t nlinks, uint16_t nick) 89510491SRishi.Srivatsavai@Sun.COM { 89610491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp; 89710491SRishi.Srivatsavai@Sun.COM 89810491SRishi.Srivatsavai@Sun.COM bfp = kmem_zalloc(sizeof (*bfp) + (nlinks * sizeof (bridge_link_t *)), 89910491SRishi.Srivatsavai@Sun.COM KM_NOSLEEP); 90010491SRishi.Srivatsavai@Sun.COM if (bfp != NULL) { 90110491SRishi.Srivatsavai@Sun.COM bcopy(addr, bfp->bf_dest, ETHERADDRL); 90211066Srafael.vanoni@sun.com bfp->bf_lastheard = ddi_get_lbolt(); 90310491SRishi.Srivatsavai@Sun.COM bfp->bf_maxlinks = nlinks; 90410491SRishi.Srivatsavai@Sun.COM bfp->bf_links = (bridge_link_t **)(bfp + 1); 90510491SRishi.Srivatsavai@Sun.COM bfp->bf_trill_nick = nick; 90610491SRishi.Srivatsavai@Sun.COM } 90710491SRishi.Srivatsavai@Sun.COM return (bfp); 90810491SRishi.Srivatsavai@Sun.COM } 90910491SRishi.Srivatsavai@Sun.COM 91010491SRishi.Srivatsavai@Sun.COM static bridge_fwd_t * 91110491SRishi.Srivatsavai@Sun.COM fwd_find(bridge_inst_t *bip, const uint8_t *addr, uint16_t vlanid) 91210491SRishi.Srivatsavai@Sun.COM { 91310491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *vbfp; 91410491SRishi.Srivatsavai@Sun.COM bridge_fwd_t match; 91510491SRishi.Srivatsavai@Sun.COM 91610491SRishi.Srivatsavai@Sun.COM bcopy(addr, match.bf_dest, ETHERADDRL); 91710491SRishi.Srivatsavai@Sun.COM match.bf_flags = 0; 91810491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 91910491SRishi.Srivatsavai@Sun.COM if ((bfp = avl_find(&bip->bi_fwd, &match, NULL)) != NULL) { 92010491SRishi.Srivatsavai@Sun.COM if (bfp->bf_vlanid != vlanid && bfp->bf_vcnt > 0) { 92110491SRishi.Srivatsavai@Sun.COM match.bf_vlanid = vlanid; 92210491SRishi.Srivatsavai@Sun.COM match.bf_flags = BFF_VLANLOCAL; 92310491SRishi.Srivatsavai@Sun.COM vbfp = avl_find(&bip->bi_fwd, &match, NULL); 92410491SRishi.Srivatsavai@Sun.COM if (vbfp != NULL) 92510491SRishi.Srivatsavai@Sun.COM bfp = vbfp; 92610491SRishi.Srivatsavai@Sun.COM } 92710491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bfp->bf_refs); 92810491SRishi.Srivatsavai@Sun.COM } 92910491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 93010491SRishi.Srivatsavai@Sun.COM return (bfp); 93110491SRishi.Srivatsavai@Sun.COM } 93210491SRishi.Srivatsavai@Sun.COM 93310491SRishi.Srivatsavai@Sun.COM static void 93410491SRishi.Srivatsavai@Sun.COM fwd_free(bridge_fwd_t *bfp) 93510491SRishi.Srivatsavai@Sun.COM { 93610491SRishi.Srivatsavai@Sun.COM uint_t i; 93710491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = bfp->bf_links[0]->bl_inst; 93810491SRishi.Srivatsavai@Sun.COM 93910491SRishi.Srivatsavai@Sun.COM KIDECR(bki_count); 94010491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) 94110491SRishi.Srivatsavai@Sun.COM link_unref(bfp->bf_links[i]); 94210491SRishi.Srivatsavai@Sun.COM kmem_free(bfp, 94310491SRishi.Srivatsavai@Sun.COM sizeof (*bfp) + bfp->bf_maxlinks * sizeof (bridge_link_t *)); 94410491SRishi.Srivatsavai@Sun.COM } 94510491SRishi.Srivatsavai@Sun.COM 94610491SRishi.Srivatsavai@Sun.COM static void 94710491SRishi.Srivatsavai@Sun.COM fwd_unref(bridge_fwd_t *bfp) 94810491SRishi.Srivatsavai@Sun.COM { 94910491SRishi.Srivatsavai@Sun.COM if (atomic_dec_uint_nv(&bfp->bf_refs) == 0) { 95010491SRishi.Srivatsavai@Sun.COM ASSERT(!(bfp->bf_flags & BFF_INTREE)); 95110491SRishi.Srivatsavai@Sun.COM fwd_free(bfp); 95210491SRishi.Srivatsavai@Sun.COM } 95310491SRishi.Srivatsavai@Sun.COM } 95410491SRishi.Srivatsavai@Sun.COM 95510491SRishi.Srivatsavai@Sun.COM static void 95610491SRishi.Srivatsavai@Sun.COM fwd_delete(bridge_fwd_t *bfp) 95710491SRishi.Srivatsavai@Sun.COM { 95810491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 95910491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfpzero; 96010491SRishi.Srivatsavai@Sun.COM 96110491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_INTREE) { 96210491SRishi.Srivatsavai@Sun.COM ASSERT(bfp->bf_nlinks > 0); 96310491SRishi.Srivatsavai@Sun.COM bip = bfp->bf_links[0]->bl_inst; 96410491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 96510491SRishi.Srivatsavai@Sun.COM /* Another thread could beat us to this */ 96610491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_INTREE) { 96710491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 96810491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 96910491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_VLANLOCAL) { 97010491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_VLANLOCAL; 97110491SRishi.Srivatsavai@Sun.COM bfpzero = avl_find(&bip->bi_fwd, bfp, NULL); 97210491SRishi.Srivatsavai@Sun.COM if (bfpzero != NULL && bfpzero->bf_vcnt > 0) 97310491SRishi.Srivatsavai@Sun.COM bfpzero->bf_vcnt--; 97410491SRishi.Srivatsavai@Sun.COM } 97510491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 97610491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); /* no longer in avl tree */ 97710491SRishi.Srivatsavai@Sun.COM } else { 97810491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 97910491SRishi.Srivatsavai@Sun.COM } 98010491SRishi.Srivatsavai@Sun.COM } 98110491SRishi.Srivatsavai@Sun.COM } 98210491SRishi.Srivatsavai@Sun.COM 98310491SRishi.Srivatsavai@Sun.COM static boolean_t 98410491SRishi.Srivatsavai@Sun.COM fwd_insert(bridge_inst_t *bip, bridge_fwd_t *bfp) 98510491SRishi.Srivatsavai@Sun.COM { 98610491SRishi.Srivatsavai@Sun.COM avl_index_t idx; 98710491SRishi.Srivatsavai@Sun.COM boolean_t retv; 98810491SRishi.Srivatsavai@Sun.COM 98910491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 99010491SRishi.Srivatsavai@Sun.COM if (!(bip->bi_flags & BIF_SHUTDOWN) && 99110491SRishi.Srivatsavai@Sun.COM avl_numnodes(&bip->bi_fwd) < bip->bi_tablemax && 99210491SRishi.Srivatsavai@Sun.COM avl_find(&bip->bi_fwd, bfp, &idx) == NULL) { 99310491SRishi.Srivatsavai@Sun.COM avl_insert(&bip->bi_fwd, bfp, idx); 99410491SRishi.Srivatsavai@Sun.COM bfp->bf_flags |= BFF_INTREE; 99510491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bfp->bf_refs); /* avl entry */ 99610491SRishi.Srivatsavai@Sun.COM retv = B_TRUE; 99710491SRishi.Srivatsavai@Sun.COM } else { 99810491SRishi.Srivatsavai@Sun.COM retv = B_FALSE; 99910491SRishi.Srivatsavai@Sun.COM } 100010491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 100110491SRishi.Srivatsavai@Sun.COM return (retv); 100210491SRishi.Srivatsavai@Sun.COM } 100310491SRishi.Srivatsavai@Sun.COM 100410491SRishi.Srivatsavai@Sun.COM static void 100510491SRishi.Srivatsavai@Sun.COM fwd_update_local(bridge_link_t *blp, const uint8_t *oldaddr, 100610491SRishi.Srivatsavai@Sun.COM const uint8_t *newaddr) 100710491SRishi.Srivatsavai@Sun.COM { 100810491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 100910491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfnew; 101010491SRishi.Srivatsavai@Sun.COM bridge_fwd_t match; 101110491SRishi.Srivatsavai@Sun.COM avl_index_t idx; 101210491SRishi.Srivatsavai@Sun.COM boolean_t drop_ref = B_FALSE; 101310491SRishi.Srivatsavai@Sun.COM 101410491SRishi.Srivatsavai@Sun.COM if (bcmp(oldaddr, newaddr, ETHERADDRL) == 0) 101510491SRishi.Srivatsavai@Sun.COM return; 101610491SRishi.Srivatsavai@Sun.COM 101710491SRishi.Srivatsavai@Sun.COM if (bcmp(oldaddr, zero_addr, ETHERADDRL) == 0) 101810491SRishi.Srivatsavai@Sun.COM goto no_old_addr; 101910491SRishi.Srivatsavai@Sun.COM 102010491SRishi.Srivatsavai@Sun.COM /* 102110491SRishi.Srivatsavai@Sun.COM * Find the previous entry, and remove our link from it. 102210491SRishi.Srivatsavai@Sun.COM */ 102310491SRishi.Srivatsavai@Sun.COM bcopy(oldaddr, match.bf_dest, ETHERADDRL); 102410491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 102510491SRishi.Srivatsavai@Sun.COM if ((bfp = avl_find(&bip->bi_fwd, &match, NULL)) != NULL) { 102610491SRishi.Srivatsavai@Sun.COM int i; 102710491SRishi.Srivatsavai@Sun.COM 102810491SRishi.Srivatsavai@Sun.COM /* 102910491SRishi.Srivatsavai@Sun.COM * See if we're in the list, and remove if so. 103010491SRishi.Srivatsavai@Sun.COM */ 103110491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) { 103210491SRishi.Srivatsavai@Sun.COM if (bfp->bf_links[i] == blp) { 103310491SRishi.Srivatsavai@Sun.COM /* 103410491SRishi.Srivatsavai@Sun.COM * We assume writes are atomic, so no special 103510491SRishi.Srivatsavai@Sun.COM * MT handling is needed. The list length is 103610491SRishi.Srivatsavai@Sun.COM * decremented first, and then we remove 103710491SRishi.Srivatsavai@Sun.COM * entries. 103810491SRishi.Srivatsavai@Sun.COM */ 103910491SRishi.Srivatsavai@Sun.COM bfp->bf_nlinks--; 104010491SRishi.Srivatsavai@Sun.COM for (; i < bfp->bf_nlinks; i++) 104110491SRishi.Srivatsavai@Sun.COM bfp->bf_links[i] = bfp->bf_links[i + 1]; 104210491SRishi.Srivatsavai@Sun.COM drop_ref = B_TRUE; 104310491SRishi.Srivatsavai@Sun.COM break; 104410491SRishi.Srivatsavai@Sun.COM } 104510491SRishi.Srivatsavai@Sun.COM } 104610491SRishi.Srivatsavai@Sun.COM /* If no more links, then remove and free up */ 104710491SRishi.Srivatsavai@Sun.COM if (bfp->bf_nlinks == 0) { 104810491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 104910491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 105010491SRishi.Srivatsavai@Sun.COM } else { 105110491SRishi.Srivatsavai@Sun.COM bfp = NULL; 105210491SRishi.Srivatsavai@Sun.COM } 105310491SRishi.Srivatsavai@Sun.COM } 105410491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 105510491SRishi.Srivatsavai@Sun.COM if (bfp != NULL) 105610491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); /* no longer in avl tree */ 105710491SRishi.Srivatsavai@Sun.COM 105810491SRishi.Srivatsavai@Sun.COM /* 105910491SRishi.Srivatsavai@Sun.COM * Now get the new link address and add this link to the list. The 106010491SRishi.Srivatsavai@Sun.COM * list should be of length 1 unless the user has configured multiple 106110491SRishi.Srivatsavai@Sun.COM * NICs with the same address. (That's an incorrect configuration, but 106210491SRishi.Srivatsavai@Sun.COM * we support it anyway.) 106310491SRishi.Srivatsavai@Sun.COM */ 106410491SRishi.Srivatsavai@Sun.COM no_old_addr: 106510491SRishi.Srivatsavai@Sun.COM bfp = NULL; 106610491SRishi.Srivatsavai@Sun.COM if ((bip->bi_flags & BIF_SHUTDOWN) || 106710491SRishi.Srivatsavai@Sun.COM bcmp(newaddr, zero_addr, ETHERADDRL) == 0) 106810491SRishi.Srivatsavai@Sun.COM goto no_new_addr; 106910491SRishi.Srivatsavai@Sun.COM 107010491SRishi.Srivatsavai@Sun.COM bcopy(newaddr, match.bf_dest, ETHERADDRL); 107110491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 107210491SRishi.Srivatsavai@Sun.COM if ((bfp = avl_find(&bip->bi_fwd, &match, &idx)) == NULL) { 107310491SRishi.Srivatsavai@Sun.COM bfnew = fwd_alloc(newaddr, 1, RBRIDGE_NICKNAME_NONE); 107410491SRishi.Srivatsavai@Sun.COM if (bfnew != NULL) 107510491SRishi.Srivatsavai@Sun.COM KIINCR(bki_count); 107610491SRishi.Srivatsavai@Sun.COM } else if (bfp->bf_nlinks < bfp->bf_maxlinks) { 107710491SRishi.Srivatsavai@Sun.COM /* special case: link fits in existing entry */ 107810491SRishi.Srivatsavai@Sun.COM bfnew = bfp; 107910491SRishi.Srivatsavai@Sun.COM } else { 108010491SRishi.Srivatsavai@Sun.COM bfnew = fwd_alloc(newaddr, bfp->bf_nlinks + 1, 108110491SRishi.Srivatsavai@Sun.COM RBRIDGE_NICKNAME_NONE); 108210491SRishi.Srivatsavai@Sun.COM if (bfnew != NULL) { 108310491SRishi.Srivatsavai@Sun.COM KIINCR(bki_count); 108410491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 108510491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 108610491SRishi.Srivatsavai@Sun.COM bfnew->bf_nlinks = bfp->bf_nlinks; 108710491SRishi.Srivatsavai@Sun.COM bcopy(bfp->bf_links, bfnew->bf_links, 108810491SRishi.Srivatsavai@Sun.COM bfp->bf_nlinks * sizeof (bfp)); 108910491SRishi.Srivatsavai@Sun.COM /* reset the idx value due to removal above */ 109010491SRishi.Srivatsavai@Sun.COM (void) avl_find(&bip->bi_fwd, &match, &idx); 109110491SRishi.Srivatsavai@Sun.COM } 109210491SRishi.Srivatsavai@Sun.COM } 109310491SRishi.Srivatsavai@Sun.COM 109410491SRishi.Srivatsavai@Sun.COM if (bfnew != NULL) { 109510491SRishi.Srivatsavai@Sun.COM bfnew->bf_links[bfnew->bf_nlinks++] = blp; 109610491SRishi.Srivatsavai@Sun.COM if (drop_ref) 109710491SRishi.Srivatsavai@Sun.COM drop_ref = B_FALSE; 109810491SRishi.Srivatsavai@Sun.COM else 109910491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_refs); /* bf_links entry */ 110010491SRishi.Srivatsavai@Sun.COM 110110491SRishi.Srivatsavai@Sun.COM if (bfnew != bfp) { 110210491SRishi.Srivatsavai@Sun.COM /* local addresses are not subject to table limits */ 110310491SRishi.Srivatsavai@Sun.COM avl_insert(&bip->bi_fwd, bfnew, idx); 110410491SRishi.Srivatsavai@Sun.COM bfnew->bf_flags |= (BFF_INTREE | BFF_LOCALADDR); 110510491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bfnew->bf_refs); /* avl entry */ 110610491SRishi.Srivatsavai@Sun.COM } 110710491SRishi.Srivatsavai@Sun.COM } 110810491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 110910491SRishi.Srivatsavai@Sun.COM 111010491SRishi.Srivatsavai@Sun.COM no_new_addr: 111110491SRishi.Srivatsavai@Sun.COM /* 111210491SRishi.Srivatsavai@Sun.COM * If we found an existing entry and we replaced it with a new one, 111310491SRishi.Srivatsavai@Sun.COM * then drop the table reference from the old one. We removed it from 111410491SRishi.Srivatsavai@Sun.COM * the AVL tree above. 111510491SRishi.Srivatsavai@Sun.COM */ 111610491SRishi.Srivatsavai@Sun.COM if (bfnew != NULL && bfp != NULL && bfnew != bfp) 111710491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 111810491SRishi.Srivatsavai@Sun.COM 111910491SRishi.Srivatsavai@Sun.COM /* Account for removed entry. */ 112010491SRishi.Srivatsavai@Sun.COM if (drop_ref) 112110491SRishi.Srivatsavai@Sun.COM link_unref(blp); 112210491SRishi.Srivatsavai@Sun.COM } 112310491SRishi.Srivatsavai@Sun.COM 112410491SRishi.Srivatsavai@Sun.COM static void 112510491SRishi.Srivatsavai@Sun.COM bridge_new_unicst(bridge_link_t *blp) 112610491SRishi.Srivatsavai@Sun.COM { 112710491SRishi.Srivatsavai@Sun.COM uint8_t new_mac[ETHERADDRL]; 112810491SRishi.Srivatsavai@Sun.COM 112910491SRishi.Srivatsavai@Sun.COM mac_unicast_primary_get(blp->bl_mh, new_mac); 113010491SRishi.Srivatsavai@Sun.COM fwd_update_local(blp, blp->bl_local_mac, new_mac); 113110491SRishi.Srivatsavai@Sun.COM bcopy(new_mac, blp->bl_local_mac, ETHERADDRL); 113210491SRishi.Srivatsavai@Sun.COM } 113310491SRishi.Srivatsavai@Sun.COM 113410491SRishi.Srivatsavai@Sun.COM /* 113510491SRishi.Srivatsavai@Sun.COM * We must shut down a link prior to freeing it, and doing that requires 113610491SRishi.Srivatsavai@Sun.COM * blocking to wait for running MAC threads while holding a reference. This is 113710491SRishi.Srivatsavai@Sun.COM * run from a taskq to accomplish proper link shutdown followed by reference 113810491SRishi.Srivatsavai@Sun.COM * drop. 113910491SRishi.Srivatsavai@Sun.COM */ 114010491SRishi.Srivatsavai@Sun.COM static void 114110491SRishi.Srivatsavai@Sun.COM link_shutdown(void *arg) 114210491SRishi.Srivatsavai@Sun.COM { 114310491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = arg; 114410491SRishi.Srivatsavai@Sun.COM mac_handle_t mh = blp->bl_mh; 114510491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 114610491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfnext; 114710491SRishi.Srivatsavai@Sun.COM avl_tree_t fwd_scavenge; 114810491SRishi.Srivatsavai@Sun.COM int i; 114910491SRishi.Srivatsavai@Sun.COM 115010491SRishi.Srivatsavai@Sun.COM /* 115110491SRishi.Srivatsavai@Sun.COM * This link is being destroyed. Notify TRILL now that it's no longer 115210491SRishi.Srivatsavai@Sun.COM * possible to send packets. Data packets may still arrive until TRILL 115310491SRishi.Srivatsavai@Sun.COM * calls bridge_trill_lnunref. 115410491SRishi.Srivatsavai@Sun.COM */ 115510491SRishi.Srivatsavai@Sun.COM if (blp->bl_trilldata != NULL) 115610491SRishi.Srivatsavai@Sun.COM trill_lndstr_fn(blp->bl_trilldata, blp); 115710491SRishi.Srivatsavai@Sun.COM 115810491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_PROM_ADDED) 115910491SRishi.Srivatsavai@Sun.COM (void) mac_promisc_remove(blp->bl_mphp); 116010491SRishi.Srivatsavai@Sun.COM 116110491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_SET_BRIDGE) 116210491SRishi.Srivatsavai@Sun.COM mac_bridge_clear(mh, (mac_handle_t)blp); 116310491SRishi.Srivatsavai@Sun.COM 116410491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_MARGIN_ADDED) { 116510501SRishi.Srivatsavai@Sun.COM (void) mac_notify_remove(blp->bl_mnh, B_TRUE); 116610491SRishi.Srivatsavai@Sun.COM (void) mac_margin_remove(mh, blp->bl_margin); 116710491SRishi.Srivatsavai@Sun.COM } 116810491SRishi.Srivatsavai@Sun.COM 116910491SRishi.Srivatsavai@Sun.COM /* Tell the clients the real link state when we leave */ 117010491SRishi.Srivatsavai@Sun.COM mac_link_redo(blp->bl_mh, 117110491SRishi.Srivatsavai@Sun.COM mac_stat_get(blp->bl_mh, MAC_STAT_LOWLINK_STATE)); 117210491SRishi.Srivatsavai@Sun.COM 117310491SRishi.Srivatsavai@Sun.COM /* Destroy all of the forwarding entries related to this link */ 117410491SRishi.Srivatsavai@Sun.COM avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 117510491SRishi.Srivatsavai@Sun.COM offsetof(bridge_fwd_t, bf_node)); 117610491SRishi.Srivatsavai@Sun.COM bip = blp->bl_inst; 117710491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 117810491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&bip->bi_fwd); 117910491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 118010491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 118110491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) { 118210491SRishi.Srivatsavai@Sun.COM if (bfp->bf_links[i] == blp) 118310491SRishi.Srivatsavai@Sun.COM break; 118410491SRishi.Srivatsavai@Sun.COM } 118510491SRishi.Srivatsavai@Sun.COM if (i >= bfp->bf_nlinks) 118610491SRishi.Srivatsavai@Sun.COM continue; 118710491SRishi.Srivatsavai@Sun.COM if (bfp->bf_nlinks > 1) { 118810491SRishi.Srivatsavai@Sun.COM /* note that this can't be the last reference */ 118910491SRishi.Srivatsavai@Sun.COM link_unref(blp); 119010491SRishi.Srivatsavai@Sun.COM bfp->bf_nlinks--; 119110491SRishi.Srivatsavai@Sun.COM for (; i < bfp->bf_nlinks; i++) 119210491SRishi.Srivatsavai@Sun.COM bfp->bf_links[i] = bfp->bf_links[i + 1]; 119310491SRishi.Srivatsavai@Sun.COM } else { 119410491SRishi.Srivatsavai@Sun.COM ASSERT(bfp->bf_flags & BFF_INTREE); 119510491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 119610491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 119710491SRishi.Srivatsavai@Sun.COM avl_add(&fwd_scavenge, bfp); 119810491SRishi.Srivatsavai@Sun.COM } 119910491SRishi.Srivatsavai@Sun.COM } 120010491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 120110491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&fwd_scavenge); 120210491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 120310491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&fwd_scavenge, bfp); 120410491SRishi.Srivatsavai@Sun.COM avl_remove(&fwd_scavenge, bfp); 120510491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 120610491SRishi.Srivatsavai@Sun.COM } 120710491SRishi.Srivatsavai@Sun.COM avl_destroy(&fwd_scavenge); 120810491SRishi.Srivatsavai@Sun.COM 120910491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_CLIENT_OPEN) 121010491SRishi.Srivatsavai@Sun.COM mac_client_close(blp->bl_mch, 0); 121110491SRishi.Srivatsavai@Sun.COM 121210491SRishi.Srivatsavai@Sun.COM mac_close(mh); 121310491SRishi.Srivatsavai@Sun.COM 121410491SRishi.Srivatsavai@Sun.COM /* 121510491SRishi.Srivatsavai@Sun.COM * We are now completely removed from the active list, so drop the 121610491SRishi.Srivatsavai@Sun.COM * reference (see bridge_add_link). 121710491SRishi.Srivatsavai@Sun.COM */ 121810491SRishi.Srivatsavai@Sun.COM link_unref(blp); 121910491SRishi.Srivatsavai@Sun.COM } 122010491SRishi.Srivatsavai@Sun.COM 122110491SRishi.Srivatsavai@Sun.COM static void 122210491SRishi.Srivatsavai@Sun.COM shutdown_inst(bridge_inst_t *bip) 122310491SRishi.Srivatsavai@Sun.COM { 122410491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp, *blnext; 122510491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp; 122610491SRishi.Srivatsavai@Sun.COM 122710491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 122810491SRishi.Srivatsavai@Sun.COM if (bip->bi_flags & BIF_SHUTDOWN) { 122910491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 123010491SRishi.Srivatsavai@Sun.COM return; 123110491SRishi.Srivatsavai@Sun.COM } 123210491SRishi.Srivatsavai@Sun.COM 123310491SRishi.Srivatsavai@Sun.COM /* 123410491SRishi.Srivatsavai@Sun.COM * Once on the inst_list, the bridge instance must not leave that list 123510491SRishi.Srivatsavai@Sun.COM * without having the shutdown flag set first. When the shutdown flag 123610491SRishi.Srivatsavai@Sun.COM * is set, we own the list reference, so we must drop it before 123710491SRishi.Srivatsavai@Sun.COM * returning. 123810491SRishi.Srivatsavai@Sun.COM */ 123910491SRishi.Srivatsavai@Sun.COM bip->bi_flags |= BIF_SHUTDOWN; 124010491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 124110491SRishi.Srivatsavai@Sun.COM 124210491SRishi.Srivatsavai@Sun.COM bip->bi_control = NULL; 124310491SRishi.Srivatsavai@Sun.COM 124410491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 124510491SRishi.Srivatsavai@Sun.COM blnext = list_head(&bip->bi_links); 124610491SRishi.Srivatsavai@Sun.COM while ((blp = blnext) != NULL) { 124710491SRishi.Srivatsavai@Sun.COM blnext = list_next(&bip->bi_links, blp); 124810491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_DELETED)) { 124910491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_DELETED; 125010491SRishi.Srivatsavai@Sun.COM (void) ddi_taskq_dispatch(bridge_taskq, link_shutdown, 125110491SRishi.Srivatsavai@Sun.COM blp, DDI_SLEEP); 125210491SRishi.Srivatsavai@Sun.COM } 125310491SRishi.Srivatsavai@Sun.COM } 125410491SRishi.Srivatsavai@Sun.COM while ((bfp = avl_first(&bip->bi_fwd)) != NULL) { 125510491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bfp->bf_refs); 125610491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 125710491SRishi.Srivatsavai@Sun.COM fwd_delete(bfp); 125810491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 125910491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 126010491SRishi.Srivatsavai@Sun.COM } 126110491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 126210491SRishi.Srivatsavai@Sun.COM 126310491SRishi.Srivatsavai@Sun.COM /* 126410491SRishi.Srivatsavai@Sun.COM * This bridge is being destroyed. Notify TRILL once all of the 126510491SRishi.Srivatsavai@Sun.COM * links are all gone. 126610491SRishi.Srivatsavai@Sun.COM */ 126710491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 126810491SRishi.Srivatsavai@Sun.COM while (bip->bi_trilldata != NULL && !list_is_empty(&bip->bi_links)) 126910491SRishi.Srivatsavai@Sun.COM cv_wait(&bip->bi_linkwait, &inst_lock); 127010491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 127110491SRishi.Srivatsavai@Sun.COM if (bip->bi_trilldata != NULL) 127210491SRishi.Srivatsavai@Sun.COM trill_brdstr_fn(bip->bi_trilldata, bip); 127310491SRishi.Srivatsavai@Sun.COM 127410491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 127510491SRishi.Srivatsavai@Sun.COM } 127610491SRishi.Srivatsavai@Sun.COM 127710491SRishi.Srivatsavai@Sun.COM /* 127810491SRishi.Srivatsavai@Sun.COM * This is called once by the TRILL module when it starts up. It just sets the 127910491SRishi.Srivatsavai@Sun.COM * global TRILL callback function pointers -- data transmit/receive and bridge 128010491SRishi.Srivatsavai@Sun.COM * and link destroy notification. There's only one TRILL module, so only one 128110491SRishi.Srivatsavai@Sun.COM * registration is needed. 128210491SRishi.Srivatsavai@Sun.COM * 128310491SRishi.Srivatsavai@Sun.COM * TRILL should call this function with NULL pointers before unloading. It 128410491SRishi.Srivatsavai@Sun.COM * must not do so before dropping all references to bridges and links. We 128510491SRishi.Srivatsavai@Sun.COM * assert that this is true on debug builds. 128610491SRishi.Srivatsavai@Sun.COM */ 128710491SRishi.Srivatsavai@Sun.COM void 128810491SRishi.Srivatsavai@Sun.COM bridge_trill_register_cb(trill_recv_pkt_t recv_fn, trill_encap_pkt_t encap_fn, 128910491SRishi.Srivatsavai@Sun.COM trill_br_dstr_t brdstr_fn, trill_ln_dstr_t lndstr_fn) 129010491SRishi.Srivatsavai@Sun.COM { 129110491SRishi.Srivatsavai@Sun.COM #ifdef DEBUG 129210491SRishi.Srivatsavai@Sun.COM if (recv_fn == NULL && trill_recv_fn != NULL) { 129310491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 129410491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 129510491SRishi.Srivatsavai@Sun.COM 129610491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 129710491SRishi.Srivatsavai@Sun.COM for (bip = list_head(&inst_list); bip != NULL; 129810491SRishi.Srivatsavai@Sun.COM bip = list_next(&inst_list, bip)) { 129910491SRishi.Srivatsavai@Sun.COM ASSERT(bip->bi_trilldata == NULL); 130010491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 130110491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 130210491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 130310491SRishi.Srivatsavai@Sun.COM ASSERT(blp->bl_trilldata == NULL); 130410491SRishi.Srivatsavai@Sun.COM } 130510491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 130610491SRishi.Srivatsavai@Sun.COM } 130710491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 130810491SRishi.Srivatsavai@Sun.COM } 130910491SRishi.Srivatsavai@Sun.COM #endif 131010491SRishi.Srivatsavai@Sun.COM trill_recv_fn = recv_fn; 131110491SRishi.Srivatsavai@Sun.COM trill_encap_fn = encap_fn; 131210491SRishi.Srivatsavai@Sun.COM trill_brdstr_fn = brdstr_fn; 131310491SRishi.Srivatsavai@Sun.COM trill_lndstr_fn = lndstr_fn; 131410491SRishi.Srivatsavai@Sun.COM } 131510491SRishi.Srivatsavai@Sun.COM 131610491SRishi.Srivatsavai@Sun.COM /* 131710491SRishi.Srivatsavai@Sun.COM * This registers the TRILL instance pointer with a bridge. Before this 131810491SRishi.Srivatsavai@Sun.COM * pointer is set, the forwarding, TRILL receive, and bridge destructor 131910491SRishi.Srivatsavai@Sun.COM * functions won't be called. 132010491SRishi.Srivatsavai@Sun.COM * 132110491SRishi.Srivatsavai@Sun.COM * TRILL holds a reference on a bridge with this call. It must free the 132210491SRishi.Srivatsavai@Sun.COM * reference by calling the unregister function below. 132310491SRishi.Srivatsavai@Sun.COM */ 132410491SRishi.Srivatsavai@Sun.COM bridge_inst_t * 132510491SRishi.Srivatsavai@Sun.COM bridge_trill_brref(const char *bname, void *ptr) 132610491SRishi.Srivatsavai@Sun.COM { 132710491SRishi.Srivatsavai@Sun.COM char bridge[MAXLINKNAMELEN]; 132810491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 132910491SRishi.Srivatsavai@Sun.COM 133010491SRishi.Srivatsavai@Sun.COM (void) snprintf(bridge, MAXLINKNAMELEN, "%s0", bname); 133110491SRishi.Srivatsavai@Sun.COM bip = bridge_find_name(bridge); 133210491SRishi.Srivatsavai@Sun.COM if (bip != NULL) { 133310491SRishi.Srivatsavai@Sun.COM ASSERT(bip->bi_trilldata == NULL && ptr != NULL); 133410491SRishi.Srivatsavai@Sun.COM bip->bi_trilldata = ptr; 133510491SRishi.Srivatsavai@Sun.COM } 133610491SRishi.Srivatsavai@Sun.COM return (bip); 133710491SRishi.Srivatsavai@Sun.COM } 133810491SRishi.Srivatsavai@Sun.COM 133910491SRishi.Srivatsavai@Sun.COM void 134010491SRishi.Srivatsavai@Sun.COM bridge_trill_brunref(bridge_inst_t *bip) 134110491SRishi.Srivatsavai@Sun.COM { 134210491SRishi.Srivatsavai@Sun.COM ASSERT(bip->bi_trilldata != NULL); 134310491SRishi.Srivatsavai@Sun.COM bip->bi_trilldata = NULL; 134410491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 134510491SRishi.Srivatsavai@Sun.COM } 134610491SRishi.Srivatsavai@Sun.COM 134710491SRishi.Srivatsavai@Sun.COM /* 134810491SRishi.Srivatsavai@Sun.COM * TRILL calls this function when referencing a particular link on a bridge. 134910491SRishi.Srivatsavai@Sun.COM * 135010491SRishi.Srivatsavai@Sun.COM * It holds a reference on the link, so TRILL must clear out the reference when 135110491SRishi.Srivatsavai@Sun.COM * it's done with the link (on unbinding). 135210491SRishi.Srivatsavai@Sun.COM */ 135310491SRishi.Srivatsavai@Sun.COM bridge_link_t * 135410491SRishi.Srivatsavai@Sun.COM bridge_trill_lnref(bridge_inst_t *bip, datalink_id_t linkid, void *ptr) 135510491SRishi.Srivatsavai@Sun.COM { 135610491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 135710491SRishi.Srivatsavai@Sun.COM 135810491SRishi.Srivatsavai@Sun.COM ASSERT(ptr != NULL); 135910491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 136010491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 136110491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 136210491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_DELETED) && 136310491SRishi.Srivatsavai@Sun.COM blp->bl_linkid == linkid && blp->bl_trilldata == NULL) { 136410491SRishi.Srivatsavai@Sun.COM blp->bl_trilldata = ptr; 136510491SRishi.Srivatsavai@Sun.COM blp->bl_flags &= ~BLF_TRILLACTIVE; 136610491SRishi.Srivatsavai@Sun.COM (void) memset(blp->bl_afs, 0, sizeof (blp->bl_afs)); 136710491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_refs); 136810491SRishi.Srivatsavai@Sun.COM break; 136910491SRishi.Srivatsavai@Sun.COM } 137010491SRishi.Srivatsavai@Sun.COM } 137110491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 137210491SRishi.Srivatsavai@Sun.COM return (blp); 137310491SRishi.Srivatsavai@Sun.COM } 137410491SRishi.Srivatsavai@Sun.COM 137510491SRishi.Srivatsavai@Sun.COM void 137610491SRishi.Srivatsavai@Sun.COM bridge_trill_lnunref(bridge_link_t *blp) 137710491SRishi.Srivatsavai@Sun.COM { 137810491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 137910491SRishi.Srivatsavai@Sun.COM ASSERT(blp->bl_trilldata != NULL); 138010491SRishi.Srivatsavai@Sun.COM blp->bl_trilldata = NULL; 138110491SRishi.Srivatsavai@Sun.COM blp->bl_flags &= ~BLF_TRILLACTIVE; 138210491SRishi.Srivatsavai@Sun.COM while (blp->bl_trillthreads > 0) 138310491SRishi.Srivatsavai@Sun.COM cv_wait(&blp->bl_trillwait, &blp->bl_trilllock); 138410491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 138510491SRishi.Srivatsavai@Sun.COM (void) memset(blp->bl_afs, 0xff, sizeof (blp->bl_afs)); 138610491SRishi.Srivatsavai@Sun.COM link_unref(blp); 138710491SRishi.Srivatsavai@Sun.COM } 138810491SRishi.Srivatsavai@Sun.COM 138910491SRishi.Srivatsavai@Sun.COM /* 139010491SRishi.Srivatsavai@Sun.COM * This periodic timer performs three functions: 139110491SRishi.Srivatsavai@Sun.COM * 1. It scans the list of learned forwarding entries, and removes ones that 139210491SRishi.Srivatsavai@Sun.COM * haven't been heard from in a while. The time limit is backed down if 139310491SRishi.Srivatsavai@Sun.COM * we're above the configured table limit. 139410491SRishi.Srivatsavai@Sun.COM * 2. It walks the links and decays away the bl_learns counter. 139510491SRishi.Srivatsavai@Sun.COM * 3. It scans the observability node entries looking for ones that can be 139610491SRishi.Srivatsavai@Sun.COM * freed up. 139710491SRishi.Srivatsavai@Sun.COM */ 139810491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 139910491SRishi.Srivatsavai@Sun.COM static void 140010491SRishi.Srivatsavai@Sun.COM bridge_timer(void *arg) 140110491SRishi.Srivatsavai@Sun.COM { 140210491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 140310491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfnext; 140410491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp, *bmnext; 140510491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 140610491SRishi.Srivatsavai@Sun.COM int err; 140710491SRishi.Srivatsavai@Sun.COM datalink_id_t tmpid; 140810491SRishi.Srivatsavai@Sun.COM avl_tree_t fwd_scavenge; 140910491SRishi.Srivatsavai@Sun.COM clock_t age_limit; 141010491SRishi.Srivatsavai@Sun.COM uint32_t ldecay; 141110491SRishi.Srivatsavai@Sun.COM 141210491SRishi.Srivatsavai@Sun.COM avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 141310491SRishi.Srivatsavai@Sun.COM offsetof(bridge_fwd_t, bf_node)); 141410491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 141510491SRishi.Srivatsavai@Sun.COM for (bip = list_head(&inst_list); bip != NULL; 141610491SRishi.Srivatsavai@Sun.COM bip = list_next(&inst_list, bip)) { 141710491SRishi.Srivatsavai@Sun.COM if (bip->bi_flags & BIF_SHUTDOWN) 141810491SRishi.Srivatsavai@Sun.COM continue; 141910491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 142010491SRishi.Srivatsavai@Sun.COM /* compute scaled maximum age based on table limit */ 142110491SRishi.Srivatsavai@Sun.COM if (avl_numnodes(&bip->bi_fwd) > bip->bi_tablemax) 142210491SRishi.Srivatsavai@Sun.COM bip->bi_tshift++; 142310491SRishi.Srivatsavai@Sun.COM else 142410491SRishi.Srivatsavai@Sun.COM bip->bi_tshift = 0; 142510491SRishi.Srivatsavai@Sun.COM if ((age_limit = bridge_fwd_age >> bip->bi_tshift) == 0) { 142610491SRishi.Srivatsavai@Sun.COM if (bip->bi_tshift != 0) 142710491SRishi.Srivatsavai@Sun.COM bip->bi_tshift--; 142810491SRishi.Srivatsavai@Sun.COM age_limit = 1; 142910491SRishi.Srivatsavai@Sun.COM } 143010491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&bip->bi_fwd); 143110491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 143210491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 143310491SRishi.Srivatsavai@Sun.COM if (!(bfp->bf_flags & BFF_LOCALADDR) && 143411066Srafael.vanoni@sun.com (ddi_get_lbolt() - bfp->bf_lastheard) > age_limit) { 143510491SRishi.Srivatsavai@Sun.COM ASSERT(bfp->bf_flags & BFF_INTREE); 143610491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 143710491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 143810491SRishi.Srivatsavai@Sun.COM avl_add(&fwd_scavenge, bfp); 143910491SRishi.Srivatsavai@Sun.COM } 144010491SRishi.Srivatsavai@Sun.COM } 144110491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 144210491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 144310491SRishi.Srivatsavai@Sun.COM ldecay = mac_get_ldecay(blp->bl_mh); 144410491SRishi.Srivatsavai@Sun.COM if (ldecay >= blp->bl_learns) 144510491SRishi.Srivatsavai@Sun.COM blp->bl_learns = 0; 144610491SRishi.Srivatsavai@Sun.COM else 144710491SRishi.Srivatsavai@Sun.COM atomic_add_int(&blp->bl_learns, -(int)ldecay); 144810491SRishi.Srivatsavai@Sun.COM } 144910491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 145010491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&fwd_scavenge); 145110491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 145210491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&fwd_scavenge, bfp); 145310491SRishi.Srivatsavai@Sun.COM avl_remove(&fwd_scavenge, bfp); 145410491SRishi.Srivatsavai@Sun.COM KIINCR(bki_expire); 145510491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); /* drop tree reference */ 145610491SRishi.Srivatsavai@Sun.COM } 145710491SRishi.Srivatsavai@Sun.COM } 145810491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 145910491SRishi.Srivatsavai@Sun.COM avl_destroy(&fwd_scavenge); 146010491SRishi.Srivatsavai@Sun.COM 146110491SRishi.Srivatsavai@Sun.COM /* 146210491SRishi.Srivatsavai@Sun.COM * Scan the bridge_mac_t entries and try to free up the ones that are 146310491SRishi.Srivatsavai@Sun.COM * no longer active. This must be done by polling, as neither DLS nor 146410491SRishi.Srivatsavai@Sun.COM * MAC provides a driver any sort of positive control over clients. 146510491SRishi.Srivatsavai@Sun.COM */ 146610491SRishi.Srivatsavai@Sun.COM rw_enter(&bmac_rwlock, RW_WRITER); 146710491SRishi.Srivatsavai@Sun.COM bmnext = list_head(&bmac_list); 146810491SRishi.Srivatsavai@Sun.COM while ((bmp = bmnext) != NULL) { 146910491SRishi.Srivatsavai@Sun.COM bmnext = list_next(&bmac_list, bmp); 147010491SRishi.Srivatsavai@Sun.COM 147110491SRishi.Srivatsavai@Sun.COM /* ignore active bridges */ 147210491SRishi.Srivatsavai@Sun.COM if (bmp->bm_inst != NULL) 147310491SRishi.Srivatsavai@Sun.COM continue; 147410491SRishi.Srivatsavai@Sun.COM 147510491SRishi.Srivatsavai@Sun.COM if (bmp->bm_flags & BMF_DLS) { 147610491SRishi.Srivatsavai@Sun.COM err = dls_devnet_destroy(bmp->bm_mh, &tmpid, B_FALSE); 147710491SRishi.Srivatsavai@Sun.COM ASSERT(err == 0 || err == EBUSY); 147810491SRishi.Srivatsavai@Sun.COM if (err == 0) 147910491SRishi.Srivatsavai@Sun.COM bmp->bm_flags &= ~BMF_DLS; 148010491SRishi.Srivatsavai@Sun.COM } 148110491SRishi.Srivatsavai@Sun.COM 148210491SRishi.Srivatsavai@Sun.COM if (!(bmp->bm_flags & BMF_DLS)) { 148310491SRishi.Srivatsavai@Sun.COM err = mac_unregister(bmp->bm_mh); 148410491SRishi.Srivatsavai@Sun.COM ASSERT(err == 0 || err == EBUSY); 148510491SRishi.Srivatsavai@Sun.COM if (err == 0) { 148610491SRishi.Srivatsavai@Sun.COM list_remove(&bmac_list, bmp); 148710491SRishi.Srivatsavai@Sun.COM kmem_free(bmp, sizeof (*bmp)); 148810491SRishi.Srivatsavai@Sun.COM } 148910491SRishi.Srivatsavai@Sun.COM } 149010491SRishi.Srivatsavai@Sun.COM } 149110491SRishi.Srivatsavai@Sun.COM if (list_is_empty(&bmac_list)) { 149210491SRishi.Srivatsavai@Sun.COM bridge_timerid = 0; 149310491SRishi.Srivatsavai@Sun.COM } else { 149410491SRishi.Srivatsavai@Sun.COM bridge_timerid = timeout(bridge_timer, NULL, 149510491SRishi.Srivatsavai@Sun.COM bridge_scan_interval); 149610491SRishi.Srivatsavai@Sun.COM } 149710491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 149810491SRishi.Srivatsavai@Sun.COM } 149910491SRishi.Srivatsavai@Sun.COM 150010491SRishi.Srivatsavai@Sun.COM static int 150110491SRishi.Srivatsavai@Sun.COM bridge_open(queue_t *rq, dev_t *devp, int oflag, int sflag, cred_t *credp) 150210491SRishi.Srivatsavai@Sun.COM { 150310491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp; 150410491SRishi.Srivatsavai@Sun.COM 150510491SRishi.Srivatsavai@Sun.COM if (rq->q_ptr != NULL) 150610491SRishi.Srivatsavai@Sun.COM return (0); 150710491SRishi.Srivatsavai@Sun.COM 150810491SRishi.Srivatsavai@Sun.COM if (sflag & MODOPEN) 150910491SRishi.Srivatsavai@Sun.COM return (EINVAL); 151010491SRishi.Srivatsavai@Sun.COM 151110491SRishi.Srivatsavai@Sun.COM /* 151210491SRishi.Srivatsavai@Sun.COM * Check the minor node number being opened. This tells us which 151310491SRishi.Srivatsavai@Sun.COM * bridge instance the user wants. 151410491SRishi.Srivatsavai@Sun.COM */ 151510491SRishi.Srivatsavai@Sun.COM if (getminor(*devp) != 0) { 151610491SRishi.Srivatsavai@Sun.COM /* 151710491SRishi.Srivatsavai@Sun.COM * This is a regular DLPI stream for snoop or the like. 151810491SRishi.Srivatsavai@Sun.COM * Redirect it through DLD. 151910491SRishi.Srivatsavai@Sun.COM */ 152010491SRishi.Srivatsavai@Sun.COM rq->q_qinfo = &bridge_dld_rinit; 152110491SRishi.Srivatsavai@Sun.COM OTHERQ(rq)->q_qinfo = &bridge_dld_winit; 152210491SRishi.Srivatsavai@Sun.COM return (dld_open(rq, devp, oflag, sflag, credp)); 152310491SRishi.Srivatsavai@Sun.COM } else { 152410491SRishi.Srivatsavai@Sun.COM /* 152510491SRishi.Srivatsavai@Sun.COM * Allocate the bridge control stream structure. 152610491SRishi.Srivatsavai@Sun.COM */ 152710491SRishi.Srivatsavai@Sun.COM if ((bsp = stream_alloc()) == NULL) 152810491SRishi.Srivatsavai@Sun.COM return (ENOSR); 152910491SRishi.Srivatsavai@Sun.COM rq->q_ptr = WR(rq)->q_ptr = (caddr_t)bsp; 153010491SRishi.Srivatsavai@Sun.COM bsp->bs_wq = WR(rq); 153110491SRishi.Srivatsavai@Sun.COM *devp = makedevice(getmajor(*devp), bsp->bs_minor); 153210491SRishi.Srivatsavai@Sun.COM qprocson(rq); 153310491SRishi.Srivatsavai@Sun.COM return (0); 153410491SRishi.Srivatsavai@Sun.COM } 153510491SRishi.Srivatsavai@Sun.COM } 153610491SRishi.Srivatsavai@Sun.COM 153710491SRishi.Srivatsavai@Sun.COM /* 153810491SRishi.Srivatsavai@Sun.COM * This is used only for bridge control streams. DLPI goes through dld 153910491SRishi.Srivatsavai@Sun.COM * instead. 154010491SRishi.Srivatsavai@Sun.COM */ 154110491SRishi.Srivatsavai@Sun.COM static int 154210491SRishi.Srivatsavai@Sun.COM bridge_close(queue_t *rq) 154310491SRishi.Srivatsavai@Sun.COM { 154410491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp = rq->q_ptr; 154510491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 154610491SRishi.Srivatsavai@Sun.COM 154710491SRishi.Srivatsavai@Sun.COM /* 154810491SRishi.Srivatsavai@Sun.COM * Wait for any stray taskq (add/delete link) entries related to this 154910491SRishi.Srivatsavai@Sun.COM * stream to leave the system. 155010491SRishi.Srivatsavai@Sun.COM */ 155110491SRishi.Srivatsavai@Sun.COM mutex_enter(&stream_ref_lock); 155210491SRishi.Srivatsavai@Sun.COM while (bsp->bs_taskq_cnt != 0) 155310491SRishi.Srivatsavai@Sun.COM cv_wait(&stream_ref_cv, &stream_ref_lock); 155410491SRishi.Srivatsavai@Sun.COM mutex_exit(&stream_ref_lock); 155510491SRishi.Srivatsavai@Sun.COM 155610491SRishi.Srivatsavai@Sun.COM qprocsoff(rq); 155710491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) != NULL) 155810491SRishi.Srivatsavai@Sun.COM shutdown_inst(bip); 155910491SRishi.Srivatsavai@Sun.COM rq->q_ptr = WR(rq)->q_ptr = NULL; 156010491SRishi.Srivatsavai@Sun.COM stream_free(bsp); 156110491SRishi.Srivatsavai@Sun.COM if (bip != NULL) 156210491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 156310491SRishi.Srivatsavai@Sun.COM 156410491SRishi.Srivatsavai@Sun.COM return (0); 156510491SRishi.Srivatsavai@Sun.COM } 156610491SRishi.Srivatsavai@Sun.COM 156710491SRishi.Srivatsavai@Sun.COM static void 156810491SRishi.Srivatsavai@Sun.COM bridge_learn(bridge_link_t *blp, const uint8_t *saddr, uint16_t ingress_nick, 156910491SRishi.Srivatsavai@Sun.COM uint16_t vlanid) 157010491SRishi.Srivatsavai@Sun.COM { 157110491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 157210491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfpnew; 157310491SRishi.Srivatsavai@Sun.COM int i; 157410491SRishi.Srivatsavai@Sun.COM boolean_t replaced = B_FALSE; 157510491SRishi.Srivatsavai@Sun.COM 157610491SRishi.Srivatsavai@Sun.COM /* Ignore multi-destination address used as source; it's nonsense. */ 157710491SRishi.Srivatsavai@Sun.COM if (*saddr & 1) 157810491SRishi.Srivatsavai@Sun.COM return; 157910491SRishi.Srivatsavai@Sun.COM 158010491SRishi.Srivatsavai@Sun.COM /* 158110491SRishi.Srivatsavai@Sun.COM * If the source is known, then check whether it belongs on this link. 158210491SRishi.Srivatsavai@Sun.COM * If not, and this isn't a fixed local address, then we've detected a 158310491SRishi.Srivatsavai@Sun.COM * move. If it's not known, learn it. 158410491SRishi.Srivatsavai@Sun.COM */ 158510491SRishi.Srivatsavai@Sun.COM if ((bfp = fwd_find(bip, saddr, vlanid)) != NULL) { 158610491SRishi.Srivatsavai@Sun.COM /* 158710491SRishi.Srivatsavai@Sun.COM * If the packet has a fixed local source address, then there's 158810491SRishi.Srivatsavai@Sun.COM * nothing we can learn. We must quit. If this was a received 158910491SRishi.Srivatsavai@Sun.COM * packet, then the sender has stolen our address, but there's 159010491SRishi.Srivatsavai@Sun.COM * nothing we can do. If it's a transmitted packet, then 159110491SRishi.Srivatsavai@Sun.COM * that's the normal case. 159210491SRishi.Srivatsavai@Sun.COM */ 159310491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_LOCALADDR) { 159410491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 159510491SRishi.Srivatsavai@Sun.COM return; 159610491SRishi.Srivatsavai@Sun.COM } 159710491SRishi.Srivatsavai@Sun.COM 159810491SRishi.Srivatsavai@Sun.COM /* 159910491SRishi.Srivatsavai@Sun.COM * Check if the link (and TRILL sender, if any) being used is 160010491SRishi.Srivatsavai@Sun.COM * among the ones registered for this address. If so, then 160110491SRishi.Srivatsavai@Sun.COM * this is information that we already know. 160210491SRishi.Srivatsavai@Sun.COM */ 160310491SRishi.Srivatsavai@Sun.COM if (bfp->bf_trill_nick == ingress_nick) { 160410491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) { 160510491SRishi.Srivatsavai@Sun.COM if (bfp->bf_links[i] == blp) { 160611066Srafael.vanoni@sun.com bfp->bf_lastheard = ddi_get_lbolt(); 160710491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 160810491SRishi.Srivatsavai@Sun.COM return; 160910491SRishi.Srivatsavai@Sun.COM } 161010491SRishi.Srivatsavai@Sun.COM } 161110491SRishi.Srivatsavai@Sun.COM } 161210491SRishi.Srivatsavai@Sun.COM } 161310491SRishi.Srivatsavai@Sun.COM 161410491SRishi.Srivatsavai@Sun.COM /* 161510491SRishi.Srivatsavai@Sun.COM * Note that we intentionally "unlearn" things that appear to be under 161610491SRishi.Srivatsavai@Sun.COM * attack on this link. The forwarding cache is a negative thing for 161710491SRishi.Srivatsavai@Sun.COM * security -- it disables reachability as a performance optimization 161810491SRishi.Srivatsavai@Sun.COM * -- so leaving out entries optimizes for success and defends against 161910491SRishi.Srivatsavai@Sun.COM * the attack. Thus, the bare increment without a check in the delete 162010491SRishi.Srivatsavai@Sun.COM * code above is right. (And it's ok if we skid over the limit a 162110491SRishi.Srivatsavai@Sun.COM * little, so there's no syncronization needed on the test.) 162210491SRishi.Srivatsavai@Sun.COM */ 162310491SRishi.Srivatsavai@Sun.COM if (blp->bl_learns >= mac_get_llimit(blp->bl_mh)) { 162410491SRishi.Srivatsavai@Sun.COM if (bfp != NULL) { 162510491SRishi.Srivatsavai@Sun.COM if (bfp->bf_vcnt == 0) 162610491SRishi.Srivatsavai@Sun.COM fwd_delete(bfp); 162710491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 162810491SRishi.Srivatsavai@Sun.COM } 162910491SRishi.Srivatsavai@Sun.COM return; 163010491SRishi.Srivatsavai@Sun.COM } 163110491SRishi.Srivatsavai@Sun.COM 163210491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_learns); 163310491SRishi.Srivatsavai@Sun.COM 163410491SRishi.Srivatsavai@Sun.COM if ((bfpnew = fwd_alloc(saddr, 1, ingress_nick)) == NULL) { 163510491SRishi.Srivatsavai@Sun.COM if (bfp != NULL) 163610491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 163710491SRishi.Srivatsavai@Sun.COM return; 163810491SRishi.Srivatsavai@Sun.COM } 163910491SRishi.Srivatsavai@Sun.COM KIINCR(bki_count); 164010491SRishi.Srivatsavai@Sun.COM 164110491SRishi.Srivatsavai@Sun.COM if (bfp != NULL) { 164210491SRishi.Srivatsavai@Sun.COM /* 164310491SRishi.Srivatsavai@Sun.COM * If this is a new destination for the same VLAN, then delete 164410491SRishi.Srivatsavai@Sun.COM * so that we can update. If it's a different VLAN, then we're 164510491SRishi.Srivatsavai@Sun.COM * not going to delete the original. Split off instead into an 164610491SRishi.Srivatsavai@Sun.COM * IVL entry. 164710491SRishi.Srivatsavai@Sun.COM */ 164810491SRishi.Srivatsavai@Sun.COM if (bfp->bf_vlanid == vlanid) { 164910491SRishi.Srivatsavai@Sun.COM /* save the count of IVL duplicates */ 165010491SRishi.Srivatsavai@Sun.COM bfpnew->bf_vcnt = bfp->bf_vcnt; 165110491SRishi.Srivatsavai@Sun.COM 165210491SRishi.Srivatsavai@Sun.COM /* entry deletes count as learning events */ 165310491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_learns); 165410491SRishi.Srivatsavai@Sun.COM 165510491SRishi.Srivatsavai@Sun.COM /* destroy and create anew; node moved */ 165610491SRishi.Srivatsavai@Sun.COM fwd_delete(bfp); 165710491SRishi.Srivatsavai@Sun.COM replaced = B_TRUE; 165810491SRishi.Srivatsavai@Sun.COM KIINCR(bki_moved); 165910491SRishi.Srivatsavai@Sun.COM } else { 166010491SRishi.Srivatsavai@Sun.COM bfp->bf_vcnt++; 166110491SRishi.Srivatsavai@Sun.COM bfpnew->bf_flags |= BFF_VLANLOCAL; 166210491SRishi.Srivatsavai@Sun.COM } 166310491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 166410491SRishi.Srivatsavai@Sun.COM } 166510491SRishi.Srivatsavai@Sun.COM bfpnew->bf_links[0] = blp; 166610491SRishi.Srivatsavai@Sun.COM bfpnew->bf_nlinks = 1; 166710491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_refs); /* bf_links entry */ 166810491SRishi.Srivatsavai@Sun.COM if (!fwd_insert(bip, bfpnew)) 166910491SRishi.Srivatsavai@Sun.COM fwd_free(bfpnew); 167010491SRishi.Srivatsavai@Sun.COM else if (!replaced) 167110491SRishi.Srivatsavai@Sun.COM KIINCR(bki_source); 167210491SRishi.Srivatsavai@Sun.COM } 167310491SRishi.Srivatsavai@Sun.COM 167410491SRishi.Srivatsavai@Sun.COM /* 167510491SRishi.Srivatsavai@Sun.COM * Process the VLAN headers for output on a given link. There are several 167610491SRishi.Srivatsavai@Sun.COM * cases (noting that we don't map VLANs): 167710491SRishi.Srivatsavai@Sun.COM * 1. The input packet is good as it is; either 167810491SRishi.Srivatsavai@Sun.COM * a. It has no tag, and output has same PVID 167910491SRishi.Srivatsavai@Sun.COM * b. It has a non-zero priority-only tag for PVID, and b_band is same 168010491SRishi.Srivatsavai@Sun.COM * c. It has a tag with VLAN different from PVID, and b_band is same 168110491SRishi.Srivatsavai@Sun.COM * 2. The tag must change: non-zero b_band is different from tag priority 168210491SRishi.Srivatsavai@Sun.COM * 3. The packet has a tag and should not (VLAN same as PVID, b_band zero) 168310491SRishi.Srivatsavai@Sun.COM * 4. The packet has no tag and needs one: 168410491SRishi.Srivatsavai@Sun.COM * a. VLAN ID same as PVID, but b_band is non-zero 168510491SRishi.Srivatsavai@Sun.COM * b. VLAN ID different from PVID 168610491SRishi.Srivatsavai@Sun.COM * We exclude case 1 first, then modify the packet. Note that output packets 168710491SRishi.Srivatsavai@Sun.COM * get a priority set by the mblk, not by the header, because QoS in bridging 168810491SRishi.Srivatsavai@Sun.COM * requires priority recalculation at each node. 168910491SRishi.Srivatsavai@Sun.COM * 169010491SRishi.Srivatsavai@Sun.COM * The passed-in tci is the "impossible" value 0xFFFF when no tag is present. 169110491SRishi.Srivatsavai@Sun.COM */ 169210491SRishi.Srivatsavai@Sun.COM static mblk_t * 169310491SRishi.Srivatsavai@Sun.COM reform_vlan_header(mblk_t *mp, uint16_t vlanid, uint16_t tci, uint16_t pvid) 169410491SRishi.Srivatsavai@Sun.COM { 169510491SRishi.Srivatsavai@Sun.COM boolean_t source_has_tag = (tci != 0xFFFF); 169610491SRishi.Srivatsavai@Sun.COM mblk_t *mpcopy; 169710491SRishi.Srivatsavai@Sun.COM size_t mlen, minlen; 169810491SRishi.Srivatsavai@Sun.COM struct ether_vlan_header *evh; 169910491SRishi.Srivatsavai@Sun.COM int pri; 170010491SRishi.Srivatsavai@Sun.COM 170110491SRishi.Srivatsavai@Sun.COM /* This helps centralize error handling in the caller. */ 170210491SRishi.Srivatsavai@Sun.COM if (mp == NULL) 170310491SRishi.Srivatsavai@Sun.COM return (mp); 170410491SRishi.Srivatsavai@Sun.COM 170510491SRishi.Srivatsavai@Sun.COM /* No forwarded packet can have hardware checksum enabled */ 170610491SRishi.Srivatsavai@Sun.COM DB_CKSUMFLAGS(mp) = 0; 170710491SRishi.Srivatsavai@Sun.COM 170810491SRishi.Srivatsavai@Sun.COM /* Get the no-modification cases out of the way first */ 170910491SRishi.Srivatsavai@Sun.COM if (!source_has_tag && vlanid == pvid) /* 1a */ 171010491SRishi.Srivatsavai@Sun.COM return (mp); 171110491SRishi.Srivatsavai@Sun.COM 171210491SRishi.Srivatsavai@Sun.COM pri = VLAN_PRI(tci); 171310491SRishi.Srivatsavai@Sun.COM if (source_has_tag && mp->b_band == pri) { 171410491SRishi.Srivatsavai@Sun.COM if (vlanid != pvid) /* 1c */ 171510491SRishi.Srivatsavai@Sun.COM return (mp); 171610491SRishi.Srivatsavai@Sun.COM if (pri != 0 && VLAN_ID(tci) == 0) /* 1b */ 171710491SRishi.Srivatsavai@Sun.COM return (mp); 171810491SRishi.Srivatsavai@Sun.COM } 171910491SRishi.Srivatsavai@Sun.COM 172010491SRishi.Srivatsavai@Sun.COM /* 172110491SRishi.Srivatsavai@Sun.COM * We now know that we must modify the packet. Prepare for that. Note 172210491SRishi.Srivatsavai@Sun.COM * that if a tag is present, the caller has already done a pullup for 172310491SRishi.Srivatsavai@Sun.COM * the VLAN header, so we're good to go. 172410491SRishi.Srivatsavai@Sun.COM */ 172510491SRishi.Srivatsavai@Sun.COM if (MBLKL(mp) < sizeof (struct ether_header)) { 172610491SRishi.Srivatsavai@Sun.COM mpcopy = msgpullup(mp, sizeof (struct ether_header)); 172710491SRishi.Srivatsavai@Sun.COM if (mpcopy == NULL) { 172810491SRishi.Srivatsavai@Sun.COM freemsg(mp); 172910491SRishi.Srivatsavai@Sun.COM return (NULL); 173010491SRishi.Srivatsavai@Sun.COM } 173110491SRishi.Srivatsavai@Sun.COM mp = mpcopy; 173210491SRishi.Srivatsavai@Sun.COM } 173310491SRishi.Srivatsavai@Sun.COM if (DB_REF(mp) > 1 || !IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)) || 173410491SRishi.Srivatsavai@Sun.COM (!source_has_tag && MBLKTAIL(mp) < VLAN_INCR)) { 173510491SRishi.Srivatsavai@Sun.COM minlen = mlen = MBLKL(mp); 173610491SRishi.Srivatsavai@Sun.COM if (!source_has_tag) 173710491SRishi.Srivatsavai@Sun.COM minlen += VLAN_INCR; 173810491SRishi.Srivatsavai@Sun.COM ASSERT(minlen >= sizeof (struct ether_vlan_header)); 173910491SRishi.Srivatsavai@Sun.COM /* 174010491SRishi.Srivatsavai@Sun.COM * We're willing to copy some data to avoid fragmentation, but 174110491SRishi.Srivatsavai@Sun.COM * not a lot. 174210491SRishi.Srivatsavai@Sun.COM */ 174310491SRishi.Srivatsavai@Sun.COM if (minlen > 256) 174410491SRishi.Srivatsavai@Sun.COM minlen = sizeof (struct ether_vlan_header); 174510491SRishi.Srivatsavai@Sun.COM mpcopy = allocb(minlen, BPRI_MED); 174610491SRishi.Srivatsavai@Sun.COM if (mpcopy == NULL) { 174710491SRishi.Srivatsavai@Sun.COM freemsg(mp); 174810491SRishi.Srivatsavai@Sun.COM return (NULL); 174910491SRishi.Srivatsavai@Sun.COM } 175010491SRishi.Srivatsavai@Sun.COM if (mlen <= minlen) { 175110491SRishi.Srivatsavai@Sun.COM /* We toss the first mblk when we can. */ 175210491SRishi.Srivatsavai@Sun.COM bcopy(mp->b_rptr, mpcopy->b_rptr, mlen); 175310491SRishi.Srivatsavai@Sun.COM mpcopy->b_wptr += mlen; 175410491SRishi.Srivatsavai@Sun.COM mpcopy->b_cont = mp->b_cont; 175510491SRishi.Srivatsavai@Sun.COM freeb(mp); 175610491SRishi.Srivatsavai@Sun.COM } else { 175710491SRishi.Srivatsavai@Sun.COM /* If not, then just copy what we need */ 175810491SRishi.Srivatsavai@Sun.COM if (!source_has_tag) 175910491SRishi.Srivatsavai@Sun.COM minlen = sizeof (struct ether_header); 176010491SRishi.Srivatsavai@Sun.COM bcopy(mp->b_rptr, mpcopy->b_rptr, minlen); 176110491SRishi.Srivatsavai@Sun.COM mpcopy->b_wptr += minlen; 176210491SRishi.Srivatsavai@Sun.COM mpcopy->b_cont = mp; 176310491SRishi.Srivatsavai@Sun.COM mp->b_rptr += minlen; 176410491SRishi.Srivatsavai@Sun.COM } 176510491SRishi.Srivatsavai@Sun.COM mp = mpcopy; 176610491SRishi.Srivatsavai@Sun.COM } 176710491SRishi.Srivatsavai@Sun.COM 176810491SRishi.Srivatsavai@Sun.COM /* LINTED: pointer alignment */ 176910491SRishi.Srivatsavai@Sun.COM evh = (struct ether_vlan_header *)mp->b_rptr; 177010491SRishi.Srivatsavai@Sun.COM if (source_has_tag) { 177110491SRishi.Srivatsavai@Sun.COM if (mp->b_band == 0 && vlanid == pvid) { /* 3 */ 177210491SRishi.Srivatsavai@Sun.COM evh->ether_tpid = evh->ether_type; 177310491SRishi.Srivatsavai@Sun.COM mlen = MBLKL(mp); 177410491SRishi.Srivatsavai@Sun.COM if (mlen > sizeof (struct ether_vlan_header)) 177510491SRishi.Srivatsavai@Sun.COM ovbcopy(mp->b_rptr + 177610491SRishi.Srivatsavai@Sun.COM sizeof (struct ether_vlan_header), 177710491SRishi.Srivatsavai@Sun.COM mp->b_rptr + sizeof (struct ether_header), 177810491SRishi.Srivatsavai@Sun.COM mlen - sizeof (struct ether_vlan_header)); 177910491SRishi.Srivatsavai@Sun.COM mp->b_wptr -= VLAN_INCR; 178010491SRishi.Srivatsavai@Sun.COM } else { /* 2 */ 178110491SRishi.Srivatsavai@Sun.COM if (vlanid == pvid) 178210491SRishi.Srivatsavai@Sun.COM vlanid = VLAN_ID_NONE; 178310491SRishi.Srivatsavai@Sun.COM tci = VLAN_TCI(mp->b_band, ETHER_CFI, vlanid); 178410491SRishi.Srivatsavai@Sun.COM evh->ether_tci = htons(tci); 178510491SRishi.Srivatsavai@Sun.COM } 178610491SRishi.Srivatsavai@Sun.COM } else { 178710491SRishi.Srivatsavai@Sun.COM /* case 4: no header present, but one is needed */ 178810491SRishi.Srivatsavai@Sun.COM mlen = MBLKL(mp); 178910491SRishi.Srivatsavai@Sun.COM if (mlen > sizeof (struct ether_header)) 179010491SRishi.Srivatsavai@Sun.COM ovbcopy(mp->b_rptr + sizeof (struct ether_header), 179110491SRishi.Srivatsavai@Sun.COM mp->b_rptr + sizeof (struct ether_vlan_header), 179210491SRishi.Srivatsavai@Sun.COM mlen - sizeof (struct ether_header)); 179310491SRishi.Srivatsavai@Sun.COM mp->b_wptr += VLAN_INCR; 179410491SRishi.Srivatsavai@Sun.COM ASSERT(mp->b_wptr <= DB_LIM(mp)); 179510491SRishi.Srivatsavai@Sun.COM if (vlanid == pvid) 179610491SRishi.Srivatsavai@Sun.COM vlanid = VLAN_ID_NONE; 179710491SRishi.Srivatsavai@Sun.COM tci = VLAN_TCI(mp->b_band, ETHER_CFI, vlanid); 179810491SRishi.Srivatsavai@Sun.COM evh->ether_type = evh->ether_tpid; 179910491SRishi.Srivatsavai@Sun.COM evh->ether_tpid = htons(ETHERTYPE_VLAN); 180010491SRishi.Srivatsavai@Sun.COM evh->ether_tci = htons(tci); 180110491SRishi.Srivatsavai@Sun.COM } 180210491SRishi.Srivatsavai@Sun.COM return (mp); 180310491SRishi.Srivatsavai@Sun.COM } 180410491SRishi.Srivatsavai@Sun.COM 180510491SRishi.Srivatsavai@Sun.COM /* Record VLAN information and strip header if requested . */ 180610491SRishi.Srivatsavai@Sun.COM static void 180710491SRishi.Srivatsavai@Sun.COM update_header(mblk_t *mp, mac_header_info_t *hdr_info, boolean_t striphdr) 180810491SRishi.Srivatsavai@Sun.COM { 180910491SRishi.Srivatsavai@Sun.COM if (hdr_info->mhi_bindsap == ETHERTYPE_VLAN) { 181010491SRishi.Srivatsavai@Sun.COM struct ether_vlan_header *evhp; 181110491SRishi.Srivatsavai@Sun.COM uint16_t ether_type; 181210491SRishi.Srivatsavai@Sun.COM 181310491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 181410491SRishi.Srivatsavai@Sun.COM evhp = (struct ether_vlan_header *)mp->b_rptr; 181510491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_istagged = B_TRUE; 181610491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_tci = ntohs(evhp->ether_tci); 181710491SRishi.Srivatsavai@Sun.COM if (striphdr) { 181810491SRishi.Srivatsavai@Sun.COM /* 181910491SRishi.Srivatsavai@Sun.COM * For VLAN tagged frames update the ether_type 182010491SRishi.Srivatsavai@Sun.COM * in hdr_info before stripping the header. 182110491SRishi.Srivatsavai@Sun.COM */ 182210491SRishi.Srivatsavai@Sun.COM ether_type = ntohs(evhp->ether_type); 182310491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_origsap = ether_type; 182410491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_bindsap = (ether_type > ETHERMTU) ? 182510491SRishi.Srivatsavai@Sun.COM ether_type : DLS_SAP_LLC; 182610491SRishi.Srivatsavai@Sun.COM mp->b_rptr = (uchar_t *)(evhp + 1); 182710491SRishi.Srivatsavai@Sun.COM } 182810491SRishi.Srivatsavai@Sun.COM } else { 182910491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_istagged = B_FALSE; 183010491SRishi.Srivatsavai@Sun.COM hdr_info->mhi_tci = VLAN_ID_NONE; 183110491SRishi.Srivatsavai@Sun.COM if (striphdr) 183210491SRishi.Srivatsavai@Sun.COM mp->b_rptr += sizeof (struct ether_header); 183310491SRishi.Srivatsavai@Sun.COM } 183410491SRishi.Srivatsavai@Sun.COM } 183510491SRishi.Srivatsavai@Sun.COM 183610491SRishi.Srivatsavai@Sun.COM /* 183710491SRishi.Srivatsavai@Sun.COM * Return B_TRUE if we're allowed to send on this link with the given VLAN ID. 183810491SRishi.Srivatsavai@Sun.COM */ 183910491SRishi.Srivatsavai@Sun.COM static boolean_t 184010491SRishi.Srivatsavai@Sun.COM bridge_can_send(bridge_link_t *blp, uint16_t vlanid) 184110491SRishi.Srivatsavai@Sun.COM { 184210491SRishi.Srivatsavai@Sun.COM ASSERT(vlanid != VLAN_ID_NONE); 184310491SRishi.Srivatsavai@Sun.COM if (blp->bl_flags & BLF_DELETED) 184410491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 184510491SRishi.Srivatsavai@Sun.COM if (blp->bl_trilldata == NULL && blp->bl_state != BLS_FORWARDING) 184610491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 184710491SRishi.Srivatsavai@Sun.COM return (BRIDGE_VLAN_ISSET(blp, vlanid) && BRIDGE_AF_ISSET(blp, vlanid)); 184810491SRishi.Srivatsavai@Sun.COM } 184910491SRishi.Srivatsavai@Sun.COM 185010491SRishi.Srivatsavai@Sun.COM /* 185110491SRishi.Srivatsavai@Sun.COM * This function scans the bridge forwarding tables in order to forward a given 185210491SRishi.Srivatsavai@Sun.COM * packet. If the packet either doesn't need forwarding (the current link is 185310491SRishi.Srivatsavai@Sun.COM * correct) or the current link needs a copy as well, then the packet is 185410491SRishi.Srivatsavai@Sun.COM * returned to the caller. 185510491SRishi.Srivatsavai@Sun.COM * 185610491SRishi.Srivatsavai@Sun.COM * If a packet has been decapsulated from TRILL, then it must *NOT* reenter a 185710491SRishi.Srivatsavai@Sun.COM * TRILL tunnel. If the destination points there, then drop instead. 185810491SRishi.Srivatsavai@Sun.COM */ 185910491SRishi.Srivatsavai@Sun.COM static mblk_t * 186010491SRishi.Srivatsavai@Sun.COM bridge_forward(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp, 186110491SRishi.Srivatsavai@Sun.COM uint16_t vlanid, uint16_t tci, boolean_t from_trill, boolean_t is_xmit) 186210491SRishi.Srivatsavai@Sun.COM { 186310491SRishi.Srivatsavai@Sun.COM mblk_t *mpsend, *mpcopy; 186410491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 186510491SRishi.Srivatsavai@Sun.COM bridge_link_t *blpsend, *blpnext; 186610491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp; 186710491SRishi.Srivatsavai@Sun.COM uint_t i; 186810491SRishi.Srivatsavai@Sun.COM boolean_t selfseen = B_FALSE; 186910491SRishi.Srivatsavai@Sun.COM void *tdp; 187010491SRishi.Srivatsavai@Sun.COM const uint8_t *daddr = hdr_info->mhi_daddr; 187110491SRishi.Srivatsavai@Sun.COM 187210491SRishi.Srivatsavai@Sun.COM /* 187310491SRishi.Srivatsavai@Sun.COM * Check for the IEEE "reserved" multicast addresses. Messages sent to 187410491SRishi.Srivatsavai@Sun.COM * these addresses are used for link-local control (STP and pause), and 187510491SRishi.Srivatsavai@Sun.COM * are never forwarded or redirected. 187610491SRishi.Srivatsavai@Sun.COM */ 187710491SRishi.Srivatsavai@Sun.COM if (daddr[0] == 1 && daddr[1] == 0x80 && daddr[2] == 0xc2 && 187810491SRishi.Srivatsavai@Sun.COM daddr[3] == 0 && daddr[4] == 0 && (daddr[5] & 0xf0) == 0) { 187910491SRishi.Srivatsavai@Sun.COM if (from_trill) { 188010491SRishi.Srivatsavai@Sun.COM freemsg(mp); 188110491SRishi.Srivatsavai@Sun.COM mp = NULL; 188210491SRishi.Srivatsavai@Sun.COM } 188310491SRishi.Srivatsavai@Sun.COM return (mp); 188410491SRishi.Srivatsavai@Sun.COM } 188510491SRishi.Srivatsavai@Sun.COM 188610491SRishi.Srivatsavai@Sun.COM if ((bfp = fwd_find(bip, daddr, vlanid)) != NULL) { 188710491SRishi.Srivatsavai@Sun.COM 188810491SRishi.Srivatsavai@Sun.COM /* 188910491SRishi.Srivatsavai@Sun.COM * If trill indicates a destination for this node, then it's 189010491SRishi.Srivatsavai@Sun.COM * clearly not intended for local delivery. We must tell TRILL 189110491SRishi.Srivatsavai@Sun.COM * to encapsulate, as long as we didn't just decapsulate it. 189210491SRishi.Srivatsavai@Sun.COM */ 189310491SRishi.Srivatsavai@Sun.COM if (bfp->bf_trill_nick != RBRIDGE_NICKNAME_NONE) { 189410491SRishi.Srivatsavai@Sun.COM /* 189510491SRishi.Srivatsavai@Sun.COM * Error case: can't reencapsulate if the protocols are 189610491SRishi.Srivatsavai@Sun.COM * working correctly. 189710491SRishi.Srivatsavai@Sun.COM */ 189810491SRishi.Srivatsavai@Sun.COM if (from_trill) { 189910491SRishi.Srivatsavai@Sun.COM freemsg(mp); 190010491SRishi.Srivatsavai@Sun.COM return (NULL); 190110491SRishi.Srivatsavai@Sun.COM } 190210491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 190310491SRishi.Srivatsavai@Sun.COM if ((tdp = blp->bl_trilldata) != NULL) { 190410491SRishi.Srivatsavai@Sun.COM blp->bl_trillthreads++; 190510491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 190610491SRishi.Srivatsavai@Sun.COM update_header(mp, hdr_info, B_FALSE); 190710491SRishi.Srivatsavai@Sun.COM if (is_xmit) 190810491SRishi.Srivatsavai@Sun.COM mp = mac_fix_cksum(mp); 190910491SRishi.Srivatsavai@Sun.COM /* all trill data frames have Inner.VLAN */ 191010491SRishi.Srivatsavai@Sun.COM mp = reform_vlan_header(mp, vlanid, tci, 0); 191110491SRishi.Srivatsavai@Sun.COM if (mp == NULL) { 191210491SRishi.Srivatsavai@Sun.COM KIINCR(bki_drops); 191310491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 191410491SRishi.Srivatsavai@Sun.COM return (NULL); 191510491SRishi.Srivatsavai@Sun.COM } 191610491SRishi.Srivatsavai@Sun.COM trill_encap_fn(tdp, blp, hdr_info, mp, 191710491SRishi.Srivatsavai@Sun.COM bfp->bf_trill_nick); 191810491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 191910491SRishi.Srivatsavai@Sun.COM if (--blp->bl_trillthreads == 0 && 192010491SRishi.Srivatsavai@Sun.COM blp->bl_trilldata == NULL) 192110491SRishi.Srivatsavai@Sun.COM cv_broadcast(&blp->bl_trillwait); 192210491SRishi.Srivatsavai@Sun.COM } 192310491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 192410491SRishi.Srivatsavai@Sun.COM 192510491SRishi.Srivatsavai@Sun.COM /* if TRILL has been disabled, then kill this stray */ 192610491SRishi.Srivatsavai@Sun.COM if (tdp == NULL) { 192710491SRishi.Srivatsavai@Sun.COM freemsg(mp); 192810491SRishi.Srivatsavai@Sun.COM fwd_delete(bfp); 192910491SRishi.Srivatsavai@Sun.COM } 193010491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 193110491SRishi.Srivatsavai@Sun.COM return (NULL); 193210491SRishi.Srivatsavai@Sun.COM } 193310491SRishi.Srivatsavai@Sun.COM 193410491SRishi.Srivatsavai@Sun.COM /* find first link we can send on */ 193510491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) { 193610491SRishi.Srivatsavai@Sun.COM blpsend = bfp->bf_links[i]; 193710491SRishi.Srivatsavai@Sun.COM if (blpsend == blp) 193810491SRishi.Srivatsavai@Sun.COM selfseen = B_TRUE; 193910491SRishi.Srivatsavai@Sun.COM else if (bridge_can_send(blpsend, vlanid)) 194010491SRishi.Srivatsavai@Sun.COM break; 194110491SRishi.Srivatsavai@Sun.COM } 194210491SRishi.Srivatsavai@Sun.COM 194310491SRishi.Srivatsavai@Sun.COM while (i < bfp->bf_nlinks) { 194410491SRishi.Srivatsavai@Sun.COM blpsend = bfp->bf_links[i]; 194510491SRishi.Srivatsavai@Sun.COM for (i++; i < bfp->bf_nlinks; i++) { 194610491SRishi.Srivatsavai@Sun.COM blpnext = bfp->bf_links[i]; 194710491SRishi.Srivatsavai@Sun.COM if (blpnext == blp) 194810491SRishi.Srivatsavai@Sun.COM selfseen = B_TRUE; 194910491SRishi.Srivatsavai@Sun.COM else if (bridge_can_send(blpnext, vlanid)) 195010491SRishi.Srivatsavai@Sun.COM break; 195110491SRishi.Srivatsavai@Sun.COM } 195210491SRishi.Srivatsavai@Sun.COM if (i == bfp->bf_nlinks && !selfseen) { 195310491SRishi.Srivatsavai@Sun.COM mpsend = mp; 195410491SRishi.Srivatsavai@Sun.COM mp = NULL; 195510491SRishi.Srivatsavai@Sun.COM } else { 195610491SRishi.Srivatsavai@Sun.COM mpsend = copymsg(mp); 195710491SRishi.Srivatsavai@Sun.COM } 195810491SRishi.Srivatsavai@Sun.COM 195910491SRishi.Srivatsavai@Sun.COM if (!from_trill && is_xmit) 196010491SRishi.Srivatsavai@Sun.COM mpsend = mac_fix_cksum(mpsend); 196110491SRishi.Srivatsavai@Sun.COM 196210491SRishi.Srivatsavai@Sun.COM mpsend = reform_vlan_header(mpsend, vlanid, tci, 196310491SRishi.Srivatsavai@Sun.COM blpsend->bl_pvid); 196410491SRishi.Srivatsavai@Sun.COM if (mpsend == NULL) { 196510491SRishi.Srivatsavai@Sun.COM KIINCR(bki_drops); 196610491SRishi.Srivatsavai@Sun.COM continue; 196710491SRishi.Srivatsavai@Sun.COM } 196810491SRishi.Srivatsavai@Sun.COM 196910491SRishi.Srivatsavai@Sun.COM KIINCR(bki_forwards); 197010491SRishi.Srivatsavai@Sun.COM /* 197110491SRishi.Srivatsavai@Sun.COM * No need to bump up the link reference count, as 197210491SRishi.Srivatsavai@Sun.COM * the forwarding entry itself holds a reference to 197310491SRishi.Srivatsavai@Sun.COM * the link. 197410491SRishi.Srivatsavai@Sun.COM */ 197510491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_LOCALADDR) { 197610491SRishi.Srivatsavai@Sun.COM mac_rx_common(blpsend->bl_mh, NULL, mpsend); 197710491SRishi.Srivatsavai@Sun.COM } else { 197810491SRishi.Srivatsavai@Sun.COM KLPINCR(blpsend, bkl_xmit); 197910491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blpsend->bl_mh, NULL, mpsend, 198010491SRishi.Srivatsavai@Sun.COM mpsend); 198110491SRishi.Srivatsavai@Sun.COM freemsg(mpsend); 198210491SRishi.Srivatsavai@Sun.COM } 198310491SRishi.Srivatsavai@Sun.COM } 198410491SRishi.Srivatsavai@Sun.COM /* 198510491SRishi.Srivatsavai@Sun.COM * Handle a special case: if we're transmitting to the original 198610491SRishi.Srivatsavai@Sun.COM * link, then check whether the localaddr flag is set. If it 198710491SRishi.Srivatsavai@Sun.COM * is, then receive instead. This doesn't happen with ordinary 198810491SRishi.Srivatsavai@Sun.COM * bridging, but does happen often with TRILL decapsulation. 198910491SRishi.Srivatsavai@Sun.COM */ 199010491SRishi.Srivatsavai@Sun.COM if (mp != NULL && is_xmit && (bfp->bf_flags & BFF_LOCALADDR)) { 199110491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, NULL, mp); 199210491SRishi.Srivatsavai@Sun.COM mp = NULL; 199310491SRishi.Srivatsavai@Sun.COM } 199410491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 199510491SRishi.Srivatsavai@Sun.COM } else { 199610491SRishi.Srivatsavai@Sun.COM /* 199710491SRishi.Srivatsavai@Sun.COM * TRILL has two cases to handle. If the packet is off the 199810491SRishi.Srivatsavai@Sun.COM * wire (not from TRILL), then we need to send up into the 199910491SRishi.Srivatsavai@Sun.COM * TRILL module to have the distribution tree computed. If the 200010491SRishi.Srivatsavai@Sun.COM * packet is from TRILL (decapsulated), then we're part of the 200110491SRishi.Srivatsavai@Sun.COM * distribution tree, and we need to copy the packet on member 200210491SRishi.Srivatsavai@Sun.COM * interfaces. 200310491SRishi.Srivatsavai@Sun.COM * 200410491SRishi.Srivatsavai@Sun.COM * Thus, the from TRILL case is identical to the STP case. 200510491SRishi.Srivatsavai@Sun.COM */ 200610491SRishi.Srivatsavai@Sun.COM if (!from_trill && blp->bl_trilldata != NULL) { 200710491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 200810491SRishi.Srivatsavai@Sun.COM if ((tdp = blp->bl_trilldata) != NULL) { 200910491SRishi.Srivatsavai@Sun.COM blp->bl_trillthreads++; 201010491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 201110491SRishi.Srivatsavai@Sun.COM if ((mpsend = copymsg(mp)) != NULL) { 201210491SRishi.Srivatsavai@Sun.COM update_header(mpsend, 201310491SRishi.Srivatsavai@Sun.COM hdr_info, B_FALSE); 201410491SRishi.Srivatsavai@Sun.COM /* 201510491SRishi.Srivatsavai@Sun.COM * all trill data frames have 201610491SRishi.Srivatsavai@Sun.COM * Inner.VLAN 201710491SRishi.Srivatsavai@Sun.COM */ 201810491SRishi.Srivatsavai@Sun.COM mpsend = reform_vlan_header(mpsend, 201910491SRishi.Srivatsavai@Sun.COM vlanid, tci, 0); 202010491SRishi.Srivatsavai@Sun.COM if (mpsend == NULL) { 202110491SRishi.Srivatsavai@Sun.COM KIINCR(bki_drops); 202210491SRishi.Srivatsavai@Sun.COM } else { 202310491SRishi.Srivatsavai@Sun.COM trill_encap_fn(tdp, blp, 202410491SRishi.Srivatsavai@Sun.COM hdr_info, mpsend, 202510491SRishi.Srivatsavai@Sun.COM RBRIDGE_NICKNAME_NONE); 202610491SRishi.Srivatsavai@Sun.COM } 202710491SRishi.Srivatsavai@Sun.COM } 202810491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 202910491SRishi.Srivatsavai@Sun.COM if (--blp->bl_trillthreads == 0 && 203010491SRishi.Srivatsavai@Sun.COM blp->bl_trilldata == NULL) 203110491SRishi.Srivatsavai@Sun.COM cv_broadcast(&blp->bl_trillwait); 203210491SRishi.Srivatsavai@Sun.COM } 203310491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 203410491SRishi.Srivatsavai@Sun.COM } 203510491SRishi.Srivatsavai@Sun.COM 203610491SRishi.Srivatsavai@Sun.COM /* 203710491SRishi.Srivatsavai@Sun.COM * This is an unknown destination, so flood. 203810491SRishi.Srivatsavai@Sun.COM */ 203910491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 204010491SRishi.Srivatsavai@Sun.COM for (blpnext = list_head(&bip->bi_links); blpnext != NULL; 204110491SRishi.Srivatsavai@Sun.COM blpnext = list_next(&bip->bi_links, blpnext)) { 204210491SRishi.Srivatsavai@Sun.COM if (blpnext == blp) 204310491SRishi.Srivatsavai@Sun.COM selfseen = B_TRUE; 204410491SRishi.Srivatsavai@Sun.COM else if (bridge_can_send(blpnext, vlanid)) 204510491SRishi.Srivatsavai@Sun.COM break; 204610491SRishi.Srivatsavai@Sun.COM } 204710491SRishi.Srivatsavai@Sun.COM if (blpnext != NULL) 204810491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blpnext->bl_refs); 204910491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 205010491SRishi.Srivatsavai@Sun.COM while ((blpsend = blpnext) != NULL) { 205110491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 205210491SRishi.Srivatsavai@Sun.COM for (blpnext = list_next(&bip->bi_links, blpsend); 205310491SRishi.Srivatsavai@Sun.COM blpnext != NULL; 205410491SRishi.Srivatsavai@Sun.COM blpnext = list_next(&bip->bi_links, blpnext)) { 205510491SRishi.Srivatsavai@Sun.COM if (blpnext == blp) 205610491SRishi.Srivatsavai@Sun.COM selfseen = B_TRUE; 205710491SRishi.Srivatsavai@Sun.COM else if (bridge_can_send(blpnext, vlanid)) 205810491SRishi.Srivatsavai@Sun.COM break; 205910491SRishi.Srivatsavai@Sun.COM } 206010491SRishi.Srivatsavai@Sun.COM if (blpnext != NULL) 206110491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blpnext->bl_refs); 206210491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 206310491SRishi.Srivatsavai@Sun.COM if (blpnext == NULL && !selfseen) { 206410491SRishi.Srivatsavai@Sun.COM mpsend = mp; 206510491SRishi.Srivatsavai@Sun.COM mp = NULL; 206610491SRishi.Srivatsavai@Sun.COM } else { 206710491SRishi.Srivatsavai@Sun.COM mpsend = copymsg(mp); 206810491SRishi.Srivatsavai@Sun.COM } 206910491SRishi.Srivatsavai@Sun.COM 207010491SRishi.Srivatsavai@Sun.COM if (!from_trill && is_xmit) 207110491SRishi.Srivatsavai@Sun.COM mpsend = mac_fix_cksum(mpsend); 207210491SRishi.Srivatsavai@Sun.COM 207310491SRishi.Srivatsavai@Sun.COM mpsend = reform_vlan_header(mpsend, vlanid, tci, 207410491SRishi.Srivatsavai@Sun.COM blpsend->bl_pvid); 207510491SRishi.Srivatsavai@Sun.COM if (mpsend == NULL) { 207610491SRishi.Srivatsavai@Sun.COM KIINCR(bki_drops); 207710491SRishi.Srivatsavai@Sun.COM continue; 207810491SRishi.Srivatsavai@Sun.COM } 207910491SRishi.Srivatsavai@Sun.COM 208010491SRishi.Srivatsavai@Sun.COM if (hdr_info->mhi_dsttype == MAC_ADDRTYPE_UNICAST) 208110491SRishi.Srivatsavai@Sun.COM KIINCR(bki_unknown); 208210491SRishi.Srivatsavai@Sun.COM else 208310491SRishi.Srivatsavai@Sun.COM KIINCR(bki_mbcast); 208410491SRishi.Srivatsavai@Sun.COM KLPINCR(blpsend, bkl_xmit); 208510491SRishi.Srivatsavai@Sun.COM if ((mpcopy = copymsg(mpsend)) != NULL) 208610491SRishi.Srivatsavai@Sun.COM mac_rx_common(blpsend->bl_mh, NULL, mpcopy); 208710491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blpsend->bl_mh, NULL, mpsend, mpsend); 208810491SRishi.Srivatsavai@Sun.COM freemsg(mpsend); 208910491SRishi.Srivatsavai@Sun.COM link_unref(blpsend); 209010491SRishi.Srivatsavai@Sun.COM } 209110491SRishi.Srivatsavai@Sun.COM } 209210491SRishi.Srivatsavai@Sun.COM 209310491SRishi.Srivatsavai@Sun.COM /* 209410491SRishi.Srivatsavai@Sun.COM * At this point, if np is non-NULL, it means that the caller needs to 209510491SRishi.Srivatsavai@Sun.COM * continue on the selected link. 209610491SRishi.Srivatsavai@Sun.COM */ 209710491SRishi.Srivatsavai@Sun.COM return (mp); 209810491SRishi.Srivatsavai@Sun.COM } 209910491SRishi.Srivatsavai@Sun.COM 210010491SRishi.Srivatsavai@Sun.COM /* 210110491SRishi.Srivatsavai@Sun.COM * Extract and validate the VLAN information for a given packet. This checks 210210491SRishi.Srivatsavai@Sun.COM * conformance with the rules for use of the PVID on the link, and for the 210310491SRishi.Srivatsavai@Sun.COM * allowed (configured) VLAN set. 210410491SRishi.Srivatsavai@Sun.COM * 210510491SRishi.Srivatsavai@Sun.COM * Returns B_TRUE if the packet passes, B_FALSE if it fails. 210610491SRishi.Srivatsavai@Sun.COM */ 210710491SRishi.Srivatsavai@Sun.COM static boolean_t 210810491SRishi.Srivatsavai@Sun.COM bridge_get_vlan(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp, 210910491SRishi.Srivatsavai@Sun.COM uint16_t *vlanidp, uint16_t *tcip) 211010491SRishi.Srivatsavai@Sun.COM { 211110491SRishi.Srivatsavai@Sun.COM uint16_t tci, vlanid; 211210491SRishi.Srivatsavai@Sun.COM 211310491SRishi.Srivatsavai@Sun.COM if (hdr_info->mhi_bindsap == ETHERTYPE_VLAN) { 211410491SRishi.Srivatsavai@Sun.COM ptrdiff_t tpos = offsetof(struct ether_vlan_header, ether_tci); 211510491SRishi.Srivatsavai@Sun.COM ptrdiff_t mlen; 211610491SRishi.Srivatsavai@Sun.COM 211710491SRishi.Srivatsavai@Sun.COM /* 211810491SRishi.Srivatsavai@Sun.COM * Extract the VLAN ID information, regardless of alignment, 211910491SRishi.Srivatsavai@Sun.COM * and without a pullup. This isn't attractive, but we do this 212010491SRishi.Srivatsavai@Sun.COM * to avoid having to deal with the pointers stashed in 212110491SRishi.Srivatsavai@Sun.COM * hdr_info moving around or having the caller deal with a new 212210491SRishi.Srivatsavai@Sun.COM * mblk_t pointer. 212310491SRishi.Srivatsavai@Sun.COM */ 212410491SRishi.Srivatsavai@Sun.COM while (mp != NULL) { 212510491SRishi.Srivatsavai@Sun.COM mlen = MBLKL(mp); 212610491SRishi.Srivatsavai@Sun.COM if (mlen > tpos && mlen > 0) 212710491SRishi.Srivatsavai@Sun.COM break; 212810491SRishi.Srivatsavai@Sun.COM tpos -= mlen; 212910491SRishi.Srivatsavai@Sun.COM mp = mp->b_cont; 213010491SRishi.Srivatsavai@Sun.COM } 213110491SRishi.Srivatsavai@Sun.COM if (mp == NULL) 213210491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 213310491SRishi.Srivatsavai@Sun.COM tci = mp->b_rptr[tpos] << 8; 213410491SRishi.Srivatsavai@Sun.COM if (++tpos >= mlen) { 213510491SRishi.Srivatsavai@Sun.COM do { 213610491SRishi.Srivatsavai@Sun.COM mp = mp->b_cont; 213710491SRishi.Srivatsavai@Sun.COM } while (mp != NULL && MBLKL(mp) == 0); 213810491SRishi.Srivatsavai@Sun.COM if (mp == NULL) 213910491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 214010491SRishi.Srivatsavai@Sun.COM tpos = 0; 214110491SRishi.Srivatsavai@Sun.COM } 214210491SRishi.Srivatsavai@Sun.COM tci |= mp->b_rptr[tpos]; 214310491SRishi.Srivatsavai@Sun.COM 214410491SRishi.Srivatsavai@Sun.COM vlanid = VLAN_ID(tci); 214510491SRishi.Srivatsavai@Sun.COM if (VLAN_CFI(tci) != ETHER_CFI || vlanid > VLAN_ID_MAX) 214610491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 214710491SRishi.Srivatsavai@Sun.COM if (vlanid == VLAN_ID_NONE || vlanid == blp->bl_pvid) 214810491SRishi.Srivatsavai@Sun.COM goto input_no_vlan; 214910491SRishi.Srivatsavai@Sun.COM if (!BRIDGE_VLAN_ISSET(blp, vlanid)) 215010491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 215110491SRishi.Srivatsavai@Sun.COM } else { 215210491SRishi.Srivatsavai@Sun.COM tci = 0xFFFF; 215310491SRishi.Srivatsavai@Sun.COM input_no_vlan: 215410491SRishi.Srivatsavai@Sun.COM /* 215510491SRishi.Srivatsavai@Sun.COM * If PVID is set to zero, then untagged traffic is not 215610491SRishi.Srivatsavai@Sun.COM * supported here. Do not learn or forward. 215710491SRishi.Srivatsavai@Sun.COM */ 215810491SRishi.Srivatsavai@Sun.COM if ((vlanid = blp->bl_pvid) == VLAN_ID_NONE) 215910491SRishi.Srivatsavai@Sun.COM return (B_FALSE); 216010491SRishi.Srivatsavai@Sun.COM } 216110491SRishi.Srivatsavai@Sun.COM 216210491SRishi.Srivatsavai@Sun.COM *tcip = tci; 216310491SRishi.Srivatsavai@Sun.COM *vlanidp = vlanid; 216410491SRishi.Srivatsavai@Sun.COM return (B_TRUE); 216510491SRishi.Srivatsavai@Sun.COM } 216610491SRishi.Srivatsavai@Sun.COM 216710491SRishi.Srivatsavai@Sun.COM /* 216810491SRishi.Srivatsavai@Sun.COM * Handle MAC notifications. 216910491SRishi.Srivatsavai@Sun.COM */ 217010491SRishi.Srivatsavai@Sun.COM static void 217110491SRishi.Srivatsavai@Sun.COM bridge_notify_cb(void *arg, mac_notify_type_t note_type) 217210491SRishi.Srivatsavai@Sun.COM { 217310491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = arg; 217410491SRishi.Srivatsavai@Sun.COM 217510491SRishi.Srivatsavai@Sun.COM switch (note_type) { 217610491SRishi.Srivatsavai@Sun.COM case MAC_NOTE_UNICST: 217710491SRishi.Srivatsavai@Sun.COM bridge_new_unicst(blp); 217810491SRishi.Srivatsavai@Sun.COM break; 217910491SRishi.Srivatsavai@Sun.COM 218010491SRishi.Srivatsavai@Sun.COM case MAC_NOTE_SDU_SIZE: { 218110491SRishi.Srivatsavai@Sun.COM uint_t maxsdu; 218210491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 218310491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = bip->bi_mac; 218410491SRishi.Srivatsavai@Sun.COM boolean_t notify = B_FALSE; 218510491SRishi.Srivatsavai@Sun.COM mblk_t *mlist = NULL; 218610491SRishi.Srivatsavai@Sun.COM 218710491SRishi.Srivatsavai@Sun.COM mac_sdu_get(blp->bl_mh, NULL, &maxsdu); 218810491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 218910491SRishi.Srivatsavai@Sun.COM if (list_prev(&bip->bi_links, blp) == NULL && 219010491SRishi.Srivatsavai@Sun.COM list_next(&bip->bi_links, blp) == NULL) { 219110491SRishi.Srivatsavai@Sun.COM notify = (maxsdu != bmp->bm_maxsdu); 219210491SRishi.Srivatsavai@Sun.COM bmp->bm_maxsdu = maxsdu; 219310491SRishi.Srivatsavai@Sun.COM } 219410491SRishi.Srivatsavai@Sun.COM blp->bl_maxsdu = maxsdu; 219510491SRishi.Srivatsavai@Sun.COM if (maxsdu != bmp->bm_maxsdu) 219610491SRishi.Srivatsavai@Sun.COM link_sdu_fail(blp, B_TRUE, &mlist); 219710491SRishi.Srivatsavai@Sun.COM else if (notify) 219810491SRishi.Srivatsavai@Sun.COM (void) mac_maxsdu_update(bmp->bm_mh, maxsdu); 219910491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 220010491SRishi.Srivatsavai@Sun.COM send_up_messages(bip, mlist); 220110491SRishi.Srivatsavai@Sun.COM break; 220210491SRishi.Srivatsavai@Sun.COM } 220310491SRishi.Srivatsavai@Sun.COM } 220410491SRishi.Srivatsavai@Sun.COM } 220510491SRishi.Srivatsavai@Sun.COM 220610491SRishi.Srivatsavai@Sun.COM /* 220710491SRishi.Srivatsavai@Sun.COM * This is called by the MAC layer. As with the transmit side, we're right in 220810491SRishi.Srivatsavai@Sun.COM * the data path for all I/O on this port, so if we don't need to forward this 220910491SRishi.Srivatsavai@Sun.COM * packet anywhere, we have to send it upwards via mac_rx_common. 221010491SRishi.Srivatsavai@Sun.COM */ 221110491SRishi.Srivatsavai@Sun.COM static void 221210491SRishi.Srivatsavai@Sun.COM bridge_recv_cb(mac_handle_t mh, mac_resource_handle_t rsrc, mblk_t *mpnext) 221310491SRishi.Srivatsavai@Sun.COM { 221410491SRishi.Srivatsavai@Sun.COM mblk_t *mp, *mpcopy; 221510491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = (bridge_link_t *)mh; 221610491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 221710491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = bip->bi_mac; 221810491SRishi.Srivatsavai@Sun.COM mac_header_info_t hdr_info; 221910491SRishi.Srivatsavai@Sun.COM uint16_t vlanid, tci; 222010491SRishi.Srivatsavai@Sun.COM boolean_t trillmode = B_FALSE; 222110491SRishi.Srivatsavai@Sun.COM 222210491SRishi.Srivatsavai@Sun.COM KIINCR(bki_recv); 222310491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_recv); 222410491SRishi.Srivatsavai@Sun.COM 222510491SRishi.Srivatsavai@Sun.COM /* 222610491SRishi.Srivatsavai@Sun.COM * Regardless of state, check for inbound TRILL packets when TRILL is 222710491SRishi.Srivatsavai@Sun.COM * active. These are pulled out of band and sent for TRILL handling. 222810491SRishi.Srivatsavai@Sun.COM */ 222910491SRishi.Srivatsavai@Sun.COM if (blp->bl_trilldata != NULL) { 223010491SRishi.Srivatsavai@Sun.COM void *tdp; 223110491SRishi.Srivatsavai@Sun.COM mblk_t *newhead; 223210491SRishi.Srivatsavai@Sun.COM mblk_t *tail = NULL; 223310491SRishi.Srivatsavai@Sun.COM 223410491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 223510491SRishi.Srivatsavai@Sun.COM if ((tdp = blp->bl_trilldata) != NULL) { 223610491SRishi.Srivatsavai@Sun.COM blp->bl_trillthreads++; 223710491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 223810491SRishi.Srivatsavai@Sun.COM trillmode = B_TRUE; 223910491SRishi.Srivatsavai@Sun.COM newhead = mpnext; 224010491SRishi.Srivatsavai@Sun.COM while ((mp = mpnext) != NULL) { 224110491SRishi.Srivatsavai@Sun.COM boolean_t raw_isis, bridge_group; 224210491SRishi.Srivatsavai@Sun.COM 224310491SRishi.Srivatsavai@Sun.COM mpnext = mp->b_next; 224410491SRishi.Srivatsavai@Sun.COM 224510491SRishi.Srivatsavai@Sun.COM /* 224610491SRishi.Srivatsavai@Sun.COM * If the header isn't readable, then leave on 224710491SRishi.Srivatsavai@Sun.COM * the list and continue. 224810491SRishi.Srivatsavai@Sun.COM */ 224910491SRishi.Srivatsavai@Sun.COM if (mac_header_info(blp->bl_mh, mp, 225010491SRishi.Srivatsavai@Sun.COM &hdr_info) != 0) { 225110491SRishi.Srivatsavai@Sun.COM tail = mp; 225210491SRishi.Srivatsavai@Sun.COM continue; 225310491SRishi.Srivatsavai@Sun.COM } 225410491SRishi.Srivatsavai@Sun.COM 225510491SRishi.Srivatsavai@Sun.COM /* 225610491SRishi.Srivatsavai@Sun.COM * The TRILL document specifies that, on 225710491SRishi.Srivatsavai@Sun.COM * Ethernet alone, IS-IS packets arrive with 225810491SRishi.Srivatsavai@Sun.COM * LLC rather than Ethertype, and using a 225910491SRishi.Srivatsavai@Sun.COM * specific destination address. We must check 226010491SRishi.Srivatsavai@Sun.COM * for that here. Also, we need to give BPDUs 226110491SRishi.Srivatsavai@Sun.COM * to TRILL for processing. 226210491SRishi.Srivatsavai@Sun.COM */ 226310491SRishi.Srivatsavai@Sun.COM raw_isis = bridge_group = B_FALSE; 226410491SRishi.Srivatsavai@Sun.COM if (hdr_info.mhi_dsttype == 226510491SRishi.Srivatsavai@Sun.COM MAC_ADDRTYPE_MULTICAST) { 226610491SRishi.Srivatsavai@Sun.COM if (memcmp(hdr_info.mhi_daddr, 226710491SRishi.Srivatsavai@Sun.COM all_isis_rbridges, ETHERADDRL) == 0) 226810491SRishi.Srivatsavai@Sun.COM raw_isis = B_TRUE; 226910491SRishi.Srivatsavai@Sun.COM else if (memcmp(hdr_info.mhi_daddr, 227010491SRishi.Srivatsavai@Sun.COM bridge_group_address, ETHERADDRL) == 227110491SRishi.Srivatsavai@Sun.COM 0) 227210491SRishi.Srivatsavai@Sun.COM bridge_group = B_TRUE; 227310491SRishi.Srivatsavai@Sun.COM } 227410491SRishi.Srivatsavai@Sun.COM if (!raw_isis && !bridge_group && 227510491SRishi.Srivatsavai@Sun.COM hdr_info.mhi_bindsap != ETHERTYPE_TRILL && 227610491SRishi.Srivatsavai@Sun.COM (hdr_info.mhi_bindsap != ETHERTYPE_VLAN || 227710491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 227810491SRishi.Srivatsavai@Sun.COM ((struct ether_vlan_header *)mp->b_rptr)-> 227910491SRishi.Srivatsavai@Sun.COM ether_type != htons(ETHERTYPE_TRILL))) { 228010491SRishi.Srivatsavai@Sun.COM tail = mp; 228110491SRishi.Srivatsavai@Sun.COM continue; 228210491SRishi.Srivatsavai@Sun.COM } 228310491SRishi.Srivatsavai@Sun.COM 228410491SRishi.Srivatsavai@Sun.COM /* 228510491SRishi.Srivatsavai@Sun.COM * We've got TRILL input. Remove from the list 228610491SRishi.Srivatsavai@Sun.COM * and send up through the TRILL module. (Send 228710491SRishi.Srivatsavai@Sun.COM * a copy through promiscuous receive just to 228810491SRishi.Srivatsavai@Sun.COM * support snooping on TRILL. Order isn't 228910491SRishi.Srivatsavai@Sun.COM * preserved strictly, but that doesn't matter 229010491SRishi.Srivatsavai@Sun.COM * here.) 229110491SRishi.Srivatsavai@Sun.COM */ 229210491SRishi.Srivatsavai@Sun.COM if (tail != NULL) 229310491SRishi.Srivatsavai@Sun.COM tail->b_next = mpnext; 229410491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 229510491SRishi.Srivatsavai@Sun.COM if (mp == newhead) 229610491SRishi.Srivatsavai@Sun.COM newhead = mpnext; 229710491SRishi.Srivatsavai@Sun.COM mac_trill_snoop(blp->bl_mh, mp); 229810491SRishi.Srivatsavai@Sun.COM update_header(mp, &hdr_info, B_TRUE); 229910491SRishi.Srivatsavai@Sun.COM /* 230010491SRishi.Srivatsavai@Sun.COM * On raw IS-IS and BPDU frames, we have to 230110491SRishi.Srivatsavai@Sun.COM * make sure that the length is trimmed 230210491SRishi.Srivatsavai@Sun.COM * properly. We use origsap in order to cope 230310491SRishi.Srivatsavai@Sun.COM * with jumbograms for IS-IS. (Regular mac 230410491SRishi.Srivatsavai@Sun.COM * can't.) 230510491SRishi.Srivatsavai@Sun.COM */ 230610491SRishi.Srivatsavai@Sun.COM if (raw_isis || bridge_group) { 230710491SRishi.Srivatsavai@Sun.COM size_t msglen = msgdsize(mp); 230810491SRishi.Srivatsavai@Sun.COM 230910491SRishi.Srivatsavai@Sun.COM if (msglen > hdr_info.mhi_origsap) { 231010491SRishi.Srivatsavai@Sun.COM (void) adjmsg(mp, 231110491SRishi.Srivatsavai@Sun.COM hdr_info.mhi_origsap - 231210491SRishi.Srivatsavai@Sun.COM msglen); 231310491SRishi.Srivatsavai@Sun.COM } else if (msglen < 231410491SRishi.Srivatsavai@Sun.COM hdr_info.mhi_origsap) { 231510491SRishi.Srivatsavai@Sun.COM freemsg(mp); 231610491SRishi.Srivatsavai@Sun.COM continue; 231710491SRishi.Srivatsavai@Sun.COM } 231810491SRishi.Srivatsavai@Sun.COM } 231910491SRishi.Srivatsavai@Sun.COM trill_recv_fn(tdp, blp, rsrc, mp, &hdr_info); 232010491SRishi.Srivatsavai@Sun.COM } 232110491SRishi.Srivatsavai@Sun.COM mpnext = newhead; 232210491SRishi.Srivatsavai@Sun.COM mutex_enter(&blp->bl_trilllock); 232310491SRishi.Srivatsavai@Sun.COM if (--blp->bl_trillthreads == 0 && 232410491SRishi.Srivatsavai@Sun.COM blp->bl_trilldata == NULL) 232510491SRishi.Srivatsavai@Sun.COM cv_broadcast(&blp->bl_trillwait); 232610491SRishi.Srivatsavai@Sun.COM } 232710491SRishi.Srivatsavai@Sun.COM mutex_exit(&blp->bl_trilllock); 232810491SRishi.Srivatsavai@Sun.COM if (mpnext == NULL) 232910491SRishi.Srivatsavai@Sun.COM return; 233010491SRishi.Srivatsavai@Sun.COM } 233110491SRishi.Srivatsavai@Sun.COM 233210491SRishi.Srivatsavai@Sun.COM /* 233310491SRishi.Srivatsavai@Sun.COM * If this is a TRILL RBridge, then just check whether this link is 233410491SRishi.Srivatsavai@Sun.COM * used at all for forwarding. If not, then we're done. 233510491SRishi.Srivatsavai@Sun.COM */ 233610491SRishi.Srivatsavai@Sun.COM if (trillmode) { 233710491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_TRILLACTIVE) || 233810491SRishi.Srivatsavai@Sun.COM (blp->bl_flags & BLF_SDUFAIL)) { 233910491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mpnext); 234010491SRishi.Srivatsavai@Sun.COM return; 234110491SRishi.Srivatsavai@Sun.COM } 234210491SRishi.Srivatsavai@Sun.COM } else { 234310491SRishi.Srivatsavai@Sun.COM /* 234410491SRishi.Srivatsavai@Sun.COM * For regular (STP) bridges, if we're in blocking or listening 234510491SRishi.Srivatsavai@Sun.COM * state, then do nothing. We don't learn or forward until 234610491SRishi.Srivatsavai@Sun.COM * told to do so. 234710491SRishi.Srivatsavai@Sun.COM */ 234810491SRishi.Srivatsavai@Sun.COM if (blp->bl_state == BLS_BLOCKLISTEN) { 234910491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mpnext); 235010491SRishi.Srivatsavai@Sun.COM return; 235110491SRishi.Srivatsavai@Sun.COM } 235210491SRishi.Srivatsavai@Sun.COM } 235310491SRishi.Srivatsavai@Sun.COM 235410491SRishi.Srivatsavai@Sun.COM /* 235510491SRishi.Srivatsavai@Sun.COM * Send a copy of the message chain up to the observability node users. 235610491SRishi.Srivatsavai@Sun.COM * For TRILL, we must obey the VLAN AF rules, so we go packet-by- 235710491SRishi.Srivatsavai@Sun.COM * packet. 235810491SRishi.Srivatsavai@Sun.COM */ 235910491SRishi.Srivatsavai@Sun.COM if (!trillmode && blp->bl_state == BLS_FORWARDING && 236010491SRishi.Srivatsavai@Sun.COM (bmp->bm_flags & BMF_STARTED) && 236110491SRishi.Srivatsavai@Sun.COM (mp = copymsgchain(mpnext)) != NULL) { 236210491SRishi.Srivatsavai@Sun.COM mac_rx(bmp->bm_mh, NULL, mp); 236310491SRishi.Srivatsavai@Sun.COM } 236410491SRishi.Srivatsavai@Sun.COM 236510491SRishi.Srivatsavai@Sun.COM /* 236610491SRishi.Srivatsavai@Sun.COM * We must be in learning or forwarding state, or using TRILL on a link 236710491SRishi.Srivatsavai@Sun.COM * with one or more VLANs active. For each packet in the list, process 236810491SRishi.Srivatsavai@Sun.COM * the source address, and then attempt to forward. 236910491SRishi.Srivatsavai@Sun.COM */ 237010491SRishi.Srivatsavai@Sun.COM while ((mp = mpnext) != NULL) { 237110491SRishi.Srivatsavai@Sun.COM mpnext = mp->b_next; 237210491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 237310491SRishi.Srivatsavai@Sun.COM 237410491SRishi.Srivatsavai@Sun.COM /* 237510491SRishi.Srivatsavai@Sun.COM * If we can't decode the header or if the header specifies a 237610491SRishi.Srivatsavai@Sun.COM * multicast source address (impossible!), then don't bother 237710491SRishi.Srivatsavai@Sun.COM * learning or forwarding, but go ahead and forward up the 237810491SRishi.Srivatsavai@Sun.COM * stack for subsequent processing. 237910491SRishi.Srivatsavai@Sun.COM */ 238010491SRishi.Srivatsavai@Sun.COM if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0 || 238110491SRishi.Srivatsavai@Sun.COM (hdr_info.mhi_saddr[0] & 1) != 0) { 238210491SRishi.Srivatsavai@Sun.COM KIINCR(bki_drops); 238310491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_drops); 238410491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mp); 238510491SRishi.Srivatsavai@Sun.COM continue; 238610491SRishi.Srivatsavai@Sun.COM } 238710491SRishi.Srivatsavai@Sun.COM 238810491SRishi.Srivatsavai@Sun.COM /* 238910491SRishi.Srivatsavai@Sun.COM * Extract and validate the VLAN ID for this packet. 239010491SRishi.Srivatsavai@Sun.COM */ 239110491SRishi.Srivatsavai@Sun.COM if (!bridge_get_vlan(blp, &hdr_info, mp, &vlanid, &tci) || 239210491SRishi.Srivatsavai@Sun.COM !BRIDGE_AF_ISSET(blp, vlanid)) { 239310491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mp); 239410491SRishi.Srivatsavai@Sun.COM continue; 239510491SRishi.Srivatsavai@Sun.COM } 239610491SRishi.Srivatsavai@Sun.COM 239710491SRishi.Srivatsavai@Sun.COM if (trillmode) { 239810491SRishi.Srivatsavai@Sun.COM /* 239910491SRishi.Srivatsavai@Sun.COM * Special test required by TRILL document: must 240010491SRishi.Srivatsavai@Sun.COM * discard frames with outer address set to ESADI. 240110491SRishi.Srivatsavai@Sun.COM */ 240210491SRishi.Srivatsavai@Sun.COM if (memcmp(hdr_info.mhi_daddr, all_esadi_rbridges, 240310491SRishi.Srivatsavai@Sun.COM ETHERADDRL) == 0) { 240410491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mp); 240510491SRishi.Srivatsavai@Sun.COM continue; 240610491SRishi.Srivatsavai@Sun.COM } 240710491SRishi.Srivatsavai@Sun.COM 240810491SRishi.Srivatsavai@Sun.COM /* 240910491SRishi.Srivatsavai@Sun.COM * If we're in TRILL mode, then the call above to get 241010491SRishi.Srivatsavai@Sun.COM * the VLAN ID has also checked that we're the 241110491SRishi.Srivatsavai@Sun.COM * appointed forwarder, so report that we're handling 241210491SRishi.Srivatsavai@Sun.COM * this packet to any observability node users. 241310491SRishi.Srivatsavai@Sun.COM */ 241410491SRishi.Srivatsavai@Sun.COM if ((bmp->bm_flags & BMF_STARTED) && 241510491SRishi.Srivatsavai@Sun.COM (mpcopy = copymsg(mp)) != NULL) 241610491SRishi.Srivatsavai@Sun.COM mac_rx(bmp->bm_mh, NULL, mpcopy); 241710491SRishi.Srivatsavai@Sun.COM } 241810491SRishi.Srivatsavai@Sun.COM 241910491SRishi.Srivatsavai@Sun.COM /* 242010491SRishi.Srivatsavai@Sun.COM * First process the source address and learn from it. For 242110491SRishi.Srivatsavai@Sun.COM * TRILL, we learn only if we're the appointed forwarder. 242210491SRishi.Srivatsavai@Sun.COM */ 242310491SRishi.Srivatsavai@Sun.COM bridge_learn(blp, hdr_info.mhi_saddr, RBRIDGE_NICKNAME_NONE, 242410491SRishi.Srivatsavai@Sun.COM vlanid); 242510491SRishi.Srivatsavai@Sun.COM 242610491SRishi.Srivatsavai@Sun.COM /* 242710491SRishi.Srivatsavai@Sun.COM * Now check whether we're forwarding and look up the 242810491SRishi.Srivatsavai@Sun.COM * destination. If we can forward, do so. 242910491SRishi.Srivatsavai@Sun.COM */ 243010491SRishi.Srivatsavai@Sun.COM if (trillmode || blp->bl_state == BLS_FORWARDING) { 243110491SRishi.Srivatsavai@Sun.COM mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci, 243210491SRishi.Srivatsavai@Sun.COM B_FALSE, B_FALSE); 243310491SRishi.Srivatsavai@Sun.COM } 243410491SRishi.Srivatsavai@Sun.COM if (mp != NULL) 243510491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, rsrc, mp); 243610491SRishi.Srivatsavai@Sun.COM } 243710491SRishi.Srivatsavai@Sun.COM } 243810491SRishi.Srivatsavai@Sun.COM 243910491SRishi.Srivatsavai@Sun.COM 244010491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 244110491SRishi.Srivatsavai@Sun.COM static mblk_t * 244210491SRishi.Srivatsavai@Sun.COM bridge_xmit_cb(mac_handle_t mh, mac_ring_handle_t rh, mblk_t *mpnext) 244310491SRishi.Srivatsavai@Sun.COM { 244410491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = (bridge_link_t *)mh; 244510491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 244610491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp = bip->bi_mac; 244710491SRishi.Srivatsavai@Sun.COM mac_header_info_t hdr_info; 244810491SRishi.Srivatsavai@Sun.COM uint16_t vlanid, tci; 244910491SRishi.Srivatsavai@Sun.COM mblk_t *mp, *mpcopy; 245010491SRishi.Srivatsavai@Sun.COM boolean_t trillmode; 245110491SRishi.Srivatsavai@Sun.COM 245210491SRishi.Srivatsavai@Sun.COM trillmode = blp->bl_trilldata != NULL; 245310491SRishi.Srivatsavai@Sun.COM 245410491SRishi.Srivatsavai@Sun.COM /* 245510491SRishi.Srivatsavai@Sun.COM * If we're using STP and we're in blocking or listening state, or if 245610491SRishi.Srivatsavai@Sun.COM * we're using TRILL and no VLANs are active, then behave as though the 245710491SRishi.Srivatsavai@Sun.COM * bridge isn't here at all, and send on the local link alone. 245810491SRishi.Srivatsavai@Sun.COM */ 245910491SRishi.Srivatsavai@Sun.COM if ((!trillmode && blp->bl_state == BLS_BLOCKLISTEN) || 246010491SRishi.Srivatsavai@Sun.COM (trillmode && 246110491SRishi.Srivatsavai@Sun.COM (!(blp->bl_flags & BLF_TRILLACTIVE) || 246210491SRishi.Srivatsavai@Sun.COM (blp->bl_flags & BLF_SDUFAIL)))) { 246310491SRishi.Srivatsavai@Sun.COM KIINCR(bki_sent); 246410491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_xmit); 246510491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blp->bl_mh, rh, mpnext, mp); 246610491SRishi.Srivatsavai@Sun.COM return (mp); 246710491SRishi.Srivatsavai@Sun.COM } 246810491SRishi.Srivatsavai@Sun.COM 246910491SRishi.Srivatsavai@Sun.COM /* 247010491SRishi.Srivatsavai@Sun.COM * Send a copy of the message up to the observability node users. 247110491SRishi.Srivatsavai@Sun.COM * TRILL needs to check on a packet-by-packet basis. 247210491SRishi.Srivatsavai@Sun.COM */ 247310491SRishi.Srivatsavai@Sun.COM if (!trillmode && blp->bl_state == BLS_FORWARDING && 247410491SRishi.Srivatsavai@Sun.COM (bmp->bm_flags & BMF_STARTED) && 247510491SRishi.Srivatsavai@Sun.COM (mp = copymsgchain(mpnext)) != NULL) { 247610491SRishi.Srivatsavai@Sun.COM mac_rx(bmp->bm_mh, NULL, mp); 247710491SRishi.Srivatsavai@Sun.COM } 247810491SRishi.Srivatsavai@Sun.COM 247910491SRishi.Srivatsavai@Sun.COM while ((mp = mpnext) != NULL) { 248010491SRishi.Srivatsavai@Sun.COM mpnext = mp->b_next; 248110491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 248210491SRishi.Srivatsavai@Sun.COM 248310491SRishi.Srivatsavai@Sun.COM if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0) { 248410491SRishi.Srivatsavai@Sun.COM freemsg(mp); 248510491SRishi.Srivatsavai@Sun.COM continue; 248610491SRishi.Srivatsavai@Sun.COM } 248710491SRishi.Srivatsavai@Sun.COM 248810491SRishi.Srivatsavai@Sun.COM /* 248910491SRishi.Srivatsavai@Sun.COM * Extract and validate the VLAN ID for this packet. 249010491SRishi.Srivatsavai@Sun.COM */ 249110491SRishi.Srivatsavai@Sun.COM if (!bridge_get_vlan(blp, &hdr_info, mp, &vlanid, &tci) || 249210491SRishi.Srivatsavai@Sun.COM !BRIDGE_AF_ISSET(blp, vlanid)) { 249310491SRishi.Srivatsavai@Sun.COM freemsg(mp); 249410491SRishi.Srivatsavai@Sun.COM continue; 249510491SRishi.Srivatsavai@Sun.COM } 249610491SRishi.Srivatsavai@Sun.COM 249710491SRishi.Srivatsavai@Sun.COM /* 249810491SRishi.Srivatsavai@Sun.COM * If we're using TRILL, then we've now validated that we're 249910491SRishi.Srivatsavai@Sun.COM * the forwarder for this VLAN, so go ahead and let 250010491SRishi.Srivatsavai@Sun.COM * observability node users know about the packet. 250110491SRishi.Srivatsavai@Sun.COM */ 250210491SRishi.Srivatsavai@Sun.COM if (trillmode && (bmp->bm_flags & BMF_STARTED) && 250310491SRishi.Srivatsavai@Sun.COM (mpcopy = copymsg(mp)) != NULL) { 250410491SRishi.Srivatsavai@Sun.COM mac_rx(bmp->bm_mh, NULL, mpcopy); 250510491SRishi.Srivatsavai@Sun.COM } 250610491SRishi.Srivatsavai@Sun.COM 250710491SRishi.Srivatsavai@Sun.COM /* 250810491SRishi.Srivatsavai@Sun.COM * We have to learn from our own transmitted packets, because 250910491SRishi.Srivatsavai@Sun.COM * there may be a Solaris DLPI raw sender (who can specify his 251010491SRishi.Srivatsavai@Sun.COM * own source address) using promiscuous mode for receive. The 251110491SRishi.Srivatsavai@Sun.COM * mac layer information won't (and can't) tell us everything 251210491SRishi.Srivatsavai@Sun.COM * we need to know. 251310491SRishi.Srivatsavai@Sun.COM */ 251410491SRishi.Srivatsavai@Sun.COM bridge_learn(blp, hdr_info.mhi_saddr, RBRIDGE_NICKNAME_NONE, 251510491SRishi.Srivatsavai@Sun.COM vlanid); 251610491SRishi.Srivatsavai@Sun.COM 251710491SRishi.Srivatsavai@Sun.COM /* attempt forwarding */ 251810491SRishi.Srivatsavai@Sun.COM if (trillmode || blp->bl_state == BLS_FORWARDING) { 251910491SRishi.Srivatsavai@Sun.COM mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci, 252010491SRishi.Srivatsavai@Sun.COM B_FALSE, B_TRUE); 252110491SRishi.Srivatsavai@Sun.COM } 252210491SRishi.Srivatsavai@Sun.COM if (mp != NULL) { 252310491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blp->bl_mh, rh, mp, mp); 252410491SRishi.Srivatsavai@Sun.COM if (mp == NULL) { 252510491SRishi.Srivatsavai@Sun.COM KIINCR(bki_sent); 252610491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_xmit); 252710491SRishi.Srivatsavai@Sun.COM } 252810491SRishi.Srivatsavai@Sun.COM } 252910491SRishi.Srivatsavai@Sun.COM /* 253010491SRishi.Srivatsavai@Sun.COM * If we get stuck, then stop. Don't let the user's output 253110491SRishi.Srivatsavai@Sun.COM * packets get out of order. (More importantly: don't try to 253210491SRishi.Srivatsavai@Sun.COM * bridge the same packet multiple times if flow control is 253310491SRishi.Srivatsavai@Sun.COM * asserted.) 253410491SRishi.Srivatsavai@Sun.COM */ 253510491SRishi.Srivatsavai@Sun.COM if (mp != NULL) { 253610491SRishi.Srivatsavai@Sun.COM mp->b_next = mpnext; 253710491SRishi.Srivatsavai@Sun.COM break; 253810491SRishi.Srivatsavai@Sun.COM } 253910491SRishi.Srivatsavai@Sun.COM } 254010491SRishi.Srivatsavai@Sun.COM return (mp); 254110491SRishi.Srivatsavai@Sun.COM } 254210491SRishi.Srivatsavai@Sun.COM 254310491SRishi.Srivatsavai@Sun.COM /* 254410491SRishi.Srivatsavai@Sun.COM * This is called by TRILL when it decapsulates an packet, and we must forward 254510491SRishi.Srivatsavai@Sun.COM * locally. On failure, we just drop. 254610491SRishi.Srivatsavai@Sun.COM * 254710491SRishi.Srivatsavai@Sun.COM * Note that the ingress_nick reported by TRILL must not represent this local 254810491SRishi.Srivatsavai@Sun.COM * node. 254910491SRishi.Srivatsavai@Sun.COM */ 255010491SRishi.Srivatsavai@Sun.COM void 255110491SRishi.Srivatsavai@Sun.COM bridge_trill_decaps(bridge_link_t *blp, mblk_t *mp, uint16_t ingress_nick) 255210491SRishi.Srivatsavai@Sun.COM { 255310491SRishi.Srivatsavai@Sun.COM mac_header_info_t hdr_info; 255410491SRishi.Srivatsavai@Sun.COM uint16_t vlanid, tci; 255510491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; /* used by macros */ 255610491SRishi.Srivatsavai@Sun.COM mblk_t *mpcopy; 255710491SRishi.Srivatsavai@Sun.COM 255810491SRishi.Srivatsavai@Sun.COM if (mac_header_info(blp->bl_mh, mp, &hdr_info) != 0) { 255910491SRishi.Srivatsavai@Sun.COM freemsg(mp); 256010491SRishi.Srivatsavai@Sun.COM return; 256110491SRishi.Srivatsavai@Sun.COM } 256210491SRishi.Srivatsavai@Sun.COM 256310491SRishi.Srivatsavai@Sun.COM /* Extract VLAN ID for this packet. */ 256410491SRishi.Srivatsavai@Sun.COM if (hdr_info.mhi_bindsap == ETHERTYPE_VLAN) { 256510491SRishi.Srivatsavai@Sun.COM struct ether_vlan_header *evhp; 256610491SRishi.Srivatsavai@Sun.COM 256710491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 256810491SRishi.Srivatsavai@Sun.COM evhp = (struct ether_vlan_header *)mp->b_rptr; 256910491SRishi.Srivatsavai@Sun.COM tci = ntohs(evhp->ether_tci); 257010491SRishi.Srivatsavai@Sun.COM vlanid = VLAN_ID(tci); 257110491SRishi.Srivatsavai@Sun.COM } else { 257210491SRishi.Srivatsavai@Sun.COM /* Inner VLAN headers are required in TRILL data packets */ 257310491SRishi.Srivatsavai@Sun.COM DTRACE_PROBE3(bridge__trill__decaps__novlan, bridge_link_t *, 257410491SRishi.Srivatsavai@Sun.COM blp, mblk_t *, mp, uint16_t, ingress_nick); 257510491SRishi.Srivatsavai@Sun.COM freemsg(mp); 257610491SRishi.Srivatsavai@Sun.COM return; 257710491SRishi.Srivatsavai@Sun.COM } 257810491SRishi.Srivatsavai@Sun.COM 257910491SRishi.Srivatsavai@Sun.COM /* Learn the location of this sender in the RBridge network */ 258010491SRishi.Srivatsavai@Sun.COM bridge_learn(blp, hdr_info.mhi_saddr, ingress_nick, vlanid); 258110491SRishi.Srivatsavai@Sun.COM 258210491SRishi.Srivatsavai@Sun.COM /* attempt forwarding */ 258310491SRishi.Srivatsavai@Sun.COM mp = bridge_forward(blp, &hdr_info, mp, vlanid, tci, B_TRUE, B_TRUE); 258410491SRishi.Srivatsavai@Sun.COM if (mp != NULL) { 258510491SRishi.Srivatsavai@Sun.COM if (bridge_can_send(blp, vlanid)) { 258610491SRishi.Srivatsavai@Sun.COM /* Deliver a copy locally as well */ 258710491SRishi.Srivatsavai@Sun.COM if ((mpcopy = copymsg(mp)) != NULL) 258810491SRishi.Srivatsavai@Sun.COM mac_rx_common(blp->bl_mh, NULL, mpcopy); 258910491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blp->bl_mh, NULL, mp, mp); 259010491SRishi.Srivatsavai@Sun.COM } 259110491SRishi.Srivatsavai@Sun.COM if (mp == NULL) { 259210491SRishi.Srivatsavai@Sun.COM KIINCR(bki_sent); 259310491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_xmit); 259410491SRishi.Srivatsavai@Sun.COM } else { 259510491SRishi.Srivatsavai@Sun.COM freemsg(mp); 259610491SRishi.Srivatsavai@Sun.COM } 259710491SRishi.Srivatsavai@Sun.COM } 259810491SRishi.Srivatsavai@Sun.COM } 259910491SRishi.Srivatsavai@Sun.COM 260010491SRishi.Srivatsavai@Sun.COM /* 260110491SRishi.Srivatsavai@Sun.COM * This function is used by TRILL _only_ to transmit TRILL-encapsulated 260210491SRishi.Srivatsavai@Sun.COM * packets. It sends on a single underlying link and does not bridge. 260310491SRishi.Srivatsavai@Sun.COM */ 260410491SRishi.Srivatsavai@Sun.COM mblk_t * 260510491SRishi.Srivatsavai@Sun.COM bridge_trill_output(bridge_link_t *blp, mblk_t *mp) 260610491SRishi.Srivatsavai@Sun.COM { 260710491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; /* used by macros */ 260810491SRishi.Srivatsavai@Sun.COM 260910491SRishi.Srivatsavai@Sun.COM mac_trill_snoop(blp->bl_mh, mp); 261010491SRishi.Srivatsavai@Sun.COM MAC_RING_TX(blp->bl_mh, NULL, mp, mp); 261110491SRishi.Srivatsavai@Sun.COM if (mp == NULL) { 261210491SRishi.Srivatsavai@Sun.COM KIINCR(bki_sent); 261310491SRishi.Srivatsavai@Sun.COM KLINCR(bkl_xmit); 261410491SRishi.Srivatsavai@Sun.COM } 261510491SRishi.Srivatsavai@Sun.COM return (mp); 261610491SRishi.Srivatsavai@Sun.COM } 261710491SRishi.Srivatsavai@Sun.COM 261810491SRishi.Srivatsavai@Sun.COM /* 261910491SRishi.Srivatsavai@Sun.COM * Set the "appointed forwarder" flag array for this link. TRILL controls 262010491SRishi.Srivatsavai@Sun.COM * forwarding on a VLAN basis. The "trillactive" flag is an optimization for 262110491SRishi.Srivatsavai@Sun.COM * the forwarder. 262210491SRishi.Srivatsavai@Sun.COM */ 262310491SRishi.Srivatsavai@Sun.COM void 262410491SRishi.Srivatsavai@Sun.COM bridge_trill_setvlans(bridge_link_t *blp, const uint8_t *arr) 262510491SRishi.Srivatsavai@Sun.COM { 262610491SRishi.Srivatsavai@Sun.COM int i; 262710491SRishi.Srivatsavai@Sun.COM uint_t newflags = 0; 262810491SRishi.Srivatsavai@Sun.COM 262910491SRishi.Srivatsavai@Sun.COM for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) { 263010491SRishi.Srivatsavai@Sun.COM if ((blp->bl_afs[i] = arr[i]) != 0) 263110491SRishi.Srivatsavai@Sun.COM newflags = BLF_TRILLACTIVE; 263210491SRishi.Srivatsavai@Sun.COM } 263310491SRishi.Srivatsavai@Sun.COM blp->bl_flags = (blp->bl_flags & ~BLF_TRILLACTIVE) | newflags; 263410491SRishi.Srivatsavai@Sun.COM } 263510491SRishi.Srivatsavai@Sun.COM 263610491SRishi.Srivatsavai@Sun.COM void 263710491SRishi.Srivatsavai@Sun.COM bridge_trill_flush(bridge_link_t *blp, uint16_t vlan, boolean_t dotrill) 263810491SRishi.Srivatsavai@Sun.COM { 263910491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip = blp->bl_inst; 264010491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfnext; 264110491SRishi.Srivatsavai@Sun.COM avl_tree_t fwd_scavenge; 264210491SRishi.Srivatsavai@Sun.COM int i; 264310491SRishi.Srivatsavai@Sun.COM 264410491SRishi.Srivatsavai@Sun.COM _NOTE(ARGUNUSED(vlan)); 264510491SRishi.Srivatsavai@Sun.COM 264610491SRishi.Srivatsavai@Sun.COM avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 264710491SRishi.Srivatsavai@Sun.COM offsetof(bridge_fwd_t, bf_node)); 264810491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 264910491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&bip->bi_fwd); 265010491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 265110491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 265210491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_LOCALADDR) 265310491SRishi.Srivatsavai@Sun.COM continue; 265410491SRishi.Srivatsavai@Sun.COM if (dotrill) { 265510491SRishi.Srivatsavai@Sun.COM /* port doesn't matter if we're flushing TRILL */ 265610491SRishi.Srivatsavai@Sun.COM if (bfp->bf_trill_nick == RBRIDGE_NICKNAME_NONE) 265710491SRishi.Srivatsavai@Sun.COM continue; 265810491SRishi.Srivatsavai@Sun.COM } else { 265910491SRishi.Srivatsavai@Sun.COM if (bfp->bf_trill_nick != RBRIDGE_NICKNAME_NONE) 266010491SRishi.Srivatsavai@Sun.COM continue; 266110491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_nlinks; i++) { 266210491SRishi.Srivatsavai@Sun.COM if (bfp->bf_links[i] == blp) 266310491SRishi.Srivatsavai@Sun.COM break; 266410491SRishi.Srivatsavai@Sun.COM } 266510491SRishi.Srivatsavai@Sun.COM if (i >= bfp->bf_nlinks) 266610491SRishi.Srivatsavai@Sun.COM continue; 266710491SRishi.Srivatsavai@Sun.COM } 266810491SRishi.Srivatsavai@Sun.COM ASSERT(bfp->bf_flags & BFF_INTREE); 266910491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 267010491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 267110491SRishi.Srivatsavai@Sun.COM avl_add(&fwd_scavenge, bfp); 267210491SRishi.Srivatsavai@Sun.COM } 267310491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 267410491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&fwd_scavenge); 267510491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 267610491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&fwd_scavenge, bfp); 267710491SRishi.Srivatsavai@Sun.COM avl_remove(&fwd_scavenge, bfp); 267810491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); 267910491SRishi.Srivatsavai@Sun.COM } 268010491SRishi.Srivatsavai@Sun.COM avl_destroy(&fwd_scavenge); 268110491SRishi.Srivatsavai@Sun.COM } 268210491SRishi.Srivatsavai@Sun.COM 268310491SRishi.Srivatsavai@Sun.COM /* 268410491SRishi.Srivatsavai@Sun.COM * Let the mac module take or drop a reference to a bridge link. When this is 268510491SRishi.Srivatsavai@Sun.COM * called, the mac module is holding the mi_bridge_lock, so the link cannot be 268610491SRishi.Srivatsavai@Sun.COM * in the process of entering or leaving a bridge. 268710491SRishi.Srivatsavai@Sun.COM */ 268810491SRishi.Srivatsavai@Sun.COM static void 268910491SRishi.Srivatsavai@Sun.COM bridge_ref_cb(mac_handle_t mh, boolean_t hold) 269010491SRishi.Srivatsavai@Sun.COM { 269110491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = (bridge_link_t *)mh; 269210491SRishi.Srivatsavai@Sun.COM 269310491SRishi.Srivatsavai@Sun.COM if (hold) 269410491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&blp->bl_refs); 269510491SRishi.Srivatsavai@Sun.COM else 269610491SRishi.Srivatsavai@Sun.COM link_unref(blp); 269710491SRishi.Srivatsavai@Sun.COM } 269810491SRishi.Srivatsavai@Sun.COM 269910491SRishi.Srivatsavai@Sun.COM /* 270010491SRishi.Srivatsavai@Sun.COM * Handle link state changes reported by the mac layer. This acts as a filter 270110491SRishi.Srivatsavai@Sun.COM * for link state changes: if a link is reporting down, but there are other 270210491SRishi.Srivatsavai@Sun.COM * links still up on the bridge, then the state is changed to "up." When the 270310491SRishi.Srivatsavai@Sun.COM * last link goes down, all are marked down, and when the first link goes up, 270410491SRishi.Srivatsavai@Sun.COM * all are marked up. (Recursion is avoided by the use of the "redo" function.) 270510491SRishi.Srivatsavai@Sun.COM * 270610491SRishi.Srivatsavai@Sun.COM * We treat unknown as equivalent to "up." 270710491SRishi.Srivatsavai@Sun.COM */ 270810491SRishi.Srivatsavai@Sun.COM static link_state_t 270910491SRishi.Srivatsavai@Sun.COM bridge_ls_cb(mac_handle_t mh, link_state_t newls) 271010491SRishi.Srivatsavai@Sun.COM { 271110491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = (bridge_link_t *)mh; 271210491SRishi.Srivatsavai@Sun.COM bridge_link_t *blcmp; 271310491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 271410491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp; 271510491SRishi.Srivatsavai@Sun.COM 271610491SRishi.Srivatsavai@Sun.COM if (newls != LINK_STATE_DOWN && blp->bl_linkstate != LINK_STATE_DOWN || 271710491SRishi.Srivatsavai@Sun.COM (blp->bl_flags & (BLF_DELETED|BLF_SDUFAIL))) { 271810491SRishi.Srivatsavai@Sun.COM blp->bl_linkstate = newls; 271910491SRishi.Srivatsavai@Sun.COM return (newls); 272010491SRishi.Srivatsavai@Sun.COM } 272110491SRishi.Srivatsavai@Sun.COM 272210491SRishi.Srivatsavai@Sun.COM /* 272310491SRishi.Srivatsavai@Sun.COM * Scan first to see if there are any other non-down links. If there 272410491SRishi.Srivatsavai@Sun.COM * are, then we're done. Otherwise, if all others are down, then the 272510491SRishi.Srivatsavai@Sun.COM * state of this link is the state of the bridge. 272610491SRishi.Srivatsavai@Sun.COM */ 272710491SRishi.Srivatsavai@Sun.COM bip = blp->bl_inst; 272810491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 272910491SRishi.Srivatsavai@Sun.COM for (blcmp = list_head(&bip->bi_links); blcmp != NULL; 273010491SRishi.Srivatsavai@Sun.COM blcmp = list_next(&bip->bi_links, blcmp)) { 273110491SRishi.Srivatsavai@Sun.COM if (blcmp != blp && 273210491SRishi.Srivatsavai@Sun.COM !(blcmp->bl_flags & (BLF_DELETED|BLF_SDUFAIL)) && 273310491SRishi.Srivatsavai@Sun.COM blcmp->bl_linkstate != LINK_STATE_DOWN) 273410491SRishi.Srivatsavai@Sun.COM break; 273510491SRishi.Srivatsavai@Sun.COM } 273610491SRishi.Srivatsavai@Sun.COM 273710491SRishi.Srivatsavai@Sun.COM if (blcmp != NULL) { 273810491SRishi.Srivatsavai@Sun.COM /* 273910491SRishi.Srivatsavai@Sun.COM * If there are other links that are considered up, then tell 274010491SRishi.Srivatsavai@Sun.COM * the caller that the link is actually still up, regardless of 274110491SRishi.Srivatsavai@Sun.COM * this link's underlying state. 274210491SRishi.Srivatsavai@Sun.COM */ 274310491SRishi.Srivatsavai@Sun.COM blp->bl_linkstate = newls; 274410491SRishi.Srivatsavai@Sun.COM newls = LINK_STATE_UP; 274510491SRishi.Srivatsavai@Sun.COM } else if (blp->bl_linkstate != newls) { 274610491SRishi.Srivatsavai@Sun.COM /* 274710491SRishi.Srivatsavai@Sun.COM * If we've found no other 'up' links, and this link has 274810491SRishi.Srivatsavai@Sun.COM * changed state, then report the new state of the bridge to 274910491SRishi.Srivatsavai@Sun.COM * all other clients. 275010491SRishi.Srivatsavai@Sun.COM */ 275110491SRishi.Srivatsavai@Sun.COM blp->bl_linkstate = newls; 275210491SRishi.Srivatsavai@Sun.COM for (blcmp = list_head(&bip->bi_links); blcmp != NULL; 275310491SRishi.Srivatsavai@Sun.COM blcmp = list_next(&bip->bi_links, blcmp)) { 275410491SRishi.Srivatsavai@Sun.COM if (blcmp != blp && !(blcmp->bl_flags & BLF_DELETED)) 275510491SRishi.Srivatsavai@Sun.COM mac_link_redo(blcmp->bl_mh, newls); 275610491SRishi.Srivatsavai@Sun.COM } 275710491SRishi.Srivatsavai@Sun.COM bmp = bip->bi_mac; 275810491SRishi.Srivatsavai@Sun.COM if ((bmp->bm_linkstate = newls) != LINK_STATE_DOWN) 275910491SRishi.Srivatsavai@Sun.COM bmp->bm_linkstate = LINK_STATE_UP; 276010491SRishi.Srivatsavai@Sun.COM mac_link_redo(bmp->bm_mh, bmp->bm_linkstate); 276110491SRishi.Srivatsavai@Sun.COM } 276210491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 276310491SRishi.Srivatsavai@Sun.COM return (newls); 276410491SRishi.Srivatsavai@Sun.COM } 276510491SRishi.Srivatsavai@Sun.COM 276610491SRishi.Srivatsavai@Sun.COM static void 276710491SRishi.Srivatsavai@Sun.COM bridge_add_link(void *arg) 276810491SRishi.Srivatsavai@Sun.COM { 276910491SRishi.Srivatsavai@Sun.COM mblk_t *mp = arg; 277010491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp; 277110491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip, *bipt; 277210491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp; 277310491SRishi.Srivatsavai@Sun.COM datalink_id_t linkid; 277410491SRishi.Srivatsavai@Sun.COM int err; 277510491SRishi.Srivatsavai@Sun.COM mac_handle_t mh; 277610491SRishi.Srivatsavai@Sun.COM uint_t maxsdu; 277710491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp = NULL, *blpt; 277810491SRishi.Srivatsavai@Sun.COM const mac_info_t *mip; 277910491SRishi.Srivatsavai@Sun.COM boolean_t macopen = B_FALSE; 278010491SRishi.Srivatsavai@Sun.COM char linkname[MAXLINKNAMELEN]; 278110491SRishi.Srivatsavai@Sun.COM char kstatname[KSTAT_STRLEN]; 278210491SRishi.Srivatsavai@Sun.COM int i; 278310491SRishi.Srivatsavai@Sun.COM link_state_t linkstate; 278410491SRishi.Srivatsavai@Sun.COM mblk_t *mlist; 278510491SRishi.Srivatsavai@Sun.COM 278610491SRishi.Srivatsavai@Sun.COM bsp = (bridge_stream_t *)mp->b_next; 278710491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 278810491SRishi.Srivatsavai@Sun.COM bip = bsp->bs_inst; 278910491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 279010491SRishi.Srivatsavai@Sun.COM linkid = *(datalink_id_t *)mp->b_cont->b_rptr; 279110491SRishi.Srivatsavai@Sun.COM 279210491SRishi.Srivatsavai@Sun.COM /* 279310491SRishi.Srivatsavai@Sun.COM * First make sure that there is no other bridge that has this link. 279410491SRishi.Srivatsavai@Sun.COM * We don't want to overlap operations from two bridges; the MAC layer 279510491SRishi.Srivatsavai@Sun.COM * supports only one bridge on a given MAC at a time. 279610491SRishi.Srivatsavai@Sun.COM * 279710491SRishi.Srivatsavai@Sun.COM * We rely on the fact that there's just one taskq thread for the 279810491SRishi.Srivatsavai@Sun.COM * bridging module: once we've checked for a duplicate, we can drop the 279910491SRishi.Srivatsavai@Sun.COM * lock, because no other thread could possibly be adding another link 280010491SRishi.Srivatsavai@Sun.COM * until we're done. 280110491SRishi.Srivatsavai@Sun.COM */ 280210491SRishi.Srivatsavai@Sun.COM mutex_enter(&inst_lock); 280310491SRishi.Srivatsavai@Sun.COM for (bipt = list_head(&inst_list); bipt != NULL; 280410491SRishi.Srivatsavai@Sun.COM bipt = list_next(&inst_list, bipt)) { 280510491SRishi.Srivatsavai@Sun.COM rw_enter(&bipt->bi_rwlock, RW_READER); 280610491SRishi.Srivatsavai@Sun.COM for (blpt = list_head(&bipt->bi_links); blpt != NULL; 280710491SRishi.Srivatsavai@Sun.COM blpt = list_next(&bipt->bi_links, blpt)) { 280810491SRishi.Srivatsavai@Sun.COM if (linkid == blpt->bl_linkid) 280910491SRishi.Srivatsavai@Sun.COM break; 281010491SRishi.Srivatsavai@Sun.COM } 281110491SRishi.Srivatsavai@Sun.COM rw_exit(&bipt->bi_rwlock); 281210491SRishi.Srivatsavai@Sun.COM if (blpt != NULL) 281310491SRishi.Srivatsavai@Sun.COM break; 281410491SRishi.Srivatsavai@Sun.COM } 281510491SRishi.Srivatsavai@Sun.COM mutex_exit(&inst_lock); 281610491SRishi.Srivatsavai@Sun.COM if (bipt != NULL) { 281710491SRishi.Srivatsavai@Sun.COM err = EBUSY; 281810491SRishi.Srivatsavai@Sun.COM goto fail; 281910491SRishi.Srivatsavai@Sun.COM } 282010491SRishi.Srivatsavai@Sun.COM 282110491SRishi.Srivatsavai@Sun.COM if ((err = mac_open_by_linkid(linkid, &mh)) != 0) 282210491SRishi.Srivatsavai@Sun.COM goto fail; 282310491SRishi.Srivatsavai@Sun.COM macopen = B_TRUE; 282410491SRishi.Srivatsavai@Sun.COM 282510491SRishi.Srivatsavai@Sun.COM /* we bridge only Ethernet */ 282610491SRishi.Srivatsavai@Sun.COM mip = mac_info(mh); 282710491SRishi.Srivatsavai@Sun.COM if (mip->mi_media != DL_ETHER) { 282810491SRishi.Srivatsavai@Sun.COM err = ENOTSUP; 282910491SRishi.Srivatsavai@Sun.COM goto fail; 283010491SRishi.Srivatsavai@Sun.COM } 283110491SRishi.Srivatsavai@Sun.COM 283210491SRishi.Srivatsavai@Sun.COM /* 283310491SRishi.Srivatsavai@Sun.COM * Get the current maximum SDU on this interface. If there are other 283410491SRishi.Srivatsavai@Sun.COM * links on the bridge, then this one must match, or it errors out. 283510491SRishi.Srivatsavai@Sun.COM * Otherwise, the first link becomes the standard for the new bridge. 283610491SRishi.Srivatsavai@Sun.COM */ 283710491SRishi.Srivatsavai@Sun.COM mac_sdu_get(mh, NULL, &maxsdu); 283810491SRishi.Srivatsavai@Sun.COM bmp = bip->bi_mac; 283910491SRishi.Srivatsavai@Sun.COM if (list_is_empty(&bip->bi_links)) { 284010491SRishi.Srivatsavai@Sun.COM bmp->bm_maxsdu = maxsdu; 284110491SRishi.Srivatsavai@Sun.COM (void) mac_maxsdu_update(bmp->bm_mh, maxsdu); 284210491SRishi.Srivatsavai@Sun.COM } 284310491SRishi.Srivatsavai@Sun.COM 284410491SRishi.Srivatsavai@Sun.COM /* figure the kstat name; also used as the mac client name */ 284510491SRishi.Srivatsavai@Sun.COM i = MBLKL(mp->b_cont) - sizeof (datalink_id_t); 284610491SRishi.Srivatsavai@Sun.COM if (i < 0 || i >= MAXLINKNAMELEN) 284710491SRishi.Srivatsavai@Sun.COM i = MAXLINKNAMELEN - 1; 284810491SRishi.Srivatsavai@Sun.COM bcopy(mp->b_cont->b_rptr + sizeof (datalink_id_t), linkname, i); 284910491SRishi.Srivatsavai@Sun.COM linkname[i] = '\0'; 285010491SRishi.Srivatsavai@Sun.COM (void) snprintf(kstatname, sizeof (kstatname), "%s-%s", bip->bi_name, 285110491SRishi.Srivatsavai@Sun.COM linkname); 285210491SRishi.Srivatsavai@Sun.COM 285310491SRishi.Srivatsavai@Sun.COM if ((blp = kmem_zalloc(sizeof (*blp), KM_NOSLEEP)) == NULL) { 285410491SRishi.Srivatsavai@Sun.COM err = ENOMEM; 285510491SRishi.Srivatsavai@Sun.COM goto fail; 285610491SRishi.Srivatsavai@Sun.COM } 285710491SRishi.Srivatsavai@Sun.COM blp->bl_lfailmp = allocb(sizeof (bridge_ctl_t), BPRI_MED); 285810491SRishi.Srivatsavai@Sun.COM if (blp->bl_lfailmp == NULL) { 285910491SRishi.Srivatsavai@Sun.COM kmem_free(blp, sizeof (*blp)); 2860*11483SRishi.Srivatsavai@Sun.COM blp = NULL; 286110491SRishi.Srivatsavai@Sun.COM err = ENOMEM; 286210491SRishi.Srivatsavai@Sun.COM goto fail; 286310491SRishi.Srivatsavai@Sun.COM } 286410491SRishi.Srivatsavai@Sun.COM 2865*11483SRishi.Srivatsavai@Sun.COM blp->bl_refs = 1; 286610491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bip->bi_refs); 286710491SRishi.Srivatsavai@Sun.COM blp->bl_inst = bip; 286810491SRishi.Srivatsavai@Sun.COM blp->bl_mh = mh; 286910491SRishi.Srivatsavai@Sun.COM blp->bl_linkid = linkid; 287010491SRishi.Srivatsavai@Sun.COM blp->bl_maxsdu = maxsdu; 287110491SRishi.Srivatsavai@Sun.COM cv_init(&blp->bl_trillwait, NULL, CV_DRIVER, NULL); 287210491SRishi.Srivatsavai@Sun.COM mutex_init(&blp->bl_trilllock, NULL, MUTEX_DRIVER, NULL); 287310491SRishi.Srivatsavai@Sun.COM (void) memset(blp->bl_afs, 0xff, sizeof (blp->bl_afs)); 287410491SRishi.Srivatsavai@Sun.COM 287510491SRishi.Srivatsavai@Sun.COM err = mac_client_open(mh, &blp->bl_mch, kstatname, 0); 287610491SRishi.Srivatsavai@Sun.COM if (err != 0) 287710491SRishi.Srivatsavai@Sun.COM goto fail; 287810491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_CLIENT_OPEN; 287910491SRishi.Srivatsavai@Sun.COM 288010491SRishi.Srivatsavai@Sun.COM err = mac_margin_add(mh, &blp->bl_margin, B_TRUE); 288110491SRishi.Srivatsavai@Sun.COM if (err != 0) 288210491SRishi.Srivatsavai@Sun.COM goto fail; 288310491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_MARGIN_ADDED; 288410491SRishi.Srivatsavai@Sun.COM 288510491SRishi.Srivatsavai@Sun.COM blp->bl_mnh = mac_notify_add(mh, bridge_notify_cb, blp); 288610491SRishi.Srivatsavai@Sun.COM 2887*11483SRishi.Srivatsavai@Sun.COM /* Enable Bridging on the link */ 288810491SRishi.Srivatsavai@Sun.COM err = mac_bridge_set(mh, (mac_handle_t)blp); 288910491SRishi.Srivatsavai@Sun.COM if (err != 0) 289010491SRishi.Srivatsavai@Sun.COM goto fail; 289110491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_SET_BRIDGE; 289210491SRishi.Srivatsavai@Sun.COM 289310491SRishi.Srivatsavai@Sun.COM err = mac_promisc_add(blp->bl_mch, MAC_CLIENT_PROMISC_ALL, NULL, 289410491SRishi.Srivatsavai@Sun.COM blp, &blp->bl_mphp, MAC_PROMISC_FLAGS_NO_TX_LOOP); 289510491SRishi.Srivatsavai@Sun.COM if (err != 0) 289610491SRishi.Srivatsavai@Sun.COM goto fail; 289710491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_PROM_ADDED; 289810491SRishi.Srivatsavai@Sun.COM 289910491SRishi.Srivatsavai@Sun.COM bridge_new_unicst(blp); 290010491SRishi.Srivatsavai@Sun.COM 290110491SRishi.Srivatsavai@Sun.COM blp->bl_ksp = kstat_setup((kstat_named_t *)&blp->bl_kstats, 290210491SRishi.Srivatsavai@Sun.COM link_kstats_list, Dim(link_kstats_list), kstatname); 290310491SRishi.Srivatsavai@Sun.COM 290410491SRishi.Srivatsavai@Sun.COM /* 290510491SRishi.Srivatsavai@Sun.COM * The link holds a reference to the bridge instance, so that the 290610491SRishi.Srivatsavai@Sun.COM * instance can't go away before the link is freed. The insertion into 2907*11483SRishi.Srivatsavai@Sun.COM * bi_links holds a reference on the link (reference set to 1 above). 2908*11483SRishi.Srivatsavai@Sun.COM * When marking as removed from bi_links (BLF_DELETED), drop the 2909*11483SRishi.Srivatsavai@Sun.COM * reference on the link. When freeing the link, drop the reference on 2910*11483SRishi.Srivatsavai@Sun.COM * the instance. BLF_LINK_ADDED tracks link insertion in bi_links list. 291110491SRishi.Srivatsavai@Sun.COM */ 291210491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 291310491SRishi.Srivatsavai@Sun.COM list_insert_tail(&bip->bi_links, blp); 2914*11483SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_LINK_ADDED; 291510491SRishi.Srivatsavai@Sun.COM 291610491SRishi.Srivatsavai@Sun.COM /* 291710491SRishi.Srivatsavai@Sun.COM * If the new link is no good on this bridge, then let the daemon know 291810491SRishi.Srivatsavai@Sun.COM * about the problem. 291910491SRishi.Srivatsavai@Sun.COM */ 292010491SRishi.Srivatsavai@Sun.COM mlist = NULL; 292110491SRishi.Srivatsavai@Sun.COM if (maxsdu != bmp->bm_maxsdu) 292210491SRishi.Srivatsavai@Sun.COM link_sdu_fail(blp, B_TRUE, &mlist); 292310491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 292410491SRishi.Srivatsavai@Sun.COM send_up_messages(bip, mlist); 292510491SRishi.Srivatsavai@Sun.COM 292610491SRishi.Srivatsavai@Sun.COM /* 292710491SRishi.Srivatsavai@Sun.COM * Trigger a link state update so that if this link is the first one 292810491SRishi.Srivatsavai@Sun.COM * "up" in the bridge, then we notify everyone. This triggers a trip 292910491SRishi.Srivatsavai@Sun.COM * through bridge_ls_cb. 293010491SRishi.Srivatsavai@Sun.COM */ 293110491SRishi.Srivatsavai@Sun.COM linkstate = mac_stat_get(mh, MAC_STAT_LOWLINK_STATE); 293210491SRishi.Srivatsavai@Sun.COM blp->bl_linkstate = LINK_STATE_DOWN; 293310491SRishi.Srivatsavai@Sun.COM mac_link_update(mh, linkstate); 293410491SRishi.Srivatsavai@Sun.COM 293510491SRishi.Srivatsavai@Sun.COM /* 293610491SRishi.Srivatsavai@Sun.COM * We now need to report back to the stream that invoked us, and then 293710491SRishi.Srivatsavai@Sun.COM * drop the reference on the stream that we're holding. 293810491SRishi.Srivatsavai@Sun.COM */ 293910491SRishi.Srivatsavai@Sun.COM miocack(bsp->bs_wq, mp, 0, 0); 294010491SRishi.Srivatsavai@Sun.COM stream_unref(bsp); 294110491SRishi.Srivatsavai@Sun.COM return; 294210491SRishi.Srivatsavai@Sun.COM 294310491SRishi.Srivatsavai@Sun.COM fail: 294410491SRishi.Srivatsavai@Sun.COM if (blp == NULL) { 294510491SRishi.Srivatsavai@Sun.COM if (macopen) 294610491SRishi.Srivatsavai@Sun.COM mac_close(mh); 294710491SRishi.Srivatsavai@Sun.COM } else { 294810491SRishi.Srivatsavai@Sun.COM link_shutdown(blp); 294910491SRishi.Srivatsavai@Sun.COM } 295010491SRishi.Srivatsavai@Sun.COM miocnak(bsp->bs_wq, mp, 0, err); 295110491SRishi.Srivatsavai@Sun.COM stream_unref(bsp); 295210491SRishi.Srivatsavai@Sun.COM } 295310491SRishi.Srivatsavai@Sun.COM 295410491SRishi.Srivatsavai@Sun.COM static void 295510491SRishi.Srivatsavai@Sun.COM bridge_rem_link(void *arg) 295610491SRishi.Srivatsavai@Sun.COM { 295710491SRishi.Srivatsavai@Sun.COM mblk_t *mp = arg; 295810491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp; 295910491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 296010491SRishi.Srivatsavai@Sun.COM bridge_mac_t *bmp; 296110491SRishi.Srivatsavai@Sun.COM datalink_id_t linkid; 296210491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp, *blsave; 296310491SRishi.Srivatsavai@Sun.COM boolean_t found; 296410491SRishi.Srivatsavai@Sun.COM mblk_t *mlist; 296510491SRishi.Srivatsavai@Sun.COM 296610491SRishi.Srivatsavai@Sun.COM bsp = (bridge_stream_t *)mp->b_next; 296710491SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 296810491SRishi.Srivatsavai@Sun.COM bip = bsp->bs_inst; 296910491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 297010491SRishi.Srivatsavai@Sun.COM linkid = *(datalink_id_t *)mp->b_cont->b_rptr; 297110491SRishi.Srivatsavai@Sun.COM 297210491SRishi.Srivatsavai@Sun.COM /* 297310491SRishi.Srivatsavai@Sun.COM * We become reader here so that we can loop over the other links and 297410491SRishi.Srivatsavai@Sun.COM * deliver link up/down notification. 297510491SRishi.Srivatsavai@Sun.COM */ 297610491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 297710491SRishi.Srivatsavai@Sun.COM found = B_FALSE; 297810491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 297910491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 298010491SRishi.Srivatsavai@Sun.COM if (blp->bl_linkid == linkid && 298110491SRishi.Srivatsavai@Sun.COM !(blp->bl_flags & BLF_DELETED)) { 298210491SRishi.Srivatsavai@Sun.COM blp->bl_flags |= BLF_DELETED; 298310491SRishi.Srivatsavai@Sun.COM (void) ddi_taskq_dispatch(bridge_taskq, link_shutdown, 298410491SRishi.Srivatsavai@Sun.COM blp, DDI_SLEEP); 298510491SRishi.Srivatsavai@Sun.COM found = B_TRUE; 298610491SRishi.Srivatsavai@Sun.COM break; 298710491SRishi.Srivatsavai@Sun.COM } 298810491SRishi.Srivatsavai@Sun.COM } 298910491SRishi.Srivatsavai@Sun.COM 299010491SRishi.Srivatsavai@Sun.COM /* 299110491SRishi.Srivatsavai@Sun.COM * Check if this link is up and the remainder of the links are all 299210491SRishi.Srivatsavai@Sun.COM * down. 299310491SRishi.Srivatsavai@Sun.COM */ 299410491SRishi.Srivatsavai@Sun.COM if (blp != NULL && blp->bl_linkstate != LINK_STATE_DOWN) { 299510491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 299610491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 299710491SRishi.Srivatsavai@Sun.COM if (blp->bl_linkstate != LINK_STATE_DOWN && 299810491SRishi.Srivatsavai@Sun.COM !(blp->bl_flags & (BLF_DELETED|BLF_SDUFAIL))) 299910491SRishi.Srivatsavai@Sun.COM break; 300010491SRishi.Srivatsavai@Sun.COM } 300110491SRishi.Srivatsavai@Sun.COM if (blp == NULL) { 300210491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 300310491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 300410491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_DELETED)) 300510491SRishi.Srivatsavai@Sun.COM mac_link_redo(blp->bl_mh, 300610491SRishi.Srivatsavai@Sun.COM LINK_STATE_DOWN); 300710491SRishi.Srivatsavai@Sun.COM } 300810491SRishi.Srivatsavai@Sun.COM bmp = bip->bi_mac; 300910491SRishi.Srivatsavai@Sun.COM bmp->bm_linkstate = LINK_STATE_DOWN; 301010491SRishi.Srivatsavai@Sun.COM mac_link_redo(bmp->bm_mh, LINK_STATE_DOWN); 301110491SRishi.Srivatsavai@Sun.COM } 301210491SRishi.Srivatsavai@Sun.COM } 301310491SRishi.Srivatsavai@Sun.COM 301410491SRishi.Srivatsavai@Sun.COM /* 301510491SRishi.Srivatsavai@Sun.COM * Check if there's just one working link left on the bridge. If so, 301610491SRishi.Srivatsavai@Sun.COM * then that link is now authoritative for bridge MTU. 301710491SRishi.Srivatsavai@Sun.COM */ 301810491SRishi.Srivatsavai@Sun.COM blsave = NULL; 301910491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 302010491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 302110491SRishi.Srivatsavai@Sun.COM if (!(blp->bl_flags & BLF_DELETED)) { 302210491SRishi.Srivatsavai@Sun.COM if (blsave == NULL) 302310491SRishi.Srivatsavai@Sun.COM blsave = blp; 302410491SRishi.Srivatsavai@Sun.COM else 302510491SRishi.Srivatsavai@Sun.COM break; 302610491SRishi.Srivatsavai@Sun.COM } 302710491SRishi.Srivatsavai@Sun.COM } 302810491SRishi.Srivatsavai@Sun.COM mlist = NULL; 302910491SRishi.Srivatsavai@Sun.COM bmp = bip->bi_mac; 303010491SRishi.Srivatsavai@Sun.COM if (blsave != NULL && blp == NULL && 303110491SRishi.Srivatsavai@Sun.COM blsave->bl_maxsdu != bmp->bm_maxsdu) { 303210491SRishi.Srivatsavai@Sun.COM bmp->bm_maxsdu = blsave->bl_maxsdu; 303310491SRishi.Srivatsavai@Sun.COM (void) mac_maxsdu_update(bmp->bm_mh, blsave->bl_maxsdu); 303410491SRishi.Srivatsavai@Sun.COM link_sdu_fail(blsave, B_FALSE, &mlist); 303510491SRishi.Srivatsavai@Sun.COM } 303610491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 303710491SRishi.Srivatsavai@Sun.COM send_up_messages(bip, mlist); 303810491SRishi.Srivatsavai@Sun.COM 303910491SRishi.Srivatsavai@Sun.COM if (found) 304010491SRishi.Srivatsavai@Sun.COM miocack(bsp->bs_wq, mp, 0, 0); 304110491SRishi.Srivatsavai@Sun.COM else 304210491SRishi.Srivatsavai@Sun.COM miocnak(bsp->bs_wq, mp, 0, ENOENT); 304310491SRishi.Srivatsavai@Sun.COM stream_unref(bsp); 304410491SRishi.Srivatsavai@Sun.COM } 304510491SRishi.Srivatsavai@Sun.COM 304610491SRishi.Srivatsavai@Sun.COM /* 304710491SRishi.Srivatsavai@Sun.COM * This function intentionally returns with bi_rwlock held; it is intended for 304810491SRishi.Srivatsavai@Sun.COM * quick checks and updates. 304910491SRishi.Srivatsavai@Sun.COM */ 305010491SRishi.Srivatsavai@Sun.COM static bridge_link_t * 305110491SRishi.Srivatsavai@Sun.COM enter_link(bridge_inst_t *bip, datalink_id_t linkid) 305210491SRishi.Srivatsavai@Sun.COM { 305310491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 305410491SRishi.Srivatsavai@Sun.COM 305510491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_READER); 305610491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 305710491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 305810491SRishi.Srivatsavai@Sun.COM if (blp->bl_linkid == linkid && !(blp->bl_flags & BLF_DELETED)) 305910491SRishi.Srivatsavai@Sun.COM break; 306010491SRishi.Srivatsavai@Sun.COM } 306110491SRishi.Srivatsavai@Sun.COM return (blp); 306210491SRishi.Srivatsavai@Sun.COM } 306310491SRishi.Srivatsavai@Sun.COM 306410491SRishi.Srivatsavai@Sun.COM static void 306510491SRishi.Srivatsavai@Sun.COM bridge_ioctl(queue_t *wq, mblk_t *mp) 306610491SRishi.Srivatsavai@Sun.COM { 306710491SRishi.Srivatsavai@Sun.COM bridge_stream_t *bsp = wq->q_ptr; 306810491SRishi.Srivatsavai@Sun.COM bridge_inst_t *bip; 306910491SRishi.Srivatsavai@Sun.COM struct iocblk *iop; 307010491SRishi.Srivatsavai@Sun.COM int rc = EINVAL; 307110491SRishi.Srivatsavai@Sun.COM int len = 0; 307210491SRishi.Srivatsavai@Sun.COM bridge_link_t *blp; 307310491SRishi.Srivatsavai@Sun.COM cred_t *cr; 307410491SRishi.Srivatsavai@Sun.COM 307510491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 307610491SRishi.Srivatsavai@Sun.COM iop = (struct iocblk *)mp->b_rptr; 307710491SRishi.Srivatsavai@Sun.COM 307810491SRishi.Srivatsavai@Sun.COM /* 307910491SRishi.Srivatsavai@Sun.COM * For now, all of the bridge ioctls are privileged. 308010491SRishi.Srivatsavai@Sun.COM */ 308110491SRishi.Srivatsavai@Sun.COM if ((cr = msg_getcred(mp, NULL)) == NULL) 308210491SRishi.Srivatsavai@Sun.COM cr = iop->ioc_cr; 308310491SRishi.Srivatsavai@Sun.COM if (cr != NULL && secpolicy_net_config(cr, B_FALSE) != 0) { 308410491SRishi.Srivatsavai@Sun.COM miocnak(wq, mp, 0, EPERM); 308510491SRishi.Srivatsavai@Sun.COM return; 308610491SRishi.Srivatsavai@Sun.COM } 308710491SRishi.Srivatsavai@Sun.COM 308810491SRishi.Srivatsavai@Sun.COM switch (iop->ioc_cmd) { 308910491SRishi.Srivatsavai@Sun.COM case BRIOC_NEWBRIDGE: { 309010491SRishi.Srivatsavai@Sun.COM bridge_newbridge_t *bnb; 309110491SRishi.Srivatsavai@Sun.COM 309210491SRishi.Srivatsavai@Sun.COM if (bsp->bs_inst != NULL || 309310491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (bridge_newbridge_t))) != 0) 309410491SRishi.Srivatsavai@Sun.COM break; 309510491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 309610491SRishi.Srivatsavai@Sun.COM bnb = (bridge_newbridge_t *)mp->b_cont->b_rptr; 309710491SRishi.Srivatsavai@Sun.COM bnb->bnb_name[MAXNAMELEN-1] = '\0'; 309810616SSebastien.Roy@Sun.COM rc = bridge_create(bnb->bnb_linkid, bnb->bnb_name, &bip, cr); 309910616SSebastien.Roy@Sun.COM if (rc != 0) 310010491SRishi.Srivatsavai@Sun.COM break; 310110491SRishi.Srivatsavai@Sun.COM 310210491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 310310491SRishi.Srivatsavai@Sun.COM if (bip->bi_control != NULL) { 310410491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 310510491SRishi.Srivatsavai@Sun.COM bridge_unref(bip); 310610491SRishi.Srivatsavai@Sun.COM rc = EBUSY; 310710491SRishi.Srivatsavai@Sun.COM } else { 310810491SRishi.Srivatsavai@Sun.COM atomic_inc_uint(&bip->bi_refs); 310910491SRishi.Srivatsavai@Sun.COM bsp->bs_inst = bip; /* stream holds reference */ 311010491SRishi.Srivatsavai@Sun.COM bip->bi_control = bsp; 311110491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 311210491SRishi.Srivatsavai@Sun.COM rc = 0; 311310491SRishi.Srivatsavai@Sun.COM } 311410491SRishi.Srivatsavai@Sun.COM break; 311510491SRishi.Srivatsavai@Sun.COM } 311610491SRishi.Srivatsavai@Sun.COM 311710491SRishi.Srivatsavai@Sun.COM case BRIOC_ADDLINK: 311810491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 311910491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (datalink_id_t))) != 0) 312010491SRishi.Srivatsavai@Sun.COM break; 312110491SRishi.Srivatsavai@Sun.COM /* 312210491SRishi.Srivatsavai@Sun.COM * We cannot perform the action in this thread, because we're 312310491SRishi.Srivatsavai@Sun.COM * not in process context, and we may already be holding 312410491SRishi.Srivatsavai@Sun.COM * MAC-related locks. Place the request on taskq. 312510491SRishi.Srivatsavai@Sun.COM */ 312610491SRishi.Srivatsavai@Sun.COM mp->b_next = (mblk_t *)bsp; 312710491SRishi.Srivatsavai@Sun.COM stream_ref(bsp); 312810491SRishi.Srivatsavai@Sun.COM (void) ddi_taskq_dispatch(bridge_taskq, bridge_add_link, mp, 312910491SRishi.Srivatsavai@Sun.COM DDI_SLEEP); 313010491SRishi.Srivatsavai@Sun.COM return; 313110491SRishi.Srivatsavai@Sun.COM 313210491SRishi.Srivatsavai@Sun.COM case BRIOC_REMLINK: 313310491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 313410491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (datalink_id_t))) != 0) 313510491SRishi.Srivatsavai@Sun.COM break; 313610491SRishi.Srivatsavai@Sun.COM /* 313710491SRishi.Srivatsavai@Sun.COM * We cannot perform the action in this thread, because we're 313810491SRishi.Srivatsavai@Sun.COM * not in process context, and we may already be holding 313910491SRishi.Srivatsavai@Sun.COM * MAC-related locks. Place the request on taskq. 314010491SRishi.Srivatsavai@Sun.COM */ 314110491SRishi.Srivatsavai@Sun.COM mp->b_next = (mblk_t *)bsp; 314210491SRishi.Srivatsavai@Sun.COM stream_ref(bsp); 314310491SRishi.Srivatsavai@Sun.COM (void) ddi_taskq_dispatch(bridge_taskq, bridge_rem_link, mp, 314410491SRishi.Srivatsavai@Sun.COM DDI_SLEEP); 314510491SRishi.Srivatsavai@Sun.COM return; 314610491SRishi.Srivatsavai@Sun.COM 314710491SRishi.Srivatsavai@Sun.COM case BRIOC_SETSTATE: { 314810491SRishi.Srivatsavai@Sun.COM bridge_setstate_t *bss; 314910491SRishi.Srivatsavai@Sun.COM 315010491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 315110491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (*bss))) != 0) 315210491SRishi.Srivatsavai@Sun.COM break; 315310491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 315410491SRishi.Srivatsavai@Sun.COM bss = (bridge_setstate_t *)mp->b_cont->b_rptr; 315510491SRishi.Srivatsavai@Sun.COM if ((blp = enter_link(bip, bss->bss_linkid)) == NULL) { 315610491SRishi.Srivatsavai@Sun.COM rc = ENOENT; 315710491SRishi.Srivatsavai@Sun.COM } else { 315810491SRishi.Srivatsavai@Sun.COM rc = 0; 315910491SRishi.Srivatsavai@Sun.COM blp->bl_state = bss->bss_state; 316010491SRishi.Srivatsavai@Sun.COM } 316110491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 316210491SRishi.Srivatsavai@Sun.COM break; 316310491SRishi.Srivatsavai@Sun.COM } 316410491SRishi.Srivatsavai@Sun.COM 316510491SRishi.Srivatsavai@Sun.COM case BRIOC_SETPVID: { 316610491SRishi.Srivatsavai@Sun.COM bridge_setpvid_t *bsv; 316710491SRishi.Srivatsavai@Sun.COM 316810491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 316910491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (*bsv))) != 0) 317010491SRishi.Srivatsavai@Sun.COM break; 317110491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 317210491SRishi.Srivatsavai@Sun.COM bsv = (bridge_setpvid_t *)mp->b_cont->b_rptr; 317310491SRishi.Srivatsavai@Sun.COM if (bsv->bsv_vlan > VLAN_ID_MAX) 317410491SRishi.Srivatsavai@Sun.COM break; 317510491SRishi.Srivatsavai@Sun.COM if ((blp = enter_link(bip, bsv->bsv_linkid)) == NULL) { 317610491SRishi.Srivatsavai@Sun.COM rc = ENOENT; 317710491SRishi.Srivatsavai@Sun.COM } else if (blp->bl_pvid == bsv->bsv_vlan) { 317810491SRishi.Srivatsavai@Sun.COM rc = 0; 317910491SRishi.Srivatsavai@Sun.COM } else { 318010491SRishi.Srivatsavai@Sun.COM rc = 0; 318110491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_CLR(blp, blp->bl_pvid); 318210491SRishi.Srivatsavai@Sun.COM blp->bl_pvid = bsv->bsv_vlan; 318310491SRishi.Srivatsavai@Sun.COM if (blp->bl_pvid != 0) 318410491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_SET(blp, blp->bl_pvid); 318510491SRishi.Srivatsavai@Sun.COM } 318610491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 318710491SRishi.Srivatsavai@Sun.COM break; 318810491SRishi.Srivatsavai@Sun.COM } 318910491SRishi.Srivatsavai@Sun.COM 319010491SRishi.Srivatsavai@Sun.COM case BRIOC_VLANENAB: { 319110491SRishi.Srivatsavai@Sun.COM bridge_vlanenab_t *bve; 319210491SRishi.Srivatsavai@Sun.COM 319310491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 319410491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (*bve))) != 0) 319510491SRishi.Srivatsavai@Sun.COM break; 319610491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 319710491SRishi.Srivatsavai@Sun.COM bve = (bridge_vlanenab_t *)mp->b_cont->b_rptr; 319810491SRishi.Srivatsavai@Sun.COM if (bve->bve_vlan > VLAN_ID_MAX) 319910491SRishi.Srivatsavai@Sun.COM break; 320010491SRishi.Srivatsavai@Sun.COM if ((blp = enter_link(bip, bve->bve_linkid)) == NULL) { 320110491SRishi.Srivatsavai@Sun.COM rc = ENOENT; 320210491SRishi.Srivatsavai@Sun.COM } else { 320310491SRishi.Srivatsavai@Sun.COM rc = 0; 320410491SRishi.Srivatsavai@Sun.COM /* special case: vlan 0 means "all" */ 320510491SRishi.Srivatsavai@Sun.COM if (bve->bve_vlan == 0) { 320610491SRishi.Srivatsavai@Sun.COM (void) memset(blp->bl_vlans, 320710491SRishi.Srivatsavai@Sun.COM bve->bve_onoff ? ~0 : 0, 320810491SRishi.Srivatsavai@Sun.COM sizeof (blp->bl_vlans)); 320910491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_CLR(blp, 0); 321010491SRishi.Srivatsavai@Sun.COM if (blp->bl_pvid != 0) 321110491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_SET(blp, blp->bl_pvid); 321210491SRishi.Srivatsavai@Sun.COM } else if (bve->bve_vlan == blp->bl_pvid) { 321310491SRishi.Srivatsavai@Sun.COM rc = EINVAL; 321410491SRishi.Srivatsavai@Sun.COM } else if (bve->bve_onoff) { 321510491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_SET(blp, bve->bve_vlan); 321610491SRishi.Srivatsavai@Sun.COM } else { 321710491SRishi.Srivatsavai@Sun.COM BRIDGE_VLAN_CLR(blp, bve->bve_vlan); 321810491SRishi.Srivatsavai@Sun.COM } 321910491SRishi.Srivatsavai@Sun.COM } 322010491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 322110491SRishi.Srivatsavai@Sun.COM break; 322210491SRishi.Srivatsavai@Sun.COM } 322310491SRishi.Srivatsavai@Sun.COM 322410491SRishi.Srivatsavai@Sun.COM case BRIOC_FLUSHFWD: { 322510491SRishi.Srivatsavai@Sun.COM bridge_flushfwd_t *bff; 322610491SRishi.Srivatsavai@Sun.COM bridge_fwd_t *bfp, *bfnext; 322710491SRishi.Srivatsavai@Sun.COM avl_tree_t fwd_scavenge; 322810491SRishi.Srivatsavai@Sun.COM int i; 322910491SRishi.Srivatsavai@Sun.COM 323010491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 323110491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (*bff))) != 0) 323210491SRishi.Srivatsavai@Sun.COM break; 323310491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 323410491SRishi.Srivatsavai@Sun.COM bff = (bridge_flushfwd_t *)mp->b_cont->b_rptr; 323510491SRishi.Srivatsavai@Sun.COM rw_enter(&bip->bi_rwlock, RW_WRITER); 323610491SRishi.Srivatsavai@Sun.COM /* This case means "all" */ 323710491SRishi.Srivatsavai@Sun.COM if (bff->bff_linkid == DATALINK_INVALID_LINKID) { 323810491SRishi.Srivatsavai@Sun.COM blp = NULL; 323910491SRishi.Srivatsavai@Sun.COM } else { 324010491SRishi.Srivatsavai@Sun.COM for (blp = list_head(&bip->bi_links); blp != NULL; 324110491SRishi.Srivatsavai@Sun.COM blp = list_next(&bip->bi_links, blp)) { 324210491SRishi.Srivatsavai@Sun.COM if (blp->bl_linkid == bff->bff_linkid && 324310491SRishi.Srivatsavai@Sun.COM !(blp->bl_flags & BLF_DELETED)) 324410491SRishi.Srivatsavai@Sun.COM break; 324510491SRishi.Srivatsavai@Sun.COM } 324610491SRishi.Srivatsavai@Sun.COM if (blp == NULL) { 324710491SRishi.Srivatsavai@Sun.COM rc = ENOENT; 324810491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 324910491SRishi.Srivatsavai@Sun.COM break; 325010491SRishi.Srivatsavai@Sun.COM } 325110491SRishi.Srivatsavai@Sun.COM } 325210491SRishi.Srivatsavai@Sun.COM avl_create(&fwd_scavenge, fwd_compare, sizeof (bridge_fwd_t), 325310491SRishi.Srivatsavai@Sun.COM offsetof(bridge_fwd_t, bf_node)); 325410491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&bip->bi_fwd); 325510491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 325610491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&bip->bi_fwd, bfp); 325710491SRishi.Srivatsavai@Sun.COM if (bfp->bf_flags & BFF_LOCALADDR) 325810491SRishi.Srivatsavai@Sun.COM continue; 325910491SRishi.Srivatsavai@Sun.COM if (blp != NULL) { 326010491SRishi.Srivatsavai@Sun.COM for (i = 0; i < bfp->bf_maxlinks; i++) { 326110491SRishi.Srivatsavai@Sun.COM if (bfp->bf_links[i] == blp) 326210491SRishi.Srivatsavai@Sun.COM break; 326310491SRishi.Srivatsavai@Sun.COM } 326410491SRishi.Srivatsavai@Sun.COM /* 326510491SRishi.Srivatsavai@Sun.COM * If the link is there and we're excluding, 326610491SRishi.Srivatsavai@Sun.COM * then skip. If the link is not there and 326710491SRishi.Srivatsavai@Sun.COM * we're doing only that link, then skip. 326810491SRishi.Srivatsavai@Sun.COM */ 326910491SRishi.Srivatsavai@Sun.COM if ((i < bfp->bf_maxlinks) == bff->bff_exclude) 327010491SRishi.Srivatsavai@Sun.COM continue; 327110491SRishi.Srivatsavai@Sun.COM } 327210491SRishi.Srivatsavai@Sun.COM ASSERT(bfp->bf_flags & BFF_INTREE); 327310491SRishi.Srivatsavai@Sun.COM avl_remove(&bip->bi_fwd, bfp); 327410491SRishi.Srivatsavai@Sun.COM bfp->bf_flags &= ~BFF_INTREE; 327510491SRishi.Srivatsavai@Sun.COM avl_add(&fwd_scavenge, bfp); 327610491SRishi.Srivatsavai@Sun.COM } 327710491SRishi.Srivatsavai@Sun.COM rw_exit(&bip->bi_rwlock); 327810491SRishi.Srivatsavai@Sun.COM bfnext = avl_first(&fwd_scavenge); 327910491SRishi.Srivatsavai@Sun.COM while ((bfp = bfnext) != NULL) { 328010491SRishi.Srivatsavai@Sun.COM bfnext = AVL_NEXT(&fwd_scavenge, bfp); 328110491SRishi.Srivatsavai@Sun.COM avl_remove(&fwd_scavenge, bfp); 328210491SRishi.Srivatsavai@Sun.COM fwd_unref(bfp); /* drop tree reference */ 328310491SRishi.Srivatsavai@Sun.COM } 328410491SRishi.Srivatsavai@Sun.COM avl_destroy(&fwd_scavenge); 328510491SRishi.Srivatsavai@Sun.COM break; 328610491SRishi.Srivatsavai@Sun.COM } 328710491SRishi.Srivatsavai@Sun.COM 328810491SRishi.Srivatsavai@Sun.COM case BRIOC_TABLEMAX: 328910491SRishi.Srivatsavai@Sun.COM if ((bip = bsp->bs_inst) == NULL || 329010491SRishi.Srivatsavai@Sun.COM (rc = miocpullup(mp, sizeof (uint32_t))) != 0) 329110491SRishi.Srivatsavai@Sun.COM break; 329210491SRishi.Srivatsavai@Sun.COM /* LINTED: alignment */ 329310491SRishi.Srivatsavai@Sun.COM bip->bi_tablemax = *(uint32_t *)mp->b_cont->b_rptr; 329410491SRishi.Srivatsavai@Sun.COM break; 329510491SRishi.Srivatsavai@Sun.COM } 329610491SRishi.Srivatsavai@Sun.COM 329710491SRishi.Srivatsavai@Sun.COM if (rc == 0) 329810491SRishi.Srivatsavai@Sun.COM miocack(wq, mp, len, 0); 329910491SRishi.Srivatsavai@Sun.COM else 330010491SRishi.Srivatsavai@Sun.COM miocnak(wq, mp, 0, rc); 330110491SRishi.Srivatsavai@Sun.COM } 330210491SRishi.Srivatsavai@Sun.COM 330310491SRishi.Srivatsavai@Sun.COM static void 330410491SRishi.Srivatsavai@Sun.COM bridge_wput(queue_t *wq, mblk_t *mp) 330510491SRishi.Srivatsavai@Sun.COM { 330610491SRishi.Srivatsavai@Sun.COM switch (DB_TYPE(mp)) { 330710491SRishi.Srivatsavai@Sun.COM case M_IOCTL: 330810491SRishi.Srivatsavai@Sun.COM bridge_ioctl(wq, mp); 330910491SRishi.Srivatsavai@Sun.COM break; 331010491SRishi.Srivatsavai@Sun.COM case M_FLUSH: 331110491SRishi.Srivatsavai@Sun.COM if (*mp->b_rptr & FLUSHW) 331210491SRishi.Srivatsavai@Sun.COM *mp->b_rptr &= ~FLUSHW; 331310491SRishi.Srivatsavai@Sun.COM if (*mp->b_rptr & FLUSHR) 331410491SRishi.Srivatsavai@Sun.COM qreply(wq, mp); 331510491SRishi.Srivatsavai@Sun.COM else 331610491SRishi.Srivatsavai@Sun.COM freemsg(mp); 331710491SRishi.Srivatsavai@Sun.COM break; 331810491SRishi.Srivatsavai@Sun.COM default: 331910491SRishi.Srivatsavai@Sun.COM freemsg(mp); 332010491SRishi.Srivatsavai@Sun.COM break; 332110491SRishi.Srivatsavai@Sun.COM } 332210491SRishi.Srivatsavai@Sun.COM } 332310491SRishi.Srivatsavai@Sun.COM 332410491SRishi.Srivatsavai@Sun.COM /* 332510491SRishi.Srivatsavai@Sun.COM * This function allocates the main data structures for the bridge driver and 332610491SRishi.Srivatsavai@Sun.COM * connects us into devfs. 332710491SRishi.Srivatsavai@Sun.COM */ 332810491SRishi.Srivatsavai@Sun.COM static void 332910491SRishi.Srivatsavai@Sun.COM bridge_inst_init(void) 333010491SRishi.Srivatsavai@Sun.COM { 333110491SRishi.Srivatsavai@Sun.COM bridge_scan_interval = 5 * drv_usectohz(1000000); 333210491SRishi.Srivatsavai@Sun.COM bridge_fwd_age = 25 * drv_usectohz(1000000); 333310491SRishi.Srivatsavai@Sun.COM 333410491SRishi.Srivatsavai@Sun.COM rw_init(&bmac_rwlock, NULL, RW_DRIVER, NULL); 333510491SRishi.Srivatsavai@Sun.COM list_create(&bmac_list, sizeof (bridge_mac_t), 333610491SRishi.Srivatsavai@Sun.COM offsetof(bridge_mac_t, bm_node)); 333710491SRishi.Srivatsavai@Sun.COM list_create(&inst_list, sizeof (bridge_inst_t), 333810491SRishi.Srivatsavai@Sun.COM offsetof(bridge_inst_t, bi_node)); 333910491SRishi.Srivatsavai@Sun.COM cv_init(&inst_cv, NULL, CV_DRIVER, NULL); 334010491SRishi.Srivatsavai@Sun.COM mutex_init(&inst_lock, NULL, MUTEX_DRIVER, NULL); 334110491SRishi.Srivatsavai@Sun.COM cv_init(&stream_ref_cv, NULL, CV_DRIVER, NULL); 334210491SRishi.Srivatsavai@Sun.COM mutex_init(&stream_ref_lock, NULL, MUTEX_DRIVER, NULL); 334310491SRishi.Srivatsavai@Sun.COM 334410491SRishi.Srivatsavai@Sun.COM mac_bridge_vectors(bridge_xmit_cb, bridge_recv_cb, bridge_ref_cb, 334510491SRishi.Srivatsavai@Sun.COM bridge_ls_cb); 334610491SRishi.Srivatsavai@Sun.COM } 334710491SRishi.Srivatsavai@Sun.COM 334810491SRishi.Srivatsavai@Sun.COM /* 334910491SRishi.Srivatsavai@Sun.COM * This function disconnects from devfs and destroys all data structures in 335010491SRishi.Srivatsavai@Sun.COM * preparation for unload. It's assumed that there are no active bridge 335110491SRishi.Srivatsavai@Sun.COM * references left at this point. 335210491SRishi.Srivatsavai@Sun.COM */ 335310491SRishi.Srivatsavai@Sun.COM static void 335410491SRishi.Srivatsavai@Sun.COM bridge_inst_fini(void) 335510491SRishi.Srivatsavai@Sun.COM { 335610491SRishi.Srivatsavai@Sun.COM mac_bridge_vectors(NULL, NULL, NULL, NULL); 335710491SRishi.Srivatsavai@Sun.COM if (bridge_timerid != 0) 335810491SRishi.Srivatsavai@Sun.COM (void) untimeout(bridge_timerid); 335910491SRishi.Srivatsavai@Sun.COM rw_destroy(&bmac_rwlock); 336010491SRishi.Srivatsavai@Sun.COM list_destroy(&bmac_list); 336110491SRishi.Srivatsavai@Sun.COM list_destroy(&inst_list); 336210491SRishi.Srivatsavai@Sun.COM cv_destroy(&inst_cv); 336310491SRishi.Srivatsavai@Sun.COM mutex_destroy(&inst_lock); 336410491SRishi.Srivatsavai@Sun.COM cv_destroy(&stream_ref_cv); 336510491SRishi.Srivatsavai@Sun.COM mutex_destroy(&stream_ref_lock); 336610491SRishi.Srivatsavai@Sun.COM } 336710491SRishi.Srivatsavai@Sun.COM 336810491SRishi.Srivatsavai@Sun.COM /* 336910491SRishi.Srivatsavai@Sun.COM * bridge_attach() 337010491SRishi.Srivatsavai@Sun.COM * 337110491SRishi.Srivatsavai@Sun.COM * Description: 337210491SRishi.Srivatsavai@Sun.COM * Attach bridge driver to the system. 337310491SRishi.Srivatsavai@Sun.COM */ 337410491SRishi.Srivatsavai@Sun.COM static int 337510491SRishi.Srivatsavai@Sun.COM bridge_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 337610491SRishi.Srivatsavai@Sun.COM { 337710491SRishi.Srivatsavai@Sun.COM if (cmd != DDI_ATTACH) 337810491SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 337910491SRishi.Srivatsavai@Sun.COM 338010491SRishi.Srivatsavai@Sun.COM if (ddi_create_minor_node(dip, BRIDGE_CTL, S_IFCHR, 0, DDI_PSEUDO, 338110491SRishi.Srivatsavai@Sun.COM CLONE_DEV) == DDI_FAILURE) { 338210491SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 338310491SRishi.Srivatsavai@Sun.COM } 338410491SRishi.Srivatsavai@Sun.COM 338510491SRishi.Srivatsavai@Sun.COM if (dld_ioc_register(BRIDGE_IOC, bridge_ioc_list, 338610491SRishi.Srivatsavai@Sun.COM DLDIOCCNT(bridge_ioc_list)) != 0) { 338710491SRishi.Srivatsavai@Sun.COM ddi_remove_minor_node(dip, BRIDGE_CTL); 338810491SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 338910491SRishi.Srivatsavai@Sun.COM } 339010491SRishi.Srivatsavai@Sun.COM 339110491SRishi.Srivatsavai@Sun.COM bridge_dev_info = dip; 339210491SRishi.Srivatsavai@Sun.COM bridge_major = ddi_driver_major(dip); 339311109SRishi.Srivatsavai@Sun.COM bridge_taskq = ddi_taskq_create(dip, BRIDGE_DEV_NAME, 1, 339411109SRishi.Srivatsavai@Sun.COM TASKQ_DEFAULTPRI, 0); 339510491SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS); 339610491SRishi.Srivatsavai@Sun.COM } 339710491SRishi.Srivatsavai@Sun.COM 339810491SRishi.Srivatsavai@Sun.COM /* 339910491SRishi.Srivatsavai@Sun.COM * bridge_detach() 340010491SRishi.Srivatsavai@Sun.COM * 340110491SRishi.Srivatsavai@Sun.COM * Description: 340210491SRishi.Srivatsavai@Sun.COM * Detach an interface to the system. 340310491SRishi.Srivatsavai@Sun.COM */ 340410491SRishi.Srivatsavai@Sun.COM static int 340510491SRishi.Srivatsavai@Sun.COM bridge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 340610491SRishi.Srivatsavai@Sun.COM { 340710491SRishi.Srivatsavai@Sun.COM if (cmd != DDI_DETACH) 340810491SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 340910491SRishi.Srivatsavai@Sun.COM 341010491SRishi.Srivatsavai@Sun.COM ddi_remove_minor_node(dip, NULL); 341110491SRishi.Srivatsavai@Sun.COM ddi_taskq_destroy(bridge_taskq); 341210491SRishi.Srivatsavai@Sun.COM bridge_dev_info = NULL; 341310491SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS); 341410491SRishi.Srivatsavai@Sun.COM } 341510491SRishi.Srivatsavai@Sun.COM 341610491SRishi.Srivatsavai@Sun.COM /* 341710491SRishi.Srivatsavai@Sun.COM * bridge_info() 341810491SRishi.Srivatsavai@Sun.COM * 341910491SRishi.Srivatsavai@Sun.COM * Description: 342010491SRishi.Srivatsavai@Sun.COM * Translate "dev_t" to a pointer to the associated "dev_info_t". 342110491SRishi.Srivatsavai@Sun.COM */ 342210491SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 342310491SRishi.Srivatsavai@Sun.COM static int 342410491SRishi.Srivatsavai@Sun.COM bridge_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 342510491SRishi.Srivatsavai@Sun.COM void **result) 342610491SRishi.Srivatsavai@Sun.COM { 342710491SRishi.Srivatsavai@Sun.COM int rc; 342810491SRishi.Srivatsavai@Sun.COM 342910491SRishi.Srivatsavai@Sun.COM switch (infocmd) { 343010491SRishi.Srivatsavai@Sun.COM case DDI_INFO_DEVT2DEVINFO: 343110491SRishi.Srivatsavai@Sun.COM if (bridge_dev_info == NULL) { 343210491SRishi.Srivatsavai@Sun.COM rc = DDI_FAILURE; 343310491SRishi.Srivatsavai@Sun.COM } else { 343410491SRishi.Srivatsavai@Sun.COM *result = (void *)bridge_dev_info; 343510491SRishi.Srivatsavai@Sun.COM rc = DDI_SUCCESS; 343610491SRishi.Srivatsavai@Sun.COM } 343710491SRishi.Srivatsavai@Sun.COM break; 343810491SRishi.Srivatsavai@Sun.COM case DDI_INFO_DEVT2INSTANCE: 343910491SRishi.Srivatsavai@Sun.COM *result = NULL; 344010491SRishi.Srivatsavai@Sun.COM rc = DDI_SUCCESS; 344110491SRishi.Srivatsavai@Sun.COM break; 344210491SRishi.Srivatsavai@Sun.COM default: 344310491SRishi.Srivatsavai@Sun.COM rc = DDI_FAILURE; 344410491SRishi.Srivatsavai@Sun.COM break; 344510491SRishi.Srivatsavai@Sun.COM } 344610491SRishi.Srivatsavai@Sun.COM return (rc); 344710491SRishi.Srivatsavai@Sun.COM } 344810491SRishi.Srivatsavai@Sun.COM 344910491SRishi.Srivatsavai@Sun.COM static struct module_info bridge_modinfo = { 345010491SRishi.Srivatsavai@Sun.COM 2105, /* mi_idnum */ 345111109SRishi.Srivatsavai@Sun.COM BRIDGE_DEV_NAME, /* mi_idname */ 345210491SRishi.Srivatsavai@Sun.COM 0, /* mi_minpsz */ 345310491SRishi.Srivatsavai@Sun.COM 16384, /* mi_maxpsz */ 345410491SRishi.Srivatsavai@Sun.COM 65536, /* mi_hiwat */ 345510491SRishi.Srivatsavai@Sun.COM 128 /* mi_lowat */ 345610491SRishi.Srivatsavai@Sun.COM }; 345710491SRishi.Srivatsavai@Sun.COM 345810491SRishi.Srivatsavai@Sun.COM static struct qinit bridge_rinit = { 345910491SRishi.Srivatsavai@Sun.COM NULL, /* qi_putp */ 346010491SRishi.Srivatsavai@Sun.COM NULL, /* qi_srvp */ 346110491SRishi.Srivatsavai@Sun.COM bridge_open, /* qi_qopen */ 346210491SRishi.Srivatsavai@Sun.COM bridge_close, /* qi_qclose */ 346310491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qadmin */ 346410491SRishi.Srivatsavai@Sun.COM &bridge_modinfo, /* qi_minfo */ 346510491SRishi.Srivatsavai@Sun.COM NULL /* qi_mstat */ 346610491SRishi.Srivatsavai@Sun.COM }; 346710491SRishi.Srivatsavai@Sun.COM 346810491SRishi.Srivatsavai@Sun.COM static struct qinit bridge_winit = { 346910491SRishi.Srivatsavai@Sun.COM (int (*)())bridge_wput, /* qi_putp */ 347010491SRishi.Srivatsavai@Sun.COM NULL, /* qi_srvp */ 347110491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qopen */ 347210491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qclose */ 347310491SRishi.Srivatsavai@Sun.COM NULL, /* qi_qadmin */ 347410491SRishi.Srivatsavai@Sun.COM &bridge_modinfo, /* qi_minfo */ 347510491SRishi.Srivatsavai@Sun.COM NULL /* qi_mstat */ 347610491SRishi.Srivatsavai@Sun.COM }; 347710491SRishi.Srivatsavai@Sun.COM 347810491SRishi.Srivatsavai@Sun.COM static struct streamtab bridge_tab = { 347910491SRishi.Srivatsavai@Sun.COM &bridge_rinit, /* st_rdinit */ 348010491SRishi.Srivatsavai@Sun.COM &bridge_winit /* st_wrinit */ 348110491SRishi.Srivatsavai@Sun.COM }; 348210491SRishi.Srivatsavai@Sun.COM 348310491SRishi.Srivatsavai@Sun.COM /* No STREAMS perimeters; we do all our own locking */ 348410491SRishi.Srivatsavai@Sun.COM DDI_DEFINE_STREAM_OPS(bridge_ops, nulldev, nulldev, bridge_attach, 348510491SRishi.Srivatsavai@Sun.COM bridge_detach, nodev, bridge_info, D_NEW | D_MP, &bridge_tab, 348610491SRishi.Srivatsavai@Sun.COM ddi_quiesce_not_supported); 348710491SRishi.Srivatsavai@Sun.COM 348810491SRishi.Srivatsavai@Sun.COM static struct modldrv modldrv = { 348910491SRishi.Srivatsavai@Sun.COM &mod_driverops, 349010491SRishi.Srivatsavai@Sun.COM "bridging driver", 349110491SRishi.Srivatsavai@Sun.COM &bridge_ops 349210491SRishi.Srivatsavai@Sun.COM }; 349310491SRishi.Srivatsavai@Sun.COM 349410491SRishi.Srivatsavai@Sun.COM static struct modlinkage modlinkage = { 349510491SRishi.Srivatsavai@Sun.COM MODREV_1, 349610491SRishi.Srivatsavai@Sun.COM (void *)&modldrv, 349710491SRishi.Srivatsavai@Sun.COM NULL 349810491SRishi.Srivatsavai@Sun.COM }; 349910491SRishi.Srivatsavai@Sun.COM 350010491SRishi.Srivatsavai@Sun.COM int 350110491SRishi.Srivatsavai@Sun.COM _init(void) 350210491SRishi.Srivatsavai@Sun.COM { 350310491SRishi.Srivatsavai@Sun.COM int retv; 350410491SRishi.Srivatsavai@Sun.COM 350511109SRishi.Srivatsavai@Sun.COM mac_init_ops(NULL, BRIDGE_DEV_NAME); 350610491SRishi.Srivatsavai@Sun.COM bridge_inst_init(); 350710491SRishi.Srivatsavai@Sun.COM if ((retv = mod_install(&modlinkage)) != 0) 350810491SRishi.Srivatsavai@Sun.COM bridge_inst_fini(); 350910491SRishi.Srivatsavai@Sun.COM return (retv); 351010491SRishi.Srivatsavai@Sun.COM } 351110491SRishi.Srivatsavai@Sun.COM 351210491SRishi.Srivatsavai@Sun.COM int 351310491SRishi.Srivatsavai@Sun.COM _fini(void) 351410491SRishi.Srivatsavai@Sun.COM { 351510491SRishi.Srivatsavai@Sun.COM int retv; 351610491SRishi.Srivatsavai@Sun.COM 351710491SRishi.Srivatsavai@Sun.COM rw_enter(&bmac_rwlock, RW_READER); 351810491SRishi.Srivatsavai@Sun.COM retv = list_is_empty(&bmac_list) ? 0 : EBUSY; 351910491SRishi.Srivatsavai@Sun.COM rw_exit(&bmac_rwlock); 352010491SRishi.Srivatsavai@Sun.COM if (retv == 0 && 352110491SRishi.Srivatsavai@Sun.COM (retv = mod_remove(&modlinkage)) == 0) 352210491SRishi.Srivatsavai@Sun.COM bridge_inst_fini(); 352310491SRishi.Srivatsavai@Sun.COM return (retv); 352410491SRishi.Srivatsavai@Sun.COM } 352510491SRishi.Srivatsavai@Sun.COM 352610491SRishi.Srivatsavai@Sun.COM int 352710491SRishi.Srivatsavai@Sun.COM _info(struct modinfo *modinfop) 352810491SRishi.Srivatsavai@Sun.COM { 352910491SRishi.Srivatsavai@Sun.COM return (mod_info(&modlinkage, modinfop)); 353010491SRishi.Srivatsavai@Sun.COM } 3531