diff options
Diffstat (limited to 'drivers/net/can/dev.c')
-rw-r--r-- | drivers/net/can/dev.c | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 8d6208c0b400..fefe2cd17721 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -958,6 +958,30 @@ static int can_changelink(struct net_device *dev, } } + if (data[IFLA_CAN_TERMINATION]) { + const u16 termval = nla_get_u16(data[IFLA_CAN_TERMINATION]); + const unsigned int num_term = priv->termination_const_cnt; + unsigned int i; + + if (!priv->do_set_termination) + return -EOPNOTSUPP; + + /* check whether given value is supported by the interface */ + for (i = 0; i < num_term; i++) { + if (termval == priv->termination_const[i]) + break; + } + if (i >= num_term) + return -EINVAL; + + /* Finally, set the termination value */ + err = priv->do_set_termination(dev, termval); + if (err) + return err; + + priv->termination = termval; + } + return 0; } @@ -980,6 +1004,11 @@ static size_t can_get_size(const struct net_device *dev) size += nla_total_size(sizeof(struct can_bittiming)); if (priv->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */ size += nla_total_size(sizeof(struct can_bittiming_const)); + if (priv->termination_const) { + size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */ + size += nla_total_size(sizeof(*priv->termination_const) * /* IFLA_CAN_TERMINATION_CONST */ + priv->termination_const_cnt); + } return size; } @@ -1018,7 +1047,15 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) (priv->data_bittiming_const && nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST, sizeof(*priv->data_bittiming_const), - priv->data_bittiming_const))) + priv->data_bittiming_const)) || + + (priv->termination_const && + (nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) || + nla_put(skb, IFLA_CAN_TERMINATION_CONST, + sizeof(*priv->termination_const) * + priv->termination_const_cnt, + priv->termination_const)))) + return -EMSGSIZE; return 0; @@ -1073,6 +1110,16 @@ static struct rtnl_link_ops can_link_ops __read_mostly = { */ int register_candev(struct net_device *dev) { + struct can_priv *priv = netdev_priv(dev); + + /* Ensure termination_const, termination_const_cnt and + * do_set_termination consistency. All must be either set or + * unset. + */ + if ((!priv->termination_const != !priv->termination_const_cnt) || + (!priv->termination_const != !priv->do_set_termination)) + return -EINVAL; + dev->rtnl_link_ops = &can_link_ops; return register_netdev(dev); } |