Merge tag 'linux-can-fixes-for-6.18-20251126' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can

Marc Kleine-Budde says:

====================
pull-request: can 2025-11-26

this is a pull request of 8 patches for net/main.

Seungjin Bae provides a patch for the kvaser_usb driver to fix a
potential infinite loop in the USB data stream command parser.

Thomas Mühlbacher's patch for the sja1000 driver IRQ handler's max
loop handling, that might lead to unhandled interrupts.

3 patches by me for the gs_usb driver fix handling of failed transmit
URBs and add checking of the actual length of received URBs before
accessing the data.

The next patch is by me and is a port of Thomas Mühlbacher's patch
(fix IRQ handler's max loop handling, that might lead to unhandled
interrupts.) to the sun4i_can driver.

Biju Das provides a patch for the rcar_canfd driver to fix the CAN-FD
mode setting.

The last patch is by Shaurya Rane for the em_canid filter to ensure
that the complete CAN frame is present in the linear data buffer
before accessing it.

* tag 'linux-can-fixes-for-6.18-20251126' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can:
  net/sched: em_canid: fix uninit-value in em_canid_match
  can: rcar_canfd: Fix CAN-FD mode as default
  can: sun4i_can: sun4i_can_interrupt(): fix max irq loop handling
  can: gs_usb: gs_usb_receive_bulk_callback(): check actual_length before accessing data
  can: gs_usb: gs_usb_receive_bulk_callback(): check actual_length before accessing header
  can: gs_usb: gs_usb_xmit_callback(): fix handling of failed transmitted URBs
  can: sja1000: fix max irq loop handling
  can: kvaser_usb: leaf: Fix potential infinite loop in command parsers
====================

Link: https://patch.msgid.link/20251126155713.217105-1-mkl@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2025-11-26 19:56:00 -08:00
6 changed files with 128 additions and 42 deletions

View File

@@ -709,6 +709,11 @@ static void rcar_canfd_set_bit_reg(void __iomem *addr, u32 val)
rcar_canfd_update(val, val, addr);
}
static void rcar_canfd_clear_bit_reg(void __iomem *addr, u32 val)
{
rcar_canfd_update(val, 0, addr);
}
static void rcar_canfd_update_bit_reg(void __iomem *addr, u32 mask, u32 val)
{
rcar_canfd_update(mask, val, addr);
@@ -755,25 +760,6 @@ static void rcar_canfd_set_rnc(struct rcar_canfd_global *gpriv, unsigned int ch,
rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLCFG(w), rnc);
}
static void rcar_canfd_set_mode(struct rcar_canfd_global *gpriv)
{
if (gpriv->info->ch_interface_mode) {
u32 ch, val = gpriv->fdmode ? RCANFD_GEN4_FDCFG_FDOE
: RCANFD_GEN4_FDCFG_CLOE;
for_each_set_bit(ch, &gpriv->channels_mask,
gpriv->info->max_channels)
rcar_canfd_set_bit_reg(&gpriv->fcbase[ch].cfdcfg, val);
} else {
if (gpriv->fdmode)
rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG,
RCANFD_GRMCFG_RCMC);
else
rcar_canfd_clear_bit(gpriv->base, RCANFD_GRMCFG,
RCANFD_GRMCFG_RCMC);
}
}
static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
{
struct device *dev = &gpriv->pdev->dev;
@@ -806,6 +792,16 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
/* Reset Global error flags */
rcar_canfd_write(gpriv->base, RCANFD_GERFL, 0x0);
/* Set the controller into appropriate mode */
if (!gpriv->info->ch_interface_mode) {
if (gpriv->fdmode)
rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG,
RCANFD_GRMCFG_RCMC);
else
rcar_canfd_clear_bit(gpriv->base, RCANFD_GRMCFG,
RCANFD_GRMCFG_RCMC);
}
/* Transition all Channels to reset mode */
for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
rcar_canfd_clear_bit(gpriv->base,
@@ -823,10 +819,23 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
dev_dbg(dev, "channel %u reset failed\n", ch);
return err;
}
}
/* Set the controller into appropriate mode */
rcar_canfd_set_mode(gpriv);
if (gpriv->info->ch_interface_mode) {
/* Do not set CLOE and FDOE simultaneously */
if (!gpriv->fdmode) {
rcar_canfd_clear_bit_reg(&gpriv->fcbase[ch].cfdcfg,
RCANFD_GEN4_FDCFG_FDOE);
rcar_canfd_set_bit_reg(&gpriv->fcbase[ch].cfdcfg,
RCANFD_GEN4_FDCFG_CLOE);
} else {
rcar_canfd_clear_bit_reg(&gpriv->fcbase[ch].cfdcfg,
RCANFD_GEN4_FDCFG_FDOE);
rcar_canfd_clear_bit_reg(&gpriv->fcbase[ch].cfdcfg,
RCANFD_GEN4_FDCFG_CLOE);
}
}
}
return 0;
}

