|
@@ -696,11 +696,17 @@ int can_change_mtu(struct net_device *dev, int new_mtu)
|
|
/* allow change of MTU according to the CANFD ability of the device */
|
|
/* allow change of MTU according to the CANFD ability of the device */
|
|
switch (new_mtu) {
|
|
switch (new_mtu) {
|
|
case CAN_MTU:
|
|
case CAN_MTU:
|
|
|
|
+ /* 'CANFD-only' controllers can not switch to CAN_MTU */
|
|
|
|
+ if (priv->ctrlmode_static & CAN_CTRLMODE_FD)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
priv->ctrlmode &= ~CAN_CTRLMODE_FD;
|
|
priv->ctrlmode &= ~CAN_CTRLMODE_FD;
|
|
break;
|
|
break;
|
|
|
|
|
|
case CANFD_MTU:
|
|
case CANFD_MTU:
|
|
- if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD))
|
|
|
|
|
|
+ /* check for potential CANFD ability */
|
|
|
|
+ if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD) &&
|
|
|
|
+ !(priv->ctrlmode_static & CAN_CTRLMODE_FD))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
priv->ctrlmode |= CAN_CTRLMODE_FD;
|
|
priv->ctrlmode |= CAN_CTRLMODE_FD;
|
|
@@ -782,6 +788,35 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
|
|
= { .len = sizeof(struct can_bittiming_const) },
|
|
= { .len = sizeof(struct can_bittiming_const) },
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static int can_validate(struct nlattr *tb[], struct nlattr *data[])
|
|
|
|
+{
|
|
|
|
+ bool is_can_fd = false;
|
|
|
|
+
|
|
|
|
+ /* Make sure that valid CAN FD configurations always consist of
|
|
|
|
+ * - nominal/arbitration bittiming
|
|
|
|
+ * - data bittiming
|
|
|
|
+ * - control mode with CAN_CTRLMODE_FD set
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ if (data[IFLA_CAN_CTRLMODE]) {
|
|
|
|
+ struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
|
|
|
+
|
|
|
|
+ is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (is_can_fd) {
|
|
|
|
+ if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING])
|
|
|
|
+ return -EOPNOTSUPP;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (data[IFLA_CAN_DATA_BITTIMING]) {
|
|
|
|
+ if (!is_can_fd || !data[IFLA_CAN_BITTIMING])
|
|
|
|
+ return -EOPNOTSUPP;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int can_changelink(struct net_device *dev,
|
|
static int can_changelink(struct net_device *dev,
|
|
struct nlattr *tb[], struct nlattr *data[])
|
|
struct nlattr *tb[], struct nlattr *data[])
|
|
{
|
|
{
|
|
@@ -813,19 +848,31 @@ static int can_changelink(struct net_device *dev,
|
|
|
|
|
|
if (data[IFLA_CAN_CTRLMODE]) {
|
|
if (data[IFLA_CAN_CTRLMODE]) {
|
|
struct can_ctrlmode *cm;
|
|
struct can_ctrlmode *cm;
|
|
|
|
+ u32 ctrlstatic;
|
|
|
|
+ u32 maskedflags;
|
|
|
|
|
|
/* Do not allow changing controller mode while running */
|
|
/* Do not allow changing controller mode while running */
|
|
if (dev->flags & IFF_UP)
|
|
if (dev->flags & IFF_UP)
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
|
cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
|
|
|
+ ctrlstatic = priv->ctrlmode_static;
|
|
|
|
+ maskedflags = cm->flags & cm->mask;
|
|
|
|
+
|
|
|
|
+ /* check whether provided bits are allowed to be passed */
|
|
|
|
+ if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic))
|
|
|
|
+ return -EOPNOTSUPP;
|
|
|
|
+
|
|
|
|
+ /* do not check for static fd-non-iso if 'fd' is disabled */
|
|
|
|
+ if (!(maskedflags & CAN_CTRLMODE_FD))
|
|
|
|
+ ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO;
|
|
|
|
|
|
- /* check whether changed bits are allowed to be modified */
|
|
|
|
- if (cm->mask & ~priv->ctrlmode_supported)
|
|
|
|
|
|
+ /* make sure static options are provided by configuration */
|
|
|
|
+ if ((maskedflags & ctrlstatic) != ctrlstatic)
|
|
return -EOPNOTSUPP;
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
/* clear bits to be modified and copy the flag values */
|
|
/* clear bits to be modified and copy the flag values */
|
|
priv->ctrlmode &= ~cm->mask;
|
|
priv->ctrlmode &= ~cm->mask;
|
|
- priv->ctrlmode |= (cm->flags & cm->mask);
|
|
|
|
|
|
+ priv->ctrlmode |= maskedflags;
|
|
|
|
|
|
/* CAN_CTRLMODE_FD can only be set when driver supports FD */
|
|
/* CAN_CTRLMODE_FD can only be set when driver supports FD */
|
|
if (priv->ctrlmode & CAN_CTRLMODE_FD)
|
|
if (priv->ctrlmode & CAN_CTRLMODE_FD)
|
|
@@ -966,6 +1013,7 @@ static struct rtnl_link_ops can_link_ops __read_mostly = {
|
|
.maxtype = IFLA_CAN_MAX,
|
|
.maxtype = IFLA_CAN_MAX,
|
|
.policy = can_policy,
|
|
.policy = can_policy,
|
|
.setup = can_setup,
|
|
.setup = can_setup,
|
|
|
|
+ .validate = can_validate,
|
|
.newlink = can_newlink,
|
|
.newlink = can_newlink,
|
|
.changelink = can_changelink,
|
|
.changelink = can_changelink,
|
|
.get_size = can_get_size,
|
|
.get_size = can_get_size,
|