Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: fix handling of unmodifiable configuration options

As described in 'can: m_can: tag current CAN FD controllers as non-ISO'
(6cfda7fbebe) it is possible to define fixed configuration options by
setting the according bit in 'ctrlmode' and clear it in 'ctrlmode_supported'.
This leads to the incovenience that the fixed configuration bits can not be
passed by netlink even when they have the correct values (e.g. non-ISO, FD).

This patch fixes that issue and not only allows fixed set bit values to be set
again but now requires(!) to provide these fixed values at configuration time.
A valid CAN FD configuration consists of a nominal/arbitration bittiming, a
data bittiming and a control mode with CAN_CTRLMODE_FD set - which is now
enforced by a new can_validate() function. This fix additionally removed the
inconsistency that was prohibiting the support of 'CANFD-only' controller
drivers, like the RCar CAN FD.

For this reason a new helper can_set_static_ctrlmode() has been introduced to
provide a proper interface to handle static enabled CAN controller options.

Reported-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Reviewed-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
Cc: <stable@vger.kernel.org> # >= 3.18
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
bb208f14 b6fd3aba

+73 -7
+52 -4
drivers/net/can/dev.c
··· 696 696 /* allow change of MTU according to the CANFD ability of the device */ 697 697 switch (new_mtu) { 698 698 case CAN_MTU: 699 + /* 'CANFD-only' controllers can not switch to CAN_MTU */ 700 + if (priv->ctrlmode_static & CAN_CTRLMODE_FD) 701 + return -EINVAL; 702 + 699 703 priv->ctrlmode &= ~CAN_CTRLMODE_FD; 700 704 break; 701 705 702 706 case CANFD_MTU: 703 - if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD)) 707 + /* check for potential CANFD ability */ 708 + if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD) && 709 + !(priv->ctrlmode_static & CAN_CTRLMODE_FD)) 704 710 return -EINVAL; 705 711 706 712 priv->ctrlmode |= CAN_CTRLMODE_FD; ··· 788 782 = { .len = sizeof(struct can_bittiming_const) }, 789 783 }; 790 784 785 + static int can_validate(struct nlattr *tb[], struct nlattr *data[]) 786 + { 787 + bool is_can_fd = false; 788 + 789 + /* Make sure that valid CAN FD configurations always consist of 790 + * - nominal/arbitration bittiming 791 + * - data bittiming 792 + * - control mode with CAN_CTRLMODE_FD set 793 + */ 794 + 795 + if (data[IFLA_CAN_CTRLMODE]) { 796 + struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); 797 + 798 + is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD; 799 + } 800 + 801 + if (is_can_fd) { 802 + if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING]) 803 + return -EOPNOTSUPP; 804 + } 805 + 806 + if (data[IFLA_CAN_DATA_BITTIMING]) { 807 + if (!is_can_fd || !data[IFLA_CAN_BITTIMING]) 808 + return -EOPNOTSUPP; 809 + } 810 + 811 + return 0; 812 + } 813 + 791 814 static int can_changelink(struct net_device *dev, 792 815 struct nlattr *tb[], struct nlattr *data[]) 793 816 { ··· 848 813 849 814 if (data[IFLA_CAN_CTRLMODE]) { 850 815 struct can_ctrlmode *cm; 816 + u32 ctrlstatic; 817 + u32 maskedflags; 851 818 852 819 /* Do not allow changing controller mode while running */ 853 820 if (dev->flags & IFF_UP) 854 821 return -EBUSY; 855 822 cm = nla_data(data[IFLA_CAN_CTRLMODE]); 823 + ctrlstatic = priv->ctrlmode_static; 824 + maskedflags = cm->flags & cm->mask; 856 825 857 - /* check whether changed bits are allowed to be modified */ 858 - if (cm->mask & ~priv->ctrlmode_supported) 826 + /* check whether provided bits are allowed to be passed */ 827 + if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic)) 828 + return -EOPNOTSUPP; 829 + 830 + /* do not check for static fd-non-iso if 'fd' is disabled */ 831 + if (!(maskedflags & CAN_CTRLMODE_FD)) 832 + ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO; 833 + 834 + /* make sure static options are provided by configuration */ 835 + if ((maskedflags & ctrlstatic) != ctrlstatic) 859 836 return -EOPNOTSUPP; 860 837 861 838 /* clear bits to be modified and copy the flag values */ 862 839 priv->ctrlmode &= ~cm->mask; 863 - priv->ctrlmode |= (cm->flags & cm->mask); 840 + priv->ctrlmode |= maskedflags; 864 841 865 842 /* CAN_CTRLMODE_FD can only be set when driver supports FD */ 866 843 if (priv->ctrlmode & CAN_CTRLMODE_FD) ··· 1013 966 .maxtype = IFLA_CAN_MAX, 1014 967 .policy = can_policy, 1015 968 .setup = can_setup, 969 + .validate = can_validate, 1016 970 .newlink = can_newlink, 1017 971 .changelink = can_changelink, 1018 972 .get_size = can_get_size,
+1 -1
drivers/net/can/m_can/m_can.c
··· 955 955 priv->can.do_get_berr_counter = m_can_get_berr_counter; 956 956 957 957 /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.1 */ 958 - priv->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO; 958 + can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO); 959 959 960 960 /* CAN_CTRLMODE_FD_NON_ISO can not be changed with M_CAN IP v3.0.1 */ 961 961 priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+20 -2
include/linux/can/dev.h
··· 40 40 struct can_clock clock; 41 41 42 42 enum can_state state; 43 - u32 ctrlmode; 44 - u32 ctrlmode_supported; 43 + 44 + /* CAN controller features - see include/uapi/linux/can/netlink.h */ 45 + u32 ctrlmode; /* current options setting */ 46 + u32 ctrlmode_supported; /* options that can be modified by netlink */ 47 + u32 ctrlmode_static; /* static enabled options for driver/hardware */ 45 48 46 49 int restart_ms; 47 50 struct timer_list restart_timer; ··· 109 106 { 110 107 /* the CAN specific type of skb is identified by its data length */ 111 108 return skb->len == CANFD_MTU; 109 + } 110 + 111 + /* helper to define static CAN controller features at device creation time */ 112 + static inline void can_set_static_ctrlmode(struct net_device *dev, 113 + u32 static_mode) 114 + { 115 + struct can_priv *priv = netdev_priv(dev); 116 + 117 + /* alloc_candev() succeeded => netdev_priv() is valid at this point */ 118 + priv->ctrlmode = static_mode; 119 + priv->ctrlmode_static = static_mode; 120 + 121 + /* override MTU which was set by default in can_setup()? */ 122 + if (static_mode & CAN_CTRLMODE_FD) 123 + dev->mtu = CANFD_MTU; 112 124 } 113 125 114 126 /* get data length from can_dlc with sanitized can_dlc */