View File

@@ -548,8 +548,8 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
if (priv->read_reg(priv, SJA1000_IER) == IRQ_OFF)
goto out;
while ((isrc = priv->read_reg(priv, SJA1000_IR)) &&
(n < SJA1000_MAX_IRQ)) {
while ((n < SJA1000_MAX_IRQ) &&
(isrc = priv->read_reg(priv, SJA1000_IR))) {
status = priv->read_reg(priv, SJA1000_SR);
/* check for absent controller due to hw unplug */

View File

@@ -657,8 +657,8 @@ static irqreturn_t sun4i_can_interrupt(int irq, void *dev_id)
u8 isrc, status;
int n = 0;
while ((isrc = readl(priv->base + SUN4I_REG_INT_ADDR)) &&
(n < SUN4I_CAN_MAX_IRQ)) {
while ((n < SUN4I_CAN_MAX_IRQ) &&
(isrc = readl(priv->base + SUN4I_REG_INT_ADDR))) {
n++;
status = readl(priv->base + SUN4I_REG_STA_ADDR);

View File

@@ -261,7 +261,13 @@ struct canfd_quirk {
u8 quirk;
} __packed;
/* struct gs_host_frame::echo_id == GS_HOST_FRAME_ECHO_ID_RX indicates
* a regular RX'ed CAN frame
*/
#define GS_HOST_FRAME_ECHO_ID_RX 0xffffffff
struct gs_host_frame {
struct_group(header,
u32 echo_id;
__le32 can_id;
@@ -269,6 +275,7 @@ struct gs_host_frame {
u8 channel;
u8 flags;
u8 reserved;
);
union {
DECLARE_FLEX_ARRAY(struct classic_can, classic_can);
@@ -568,6 +575,37 @@ gs_usb_get_echo_skb(struct gs_can *dev, struct sk_buff *skb,
return len;
}
static unsigned int
gs_usb_get_minimum_rx_length(const struct gs_can *dev, const struct gs_host_frame *hf,
unsigned int *data_length_p)
{
unsigned int minimum_length, data_length = 0;
if (hf->flags & GS_CAN_FLAG_FD) {
if (hf->echo_id == GS_HOST_FRAME_ECHO_ID_RX)
data_length = can_fd_dlc2len(hf->can_dlc);
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
/* timestamp follows data field of max size */
minimum_length = struct_size(hf, canfd_ts, 1);
else
minimum_length = sizeof(hf->header) + data_length;
} else {
if (hf->echo_id == GS_HOST_FRAME_ECHO_ID_RX &&
!(hf->can_id & cpu_to_le32(CAN_RTR_FLAG)))
data_length = can_cc_dlc2len(hf->can_dlc);
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
/* timestamp follows data field of max size */
minimum_length = struct_size(hf, classic_can_ts, 1);
else
minimum_length = sizeof(hf->header) + data_length;
}
*data_length_p = data_length;
return minimum_length;
}
static void gs_usb_receive_bulk_callback(struct urb *urb)
{
struct gs_usb *parent = urb->context;
@@ -576,6 +614,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
int rc;
struct net_device_stats *stats;
struct gs_host_frame *hf = urb->transfer_buffer;
unsigned int minimum_length, data_length;
struct gs_tx_context *txc;
struct can_frame *cf;
struct canfd_frame *cfd;
@@ -594,6 +633,15 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
return;
}
minimum_length = sizeof(hf->header);
if (urb->actual_length < minimum_length) {
dev_err_ratelimited(&parent->udev->dev,
"short read (actual_length=%u, minimum_length=%u)\n",
urb->actual_length, minimum_length);
goto resubmit_urb;
}
/* device reports out of range channel id */
if (hf->channel >= parent->channel_cnt)
goto device_detach;
@@ -609,20 +657,33 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
if (!netif_running(netdev))
goto resubmit_urb;
if (hf->echo_id == -1) { /* normal rx */
minimum_length = gs_usb_get_minimum_rx_length(dev, hf, &data_length);
if (urb->actual_length < minimum_length) {
stats->rx_errors++;
stats->rx_length_errors++;
if (net_ratelimit())
netdev_err(netdev,
"short read (actual_length=%u, minimum_length=%u)\n",
urb->actual_length, minimum_length);
goto resubmit_urb;
}
if (hf->echo_id == GS_HOST_FRAME_ECHO_ID_RX) { /* normal rx */
if (hf->flags & GS_CAN_FLAG_FD) {
skb = alloc_canfd_skb(netdev, &cfd);
if (!skb)
return;
cfd->can_id = le32_to_cpu(hf->can_id);
cfd->len = can_fd_dlc2len(hf->can_dlc);
cfd->len = data_length;
if (hf->flags & GS_CAN_FLAG_BRS)
cfd->flags |= CANFD_BRS;
if (hf->flags & GS_CAN_FLAG_ESI)
cfd->flags |= CANFD_ESI;
memcpy(cfd->data, hf->canfd->data, cfd->len);
memcpy(cfd->data, hf->canfd->data, data_length);
} else {
skb = alloc_can_skb(netdev, &cf);
if (!skb)
@@ -631,7 +692,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
cf->can_id = le32_to_cpu(hf->can_id);
can_frame_set_cc_len(cf, hf->can_dlc, dev->can.ctrlmode);
memcpy(cf->data, hf->classic_can->data, 8);
memcpy(cf->data, hf->classic_can->data, data_length);
/* ERROR frames tell us information about the controller */
if (le32_to_cpu(hf->can_id) & CAN_ERR_FLAG)
@@ -687,7 +748,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
resubmit_urb:
usb_fill_bulk_urb(urb, parent->udev,
parent->pipe_in,
hf, dev->parent->hf_size_rx,
hf, parent->hf_size_rx,
gs_usb_receive_bulk_callback, parent);
rc = usb_submit_urb(urb, GFP_ATOMIC);
@@ -750,8 +811,21 @@ static void gs_usb_xmit_callback(struct urb *urb)
struct gs_can *dev = txc->dev;
struct net_device *netdev = dev->netdev;
if (urb->status)
netdev_info(netdev, "usb xmit fail %u\n", txc->echo_id);
if (!urb->status)
return;
if (urb->status != -ESHUTDOWN && net_ratelimit())
netdev_info(netdev, "failed to xmit URB %u: %pe\n",
txc->echo_id, ERR_PTR(urb->status));
netdev->stats.tx_dropped++;
netdev->stats.tx_errors++;
can_free_echo_skb(netdev, txc->echo_id, NULL);
gs_free_tx_context(txc);
atomic_dec(&dev->active_tx_urbs);
netif_wake_queue(netdev);
}
static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,

View File

@@ -685,7 +685,7 @@ static int kvaser_usb_leaf_wait_cmd(const struct kvaser_usb *dev, u8 id,
* for further details.
*/
if (tmp->len == 0) {
pos = round_up(pos,
pos = round_up(pos + 1,
le16_to_cpu
(dev->bulk_in->wMaxPacketSize));
continue;
@@ -1732,7 +1732,7 @@ static void kvaser_usb_leaf_read_bulk_callback(struct kvaser_usb *dev,
* number of events in case of a heavy rx load on the bus.
*/
if (cmd->len == 0) {
pos = round_up(pos, le16_to_cpu
pos = round_up(pos + 1, le16_to_cpu
(dev->bulk_in->wMaxPacketSize));
continue;
}

View File

@@ -99,6 +99,9 @@ static int em_canid_match(struct sk_buff *skb, struct tcf_ematch *m,
int i;
const struct can_filter *lp;
if (!pskb_may_pull(skb, CAN_MTU))
return 0;
can_id = em_canid_get_id(skb);
if (can_id & CAN_EFF_FLAG) {