diff options
author | Nikolay Aleksandrov <nikolay@cumulusnetworks.com> | 2020-01-14 19:56:07 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-01-15 13:48:17 +0100 |
commit | 5a46facbbcd454985992b5109185329aebf82a02 (patch) | |
tree | c7245d4d5e613d6b80f8b3b2a4c0d4473e49dd20 | |
parent | f6310b61076028dfa5c11d9d68c7ad4adcb7742e (diff) | |
download | linux-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.c | 13 | ||||
-rw-r--r-- | net/bridge/br_private.h | 31 |
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) { |