Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_bridgeif_fdb.c Source File

lwip_bridgeif_fdb.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * lwIP netif implementing an FDB for 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_fdb FDB example code
00040  * @ingroup bridgeif
00041  * This file implements an example for an FDB (Forwarding DataBase)
00042  */
00043 
00044 #include "netif/bridgeif.h"
00045 #include "lwip/sys.h"
00046 #include "lwip/mem.h"
00047 #include "lwip/timeouts.h"
00048 #include <string.h>
00049 
00050 #define BRIDGEIF_AGE_TIMER_MS 1000
00051 
00052 #define BR_FDB_TIMEOUT_SEC  (60*5) /* 5 minutes FDB timeout */
00053 
00054 typedef struct bridgeif_dfdb_entry_s {
00055   u8_t used;
00056   u8_t port;
00057   u32_t ts;
00058   struct eth_addr addr;
00059 } bridgeif_dfdb_entry_t;
00060 
00061 typedef struct bridgeif_dfdb_s {
00062   u16_t max_fdb_entries;
00063   bridgeif_dfdb_entry_t *fdb;
00064 } bridgeif_dfdb_t;
00065 
00066 /**
00067  * @ingroup bridgeif_fdb
00068  * A real simple and slow implementation of an auto-learning forwarding database that
00069  * remembers known src mac addresses to know which port to send frames destined for that
00070  * mac address.
00071  *
00072  * ATTENTION: This is meant as an example only, in real-world use, you should 
00073  * provide a better implementation :-)
00074  */
00075 void
00076 bridgeif_fdb_update_src(void *fdb_ptr, struct eth_addr *src_addr, u8_t port_idx)
00077 {
00078   int i;
00079   bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)fdb_ptr;
00080   BRIDGEIF_DECL_PROTECT(lev);
00081   BRIDGEIF_READ_PROTECT(lev);
00082   for (i = 0; i < fdb->max_fdb_entries; i++) {
00083     bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
00084     if (e->used && e->ts) {
00085       if (!memcmp(&e->addr, src_addr, sizeof(struct eth_addr))) {
00086         LWIP_DEBUGF(BRIDGEIF_FDB_DEBUG, ("br: update src %02x:%02x:%02x:%02x:%02x:%02x (from %d) @ idx %d\n",
00087                                          src_addr->addr[0], src_addr->addr[1], src_addr->addr[2], src_addr->addr[3], src_addr->addr[4], src_addr->addr[5],
00088                                          port_idx, i));
00089         BRIDGEIF_WRITE_PROTECT(lev);
00090         e->ts = BR_FDB_TIMEOUT_SEC;
00091         e->port = port_idx;
00092         BRIDGEIF_WRITE_UNPROTECT(lev);
00093         BRIDGEIF_READ_UNPROTECT(lev);
00094         return;
00095       }
00096     }
00097   }
00098   /* not found, allocate new entry from free */
00099   for (i = 0; i < fdb->max_fdb_entries; i++) {
00100     bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
00101     if (!e->used || !e->ts) {
00102       BRIDGEIF_WRITE_PROTECT(lev);
00103       /* check again when protected */
00104       if (!e->used || !e->ts) {
00105         LWIP_DEBUGF(BRIDGEIF_FDB_DEBUG, ("br: create src %02x:%02x:%02x:%02x:%02x:%02x (from %d) @ idx %d\n",
00106                                          src_addr->addr[0], src_addr->addr[1], src_addr->addr[2], src_addr->addr[3], src_addr->addr[4], src_addr->addr[5],
00107                                          port_idx, i));
00108         memcpy(&e->addr, src_addr, sizeof(struct eth_addr));
00109         e->ts = BR_FDB_TIMEOUT_SEC;
00110         e->port = port_idx;
00111         e->used = 1;
00112         BRIDGEIF_WRITE_UNPROTECT(lev);
00113         BRIDGEIF_READ_UNPROTECT(lev);
00114         return;
00115       }
00116       BRIDGEIF_WRITE_UNPROTECT(lev);
00117     }
00118   }
00119   BRIDGEIF_READ_UNPROTECT(lev);
00120   /* not found, no free entry -> flood */
00121 }
00122 
00123 /** 
00124  * @ingroup bridgeif_fdb
00125  * Walk our list of auto-learnt fdb entries and return a port to forward or BR_FLOOD if unknown 
00126  */
00127 bridgeif_portmask_t
00128 bridgeif_fdb_get_dst_ports(void *fdb_ptr, struct eth_addr *dst_addr)
00129 {
00130   int i;
00131   bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)fdb_ptr;
00132   BRIDGEIF_DECL_PROTECT(lev);
00133   BRIDGEIF_READ_PROTECT(lev);
00134   for (i = 0; i < fdb->max_fdb_entries; i++) {
00135     bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
00136     if (e->used && e->ts) {
00137       if (!memcmp(&e->addr, dst_addr, sizeof(struct eth_addr))) {
00138         bridgeif_portmask_t ret = (bridgeif_portmask_t)(1 << e->port);
00139         BRIDGEIF_READ_UNPROTECT(lev);
00140         return ret;
00141       }
00142     }
00143   }
00144   BRIDGEIF_READ_UNPROTECT(lev);
00145   return BR_FLOOD;
00146 }
00147 
00148 /**
00149  * @ingroup bridgeif_fdb
00150  * Aging implementation of our simple fdb
00151  */
00152 static void
00153 bridgeif_fdb_age_one_second(void *fdb_ptr)
00154 {
00155   int i;
00156   bridgeif_dfdb_t *fdb;
00157   BRIDGEIF_DECL_PROTECT(lev);
00158 
00159   fdb = (bridgeif_dfdb_t *)fdb_ptr;
00160   BRIDGEIF_READ_PROTECT(lev);
00161 
00162   for (i = 0; i < fdb->max_fdb_entries; i++) {
00163     bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
00164     if (e->used && e->ts) {
00165       BRIDGEIF_WRITE_PROTECT(lev);
00166       /* check again when protected */
00167       if (e->used && e->ts) {
00168         if (--e->ts == 0) {
00169           e->used = 0;
00170         }
00171       }
00172       BRIDGEIF_WRITE_UNPROTECT(lev);
00173     }
00174   }
00175   BRIDGEIF_READ_UNPROTECT(lev);
00176 }
00177 
00178 /** Timer callback for fdb aging, called once per second */
00179 static void
00180 bridgeif_age_tmr(void *arg)
00181 {
00182   bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)arg;
00183 
00184   LWIP_ASSERT("invalid arg", arg != NULL);
00185 
00186   bridgeif_fdb_age_one_second(fdb);
00187   sys_timeout(BRIDGEIF_AGE_TIMER_MS, bridgeif_age_tmr, arg);
00188 }
00189 
00190 /**
00191  * @ingroup bridgeif_fdb
00192  * Init our simple fdb list
00193  */
00194 void *
00195 bridgeif_fdb_init(u16_t max_fdb_entries)
00196 {
00197   bridgeif_dfdb_t *fdb;
00198   size_t alloc_len_sizet = sizeof(bridgeif_dfdb_t) + (max_fdb_entries * sizeof(bridgeif_dfdb_entry_t));
00199   mem_size_t alloc_len = (mem_size_t)alloc_len_sizet;
00200   LWIP_ASSERT("alloc_len == alloc_len_sizet", alloc_len == alloc_len_sizet);
00201   LWIP_DEBUGF(BRIDGEIF_DEBUG, ("bridgeif_fdb_init: allocating %d bytes for private FDB data\n", (int)alloc_len));
00202   fdb = (bridgeif_dfdb_t *)mem_calloc(1, alloc_len);
00203   if (fdb == NULL) {
00204     return NULL;
00205   }
00206   fdb->max_fdb_entries = max_fdb_entries;
00207   fdb->fdb = (bridgeif_dfdb_entry_t *)(fdb + 1);
00208 
00209   sys_timeout(BRIDGEIF_AGE_TIMER_MS, bridgeif_age_tmr, fdb);
00210 
00211   return fdb;
00212 }