Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_bridgeif.c
00001 /** 00002 * @file 00003 * lwIP netif implementing an IEEE 802.1D MAC Bridge 00004 */ 00005 00006 /* 00007 * Copyright (c) 2017 Simon Goldschmidt. 00008 * All rights reserved. 00009 * 00010 * Redistribution and use in source and binary forms, with or without modification, 00011 * are permitted provided that the following conditions are met: 00012 * 00013 * 1. Redistributions of source code must retain the above copyright notice, 00014 * this list of conditions and the following disclaimer. 00015 * 2. Redistributions in binary form must reproduce the above copyright notice, 00016 * this list of conditions and the following disclaimer in the documentation 00017 * and/or other materials provided with the distribution. 00018 * 3. The name of the author may not be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00022 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00024 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00026 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00029 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00030 * OF SUCH DAMAGE. 00031 * 00032 * This file is part of the lwIP TCP/IP stack. 00033 * 00034 * Author: Simon Goldschmidt <goldsimon@gmx.de> 00035 * 00036 */ 00037 00038 /** 00039 * @defgroup bridgeif IEEE 802.1D bridge 00040 * @ingroup netifs 00041 * This file implements an IEEE 802.1D bridge by using a multilayer netif approach 00042 * (one hardware-independent netif for the bridge that uses hardware netifs for its ports). 00043 * On transmit, the bridge selects the outgoing port(s). 00044 * On receive, the port netif calls into the bridge (via its netif->input function) and 00045 * the bridge selects the port(s) (and/or its netif->input function) to pass the received pbuf to. 00046 * 00047 * Usage: 00048 * - add the port netifs just like you would when using them as dedicated netif without a bridge 00049 * - only NETIF_FLAG_ETHARP/NETIF_FLAG_ETHERNET netifs are supported as bridge ports 00050 * - add the bridge port netifs without IPv4 addresses (i.e. pass 'NULL, NULL, NULL') 00051 * - don't add IPv6 addresses to the port netifs! 00052 * - set up the bridge configuration in a global variable of type 'bridgeif_initdata_t' that contains 00053 * - the MAC address of the bridge 00054 * - some configuration options controlling the memory consumption (maximum number of ports 00055 * and FDB entries) 00056 * - e.g. for a bridge MAC address 00-01-02-03-04-05, 2 bridge ports, 1024 FDB entries + 16 static MAC entries: 00057 * bridgeif_initdata_t mybridge_initdata = BRIDGEIF_INITDATA1(2, 1024, 16, ETH_ADDR(0, 1, 2, 3, 4, 5)); 00058 * - add the bridge netif (with IPv4 config): 00059 * struct netif bridge_netif; 00060 * netif_add(&bridge_netif, &my_ip, &my_netmask, &my_gw, &mybridge_initdata, bridgeif_init, tcpip_input); 00061 * NOTE: the passed 'input' function depends on BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT setting, 00062 * which controls where the forwarding is done (netif low level input context vs. tcpip_thread) 00063 * - set up all ports netifs and the bridge netif 00064 * 00065 * - When adding a port netif, NETIF_FLAG_ETHARP flag will be removed from a port 00066 * to prevent ETHARP working on that port netif (we only want one IP per bridge not per port). 00067 * - When adding a port netif, its input function is changed to call into the bridge. 00068 * 00069 * 00070 * @todo: 00071 * - compact static FDB entries (instead of walking the whole array) 00072 * - add FDB query/read access 00073 * - add FDB change callback (when learning or dropping auto-learned entries) 00074 * - prefill FDB with MAC classes that should never be forwarded 00075 * - multicast snooping? (and only forward group addresses to interested ports) 00076 * - support removing ports 00077 * - check SNMP integration 00078 * - VLAN handling / trunk ports 00079 * - priority handling? (although that largely depends on TX queue limitations and lwIP doesn't provide tx-done handling) 00080 */ 00081 00082 #include "netif/bridgeif.h" 00083 #include "lwip/netif.h" 00084 #include "lwip/sys.h" 00085 #include "lwip/etharp.h" 00086 #include "lwip/ethip6.h" 00087 #include "lwip/snmp.h" 00088 #include "lwip/timeouts.h" 00089 #include <string.h> 00090 00091 #if LWIP_NUM_NETIF_CLIENT_DATA 00092 00093 /* Define those to better describe your network interface. */ 00094 #define IFNAME0 'b' 00095 #define IFNAME1 'r' 00096 00097 struct bridgeif_private_s; 00098 typedef struct bridgeif_port_private_s { 00099 struct bridgeif_private_s *bridge; 00100 struct netif *port_netif; 00101 u8_t port_num; 00102 } bridgeif_port_t; 00103 00104 typedef struct bridgeif_fdb_static_entry_s { 00105 u8_t used; 00106 bridgeif_portmask_t dst_ports; 00107 struct eth_addr addr; 00108 } bridgeif_fdb_static_entry_t; 00109 00110 typedef struct bridgeif_private_s { 00111 struct netif *netif; 00112 struct eth_addr ethaddr; 00113 u8_t max_ports; 00114 u8_t num_ports; 00115 bridgeif_port_t *ports; 00116 u16_t max_fdbs_entries; 00117 bridgeif_fdb_static_entry_t *fdbs; 00118 u16_t max_fdbd_entries; 00119 void *fdbd; 00120 } bridgeif_private_t; 00121 00122 /* netif data index to get the bridge on input */ 00123 u8_t bridgeif_netif_client_id = 0xff; 00124 00125 /** 00126 * @ingroup bridgeif 00127 * Add a static entry to the forwarding database. 00128 * A static entry marks where frames to a specific eth address (unicast or group address) are 00129 * forwarded. 00130 * bits [0..(BRIDGEIF_MAX_PORTS-1)]: hw ports 00131 * bit [BRIDGEIF_MAX_PORTS]: cpu port 00132 * 0: drop 00133 */ 00134 err_t 00135 bridgeif_fdb_add(struct netif *bridgeif, const struct eth_addr *addr, bridgeif_portmask_t ports) 00136 { 00137 int i; 00138 bridgeif_private_t *br; 00139 BRIDGEIF_DECL_PROTECT(lev); 00140 LWIP_ASSERT("invalid netif", bridgeif != NULL); 00141 br = (bridgeif_private_t *)bridgeif->state; 00142 LWIP_ASSERT("invalid state", br != NULL); 00143 00144 BRIDGEIF_READ_PROTECT(lev); 00145 for (i = 0; i < br->max_fdbs_entries; i++) { 00146 if (!br->fdbs[i].used) { 00147 BRIDGEIF_WRITE_PROTECT(lev); 00148 if (!br->fdbs[i].used) { 00149 br->fdbs[i].used = 1; 00150 br->fdbs[i].dst_ports = ports; 00151 memcpy(&br->fdbs[i].addr, addr, sizeof(struct eth_addr)); 00152 BRIDGEIF_WRITE_UNPROTECT(lev); 00153 BRIDGEIF_READ_UNPROTECT(lev); 00154 return ERR_OK; 00155 } 00156 BRIDGEIF_WRITE_UNPROTECT(lev); 00157 } 00158 } 00159 BRIDGEIF_READ_UNPROTECT(lev); 00160 return ERR_MEM; 00161 } 00162 00163 /** 00164 * @ingroup bridgeif 00165 * Remove a static entry from the forwarding database 00166 */ 00167 err_t 00168 bridgeif_fdb_remove(struct netif *bridgeif, const struct eth_addr *addr) 00169 { 00170 int i; 00171 bridgeif_private_t *br; 00172 BRIDGEIF_DECL_PROTECT(lev); 00173 LWIP_ASSERT("invalid netif", bridgeif != NULL); 00174 br = (bridgeif_private_t *)bridgeif->state; 00175 LWIP_ASSERT("invalid state", br != NULL); 00176 00177 BRIDGEIF_READ_PROTECT(lev); 00178 for (i = 0; i < br->max_fdbs_entries; i++) { 00179 if (br->fdbs[i].used && !memcmp(&br->fdbs[i].addr, addr, sizeof(struct eth_addr))) { 00180 BRIDGEIF_WRITE_PROTECT(lev); 00181 if (br->fdbs[i].used && !memcmp(&br->fdbs[i].addr, addr, sizeof(struct eth_addr))) { 00182 memset(&br->fdbs[i], 0, sizeof(bridgeif_fdb_static_entry_t)); 00183 BRIDGEIF_WRITE_UNPROTECT(lev); 00184 BRIDGEIF_READ_UNPROTECT(lev); 00185 return ERR_OK; 00186 } 00187 BRIDGEIF_WRITE_UNPROTECT(lev); 00188 } 00189 } 00190 BRIDGEIF_READ_UNPROTECT(lev); 00191 return ERR_VAL; 00192 } 00193 00194 /** Get the forwarding port(s) (as bit mask) for the specified destination mac address */ 00195 static bridgeif_portmask_t 00196 bridgeif_find_dst_ports(bridgeif_private_t *br, struct eth_addr *dst_addr) 00197 { 00198 int i; 00199 BRIDGEIF_DECL_PROTECT(lev); 00200 BRIDGEIF_READ_PROTECT(lev); 00201 /* first check for static entries */ 00202 for (i = 0; i < br->max_fdbs_entries; i++) { 00203 if (br->fdbs[i].used) { 00204 if (!memcmp(&br->fdbs[i].addr, dst_addr, sizeof(struct eth_addr))) { 00205 bridgeif_portmask_t ret = br->fdbs[i].dst_ports; 00206 BRIDGEIF_READ_UNPROTECT(lev); 00207 return ret; 00208 } 00209 } 00210 } 00211 if (dst_addr->addr[0] & 1) { 00212 /* no match found: flood remaining group address */ 00213 BRIDGEIF_READ_UNPROTECT(lev); 00214 return BR_FLOOD; 00215 } 00216 BRIDGEIF_READ_UNPROTECT(lev); 00217 /* no match found: check dynamic fdb for port or fall back to flooding */ 00218 return bridgeif_fdb_get_dst_ports(br->fdbd, dst_addr); 00219 } 00220 00221 /** Helper function to see if a destination mac belongs to the bridge 00222 * (bridge netif or one of the port netifs), in which case the frame 00223 * is sent to the cpu only. 00224 */ 00225 static int 00226 bridgeif_is_local_mac(bridgeif_private_t *br, struct eth_addr *addr) 00227 { 00228 int i; 00229 BRIDGEIF_DECL_PROTECT(lev); 00230 if (!memcmp(br->netif->hwaddr, addr, sizeof(struct eth_addr))) { 00231 return 1; 00232 } 00233 BRIDGEIF_READ_PROTECT(lev); 00234 for (i = 0; i < br->num_ports; i++) { 00235 struct netif *portif = br->ports[i].port_netif; 00236 if (portif != NULL) { 00237 if (!memcmp(portif->hwaddr, addr, sizeof(struct eth_addr))) { 00238 BRIDGEIF_READ_UNPROTECT(lev); 00239 return 1; 00240 } 00241 } 00242 } 00243 BRIDGEIF_READ_UNPROTECT(lev); 00244 return 0; 00245 } 00246 00247 /* Output helper function */ 00248 static err_t 00249 bridgeif_send_to_port(bridgeif_private_t *br, struct pbuf *p, u8_t dstport_idx) 00250 { 00251 if (dstport_idx < BRIDGEIF_MAX_PORTS) { 00252 /* possibly an external port */ 00253 if (dstport_idx < br->max_ports) { 00254 struct netif *portif = br->ports[dstport_idx].port_netif; 00255 if ((portif != NULL) && (portif->linkoutput != NULL)) { 00256 /* prevent sending out to rx port */ 00257 if (netif_get_index(portif) != p->if_idx) { 00258 if (netif_is_link_up(portif)) { 00259 LWIP_DEBUGF(BRIDGEIF_FW_DEBUG, ("br -> flood(%p:%d) -> %d\n", (void *)p, p->if_idx, netif_get_index(portif))); 00260 return portif->linkoutput(portif, p); 00261 } 00262 } 00263 } 00264 } 00265 } else { 00266 LWIP_ASSERT("invalid port index", dstport_idx == BRIDGEIF_MAX_PORTS); 00267 } 00268 return ERR_OK; 00269 } 00270 00271 /** Helper function to pass a pbuf to all ports marked in 'dstports' 00272 */ 00273 static err_t 00274 bridgeif_send_to_ports(bridgeif_private_t *br, struct pbuf *p, bridgeif_portmask_t dstports) 00275 { 00276 err_t err, ret_err = ERR_OK; 00277 u8_t i; 00278 bridgeif_portmask_t mask = 1; 00279 BRIDGEIF_DECL_PROTECT(lev); 00280 BRIDGEIF_READ_PROTECT(lev); 00281 for (i = 0; i < BRIDGEIF_MAX_PORTS; i++, mask = (bridgeif_portmask_t)(mask << 1)) { 00282 if (dstports & mask) { 00283 err = bridgeif_send_to_port(br, p, i); 00284 if (err != ERR_OK) { 00285 ret_err = err; 00286 } 00287 } 00288 } 00289 BRIDGEIF_READ_UNPROTECT(lev); 00290 return ret_err; 00291 } 00292 00293 /** Output function of the application port of the bridge (the one with an ip address). 00294 * The forwarding port(s) where this pbuf is sent on is/are automatically selected 00295 * from the FDB. 00296 */ 00297 static err_t 00298 bridgeif_output(struct netif *netif, struct pbuf *p) 00299 { 00300 err_t err; 00301 bridgeif_private_t *br = (bridgeif_private_t *)netif->state; 00302 struct eth_addr *dst = (struct eth_addr *)(p->payload); 00303 00304 bridgeif_portmask_t dstports = bridgeif_find_dst_ports(br, dst); 00305 err = bridgeif_send_to_ports(br, p, dstports); 00306 00307 MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); 00308 if (((u8_t *)p->payload)[0] & 1) { 00309 /* broadcast or multicast packet*/ 00310 MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); 00311 } else { 00312 /* unicast packet */ 00313 MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); 00314 } 00315 /* increase ifoutdiscards or ifouterrors on error */ 00316 00317 LINK_STATS_INC(link.xmit); 00318 00319 return err; 00320 } 00321 00322 /** The actual bridge input function. Port netif's input is changed to call 00323 * here. This function decides where the frame is forwarded. 00324 */ 00325 static err_t 00326 bridgeif_input(struct pbuf *p, struct netif *netif) 00327 { 00328 u8_t rx_idx; 00329 bridgeif_portmask_t dstports; 00330 struct eth_addr *src, *dst; 00331 bridgeif_private_t *br; 00332 bridgeif_port_t *port; 00333 if (p == NULL || netif == NULL) { 00334 return ERR_VAL; 00335 } 00336 port = (bridgeif_port_t *)netif_get_client_data(netif, bridgeif_netif_client_id); 00337 LWIP_ASSERT("port data not set", port != NULL); 00338 if (port == NULL || port->bridge == NULL) { 00339 return ERR_VAL; 00340 } 00341 br = (bridgeif_private_t *)port->bridge; 00342 rx_idx = netif_get_index(netif); 00343 /* store receive index in pbuf */ 00344 p->if_idx = rx_idx; 00345 00346 dst = (struct eth_addr *)p->payload; 00347 src = (struct eth_addr *)(((u8_t *)p->payload) + sizeof(struct eth_addr)); 00348 00349 if ((src->addr[0] & 1) == 0) { 00350 /* update src for all non-group addresses */ 00351 bridgeif_fdb_update_src(br->fdbd, src, port->port_num); 00352 } 00353 00354 if (dst->addr[0] & 1) { 00355 /* group address -> flood + cpu? */ 00356 dstports = bridgeif_find_dst_ports(br, dst); 00357 bridgeif_send_to_ports(br, p, dstports); 00358 if (dstports & (1 << BRIDGEIF_MAX_PORTS)) { 00359 /* we pass the reference to ->input or have to free it */ 00360 LWIP_DEBUGF(BRIDGEIF_FW_DEBUG, ("br -> input(%p)\n", (void *)p)); 00361 if (br->netif->input(p, br->netif) != ERR_OK) { 00362 pbuf_free(p); 00363 } 00364 } else { 00365 /* all references done */ 00366 pbuf_free(p); 00367 } 00368 /* always return ERR_OK here to prevent the caller freeing the pbuf */ 00369 return ERR_OK; 00370 } else { 00371 /* is this for one of the local ports? */ 00372 if (bridgeif_is_local_mac(br, dst)) { 00373 /* yes, send to cpu port only */ 00374 LWIP_DEBUGF(BRIDGEIF_FW_DEBUG, ("br -> input(%p)\n", (void *)p)); 00375 return br->netif->input(p, br->netif); 00376 } 00377 00378 /* get dst port */ 00379 dstports = bridgeif_find_dst_ports(br, dst); 00380 bridgeif_send_to_ports(br, p, dstports); 00381 /* no need to send to cpu, flooding is for external ports only */ 00382 /* by this, we consumed the pbuf */ 00383 pbuf_free(p); 00384 /* always return ERR_OK here to prevent the caller freeing the pbuf */ 00385 return ERR_OK; 00386 } 00387 } 00388 00389 #if !BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT 00390 /** Input function for port netifs used to synchronize into tcpip_thread. 00391 */ 00392 static err_t 00393 bridgeif_tcpip_input(struct pbuf *p, struct netif *netif) 00394 { 00395 return tcpip_inpkt(p, netif, bridgeif_input); 00396 } 00397 #endif /* BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT */ 00398 00399 /** 00400 * @ingroup bridgeif 00401 * Initialization function passed to netif_add(). 00402 * 00403 * ATTENTION: A pointer to a @ref bridgeif_initdata_t must be passed as 'state' 00404 * to @ref netif_add when adding the bridge. I supplies MAC address 00405 * and controls memory allocation (number of ports, FDB size). 00406 * 00407 * @param netif the lwip network interface structure for this ethernetif 00408 * @return ERR_OK if the loopif is initialized 00409 * ERR_MEM if private data couldn't be allocated 00410 * any other err_t on error 00411 */ 00412 err_t 00413 bridgeif_init(struct netif *netif) 00414 { 00415 bridgeif_initdata_t *init_data; 00416 bridgeif_private_t *br; 00417 size_t alloc_len_sizet; 00418 mem_size_t alloc_len; 00419 00420 LWIP_ASSERT("netif != NULL", (netif != NULL)); 00421 LWIP_ASSERT("bridgeif needs an input callback", (netif->input != NULL)); 00422 #if !BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT 00423 if (netif->input == tcpip_input) { 00424 LWIP_DEBUGF(BRIDGEIF_DEBUG | LWIP_DBG_ON, ("bridgeif does not need tcpip_input, use netif_input/ethernet_input instead")); 00425 } 00426 #endif 00427 00428 if (bridgeif_netif_client_id == 0xFF) { 00429 bridgeif_netif_client_id = netif_alloc_client_data_id(); 00430 } 00431 00432 init_data = (bridgeif_initdata_t *)netif->state; 00433 LWIP_ASSERT("init_data != NULL", (init_data != NULL)); 00434 LWIP_ASSERT("init_data->max_ports <= BRIDGEIF_MAX_PORTS", 00435 init_data->max_ports <= BRIDGEIF_MAX_PORTS); 00436 00437 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))); 00438 alloc_len = (mem_size_t)alloc_len_sizet; 00439 LWIP_ASSERT("alloc_len == alloc_len_sizet", alloc_len == alloc_len_sizet); 00440 LWIP_DEBUGF(BRIDGEIF_DEBUG, ("bridgeif_init: allocating %d bytes for private data\n", (int)alloc_len)); 00441 br = (bridgeif_private_t *)mem_calloc(1, alloc_len); 00442 if (br == NULL) { 00443 LWIP_DEBUGF(NETIF_DEBUG, ("bridgeif_init: out of memory\n")); 00444 return ERR_MEM; 00445 } 00446 memcpy(&br->ethaddr, &init_data->ethaddr, sizeof(br->ethaddr)); 00447 br->netif = netif; 00448 00449 br->max_ports = init_data->max_ports; 00450 br->ports = (bridgeif_port_t *)(br + 1); 00451 00452 br->max_fdbs_entries = init_data->max_fdb_static_entries; 00453 br->fdbs = (bridgeif_fdb_static_entry_t *)(((u8_t *)(br + 1)) + (init_data->max_ports * sizeof(bridgeif_port_t))); 00454 00455 br->max_fdbd_entries = init_data->max_fdb_dynamic_entries; 00456 br->fdbd = bridgeif_fdb_init(init_data->max_fdb_dynamic_entries); 00457 if (br->fdbd == NULL) { 00458 LWIP_DEBUGF(NETIF_DEBUG, ("bridgeif_init: out of memory in fdb_init\n")); 00459 mem_free(br); 00460 return ERR_MEM; 00461 } 00462 00463 #if LWIP_NETIF_HOSTNAME 00464 /* Initialize interface hostname */ 00465 netif->hostname = "lwip"; 00466 #endif /* LWIP_NETIF_HOSTNAME */ 00467 00468 /* 00469 * Initialize the snmp variables and counters inside the struct netif. 00470 * The last argument should be replaced with your link speed, in units 00471 * of bits per second. 00472 */ 00473 MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 0); 00474 00475 netif->state = br; 00476 netif->name[0] = IFNAME0; 00477 netif->name[1] = IFNAME1; 00478 /* We directly use etharp_output() here to save a function call. 00479 * You can instead declare your own function an call etharp_output() 00480 * from it if you have to do some checks before sending (e.g. if link 00481 * is available...) */ 00482 #if LWIP_IPV4 00483 netif->output = etharp_output; 00484 #endif /* LWIP_IPV4 */ 00485 #if LWIP_IPV6 00486 netif->output_ip6 = ethip6_output; 00487 #endif /* LWIP_IPV6 */ 00488 netif->linkoutput = bridgeif_output; 00489 00490 /* set MAC hardware address length */ 00491 netif->hwaddr_len = ETH_HWADDR_LEN; 00492 00493 /* set MAC hardware address */ 00494 memcpy(netif->hwaddr, &br->ethaddr, ETH_HWADDR_LEN); 00495 00496 /* maximum transfer unit */ 00497 netif->mtu = 1500; 00498 00499 /* device capabilities */ 00500 /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ 00501 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6 | NETIF_FLAG_LINK_UP; 00502 00503 #if LWIP_IPV6 && LWIP_IPV6_MLD 00504 /* 00505 * For hardware/netifs that implement MAC filtering. 00506 * All-nodes link-local is handled by default, so we must let the hardware know 00507 * to allow multicast packets in. 00508 * Should set mld_mac_filter previously. */ 00509 if (netif->mld_mac_filter != NULL) { 00510 ip6_addr_t ip6_allnodes_ll; 00511 ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); 00512 netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER); 00513 } 00514 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ 00515 00516 return ERR_OK; 00517 } 00518 00519 /** 00520 * @ingroup bridgeif 00521 * Add a port to the bridge 00522 */ 00523 err_t 00524 bridgeif_add_port(struct netif *bridgeif, struct netif *portif) 00525 { 00526 bridgeif_private_t *br; 00527 bridgeif_port_t *port; 00528 00529 LWIP_ASSERT("bridgeif != NULL", bridgeif != NULL); 00530 LWIP_ASSERT("bridgeif->state != NULL", bridgeif->state != NULL); 00531 LWIP_ASSERT("portif != NULL", portif != NULL); 00532 00533 if (!(portif->flags & NETIF_FLAG_ETHARP) || !(portif->flags & NETIF_FLAG_ETHERNET)) { 00534 /* can only add ETHERNET/ETHARP interfaces */ 00535 return ERR_VAL; 00536 } 00537 00538 br = (bridgeif_private_t *)bridgeif->state; 00539 00540 if (br->num_ports >= br->max_ports) { 00541 return ERR_VAL; 00542 } 00543 port = &br->ports[br->num_ports]; 00544 port->port_netif = portif; 00545 port->port_num = br->num_ports; 00546 port->bridge = br; 00547 br->num_ports++; 00548 00549 /* let the port call us on input */ 00550 #if BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT 00551 portif->input = bridgeif_input; 00552 #else 00553 portif->input = bridgeif_tcpip_input; 00554 #endif 00555 /* store pointer to bridge in netif */ 00556 netif_set_client_data(portif, bridgeif_netif_client_id, port); 00557 /* remove ETHARP flag to prevent sending report events on netif-up */ 00558 netif_clear_flags(portif, NETIF_FLAG_ETHARP); 00559 00560 return ERR_OK; 00561 } 00562 00563 #endif /* LWIP_NUM_NETIF_CLIENT_DATA */
Generated on Tue Jul 12 2022 13:54:28 by
