summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Didelot <vivien.didelot@savoirfairelinux.com>2017-03-15 15:53:49 -0400
committerDavid S. Miller <davem@davemloft.net>2017-03-15 15:34:13 -0700
commit0f3da6afeef1f63c7254965253f7e6535dc7910c (patch)
treef5a40b417d8295bc496b39a30acda78e11c09736
parente893de1ba1d39e78750ffadf7191aef8133c8fe8 (diff)
net: dsa: check out-of-range ageing time value
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>
-rw-r--r--include/net/dsa.h4
-rw-r--r--net/dsa/slave.c8
2 files changed, 10 insertions, 2 deletions
diff --git a/include/net/dsa.h b/include/net/dsa.h
index bf0e42c2a6f7..e42897fd7a96 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -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[];
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index cec47e843570..78128acfbf63 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -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;