summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Aleksandrov <nikolay@cumulusnetworks.com>2020-01-14 19:56:07 +0200
committerDavid S. Miller <davem@davemloft.net>2020-01-15 13:48:17 +0100
commit5a46facbbcd454985992b5109185329aebf82a02 (patch)
treec7245d4d5e613d6b80f8b3b2a4c0d4473e49dd20
parentf6310b61076028dfa5c11d9d68c7ad4adcb7742e (diff)
downloadlinux-5a46facbbcd454985992b5109185329aebf82a02.tar.gz
linux-5a46facbbcd454985992b5109185329aebf82a02.tar.bz2
linux-5a46facbbcd454985992b5109185329aebf82a02.zip
net: bridge: vlan: add helpers to check for vlan id/range validity
Add helpers to check if a vlan id or range are valid. The range helper must be called when range start or end are detected. Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/bridge/br_netlink.c13
-rw-r--r--net/bridge/br_private.h31
2 files changed, 34 insertions, 10 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 60136575aea4..14100e8653e6 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -568,17 +568,13 @@ static int br_process_vlan_info(struct net_bridge *br,
bool *changed,
struct netlink_ext_ack *extack)
{
- if (!vinfo_curr->vid || vinfo_curr->vid >= VLAN_VID_MASK)
+ if (!br_vlan_valid_id(vinfo_curr->vid))
return -EINVAL;
if (vinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
- /* check if we are already processing a range */
- if (*vinfo_last)
+ if (!br_vlan_valid_range(vinfo_curr, *vinfo_last))
return -EINVAL;
*vinfo_last = vinfo_curr;
- /* don't allow range of pvids */
- if ((*vinfo_last)->flags & BRIDGE_VLAN_INFO_PVID)
- return -EINVAL;
return 0;
}
@@ -586,10 +582,7 @@ static int br_process_vlan_info(struct net_bridge *br,
struct bridge_vlan_info tmp_vinfo;
int v, err;
- if (!(vinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_END))
- return -EINVAL;
-
- if (vinfo_curr->vid <= (*vinfo_last)->vid)
+ if (!br_vlan_valid_range(vinfo_curr, *vinfo_last))
return -EINVAL;
memcpy(&tmp_vinfo, *vinfo_last,
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index f540f3bdf294..dbc0089e2c1a 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -507,6 +507,37 @@ static inline bool nbp_state_should_learn(const struct net_bridge_port *p)
return p->state == BR_STATE_LEARNING || p->state == BR_STATE_FORWARDING;
}
+static inline bool br_vlan_valid_id(u16 vid)
+{
+ return vid > 0 && vid < VLAN_VID_MASK;
+}
+
+static inline bool br_vlan_valid_range(const struct bridge_vlan_info *cur,
+ const struct bridge_vlan_info *last)
+{
+ /* pvid flag is not allowed in ranges */
+ if (cur->flags & BRIDGE_VLAN_INFO_PVID)
+ return false;
+
+ /* check for required range flags */
+ if (!(cur->flags & (BRIDGE_VLAN_INFO_RANGE_BEGIN |
+ BRIDGE_VLAN_INFO_RANGE_END)))
+ return false;
+
+ /* when cur is the range end, check if:
+ * - it has range start flag
+ * - range ids are invalid (end is equal to or before start)
+ */
+ if (last) {
+ if (cur->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
+ return false;
+ else if (cur->vid <= last->vid)
+ return false;
+ }
+
+ return true;
+}
+
static inline int br_opt_get(const struct net_bridge *br,
enum net_bridge_opts opt)
{