1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * lwIP netif implementing an IEEE 802.1D MAC Bridge 4195972f6Sopenharmony_ci */ 5195972f6Sopenharmony_ci 6195972f6Sopenharmony_ci/* 7195972f6Sopenharmony_ci * Copyright (c) 2017 Simon Goldschmidt. 8195972f6Sopenharmony_ci * All rights reserved. 9195972f6Sopenharmony_ci * 10195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 11195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 12195972f6Sopenharmony_ci * 13195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 14195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 15195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 16195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 17195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 18195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 19195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 20195972f6Sopenharmony_ci * 21195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 22195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 24195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 26195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 30195972f6Sopenharmony_ci * OF SUCH DAMAGE. 31195972f6Sopenharmony_ci * 32195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 33195972f6Sopenharmony_ci * 34195972f6Sopenharmony_ci * Author: Simon Goldschmidt <goldsimon@gmx.de> 35195972f6Sopenharmony_ci * 36195972f6Sopenharmony_ci */ 37195972f6Sopenharmony_ci 38195972f6Sopenharmony_ci/** 39195972f6Sopenharmony_ci * @defgroup bridgeif IEEE 802.1D bridge 40195972f6Sopenharmony_ci * @ingroup netifs 41195972f6Sopenharmony_ci * This file implements an IEEE 802.1D bridge by using a multilayer netif approach 42195972f6Sopenharmony_ci * (one hardware-independent netif for the bridge that uses hardware netifs for its ports). 43195972f6Sopenharmony_ci * On transmit, the bridge selects the outgoing port(s). 44195972f6Sopenharmony_ci * On receive, the port netif calls into the bridge (via its netif->input function) and 45195972f6Sopenharmony_ci * the bridge selects the port(s) (and/or its netif->input function) to pass the received pbuf to. 46195972f6Sopenharmony_ci * 47195972f6Sopenharmony_ci * Usage: 48195972f6Sopenharmony_ci * - add the port netifs just like you would when using them as dedicated netif without a bridge 49195972f6Sopenharmony_ci * - only NETIF_FLAG_ETHARP/NETIF_FLAG_ETHERNET netifs are supported as bridge ports 50195972f6Sopenharmony_ci * - add the bridge port netifs without IPv4 addresses (i.e. pass 'NULL, NULL, NULL') 51195972f6Sopenharmony_ci * - don't add IPv6 addresses to the port netifs! 52195972f6Sopenharmony_ci * - set up the bridge configuration in a global variable of type 'bridgeif_initdata_t' that contains 53195972f6Sopenharmony_ci * - the MAC address of the bridge 54195972f6Sopenharmony_ci * - some configuration options controlling the memory consumption (maximum number of ports 55195972f6Sopenharmony_ci * and FDB entries) 56195972f6Sopenharmony_ci * - e.g. for a bridge MAC address 00-01-02-03-04-05, 2 bridge ports, 1024 FDB entries + 16 static MAC entries: 57195972f6Sopenharmony_ci * bridgeif_initdata_t mybridge_initdata = BRIDGEIF_INITDATA1(2, 1024, 16, ETH_ADDR(0, 1, 2, 3, 4, 5)); 58195972f6Sopenharmony_ci * - add the bridge netif (with IPv4 config): 59195972f6Sopenharmony_ci * struct netif bridge_netif; 60195972f6Sopenharmony_ci * netif_add(&bridge_netif, &my_ip, &my_netmask, &my_gw, &mybridge_initdata, bridgeif_init, tcpip_input); 61195972f6Sopenharmony_ci * NOTE: the passed 'input' function depends on BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT setting, 62195972f6Sopenharmony_ci * which controls where the forwarding is done (netif low level input context vs. tcpip_thread) 63195972f6Sopenharmony_ci * - set up all ports netifs and the bridge netif 64195972f6Sopenharmony_ci * 65195972f6Sopenharmony_ci * - When adding a port netif, NETIF_FLAG_ETHARP flag will be removed from a port 66195972f6Sopenharmony_ci * to prevent ETHARP working on that port netif (we only want one IP per bridge not per port). 67195972f6Sopenharmony_ci * - When adding a port netif, its input function is changed to call into the bridge. 68195972f6Sopenharmony_ci * 69195972f6Sopenharmony_ci * 70195972f6Sopenharmony_ci * @todo: 71195972f6Sopenharmony_ci * - compact static FDB entries (instead of walking the whole array) 72195972f6Sopenharmony_ci * - add FDB query/read access 73195972f6Sopenharmony_ci * - add FDB change callback (when learning or dropping auto-learned entries) 74195972f6Sopenharmony_ci * - prefill FDB with MAC classes that should never be forwarded 75195972f6Sopenharmony_ci * - multicast snooping? (and only forward group addresses to interested ports) 76195972f6Sopenharmony_ci * - support removing ports 77195972f6Sopenharmony_ci * - check SNMP integration 78195972f6Sopenharmony_ci * - VLAN handling / trunk ports 79195972f6Sopenharmony_ci * - priority handling? (although that largely depends on TX queue limitations and lwIP doesn't provide tx-done handling) 80195972f6Sopenharmony_ci */ 81195972f6Sopenharmony_ci 82195972f6Sopenharmony_ci#include "netif/bridgeif.h" 83195972f6Sopenharmony_ci#include "lwip/netif.h" 84195972f6Sopenharmony_ci#include "lwip/sys.h" 85195972f6Sopenharmony_ci#include "lwip/etharp.h" 86195972f6Sopenharmony_ci#include "lwip/ethip6.h" 87195972f6Sopenharmony_ci#include "lwip/snmp.h" 88195972f6Sopenharmony_ci#include "lwip/timeouts.h" 89195972f6Sopenharmony_ci#include <string.h> 90195972f6Sopenharmony_ci 91195972f6Sopenharmony_ci#if LWIP_NUM_NETIF_CLIENT_DATA 92195972f6Sopenharmony_ci 93195972f6Sopenharmony_ci/* Define those to better describe your network interface. */ 94195972f6Sopenharmony_ci#define IFNAME0 'b' 95195972f6Sopenharmony_ci#define IFNAME1 'r' 96195972f6Sopenharmony_ci 97195972f6Sopenharmony_cistruct bridgeif_private_s; 98195972f6Sopenharmony_citypedef struct bridgeif_port_private_s { 99195972f6Sopenharmony_ci struct bridgeif_private_s *bridge; 100195972f6Sopenharmony_ci struct netif *port_netif; 101195972f6Sopenharmony_ci u8_t port_num; 102195972f6Sopenharmony_ci} bridgeif_port_t; 103195972f6Sopenharmony_ci 104195972f6Sopenharmony_citypedef struct bridgeif_fdb_static_entry_s { 105195972f6Sopenharmony_ci u8_t used; 106195972f6Sopenharmony_ci bridgeif_portmask_t dst_ports; 107195972f6Sopenharmony_ci struct eth_addr addr; 108195972f6Sopenharmony_ci} bridgeif_fdb_static_entry_t; 109195972f6Sopenharmony_ci 110195972f6Sopenharmony_citypedef struct bridgeif_private_s { 111195972f6Sopenharmony_ci struct netif *netif; 112195972f6Sopenharmony_ci struct eth_addr ethaddr; 113195972f6Sopenharmony_ci u8_t max_ports; 114195972f6Sopenharmony_ci u8_t num_ports; 115195972f6Sopenharmony_ci bridgeif_port_t *ports; 116195972f6Sopenharmony_ci u16_t max_fdbs_entries; 117195972f6Sopenharmony_ci bridgeif_fdb_static_entry_t *fdbs; 118195972f6Sopenharmony_ci u16_t max_fdbd_entries; 119195972f6Sopenharmony_ci void *fdbd; 120195972f6Sopenharmony_ci} bridgeif_private_t; 121195972f6Sopenharmony_ci 122195972f6Sopenharmony_ci/* netif data index to get the bridge on input */ 123195972f6Sopenharmony_ciu8_t bridgeif_netif_client_id = 0xff; 124195972f6Sopenharmony_ci 125195972f6Sopenharmony_ci/** 126195972f6Sopenharmony_ci * @ingroup bridgeif 127195972f6Sopenharmony_ci * Add a static entry to the forwarding database. 128195972f6Sopenharmony_ci * A static entry marks where frames to a specific eth address (unicast or group address) are 129195972f6Sopenharmony_ci * forwarded. 130195972f6Sopenharmony_ci * bits [0..(BRIDGEIF_MAX_PORTS-1)]: hw ports 131195972f6Sopenharmony_ci * bit [BRIDGEIF_MAX_PORTS]: cpu port 132195972f6Sopenharmony_ci * 0: drop 133195972f6Sopenharmony_ci */ 134195972f6Sopenharmony_cierr_t 135195972f6Sopenharmony_cibridgeif_fdb_add(struct netif *bridgeif, const struct eth_addr *addr, bridgeif_portmask_t ports) 136195972f6Sopenharmony_ci{ 137195972f6Sopenharmony_ci int i; 138195972f6Sopenharmony_ci bridgeif_private_t *br; 139195972f6Sopenharmony_ci BRIDGEIF_DECL_PROTECT(lev); 140195972f6Sopenharmony_ci LWIP_ASSERT("invalid netif", bridgeif != NULL); 141195972f6Sopenharmony_ci br = (bridgeif_private_t *)bridgeif->state; 142195972f6Sopenharmony_ci LWIP_ASSERT("invalid state", br != NULL); 143195972f6Sopenharmony_ci 144195972f6Sopenharmony_ci BRIDGEIF_READ_PROTECT(lev); 145195972f6Sopenharmony_ci for (i = 0; i < br->max_fdbs_entries; i++) { 146195972f6Sopenharmony_ci if (!br->fdbs[i].used) { 147195972f6Sopenharmony_ci BRIDGEIF_WRITE_PROTECT(lev); 148195972f6Sopenharmony_ci if (!br->fdbs[i].used) { 149195972f6Sopenharmony_ci br->fdbs[i].used = 1; 150195972f6Sopenharmony_ci br->fdbs[i].dst_ports = ports; 151195972f6Sopenharmony_ci memcpy(&br->fdbs[i].addr, addr, sizeof(struct eth_addr)); 152195972f6Sopenharmony_ci BRIDGEIF_WRITE_UNPROTECT(lev); 153195972f6Sopenharmony_ci BRIDGEIF_READ_UNPROTECT(lev); 154195972f6Sopenharmony_ci return ERR_OK; 155195972f6Sopenharmony_ci } 156195972f6Sopenharmony_ci BRIDGEIF_WRITE_UNPROTECT(lev); 157195972f6Sopenharmony_ci } 158195972f6Sopenharmony_ci } 159195972f6Sopenharmony_ci BRIDGEIF_READ_UNPROTECT(lev); 160195972f6Sopenharmony_ci return ERR_MEM; 161195972f6Sopenharmony_ci} 162195972f6Sopenharmony_ci 163195972f6Sopenharmony_ci/** 164195972f6Sopenharmony_ci * @ingroup bridgeif 165195972f6Sopenharmony_ci * Remove a static entry from the forwarding database 166195972f6Sopenharmony_ci */ 167195972f6Sopenharmony_cierr_t 168195972f6Sopenharmony_cibridgeif_fdb_remove(struct netif *bridgeif, const struct eth_addr *addr) 169195972f6Sopenharmony_ci{ 170195972f6Sopenharmony_ci int i; 171195972f6Sopenharmony_ci bridgeif_private_t *br; 172195972f6Sopenharmony_ci BRIDGEIF_DECL_PROTECT(lev); 173195972f6Sopenharmony_ci LWIP_ASSERT("invalid netif", bridgeif != NULL); 174195972f6Sopenharmony_ci br = (bridgeif_private_t *)bridgeif->state; 175195972f6Sopenharmony_ci LWIP_ASSERT("invalid state", br != NULL); 176195972f6Sopenharmony_ci 177195972f6Sopenharmony_ci BRIDGEIF_READ_PROTECT(lev); 178195972f6Sopenharmony_ci for (i = 0; i < br->max_fdbs_entries; i++) { 179195972f6Sopenharmony_ci if (br->fdbs[i].used && !memcmp(&br->fdbs[i].addr, addr, sizeof(struct eth_addr))) { 180195972f6Sopenharmony_ci BRIDGEIF_WRITE_PROTECT(lev); 181195972f6Sopenharmony_ci if (br->fdbs[i].used && !memcmp(&br->fdbs[i].addr, addr, sizeof(struct eth_addr))) { 182195972f6Sopenharmony_ci memset(&br->fdbs[i], 0, sizeof(bridgeif_fdb_static_entry_t)); 183195972f6Sopenharmony_ci BRIDGEIF_WRITE_UNPROTECT(lev); 184195972f6Sopenharmony_ci BRIDGEIF_READ_UNPROTECT(lev); 185195972f6Sopenharmony_ci return ERR_OK; 186195972f6Sopenharmony_ci } 187195972f6Sopenharmony_ci BRIDGEIF_WRITE_UNPROTECT(lev); 188195972f6Sopenharmony_ci } 189195972f6Sopenharmony_ci } 190195972f6Sopenharmony_ci BRIDGEIF_READ_UNPROTECT(lev); 191195972f6Sopenharmony_ci return ERR_VAL; 192195972f6Sopenharmony_ci} 193195972f6Sopenharmony_ci 194195972f6Sopenharmony_ci/** Get the forwarding port(s) (as bit mask) for the specified destination mac address */ 195195972f6Sopenharmony_cistatic bridgeif_portmask_t 196195972f6Sopenharmony_cibridgeif_find_dst_ports(bridgeif_private_t *br, struct eth_addr *dst_addr) 197195972f6Sopenharmony_ci{ 198195972f6Sopenharmony_ci int i; 199195972f6Sopenharmony_ci BRIDGEIF_DECL_PROTECT(lev); 200195972f6Sopenharmony_ci BRIDGEIF_READ_PROTECT(lev); 201195972f6Sopenharmony_ci /* first check for static entries */ 202195972f6Sopenharmony_ci for (i = 0; i < br->max_fdbs_entries; i++) { 203195972f6Sopenharmony_ci if (br->fdbs[i].used) { 204195972f6Sopenharmony_ci if (!memcmp(&br->fdbs[i].addr, dst_addr, sizeof(struct eth_addr))) { 205195972f6Sopenharmony_ci bridgeif_portmask_t ret = br->fdbs[i].dst_ports; 206195972f6Sopenharmony_ci BRIDGEIF_READ_UNPROTECT(lev); 207195972f6Sopenharmony_ci return ret; 208195972f6Sopenharmony_ci } 209195972f6Sopenharmony_ci } 210195972f6Sopenharmony_ci } 211195972f6Sopenharmony_ci if (dst_addr->addr[0] & 1) { 212195972f6Sopenharmony_ci /* no match found: flood remaining group address */ 213195972f6Sopenharmony_ci BRIDGEIF_READ_UNPROTECT(lev); 214195972f6Sopenharmony_ci return BR_FLOOD; 215195972f6Sopenharmony_ci } 216195972f6Sopenharmony_ci BRIDGEIF_READ_UNPROTECT(lev); 217195972f6Sopenharmony_ci /* no match found: check dynamic fdb for port or fall back to flooding */ 218195972f6Sopenharmony_ci return bridgeif_fdb_get_dst_ports(br->fdbd, dst_addr); 219195972f6Sopenharmony_ci} 220195972f6Sopenharmony_ci 221195972f6Sopenharmony_ci/** Helper function to see if a destination mac belongs to the bridge 222195972f6Sopenharmony_ci * (bridge netif or one of the port netifs), in which case the frame 223195972f6Sopenharmony_ci * is sent to the cpu only. 224195972f6Sopenharmony_ci */ 225195972f6Sopenharmony_cistatic int 226195972f6Sopenharmony_cibridgeif_is_local_mac(bridgeif_private_t *br, struct eth_addr *addr) 227195972f6Sopenharmony_ci{ 228195972f6Sopenharmony_ci int i; 229195972f6Sopenharmony_ci BRIDGEIF_DECL_PROTECT(lev); 230195972f6Sopenharmony_ci if (!memcmp(br->netif->hwaddr, addr, sizeof(struct eth_addr))) { 231195972f6Sopenharmony_ci return 1; 232195972f6Sopenharmony_ci } 233195972f6Sopenharmony_ci BRIDGEIF_READ_PROTECT(lev); 234195972f6Sopenharmony_ci for (i = 0; i < br->num_ports; i++) { 235195972f6Sopenharmony_ci struct netif *portif = br->ports[i].port_netif; 236195972f6Sopenharmony_ci if (portif != NULL) { 237195972f6Sopenharmony_ci if (!memcmp(portif->hwaddr, addr, sizeof(struct eth_addr))) { 238195972f6Sopenharmony_ci BRIDGEIF_READ_UNPROTECT(lev); 239195972f6Sopenharmony_ci return 1; 240195972f6Sopenharmony_ci } 241195972f6Sopenharmony_ci } 242195972f6Sopenharmony_ci } 243195972f6Sopenharmony_ci BRIDGEIF_READ_UNPROTECT(lev); 244195972f6Sopenharmony_ci return 0; 245195972f6Sopenharmony_ci} 246195972f6Sopenharmony_ci 247195972f6Sopenharmony_ci/* Output helper function */ 248195972f6Sopenharmony_cistatic err_t 249195972f6Sopenharmony_cibridgeif_send_to_port(bridgeif_private_t *br, struct pbuf *p, u8_t dstport_idx) 250195972f6Sopenharmony_ci{ 251195972f6Sopenharmony_ci if (dstport_idx < BRIDGEIF_MAX_PORTS) { 252195972f6Sopenharmony_ci /* possibly an external port */ 253195972f6Sopenharmony_ci if (dstport_idx < br->max_ports) { 254195972f6Sopenharmony_ci struct netif *portif = br->ports[dstport_idx].port_netif; 255195972f6Sopenharmony_ci if ((portif != NULL) && (portif->linkoutput != NULL)) { 256195972f6Sopenharmony_ci /* prevent sending out to rx port */ 257195972f6Sopenharmony_ci if (netif_get_index(portif) != p->if_idx) { 258195972f6Sopenharmony_ci if (netif_is_link_up(portif)) { 259195972f6Sopenharmony_ci LWIP_DEBUGF(BRIDGEIF_FW_DEBUG, ("br -> flood(%p:%d) -> %d\n", (void *)p, p->if_idx, netif_get_index(portif))); 260195972f6Sopenharmony_ci return portif->linkoutput(portif, p); 261195972f6Sopenharmony_ci } 262195972f6Sopenharmony_ci } 263195972f6Sopenharmony_ci } 264195972f6Sopenharmony_ci } 265195972f6Sopenharmony_ci } else { 266195972f6Sopenharmony_ci LWIP_ASSERT("invalid port index", dstport_idx == BRIDGEIF_MAX_PORTS); 267195972f6Sopenharmony_ci } 268195972f6Sopenharmony_ci return ERR_OK; 269195972f6Sopenharmony_ci} 270195972f6Sopenharmony_ci 271195972f6Sopenharmony_ci/** Helper function to pass a pbuf to all ports marked in 'dstports' 272195972f6Sopenharmony_ci */ 273195972f6Sopenharmony_cistatic err_t 274195972f6Sopenharmony_cibridgeif_send_to_ports(bridgeif_private_t *br, struct pbuf *p, bridgeif_portmask_t dstports) 275195972f6Sopenharmony_ci{ 276195972f6Sopenharmony_ci err_t err, ret_err = ERR_OK; 277195972f6Sopenharmony_ci u8_t i; 278195972f6Sopenharmony_ci bridgeif_portmask_t mask = 1; 279195972f6Sopenharmony_ci BRIDGEIF_DECL_PROTECT(lev); 280195972f6Sopenharmony_ci BRIDGEIF_READ_PROTECT(lev); 281195972f6Sopenharmony_ci for (i = 0; i < BRIDGEIF_MAX_PORTS; i++, mask = (bridgeif_portmask_t)(mask << 1)) { 282195972f6Sopenharmony_ci if (dstports & mask) { 283195972f6Sopenharmony_ci err = bridgeif_send_to_port(br, p, i); 284195972f6Sopenharmony_ci if (err != ERR_OK) { 285195972f6Sopenharmony_ci ret_err = err; 286195972f6Sopenharmony_ci } 287195972f6Sopenharmony_ci } 288195972f6Sopenharmony_ci } 289195972f6Sopenharmony_ci BRIDGEIF_READ_UNPROTECT(lev); 290195972f6Sopenharmony_ci return ret_err; 291195972f6Sopenharmony_ci} 292195972f6Sopenharmony_ci 293195972f6Sopenharmony_ci/** Output function of the application port of the bridge (the one with an ip address). 294195972f6Sopenharmony_ci * The forwarding port(s) where this pbuf is sent on is/are automatically selected 295195972f6Sopenharmony_ci * from the FDB. 296195972f6Sopenharmony_ci */ 297195972f6Sopenharmony_cistatic err_t 298195972f6Sopenharmony_cibridgeif_output(struct netif *netif, struct pbuf *p) 299195972f6Sopenharmony_ci{ 300195972f6Sopenharmony_ci err_t err; 301195972f6Sopenharmony_ci bridgeif_private_t *br = (bridgeif_private_t *)netif->state; 302195972f6Sopenharmony_ci struct eth_addr *dst = (struct eth_addr *)(p->payload); 303195972f6Sopenharmony_ci 304195972f6Sopenharmony_ci bridgeif_portmask_t dstports = bridgeif_find_dst_ports(br, dst); 305195972f6Sopenharmony_ci err = bridgeif_send_to_ports(br, p, dstports); 306195972f6Sopenharmony_ci 307195972f6Sopenharmony_ci MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); 308195972f6Sopenharmony_ci if (((u8_t *)p->payload)[0] & 1) { 309195972f6Sopenharmony_ci /* broadcast or multicast packet*/ 310195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); 311195972f6Sopenharmony_ci } else { 312195972f6Sopenharmony_ci /* unicast packet */ 313195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); 314195972f6Sopenharmony_ci } 315195972f6Sopenharmony_ci /* increase ifoutdiscards or ifouterrors on error */ 316195972f6Sopenharmony_ci 317195972f6Sopenharmony_ci LINK_STATS_INC(link.xmit); 318195972f6Sopenharmony_ci 319195972f6Sopenharmony_ci return err; 320195972f6Sopenharmony_ci} 321195972f6Sopenharmony_ci 322195972f6Sopenharmony_ci/** The actual bridge input function. Port netif's input is changed to call 323195972f6Sopenharmony_ci * here. This function decides where the frame is forwarded. 324195972f6Sopenharmony_ci */ 325195972f6Sopenharmony_cistatic err_t 326195972f6Sopenharmony_cibridgeif_input(struct pbuf *p, struct netif *netif) 327195972f6Sopenharmony_ci{ 328195972f6Sopenharmony_ci u8_t rx_idx; 329195972f6Sopenharmony_ci bridgeif_portmask_t dstports; 330195972f6Sopenharmony_ci struct eth_addr *src, *dst; 331195972f6Sopenharmony_ci bridgeif_private_t *br; 332195972f6Sopenharmony_ci bridgeif_port_t *port; 333195972f6Sopenharmony_ci if (p == NULL || netif == NULL) { 334195972f6Sopenharmony_ci return ERR_VAL; 335195972f6Sopenharmony_ci } 336195972f6Sopenharmony_ci port = (bridgeif_port_t *)netif_get_client_data(netif, bridgeif_netif_client_id); 337195972f6Sopenharmony_ci LWIP_ASSERT("port data not set", port != NULL); 338195972f6Sopenharmony_ci if (port == NULL || port->bridge == NULL) { 339195972f6Sopenharmony_ci return ERR_VAL; 340195972f6Sopenharmony_ci } 341195972f6Sopenharmony_ci br = (bridgeif_private_t *)port->bridge; 342195972f6Sopenharmony_ci rx_idx = netif_get_index(netif); 343195972f6Sopenharmony_ci /* store receive index in pbuf */ 344195972f6Sopenharmony_ci p->if_idx = rx_idx; 345195972f6Sopenharmony_ci 346195972f6Sopenharmony_ci dst = (struct eth_addr *)p->payload; 347195972f6Sopenharmony_ci src = (struct eth_addr *)(((u8_t *)p->payload) + sizeof(struct eth_addr)); 348195972f6Sopenharmony_ci 349195972f6Sopenharmony_ci if ((src->addr[0] & 1) == 0) { 350195972f6Sopenharmony_ci /* update src for all non-group addresses */ 351195972f6Sopenharmony_ci bridgeif_fdb_update_src(br->fdbd, src, port->port_num); 352195972f6Sopenharmony_ci } 353195972f6Sopenharmony_ci 354195972f6Sopenharmony_ci if (dst->addr[0] & 1) { 355195972f6Sopenharmony_ci /* group address -> flood + cpu? */ 356195972f6Sopenharmony_ci dstports = bridgeif_find_dst_ports(br, dst); 357195972f6Sopenharmony_ci bridgeif_send_to_ports(br, p, dstports); 358195972f6Sopenharmony_ci if (dstports & (1 << BRIDGEIF_MAX_PORTS)) { 359195972f6Sopenharmony_ci /* we pass the reference to ->input or have to free it */ 360195972f6Sopenharmony_ci LWIP_DEBUGF(BRIDGEIF_FW_DEBUG, ("br -> input(%p)\n", (void *)p)); 361195972f6Sopenharmony_ci if (br->netif->input(p, br->netif) != ERR_OK) { 362195972f6Sopenharmony_ci pbuf_free(p); 363195972f6Sopenharmony_ci } 364195972f6Sopenharmony_ci } else { 365195972f6Sopenharmony_ci /* all references done */ 366195972f6Sopenharmony_ci pbuf_free(p); 367195972f6Sopenharmony_ci } 368195972f6Sopenharmony_ci /* always return ERR_OK here to prevent the caller freeing the pbuf */ 369195972f6Sopenharmony_ci return ERR_OK; 370195972f6Sopenharmony_ci } else { 371195972f6Sopenharmony_ci /* is this for one of the local ports? */ 372195972f6Sopenharmony_ci if (bridgeif_is_local_mac(br, dst)) { 373195972f6Sopenharmony_ci /* yes, send to cpu port only */ 374195972f6Sopenharmony_ci LWIP_DEBUGF(BRIDGEIF_FW_DEBUG, ("br -> input(%p)\n", (void *)p)); 375195972f6Sopenharmony_ci return br->netif->input(p, br->netif); 376195972f6Sopenharmony_ci } 377195972f6Sopenharmony_ci 378195972f6Sopenharmony_ci /* get dst port */ 379195972f6Sopenharmony_ci dstports = bridgeif_find_dst_ports(br, dst); 380195972f6Sopenharmony_ci bridgeif_send_to_ports(br, p, dstports); 381195972f6Sopenharmony_ci /* no need to send to cpu, flooding is for external ports only */ 382195972f6Sopenharmony_ci /* by this, we consumed the pbuf */ 383195972f6Sopenharmony_ci pbuf_free(p); 384195972f6Sopenharmony_ci /* always return ERR_OK here to prevent the caller freeing the pbuf */ 385195972f6Sopenharmony_ci return ERR_OK; 386195972f6Sopenharmony_ci } 387195972f6Sopenharmony_ci} 388195972f6Sopenharmony_ci 389195972f6Sopenharmony_ci#if !BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT 390195972f6Sopenharmony_ci/** Input function for port netifs used to synchronize into tcpip_thread. 391195972f6Sopenharmony_ci */ 392195972f6Sopenharmony_cistatic err_t 393195972f6Sopenharmony_cibridgeif_tcpip_input(struct pbuf *p, struct netif *netif) 394195972f6Sopenharmony_ci{ 395195972f6Sopenharmony_ci return tcpip_inpkt(p, netif, bridgeif_input); 396195972f6Sopenharmony_ci} 397195972f6Sopenharmony_ci#endif /* BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT */ 398195972f6Sopenharmony_ci 399195972f6Sopenharmony_ci/** 400195972f6Sopenharmony_ci * @ingroup bridgeif 401195972f6Sopenharmony_ci * Initialization function passed to netif_add(). 402195972f6Sopenharmony_ci * 403195972f6Sopenharmony_ci * ATTENTION: A pointer to a @ref bridgeif_initdata_t must be passed as 'state' 404195972f6Sopenharmony_ci * to @ref netif_add when adding the bridge. I supplies MAC address 405195972f6Sopenharmony_ci * and controls memory allocation (number of ports, FDB size). 406195972f6Sopenharmony_ci * 407195972f6Sopenharmony_ci * @param netif the lwip network interface structure for this ethernetif 408195972f6Sopenharmony_ci * @return ERR_OK if the loopif is initialized 409195972f6Sopenharmony_ci * ERR_MEM if private data couldn't be allocated 410195972f6Sopenharmony_ci * any other err_t on error 411195972f6Sopenharmony_ci */ 412195972f6Sopenharmony_cierr_t 413195972f6Sopenharmony_cibridgeif_init(struct netif *netif) 414195972f6Sopenharmony_ci{ 415195972f6Sopenharmony_ci bridgeif_initdata_t *init_data; 416195972f6Sopenharmony_ci bridgeif_private_t *br; 417195972f6Sopenharmony_ci size_t alloc_len_sizet; 418195972f6Sopenharmony_ci mem_size_t alloc_len; 419195972f6Sopenharmony_ci 420195972f6Sopenharmony_ci LWIP_ASSERT("netif != NULL", (netif != NULL)); 421195972f6Sopenharmony_ci LWIP_ASSERT("bridgeif needs an input callback", (netif->input != NULL)); 422195972f6Sopenharmony_ci#if !BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT 423195972f6Sopenharmony_ci if (netif->input == tcpip_input) { 424195972f6Sopenharmony_ci LWIP_DEBUGF(BRIDGEIF_DEBUG | LWIP_DBG_ON, ("bridgeif does not need tcpip_input, use netif_input/ethernet_input instead")); 425195972f6Sopenharmony_ci } 426195972f6Sopenharmony_ci#endif 427195972f6Sopenharmony_ci 428195972f6Sopenharmony_ci if (bridgeif_netif_client_id == 0xFF) { 429195972f6Sopenharmony_ci bridgeif_netif_client_id = netif_alloc_client_data_id(); 430195972f6Sopenharmony_ci } 431195972f6Sopenharmony_ci 432195972f6Sopenharmony_ci init_data = (bridgeif_initdata_t *)netif->state; 433195972f6Sopenharmony_ci LWIP_ASSERT("init_data != NULL", (init_data != NULL)); 434195972f6Sopenharmony_ci LWIP_ASSERT("init_data->max_ports <= BRIDGEIF_MAX_PORTS", 435195972f6Sopenharmony_ci init_data->max_ports <= BRIDGEIF_MAX_PORTS); 436195972f6Sopenharmony_ci 437195972f6Sopenharmony_ci alloc_len_sizet = sizeof(bridgeif_private_t) + (init_data->max_ports * sizeof(bridgeif_port_t) + (init_data->max_fdb_static_entries * sizeof(bridgeif_fdb_static_entry_t))); 438195972f6Sopenharmony_ci alloc_len = (mem_size_t)alloc_len_sizet; 439195972f6Sopenharmony_ci LWIP_ASSERT("alloc_len == alloc_len_sizet", alloc_len == alloc_len_sizet); 440195972f6Sopenharmony_ci LWIP_DEBUGF(BRIDGEIF_DEBUG, ("bridgeif_init: allocating %d bytes for private data\n", (int)alloc_len)); 441195972f6Sopenharmony_ci br = (bridgeif_private_t *)mem_calloc(1, alloc_len); 442195972f6Sopenharmony_ci if (br == NULL) { 443195972f6Sopenharmony_ci LWIP_DEBUGF(NETIF_DEBUG, ("bridgeif_init: out of memory\n")); 444195972f6Sopenharmony_ci return ERR_MEM; 445195972f6Sopenharmony_ci } 446195972f6Sopenharmony_ci memcpy(&br->ethaddr, &init_data->ethaddr, sizeof(br->ethaddr)); 447195972f6Sopenharmony_ci br->netif = netif; 448195972f6Sopenharmony_ci 449195972f6Sopenharmony_ci br->max_ports = init_data->max_ports; 450195972f6Sopenharmony_ci br->ports = (bridgeif_port_t *)(br + 1); 451195972f6Sopenharmony_ci 452195972f6Sopenharmony_ci br->max_fdbs_entries = init_data->max_fdb_static_entries; 453195972f6Sopenharmony_ci br->fdbs = (bridgeif_fdb_static_entry_t *)(((u8_t *)(br + 1)) + (init_data->max_ports * sizeof(bridgeif_port_t))); 454195972f6Sopenharmony_ci 455195972f6Sopenharmony_ci br->max_fdbd_entries = init_data->max_fdb_dynamic_entries; 456195972f6Sopenharmony_ci br->fdbd = bridgeif_fdb_init(init_data->max_fdb_dynamic_entries); 457195972f6Sopenharmony_ci if (br->fdbd == NULL) { 458195972f6Sopenharmony_ci LWIP_DEBUGF(NETIF_DEBUG, ("bridgeif_init: out of memory in fdb_init\n")); 459195972f6Sopenharmony_ci mem_free(br); 460195972f6Sopenharmony_ci return ERR_MEM; 461195972f6Sopenharmony_ci } 462195972f6Sopenharmony_ci 463195972f6Sopenharmony_ci#if LWIP_NETIF_HOSTNAME 464195972f6Sopenharmony_ci /* Initialize interface hostname */ 465195972f6Sopenharmony_ci netif->hostname = "lwip"; 466195972f6Sopenharmony_ci#endif /* LWIP_NETIF_HOSTNAME */ 467195972f6Sopenharmony_ci 468195972f6Sopenharmony_ci /* 469195972f6Sopenharmony_ci * Initialize the snmp variables and counters inside the struct netif. 470195972f6Sopenharmony_ci * The last argument should be replaced with your link speed, in units 471195972f6Sopenharmony_ci * of bits per second. 472195972f6Sopenharmony_ci */ 473195972f6Sopenharmony_ci MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 0); 474195972f6Sopenharmony_ci 475195972f6Sopenharmony_ci netif->state = br; 476195972f6Sopenharmony_ci netif->name[0] = IFNAME0; 477195972f6Sopenharmony_ci netif->name[1] = IFNAME1; 478195972f6Sopenharmony_ci /* We directly use etharp_output() here to save a function call. 479195972f6Sopenharmony_ci * You can instead declare your own function an call etharp_output() 480195972f6Sopenharmony_ci * from it if you have to do some checks before sending (e.g. if link 481195972f6Sopenharmony_ci * is available...) */ 482195972f6Sopenharmony_ci#if LWIP_IPV4 483195972f6Sopenharmony_ci netif->output = etharp_output; 484195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 485195972f6Sopenharmony_ci#if LWIP_IPV6 486195972f6Sopenharmony_ci netif->output_ip6 = ethip6_output; 487195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 488195972f6Sopenharmony_ci netif->linkoutput = bridgeif_output; 489195972f6Sopenharmony_ci 490195972f6Sopenharmony_ci /* set MAC hardware address length */ 491195972f6Sopenharmony_ci netif->hwaddr_len = ETH_HWADDR_LEN; 492195972f6Sopenharmony_ci 493195972f6Sopenharmony_ci /* set MAC hardware address */ 494195972f6Sopenharmony_ci memcpy(netif->hwaddr, &br->ethaddr, ETH_HWADDR_LEN); 495195972f6Sopenharmony_ci 496195972f6Sopenharmony_ci /* maximum transfer unit */ 497195972f6Sopenharmony_ci netif->mtu = 1500; 498195972f6Sopenharmony_ci 499195972f6Sopenharmony_ci /* device capabilities */ 500195972f6Sopenharmony_ci /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ 501195972f6Sopenharmony_ci netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6 | NETIF_FLAG_LINK_UP; 502195972f6Sopenharmony_ci 503195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV6_MLD 504195972f6Sopenharmony_ci /* 505195972f6Sopenharmony_ci * For hardware/netifs that implement MAC filtering. 506195972f6Sopenharmony_ci * All-nodes link-local is handled by default, so we must let the hardware know 507195972f6Sopenharmony_ci * to allow multicast packets in. 508195972f6Sopenharmony_ci * Should set mld_mac_filter previously. */ 509195972f6Sopenharmony_ci if (netif->mld_mac_filter != NULL) { 510195972f6Sopenharmony_ci ip6_addr_t ip6_allnodes_ll; 511195972f6Sopenharmony_ci ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); 512195972f6Sopenharmony_ci netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER); 513195972f6Sopenharmony_ci } 514195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ 515195972f6Sopenharmony_ci 516195972f6Sopenharmony_ci return ERR_OK; 517195972f6Sopenharmony_ci} 518195972f6Sopenharmony_ci 519195972f6Sopenharmony_ci/** 520195972f6Sopenharmony_ci * @ingroup bridgeif 521195972f6Sopenharmony_ci * Add a port to the bridge 522195972f6Sopenharmony_ci */ 523195972f6Sopenharmony_cierr_t 524195972f6Sopenharmony_cibridgeif_add_port(struct netif *bridgeif, struct netif *portif) 525195972f6Sopenharmony_ci{ 526195972f6Sopenharmony_ci bridgeif_private_t *br; 527195972f6Sopenharmony_ci bridgeif_port_t *port; 528195972f6Sopenharmony_ci 529195972f6Sopenharmony_ci LWIP_ASSERT("bridgeif != NULL", bridgeif != NULL); 530195972f6Sopenharmony_ci LWIP_ASSERT("bridgeif->state != NULL", bridgeif->state != NULL); 531195972f6Sopenharmony_ci LWIP_ASSERT("portif != NULL", portif != NULL); 532195972f6Sopenharmony_ci 533195972f6Sopenharmony_ci if (!(portif->flags & NETIF_FLAG_ETHARP) || !(portif->flags & NETIF_FLAG_ETHERNET)) { 534195972f6Sopenharmony_ci /* can only add ETHERNET/ETHARP interfaces */ 535195972f6Sopenharmony_ci return ERR_VAL; 536195972f6Sopenharmony_ci } 537195972f6Sopenharmony_ci 538195972f6Sopenharmony_ci br = (bridgeif_private_t *)bridgeif->state; 539195972f6Sopenharmony_ci 540195972f6Sopenharmony_ci if (br->num_ports >= br->max_ports) { 541195972f6Sopenharmony_ci return ERR_VAL; 542195972f6Sopenharmony_ci } 543195972f6Sopenharmony_ci port = &br->ports[br->num_ports]; 544195972f6Sopenharmony_ci port->port_netif = portif; 545195972f6Sopenharmony_ci port->port_num = br->num_ports; 546195972f6Sopenharmony_ci port->bridge = br; 547195972f6Sopenharmony_ci br->num_ports++; 548195972f6Sopenharmony_ci 549195972f6Sopenharmony_ci /* let the port call us on input */ 550195972f6Sopenharmony_ci#if BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT 551195972f6Sopenharmony_ci portif->input = bridgeif_input; 552195972f6Sopenharmony_ci#else 553195972f6Sopenharmony_ci portif->input = bridgeif_tcpip_input; 554195972f6Sopenharmony_ci#endif 555195972f6Sopenharmony_ci /* store pointer to bridge in netif */ 556195972f6Sopenharmony_ci netif_set_client_data(portif, bridgeif_netif_client_id, port); 557195972f6Sopenharmony_ci /* remove ETHARP flag to prevent sending report events on netif-up */ 558195972f6Sopenharmony_ci netif_clear_flags(portif, NETIF_FLAG_ETHARP); 559195972f6Sopenharmony_ci 560195972f6Sopenharmony_ci return ERR_OK; 561195972f6Sopenharmony_ci} 562195972f6Sopenharmony_ci 563195972f6Sopenharmony_ci#endif /* LWIP_NUM_NETIF_CLIENT_DATA */ 564