// SPDX-License-Identifier: GPL-2.0-only/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix * Copyright (C) 2006 Andrey Volkov, Varma Electronics * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> * Copyright (C) 2021-2025 Vincent Mailhol <mailhol@kernel.org> */ #include <linux/can/dev.h>#include <net/rtnetlink.h> static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { [IFLA_CAN_STATE] = { .type = NLA_U32 }, [IFLA_CAN_CTRLMODE] = { .len = sizeof(struct can_ctrlmode) }, [IFLA_CAN_RESTART_MS] = { .type = NLA_U32 }, [IFLA_CAN_RESTART] = { .type = NLA_U32 }, [IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) }, [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) }, [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) }, [IFLA_CAN_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) }, [IFLA_CAN_TERMINATION] = { .type = NLA_U16 }, [IFLA_CAN_TDC] = { .type = NLA_NESTED }, [IFLA_CAN_CTRLMODE_EXT] = { .type = NLA_NESTED }, [IFLA_CAN_XL_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_XL_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) }, [IFLA_CAN_XL_TDC] = { .type = NLA_NESTED }, [IFLA_CAN_XL_PWM] = { .type = NLA_NESTED },}; static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] = { [IFLA_CAN_TDC_TDCV_MIN] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCV_MAX] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCO_MIN] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCO_MAX] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCF_MIN] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCF_MAX] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCV] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCO] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCF] = { .type = NLA_U32 },}; static const struct nla_policy can_pwm_policy[IFLA_CAN_PWM_MAX + 1] = { [IFLA_CAN_PWM_PWMS_MIN] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWMS_MAX] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWML_MIN] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWML_MAX] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWMO_MIN] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWMO_MAX] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWMS] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWML] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWMO] = { .type = NLA_U32 },}; static int can_validate_bittiming(struct nlattr *data[], struct netlink_ext_ack *extack, int ifla_can_bittiming){ struct can_bittiming *bt; if (!data[ifla_can_bittiming]) return 0; static_assert(__alignof__(*bt) <= NLA_ALIGNTO); bt = nla_data(data[ifla_can_bittiming]); /* sample point is in one-tenth of a percent */ if (bt->sample_point >= 1000) { NL_SET_ERR_MSG(extack, "sample point must be between 0 and 100%"); return -EINVAL; } return 0;} static int can_validate_tdc(struct nlattr *data_tdc, struct netlink_ext_ack *extack, u32 tdc_flags){ bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK; bool tdc_auto = tdc_flags & CAN_CTRLMODE_TDC_AUTO_MASK; int err; if (tdc_auto && tdc_manual) { NL_SET_ERR_MSG(extack, "TDC manual and auto modes are mutually exclusive"); return -EOPNOTSUPP; } /* If one of the CAN_CTRLMODE_{,XL}_TDC_* flags is set then TDC * must be set and vice-versa */ if ((tdc_auto || tdc_manual) && !data_tdc) { NL_SET_ERR_MSG(extack, "TDC parameters are missing"); return -EOPNOTSUPP; } if (!(tdc_auto || tdc_manual) && data_tdc) { NL_SET_ERR_MSG(extack, "TDC mode (auto or manual) is missing"); return -EOPNOTSUPP; } /* If providing TDC parameters, at least TDCO is needed. TDCV is * needed if and only if CAN_CTRLMODE_{,XL}_TDC_MANUAL is set */ if (data_tdc) { struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1]; err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, data_tdc, can_tdc_policy, extack); if (err) return err; if (tb_tdc[IFLA_CAN_TDC_TDCV]) { if (tdc_auto) { NL_SET_ERR_MSG(extack, "TDCV is incompatible with TDC auto mode"); return -EOPNOTSUPP; } } else { if (tdc_manual) { NL_SET_ERR_MSG(extack, "TDC manual mode requires TDCV"); return -EOPNOTSUPP; } } if (!tb_tdc[IFLA_CAN_TDC_TDCO]) { NL_SET_ERR_MSG(extack, "TDCO is missing"); return -EOPNOTSUPP; } } return 0;} static int can_validate_pwm(struct nlattr *data[], struct netlink_ext_ack *extack, u32 flags){ struct nlattr *tb_pwm[IFLA_CAN_PWM_MAX + 1]; int err; if (!data[IFLA_CAN_XL_PWM]) return 0; if (!(flags & CAN_CTRLMODE_XL_TMS)) { NL_SET_ERR_MSG(extack, "PWM requires TMS"); return -EOPNOTSUPP; } err = nla_parse_nested(tb_pwm, IFLA_CAN_PWM_MAX, data[IFLA_CAN_XL_PWM], can_pwm_policy, extack); if (err) return err; if (!tb_pwm[IFLA_CAN_PWM_PWMS] != !tb_pwm[IFLA_CAN_PWM_PWML]) { NL_SET_ERR_MSG(extack, "Provide either both PWMS and PWML, or none for automatic calculation"); return -EOPNOTSUPP; } if (tb_pwm[IFLA_CAN_PWM_PWMO] && (!tb_pwm[IFLA_CAN_PWM_PWMS] || !tb_pwm[IFLA_CAN_PWM_PWML])) { NL_SET_ERR_MSG(extack, "PWMO requires both PWMS and PWML"); return -EOPNOTSUPP; } return 0;} static int can_validate_databittiming(struct nlattr *data[], struct netlink_ext_ack *extack, int ifla_can_data_bittiming, u32 flags){ struct nlattr *data_tdc; const char *type; u32 tdc_flags; bool is_on; int err; /* Make sure that valid CAN FD/XL configurations always consist of * - nominal/arbitration bittiming * - data bittiming * - control mode with CAN_CTRLMODE_{FD,XL} set * - TDC parameters are coherent (details in can_validate_tdc()) */ if (ifla_can_data_bittiming == IFLA_CAN_DATA_BITTIMING) { data_tdc = data[IFLA_CAN_TDC]; tdc_flags = flags & CAN_CTRLMODE_FD_TDC_MASK; is_on = flags & CAN_CTRLMODE_FD; type = "FD"; } else { data_tdc = data[IFLA_CAN_XL_TDC]; tdc_flags = flags & CAN_CTRLMODE_XL_TDC_MASK; is_on = flags & CAN_CTRLMODE_XL; type = "XL"; } if (is_on) { if (!data[IFLA_CAN_BITTIMING] || !data[ifla_can_data_bittiming]) { NL_SET_ERR_MSG_FMT(extack, "Provide both nominal and %s data bittiming", type); return -EOPNOTSUPP; } } else { if (data[ifla_can_data_bittiming]) { NL_SET_ERR_MSG_FMT(extack, "%s data bittiming requires CAN %s", type, type); return -EOPNOTSUPP; } if (data_tdc) { NL_SET_ERR_MSG_FMT(extack, "%s TDC requires CAN %s", type, type); return -EOPNOTSUPP; } } err = can_validate_bittiming(data, extack, ifla_can_data_bittiming); if (err) return err; err = can_validate_tdc(data_tdc, extack, tdc_flags); if (err) return err; return 0;} static int can_validate_xl_flags(struct netlink_ext_ack *extack, u32 masked_flags, u32 mask){ if (masked_flags & CAN_CTRLMODE_XL) { if (masked_flags & CAN_CTRLMODE_XL_TMS) { const u32 tms_conflicts_mask = CAN_CTRLMODE_FD | CAN_CTRLMODE_XL_TDC_MASK; u32 tms_conflicts = masked_flags & tms_conflicts_mask; if (tms_conflicts) { NL_SET_ERR_MSG_FMT(extack, "TMS and %s are mutually exclusive", can_get_ctrlmode_str(tms_conflicts)); return -EOPNOTSUPP; } } } else { if (mask & CAN_CTRLMODE_XL_TMS) { NL_SET_ERR_MSG(extack, "TMS requires CAN XL"); return -EOPNOTSUPP; } } return 0;} static int can_validate(struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack){ u32 flags = 0; int err; if (!data) return 0; if (data[IFLA_CAN_CTRLMODE]) { struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); flags = cm->flags & cm->mask; if ((flags & CAN_CTRLMODE_LISTENONLY) && (flags & CAN_CTRLMODE_RESTRICTED)) { NL_SET_ERR_MSG(extack, "LISTEN-ONLY and RESTRICTED modes are mutually exclusive"); return -EOPNOTSUPP; } err = can_validate_xl_flags(extack, flags, cm->mask); if (err) return err; } err = can_validate_bittiming(data, extack, IFLA_CAN_BITTIMING); if (err) return err; err = can_validate_databittiming(data, extack, IFLA_CAN_DATA_BITTIMING, flags); if (err) return err; err = can_validate_databittiming(data, extack, IFLA_CAN_XL_DATA_BITTIMING, flags); if (err) return err; err = can_validate_pwm(data, extack, flags); if (err) return err; return 0;} static int can_ctrlmode_changelink(struct net_device *dev, struct nlattr *data[], struct netlink_ext_ack *extack){ struct can_priv *priv = netdev_priv(dev); struct can_ctrlmode *cm; u32 ctrlstatic, maskedflags, deactivated, notsupp, ctrlstatic_missing; if (!data[IFLA_CAN_CTRLMODE]) return 0; /* Do not allow changing controller mode while running */ if (dev->flags & IFF_UP) return -EBUSY; cm = nla_data(data[IFLA_CAN_CTRLMODE]); ctrlstatic = can_get_static_ctrlmode(priv); maskedflags = cm->flags & cm->mask; deactivated = ~cm->flags & cm->mask; notsupp = maskedflags & ~(priv->ctrlmode_supported | ctrlstatic); ctrlstatic_missing = (maskedflags & ctrlstatic) ^ ctrlstatic; if (notsupp) { NL_SET_ERR_MSG_FMT(extack, "requested control mode %s not supported", can_get_ctrlmode_str(notsupp)); 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; if (ctrlstatic_missing) { NL_SET_ERR_MSG_FMT(extack, "missing required %s static control mode", can_get_ctrlmode_str(ctrlstatic_missing)); return -EOPNOTSUPP; } /* If FD was active and is not turned off, check for XL conflicts */ if (priv->ctrlmode & CAN_CTRLMODE_FD & ~deactivated) { if (maskedflags & CAN_CTRLMODE_XL_TMS) { NL_SET_ERR_MSG(extack, "TMS can not be activated while CAN FD is on"); return -EOPNOTSUPP; } } /* If a top dependency flag is provided, reset all its dependencies */ if (cm->mask & CAN_CTRLMODE_FD) priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; if (cm->mask & CAN_CTRLMODE_XL) priv->ctrlmode &= ~(CAN_CTRLMODE_XL_TDC_MASK | CAN_CTRLMODE_XL_TMS); /* clear bits to be modified and copy the flag values */ priv->ctrlmode &= ~cm->mask; priv->ctrlmode |= maskedflags; /* Wipe potential leftovers from previous CAN FD/XL config */ if (!(priv->ctrlmode & CAN_CTRLMODE_FD)) { memset(&priv->fd.data_bittiming, 0, sizeof(priv->fd.data_bittiming)); priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc)); } if (!(priv->ctrlmode & CAN_CTRLMODE_XL)) { memset(&priv->xl.data_bittiming, 0, sizeof(priv->fd.data_bittiming)); priv->ctrlmode &= ~CAN_CTRLMODE_XL_TDC_MASK; memset(&priv->xl.tdc, 0, sizeof(priv->xl.tdc)); memset(&priv->xl.pwm, 0, sizeof(priv->xl.pwm)); } can_set_default_mtu(dev); can_set_cap_info(dev); return 0;} static int can_tdc_changelink(struct data_bittiming_params *dbt_params, const struct nlattr *nla, struct netlink_ext_ack *extack){ struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1]; struct can_tdc tdc = { 0 }; const struct can_tdc_const *tdc_const = dbt_params->tdc_const; int err; if (!tdc_const) { NL_SET_ERR_MSG(extack, "The device does not support TDC"); return -EOPNOTSUPP; } err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, nla, can_tdc_policy, extack); if (err) return err; if (tb_tdc[IFLA_CAN_TDC_TDCV]) { u32 tdcv = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCV]); if (tdcv < tdc_const->tdcv_min || tdcv > tdc_const->tdcv_max) return -EINVAL; tdc.tdcv = tdcv; } if (tb_tdc[IFLA_CAN_TDC_TDCO]) { u32 tdco = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCO]); if (tdco < tdc_const->tdco_min || tdco > tdc_const->tdco_max) return -EINVAL; tdc.tdco = tdco; } if (tb_tdc[IFLA_CAN_TDC_TDCF]) { u32 tdcf = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCF]); if (tdcf < tdc_const->tdcf_min || tdcf > tdc_const->tdcf_max) return -EINVAL; tdc.tdcf = tdcf; } dbt_params->tdc = tdc; return 0;} static int can_dbt_changelink(struct net_device *dev, struct nlattr *data[], bool fd, struct netlink_ext_ack *extack){ struct nlattr *data_bittiming, *data_tdc; struct can_priv *priv = netdev_priv(dev); struct data_bittiming_params *dbt_params; struct can_bittiming dbt; bool need_tdc_calc = false; u32 tdc_mask; int err; if (fd) { data_bittiming = data[IFLA_CAN_DATA_BITTIMING]; data_tdc = data[IFLA_CAN_TDC]; dbt_params = &priv->fd; tdc_mask = CAN_CTRLMODE_FD_TDC_MASK; } else { data_bittiming = data[IFLA_CAN_XL_DATA_BITTIMING]; data_tdc = data[IFLA_CAN_XL_TDC]; dbt_params = &priv->xl; tdc_mask = CAN_CTRLMODE_XL_TDC_MASK; } if (!data_bittiming) return 0; /* Do not allow changing bittiming while running */ if (dev->flags & IFF_UP) return -EBUSY; /* Calculate bittiming parameters based on data_bittiming_const * if set, otherwise pass bitrate directly via do_set_bitrate(). * Bail out if neither is given. */ if (!dbt_params->data_bittiming_const && !dbt_params->do_set_data_bittiming && !dbt_params->data_bitrate_const) return -EOPNOTSUPP; memcpy(&dbt, nla_data(data_bittiming), sizeof(dbt)); err = can_get_bittiming(dev, &dbt, dbt_params->data_bittiming_const, dbt_params->data_bitrate_const, dbt_params->data_bitrate_const_cnt, extack); if (err) return err; if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) { NL_SET_ERR_MSG_FMT(extack, "CAN data bitrate %u bps surpasses transceiver capabilities of %u bps", dbt.bitrate, priv->bitrate_max); return -EINVAL; } memset(&dbt_params->tdc, 0, sizeof(dbt_params->tdc)); if (data[IFLA_CAN_CTRLMODE]) { struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); if (fd || !(priv->ctrlmode & CAN_CTRLMODE_XL_TMS)) need_tdc_calc = !(cm->mask & tdc_mask); } if (data_tdc) { /* TDC parameters are provided: use them */ err = can_tdc_changelink(dbt_params, data_tdc, extack); if (err) { priv->ctrlmode &= ~tdc_mask; return err;Lines 1–500 of 1114. Load more
// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix * Copyright (C) 2006 Andrey Volkov, Varma Electronics * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> * Copyright (C) 2021-2025 Vincent Mailhol <mailhol@kernel.org> */ #include <linux/can/dev.h> #include <net/rtnetlink.h> static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { [IFLA_CAN_STATE] = { .type = NLA_U32 }, [IFLA_CAN_CTRLMODE] = { .len = sizeof(struct can_ctrlmode) }, [IFLA_CAN_RESTART_MS] = { .type = NLA_U32 }, [IFLA_CAN_RESTART] = { .type = NLA_U32 }, [IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) }, [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) }, [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) }, [IFLA_CAN_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) }, [IFLA_CAN_TERMINATION] = { .type = NLA_U16 }, [IFLA_CAN_TDC] = { .type = NLA_NESTED }, [IFLA_CAN_CTRLMODE_EXT] = { .type = NLA_NESTED }, [IFLA_CAN_XL_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_XL_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) }, [IFLA_CAN_XL_TDC] = { .type = NLA_NESTED }, [IFLA_CAN_XL_PWM] = { .type = NLA_NESTED }, }; static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] = { [IFLA_CAN_TDC_TDCV_MIN] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCV_MAX] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCO_MIN] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCO_MAX] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCF_MIN] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCF_MAX] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCV] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCO] = { .type = NLA_U32 }, [IFLA_CAN_TDC_TDCF] = { .type = NLA_U32 }, }; static const struct nla_policy can_pwm_policy[IFLA_CAN_PWM_MAX + 1] = { [IFLA_CAN_PWM_PWMS_MIN] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWMS_MAX] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWML_MIN] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWML_MAX] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWMO_MIN] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWMO_MAX] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWMS] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWML] = { .type = NLA_U32 }, [IFLA_CAN_PWM_PWMO] = { .type = NLA_U32 }, }; static int can_validate_bittiming(struct nlattr *data[], struct netlink_ext_ack *extack, int ifla_can_bittiming) { struct can_bittiming *bt; if (!data[ifla_can_bittiming]) return 0; static_assert(__alignof__(*bt) <= NLA_ALIGNTO); bt = nla_data(data[ifla_can_bittiming]); /* sample point is in one-tenth of a percent */ if (bt->sample_point >= 1000) { NL_SET_ERR_MSG(extack, "sample point must be between 0 and 100%"); return -EINVAL; } return 0; } static int can_validate_tdc(struct nlattr *data_tdc, struct netlink_ext_ack *extack, u32 tdc_flags) { bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK; bool tdc_auto = tdc_flags & CAN_CTRLMODE_TDC_AUTO_MASK; int err; if (tdc_auto && tdc_manual) { NL_SET_ERR_MSG(extack, "TDC manual and auto modes are mutually exclusive"); return -EOPNOTSUPP; } /* If one of the CAN_CTRLMODE_{,XL}_TDC_* flags is set then TDC * must be set and vice-versa */ if ((tdc_auto || tdc_manual) && !data_tdc) { NL_SET_ERR_MSG(extack, "TDC parameters are missing"); return -EOPNOTSUPP; } if (!(tdc_auto || tdc_manual) && data_tdc) { NL_SET_ERR_MSG(extack, "TDC mode (auto or manual) is missing"); return -EOPNOTSUPP; } /* If providing TDC parameters, at least TDCO is needed. TDCV is * needed if and only if CAN_CTRLMODE_{,XL}_TDC_MANUAL is set */ if (data_tdc) { struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1]; err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, data_tdc, can_tdc_policy, extack); if (err) return err; if (tb_tdc[IFLA_CAN_TDC_TDCV]) { if (tdc_auto) { NL_SET_ERR_MSG(extack, "TDCV is incompatible with TDC auto mode"); return -EOPNOTSUPP; } } else { if (tdc_manual) { NL_SET_ERR_MSG(extack, "TDC manual mode requires TDCV"); return -EOPNOTSUPP; } } if (!tb_tdc[IFLA_CAN_TDC_TDCO]) { NL_SET_ERR_MSG(extack, "TDCO is missing"); return -EOPNOTSUPP; } } return 0; } static int can_validate_pwm(struct nlattr *data[], struct netlink_ext_ack *extack, u32 flags) { struct nlattr *tb_pwm[IFLA_CAN_PWM_MAX + 1]; int err; if (!data[IFLA_CAN_XL_PWM]) return 0; if (!(flags & CAN_CTRLMODE_XL_TMS)) { NL_SET_ERR_MSG(extack, "PWM requires TMS"); return -EOPNOTSUPP; } err = nla_parse_nested(tb_pwm, IFLA_CAN_PWM_MAX, data[IFLA_CAN_XL_PWM], can_pwm_policy, extack); if (err) return err; if (!tb_pwm[IFLA_CAN_PWM_PWMS] != !tb_pwm[IFLA_CAN_PWM_PWML]) { NL_SET_ERR_MSG(extack, "Provide either both PWMS and PWML, or none for automatic calculation"); return -EOPNOTSUPP; } if (tb_pwm[IFLA_CAN_PWM_PWMO] && (!tb_pwm[IFLA_CAN_PWM_PWMS] || !tb_pwm[IFLA_CAN_PWM_PWML])) { NL_SET_ERR_MSG(extack, "PWMO requires both PWMS and PWML"); return -EOPNOTSUPP; } return 0; } static int can_validate_databittiming(struct nlattr *data[], struct netlink_ext_ack *extack, int ifla_can_data_bittiming, u32 flags) { struct nlattr *data_tdc; const char *type; u32 tdc_flags; bool is_on; int err; /* Make sure that valid CAN FD/XL configurations always consist of * - nominal/arbitration bittiming * - data bittiming * - control mode with CAN_CTRLMODE_{FD,XL} set * - TDC parameters are coherent (details in can_validate_tdc()) */ if (ifla_can_data_bittiming == IFLA_CAN_DATA_BITTIMING) { data_tdc = data[IFLA_CAN_TDC]; tdc_flags = flags & CAN_CTRLMODE_FD_TDC_MASK; is_on = flags & CAN_CTRLMODE_FD; type = "FD"; } else { data_tdc = data[IFLA_CAN_XL_TDC]; tdc_flags = flags & CAN_CTRLMODE_XL_TDC_MASK; is_on = flags & CAN_CTRLMODE_XL; type = "XL"; } if (is_on) { if (!data[IFLA_CAN_BITTIMING] || !data[ifla_can_data_bittiming]) { NL_SET_ERR_MSG_FMT(extack, "Provide both nominal and %s data bittiming", type); return -EOPNOTSUPP; } } else { if (data[ifla_can_data_bittiming]) { NL_SET_ERR_MSG_FMT(extack, "%s data bittiming requires CAN %s", type, type); return -EOPNOTSUPP; } if (data_tdc) { NL_SET_ERR_MSG_FMT(extack, "%s TDC requires CAN %s", type, type); return -EOPNOTSUPP; } } err = can_validate_bittiming(data, extack, ifla_can_data_bittiming); if (err) return err; err = can_validate_tdc(data_tdc, extack, tdc_flags); if (err) return err; return 0; } static int can_validate_xl_flags(struct netlink_ext_ack *extack, u32 masked_flags, u32 mask) { if (masked_flags & CAN_CTRLMODE_XL) { if (masked_flags & CAN_CTRLMODE_XL_TMS) { const u32 tms_conflicts_mask = CAN_CTRLMODE_FD | CAN_CTRLMODE_XL_TDC_MASK; u32 tms_conflicts = masked_flags & tms_conflicts_mask; if (tms_conflicts) { NL_SET_ERR_MSG_FMT(extack, "TMS and %s are mutually exclusive", can_get_ctrlmode_str(tms_conflicts)); return -EOPNOTSUPP; } } } else { if (mask & CAN_CTRLMODE_XL_TMS) { NL_SET_ERR_MSG(extack, "TMS requires CAN XL"); return -EOPNOTSUPP; } } return 0; } static int can_validate(struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { u32 flags = 0; int err; if (!data) return 0; if (data[IFLA_CAN_CTRLMODE]) { struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); flags = cm->flags & cm->mask; if ((flags & CAN_CTRLMODE_LISTENONLY) && (flags & CAN_CTRLMODE_RESTRICTED)) { NL_SET_ERR_MSG(extack, "LISTEN-ONLY and RESTRICTED modes are mutually exclusive"); return -EOPNOTSUPP; } err = can_validate_xl_flags(extack, flags, cm->mask); if (err) return err; } err = can_validate_bittiming(data, extack, IFLA_CAN_BITTIMING); if (err) return err; err = can_validate_databittiming(data, extack, IFLA_CAN_DATA_BITTIMING, flags); if (err) return err; err = can_validate_databittiming(data, extack, IFLA_CAN_XL_DATA_BITTIMING, flags); if (err) return err; err = can_validate_pwm(data, extack, flags); if (err) return err; return 0; } static int can_ctrlmode_changelink(struct net_device *dev, struct nlattr *data[], struct netlink_ext_ack *extack) { struct can_priv *priv = netdev_priv(dev); struct can_ctrlmode *cm; u32 ctrlstatic, maskedflags, deactivated, notsupp, ctrlstatic_missing; if (!data[IFLA_CAN_CTRLMODE]) return 0; /* Do not allow changing controller mode while running */ if (dev->flags & IFF_UP) return -EBUSY; cm = nla_data(data[IFLA_CAN_CTRLMODE]); ctrlstatic = can_get_static_ctrlmode(priv); maskedflags = cm->flags & cm->mask; deactivated = ~cm->flags & cm->mask; notsupp = maskedflags & ~(priv->ctrlmode_supported | ctrlstatic); ctrlstatic_missing = (maskedflags & ctrlstatic) ^ ctrlstatic; if (notsupp) { NL_SET_ERR_MSG_FMT(extack, "requested control mode %s not supported", can_get_ctrlmode_str(notsupp)); 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; if (ctrlstatic_missing) { NL_SET_ERR_MSG_FMT(extack, "missing required %s static control mode", can_get_ctrlmode_str(ctrlstatic_missing)); return -EOPNOTSUPP; } /* If FD was active and is not turned off, check for XL conflicts */ if (priv->ctrlmode & CAN_CTRLMODE_FD & ~deactivated) { if (maskedflags & CAN_CTRLMODE_XL_TMS) { NL_SET_ERR_MSG(extack, "TMS can not be activated while CAN FD is on"); return -EOPNOTSUPP; } } /* If a top dependency flag is provided, reset all its dependencies */ if (cm->mask & CAN_CTRLMODE_FD) priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; if (cm->mask & CAN_CTRLMODE_XL) priv->ctrlmode &= ~(CAN_CTRLMODE_XL_TDC_MASK | CAN_CTRLMODE_XL_TMS); /* clear bits to be modified and copy the flag values */ priv->ctrlmode &= ~cm->mask; priv->ctrlmode |= maskedflags; /* Wipe potential leftovers from previous CAN FD/XL config */ if (!(priv->ctrlmode & CAN_CTRLMODE_FD)) { memset(&priv->fd.data_bittiming, 0, sizeof(priv->fd.data_bittiming)); priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc)); } if (!(priv->ctrlmode & CAN_CTRLMODE_XL)) { memset(&priv->xl.data_bittiming, 0, sizeof(priv->fd.data_bittiming)); priv->ctrlmode &= ~CAN_CTRLMODE_XL_TDC_MASK; memset(&priv->xl.tdc, 0, sizeof(priv->xl.tdc)); memset(&priv->xl.pwm, 0, sizeof(priv->xl.pwm)); } can_set_default_mtu(dev); can_set_cap_info(dev); return 0; } static int can_tdc_changelink(struct data_bittiming_params *dbt_params, const struct nlattr *nla, struct netlink_ext_ack *extack) { struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1]; struct can_tdc tdc = { 0 }; const struct can_tdc_const *tdc_const = dbt_params->tdc_const; int err; if (!tdc_const) { NL_SET_ERR_MSG(extack, "The device does not support TDC"); return -EOPNOTSUPP; } err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, nla, can_tdc_policy, extack); if (err) return err; if (tb_tdc[IFLA_CAN_TDC_TDCV]) { u32 tdcv = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCV]); if (tdcv < tdc_const->tdcv_min || tdcv > tdc_const->tdcv_max) return -EINVAL; tdc.tdcv = tdcv; } if (tb_tdc[IFLA_CAN_TDC_TDCO]) { u32 tdco = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCO]); if (tdco < tdc_const->tdco_min || tdco > tdc_const->tdco_max) return -EINVAL; tdc.tdco = tdco; } if (tb_tdc[IFLA_CAN_TDC_TDCF]) { u32 tdcf = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCF]); if (tdcf < tdc_const->tdcf_min || tdcf > tdc_const->tdcf_max) return -EINVAL; tdc.tdcf = tdcf; } dbt_params->tdc = tdc; return 0; } static int can_dbt_changelink(struct net_device *dev, struct nlattr *data[], bool fd, struct netlink_ext_ack *extack) { struct nlattr *data_bittiming, *data_tdc; struct can_priv *priv = netdev_priv(dev); struct data_bittiming_params *dbt_params; struct can_bittiming dbt; bool need_tdc_calc = false; u32 tdc_mask; int err; if (fd) { data_bittiming = data[IFLA_CAN_DATA_BITTIMING]; data_tdc = data[IFLA_CAN_TDC]; dbt_params = &priv->fd; tdc_mask = CAN_CTRLMODE_FD_TDC_MASK; } else { data_bittiming = data[IFLA_CAN_XL_DATA_BITTIMING]; data_tdc = data[IFLA_CAN_XL_TDC]; dbt_params = &priv->xl; tdc_mask = CAN_CTRLMODE_XL_TDC_MASK; } if (!data_bittiming) return 0; /* Do not allow changing bittiming while running */ if (dev->flags & IFF_UP) return -EBUSY; /* Calculate bittiming parameters based on data_bittiming_const * if set, otherwise pass bitrate directly via do_set_bitrate(). * Bail out if neither is given. */ if (!dbt_params->data_bittiming_const && !dbt_params->do_set_data_bittiming && !dbt_params->data_bitrate_const) return -EOPNOTSUPP; memcpy(&dbt, nla_data(data_bittiming), sizeof(dbt)); err = can_get_bittiming(dev, &dbt, dbt_params->data_bittiming_const, dbt_params->data_bitrate_const, dbt_params->data_bitrate_const_cnt, extack); if (err) return err; if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) { NL_SET_ERR_MSG_FMT(extack, "CAN data bitrate %u bps surpasses transceiver capabilities of %u bps", dbt.bitrate, priv->bitrate_max); return -EINVAL; } memset(&dbt_params->tdc, 0, sizeof(dbt_params->tdc)); if (data[IFLA_CAN_CTRLMODE]) { struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); if (fd || !(priv->ctrlmode & CAN_CTRLMODE_XL_TMS)) need_tdc_calc = !(cm->mask & tdc_mask); } if (data_tdc) { /* TDC parameters are provided: use them */ err = can_tdc_changelink(dbt_params, data_tdc, extack); if (err) { priv->ctrlmode &= ~tdc_mask; return err;