@@ -481,6 +481,12 @@ enum batadv_nl_attrs {
*/
BATADV_ATTR_MULTICAST_FANOUT,
+ /**
+ * @BATADV_ATTR_VLAN_DYN_MAX: defines the maximum number of allowed
+ * learned VLANs from bridged-in clients.
+ */
+ BATADV_ATTR_VLAN_DYN_MAX,
+
/* add attributes above here, update the policy in netlink.c */
/**
@@ -129,6 +129,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = {
[BATADV_ATTR_MCAST_FLAGS] = { .type = NLA_U32 },
[BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NLA_U32 },
[BATADV_ATTR_VLANID] = { .type = NLA_U16 },
+ [BATADV_ATTR_VLAN_DYN_MAX] = { .type = NLA_U16 },
[BATADV_ATTR_AGGREGATED_OGMS_ENABLED] = { .type = NLA_U8 },
[BATADV_ATTR_AP_ISOLATION_ENABLED] = { .type = NLA_U8 },
[BATADV_ATTR_ISOLATION_MARK] = { .type = NLA_U32 },
@@ -357,6 +358,10 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg,
atomic_read(&bat_priv->orig_interval)))
goto nla_put_failure;
+ if (nla_put_u16(msg, BATADV_ATTR_VLAN_DYN_MAX,
+ bat_priv->softif_vlan_dyn_max))
+ goto nla_put_failure;
+
batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr);
@@ -611,6 +616,16 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info)
atomic_set(&bat_priv->orig_interval, orig_interval);
}
+ if (info->attrs[BATADV_ATTR_VLAN_DYN_MAX]) {
+ u16 vlan_dyn_max;
+
+ attr = info->attrs[BATADV_ATTR_VLAN_DYN_MAX];
+ vlan_dyn_max = nla_get_u16(attr);
+ vlan_dyn_max = min_t(u16, vlan_dyn_max, VLAN_N_VID);
+
+ bat_priv->softif_vlan_dyn_max = vlan_dyn_max;
+ }
+
batadv_netlink_notify_mesh(bat_priv);
return 0;
@@ -46,6 +46,7 @@
#include "distributed-arp-table.h"
#include "gateway_client.h"
#include "hard-interface.h"
+#include "log.h"
#include "multicast.h"
#include "network-coding.h"
#include "send.h"
@@ -561,8 +562,9 @@ struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
* otherwise.
*/
static struct batadv_softif_vlan *
-batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
+batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid, bool own)
{
+ unsigned short vlan_dyn_max, vlan_dyn_count;
struct batadv_softif_vlan *vlan;
spin_lock_bh(&bat_priv->softif_vlan_list_lock);
@@ -573,6 +575,19 @@ batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
return vlan;
}
+ vlan_dyn_max = bat_priv->softif_vlan_dyn_max;
+ vlan_dyn_count = bat_priv->softif_vlan_dyn_count;
+
+ if (vid & BATADV_VLAN_HAS_TAG && !own &&
+ vlan_dyn_max <= vlan_dyn_count) {
+ spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
+
+ net_ratelimited_function(batadv_info, bat_priv->soft_iface,
+ "not adding VLAN %d, already learned %hu VID(s)\n",
+ batadv_print_vid(vid), vlan_dyn_max);
+ return NULL;
+ }
+
vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
if (!vlan) {
spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
@@ -588,6 +603,9 @@ batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
atomic_set(&vlan->ap_isolation, 0);
+ if (vid & BATADV_VLAN_HAS_TAG && !own)
+ bat_priv->softif_vlan_dyn_count++;
+
hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
@@ -597,20 +615,21 @@ batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
/**
* batadv_softif_vlan_get_or_create() - retrieve or create a softif vlan struct
* @bat_priv: the bat priv with all the soft interface information
+ * @addr: the mac address of the client to add
* @vid: the VLAN identifier
*
* Return: the softif vlan struct if found or created or NULL otherwise.
*/
struct batadv_softif_vlan *
-batadv_softif_vlan_get_or_create(struct batadv_priv *bat_priv,
- unsigned short vid)
+batadv_softif_vlan_get_or_create(struct batadv_priv *bat_priv, const u8 *addr,
+ unsigned short vid, bool own)
{
struct batadv_softif_vlan *vlan = batadv_softif_vlan_get(bat_priv, vid);
if (vlan)
return vlan;
- return batadv_softif_create_vlan(bat_priv, vid);
+ return batadv_softif_create_vlan(bat_priv, vid, own);
}
/**
@@ -810,6 +829,8 @@ static int batadv_softif_init_late(struct net_device *dev)
bat_priv->tt.last_changeset_len = 0;
bat_priv->isolation_mark = 0;
bat_priv->isolation_mark_mask = 0;
+ bat_priv->softif_vlan_dyn_max = 0;
+ bat_priv->softif_vlan_dyn_count = 0;
/* randomize initial seqno to avoid collision */
get_random_bytes(&random_seqno, sizeof(random_seqno));
@@ -27,8 +27,8 @@ void batadv_softif_vlan_release(struct kref *ref);
struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
unsigned short vid);
struct batadv_softif_vlan *
-batadv_softif_vlan_get_or_create(struct batadv_priv *bat_priv,
- unsigned short vid);
+batadv_softif_vlan_get_or_create(struct batadv_priv *bat_priv, const u8 *addr,
+ unsigned short vid, bool own);
/**
* batadv_softif_vlan_put() - decrease the vlan object refcounter and
@@ -635,6 +635,7 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
int batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
unsigned short vid, int ifindex, u32 mark)
{
+ bool own = (ifindex == BATADV_NULL_IFINDEX) ? true : false;
struct batadv_priv *bat_priv = netdev_priv(soft_iface);
struct batadv_tt_local_entry *tt_local;
struct batadv_tt_global_entry *tt_global = NULL;
@@ -710,7 +711,7 @@ int batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
}
/* increase the refcounter of the related vlan */
- vlan = batadv_softif_vlan_get_or_create(bat_priv, vid);
+ vlan = batadv_softif_vlan_get_or_create(bat_priv, addr, vid, own);
if (!vlan) {
kmem_cache_free(batadv_tl_cache, tt_local);
tt_local = NULL;
@@ -1771,6 +1771,12 @@ struct batadv_priv {
/** @softif_vlan_list_lock: lock protecting softif_vlan_list */
spinlock_t softif_vlan_list_lock;
+ /** @softif_vlan_dyn_max: maximum number of allowed learned VLANs */
+ unsigned short softif_vlan_dyn_max;
+
+ /** @softif_vlan_dyn_count: current number of learned VLANs */
+ unsigned short softif_vlan_dyn_count;
+
#ifdef CONFIG_BATMAN_ADV_BLA
/** @bla: bridge loop avoidance data */
struct batadv_priv_bla bla;