net: bridge: vlan: add helpers to check for vlan id/range validity
authorNikolay Aleksandrov <nikolay@cumulusnetworks.com>
Tue, 14 Jan 2020 17:56:07 +0000 (19:56 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 15 Jan 2020 12:48:17 +0000 (13:48 +0100)
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>
net/bridge/br_netlink.c
net/bridge/br_private.h

index 6013657..14100e8 100644 (file)
@@ -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,
index f540f3b..dbc0089 100644 (file)
@@ -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)
 {