net: dsa: check out-of-range ageing time value
authorVivien Didelot <vivien.didelot@savoirfairelinux.com>
Wed, 15 Mar 2017 19:53:49 +0000 (15:53 -0400)
committerDavid S. Miller <davem@davemloft.net>
Wed, 15 Mar 2017 22:34:13 +0000 (15:34 -0700)
If a DSA switch driver cannot program an ageing time value due to it
being out-of-range, switchdev will raise a stack trace before failing.

To fix this, add ageing_time_min and ageing_time_max members to the
dsa_switch in order for the switch drivers to optionally specify their
supported ageing time limits.

The DSA core will now check for provided ageing time limits and return
-ERANGE from the switchdev prepare phase if the value is out-of-range.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/dsa.h
net/dsa/slave.c

index bf0e42c2a6f78b2f92cdd17f2f06aa9e46feb8e6..e42897fd7a9658c81485aecbba34f4ee16bedd56 100644 (file)
@@ -233,6 +233,10 @@ struct dsa_switch {
        u32                     phys_mii_mask;
        struct mii_bus          *slave_mii_bus;
 
+       /* Ageing Time limits in msecs */
+       unsigned int ageing_time_min;
+       unsigned int ageing_time_max;
+
        /* Dynamically allocated ports, keep last */
        size_t num_ports;
        struct dsa_port ports[];
index cec47e8435705384f8a271150ee3d81d51f646fc..78128acfbf633b255d4c4ce87b66564ba416a85d 100644 (file)
@@ -443,9 +443,13 @@ static int dsa_slave_ageing_time(struct net_device *dev,
        unsigned long ageing_jiffies = clock_t_to_jiffies(attr->u.ageing_time);
        unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies);
 
-       /* bridge skips -EOPNOTSUPP, so skip the prepare phase */
-       if (switchdev_trans_ph_prepare(trans))
+       if (switchdev_trans_ph_prepare(trans)) {
+               if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
+                       return -ERANGE;
+               if (ds->ageing_time_max && ageing_time > ds->ageing_time_max)
+                       return -ERANGE;
                return 0;
+       }
 
        /* Keep the fastest ageing time in case of multiple bridges */
        p->dp->ageing_time = ageing_time;