Commit e2142ef2 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'linux-can-fixes-for-5.10-20201115' of...

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

Marc Kleine-Budde says:

====================
pull-request: can 2020-11-15

Anant Thazhemadam contributed two patches for the AF_CAN that prevent potential
access of uninitialized member in can_rcv() and canfd_rcv().

The next patch is by Alejandro Concepcion Rodriguez and changes can_restart()
to use the correct function to push a skb into the networking stack from
process context.

Zhang Qilong's patch fixes a memory leak in the error path of the ti_hecc's
probe function.

A patch by me fixes mcba_usb_start_xmit() function in the mcba_usb driver, to
first fill the skb and then pass it to can_put_echo_skb().

Colin Ian King's patch fixes a potential integer overflow on shift in the
peak_usb driver.

The next two patches target the flexcan driver, a patch by me adds the missing
"req_bit" to the stop mode property comment (which was broken during net-next
for v5.10). Zhang Qilong's patch fixes the failure handling of
pm_runtime_get_sync().

The next seven patches target the m_can driver including the tcan4x5x spi
driver glue code. Enric Balletbo i Serra's patch for the tcan4x5x Kconfig fix
the REGMAP_SPI dependency handling. A patch by me for the tcan4x5x driver's
probe() function adds missing error handling to for devm_regmap_init(), and in
tcan4x5x_can_remove() the order of deregistration is fixed. Wu Bo's patch for
the m_can driver fixes the state change handling in
m_can_handle_state_change(). Two patches by Dan Murphy first introduce
m_can_class_free_dev() and then make use of it to fix the freeing of the can
device. A patch by Faiz Abbas add a missing shutdown of the CAN controller in
the m_can_stop() function.

* tag 'linux-can-fixes-for-5.10-20201115' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can:
  can: m_can: m_can_stop(): set device to software init mode before closing
  can: m_can: Fix freeing of can device from peripherials
  can: m_can: m_can_class_free_dev(): introduce new function
  can: m_can: m_can_handle_state_change(): fix state change
  can: tcan4x5x: tcan4x5x_can_remove(): fix order of deregistration
  can: tcan4x5x: tcan4x5x_can_probe(): add missing error checking for devm_regmap_init()
  can: tcan4x5x: replace depends on REGMAP_SPI with depends on SPI
  can: flexcan: fix failure handling of pm_runtime_get_sync()
  can: flexcan: flexcan_setup_stop_mode(): add missing "req_bit" to stop mode property comment
  can: peak_usb: fix potential integer overflow on shift of a int
  can: mcba_usb: mcba_usb_start_xmit(): first fill skb, then pass to can_put_echo_skb()
  can: ti_hecc: Fix memleak in ti_hecc_probe
  can: dev: can_restart(): post buffer from the right context
  can: af_can: prevent potential access of uninitialized member in canfd_rcv()
  can: af_can: prevent potential access of uninitialized member in can_rcv()
====================

Link: https://lore.kernel.org/r/20201115174131.2089251-1-mkl@pengutronix.deSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 849920c7 a584e9bc
...@@ -592,7 +592,7 @@ static void can_restart(struct net_device *dev) ...@@ -592,7 +592,7 @@ static void can_restart(struct net_device *dev)
cf->can_id |= CAN_ERR_RESTARTED; cf->can_id |= CAN_ERR_RESTARTED;
netif_rx(skb); netif_rx_ni(skb);
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += cf->can_dlc; stats->rx_bytes += cf->can_dlc;
......
...@@ -728,8 +728,10 @@ static int flexcan_get_berr_counter(const struct net_device *dev, ...@@ -728,8 +728,10 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
int err; int err;
err = pm_runtime_get_sync(priv->dev); err = pm_runtime_get_sync(priv->dev);
if (err < 0) if (err < 0) {
pm_runtime_put_noidle(priv->dev);
return err; return err;
}
err = __flexcan_get_berr_counter(dev, bec); err = __flexcan_get_berr_counter(dev, bec);
...@@ -1654,8 +1656,10 @@ static int flexcan_open(struct net_device *dev) ...@@ -1654,8 +1656,10 @@ static int flexcan_open(struct net_device *dev)
} }
err = pm_runtime_get_sync(priv->dev); err = pm_runtime_get_sync(priv->dev);
if (err < 0) if (err < 0) {
pm_runtime_put_noidle(priv->dev);
return err; return err;
}
err = open_candev(dev); err = open_candev(dev);
if (err) if (err)
...@@ -1852,7 +1856,7 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) ...@@ -1852,7 +1856,7 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
/* stop mode property format is: /* stop mode property format is:
* <&gpr req_gpr>. * <&gpr req_gpr req_bit>.
*/ */
ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val, ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val,
ARRAY_SIZE(out_val)); ARRAY_SIZE(out_val));
......
...@@ -16,7 +16,8 @@ config CAN_M_CAN_PLATFORM ...@@ -16,7 +16,8 @@ config CAN_M_CAN_PLATFORM
config CAN_M_CAN_TCAN4X5X config CAN_M_CAN_TCAN4X5X
depends on CAN_M_CAN depends on CAN_M_CAN
depends on REGMAP_SPI depends on SPI
select REGMAP_SPI
tristate "TCAN4X5X M_CAN device" tristate "TCAN4X5X M_CAN device"
help help
Say Y here if you want support for Texas Instruments TCAN4x5x Say Y here if you want support for Texas Instruments TCAN4x5x
......
...@@ -665,7 +665,7 @@ static int m_can_handle_state_change(struct net_device *dev, ...@@ -665,7 +665,7 @@ static int m_can_handle_state_change(struct net_device *dev,
unsigned int ecr; unsigned int ecr;
switch (new_state) { switch (new_state) {
case CAN_STATE_ERROR_ACTIVE: case CAN_STATE_ERROR_WARNING:
/* error warning state */ /* error warning state */
cdev->can.can_stats.error_warning++; cdev->can.can_stats.error_warning++;
cdev->can.state = CAN_STATE_ERROR_WARNING; cdev->can.state = CAN_STATE_ERROR_WARNING;
...@@ -694,7 +694,7 @@ static int m_can_handle_state_change(struct net_device *dev, ...@@ -694,7 +694,7 @@ static int m_can_handle_state_change(struct net_device *dev,
__m_can_get_berr_counter(dev, &bec); __m_can_get_berr_counter(dev, &bec);
switch (new_state) { switch (new_state) {
case CAN_STATE_ERROR_ACTIVE: case CAN_STATE_ERROR_WARNING:
/* error warning state */ /* error warning state */
cf->can_id |= CAN_ERR_CRTL; cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = (bec.txerr > bec.rxerr) ? cf->data[1] = (bec.txerr > bec.rxerr) ?
...@@ -1414,6 +1414,9 @@ static void m_can_stop(struct net_device *dev) ...@@ -1414,6 +1414,9 @@ static void m_can_stop(struct net_device *dev)
/* disable all interrupts */ /* disable all interrupts */
m_can_disable_all_interrupts(cdev); m_can_disable_all_interrupts(cdev);
/* Set init mode to disengage from the network */
m_can_config_endisable(cdev, true);
/* set the state as STOPPED */ /* set the state as STOPPED */
cdev->can.state = CAN_STATE_STOPPED; cdev->can.state = CAN_STATE_STOPPED;
} }
...@@ -1812,6 +1815,12 @@ struct m_can_classdev *m_can_class_allocate_dev(struct device *dev) ...@@ -1812,6 +1815,12 @@ struct m_can_classdev *m_can_class_allocate_dev(struct device *dev)
} }
EXPORT_SYMBOL_GPL(m_can_class_allocate_dev); EXPORT_SYMBOL_GPL(m_can_class_allocate_dev);
void m_can_class_free_dev(struct net_device *net)
{
free_candev(net);
}
EXPORT_SYMBOL_GPL(m_can_class_free_dev);
int m_can_class_register(struct m_can_classdev *m_can_dev) int m_can_class_register(struct m_can_classdev *m_can_dev)
{ {
int ret; int ret;
...@@ -1850,7 +1859,6 @@ int m_can_class_register(struct m_can_classdev *m_can_dev) ...@@ -1850,7 +1859,6 @@ int m_can_class_register(struct m_can_classdev *m_can_dev)
if (ret) { if (ret) {
if (m_can_dev->pm_clock_support) if (m_can_dev->pm_clock_support)
pm_runtime_disable(m_can_dev->dev); pm_runtime_disable(m_can_dev->dev);
free_candev(m_can_dev->net);
} }
return ret; return ret;
...@@ -1908,8 +1916,6 @@ void m_can_class_unregister(struct m_can_classdev *m_can_dev) ...@@ -1908,8 +1916,6 @@ void m_can_class_unregister(struct m_can_classdev *m_can_dev)
unregister_candev(m_can_dev->net); unregister_candev(m_can_dev->net);
m_can_clk_stop(m_can_dev); m_can_clk_stop(m_can_dev);
free_candev(m_can_dev->net);
} }
EXPORT_SYMBOL_GPL(m_can_class_unregister); EXPORT_SYMBOL_GPL(m_can_class_unregister);
......
...@@ -99,6 +99,7 @@ struct m_can_classdev { ...@@ -99,6 +99,7 @@ struct m_can_classdev {
}; };
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev); struct m_can_classdev *m_can_class_allocate_dev(struct device *dev);
void m_can_class_free_dev(struct net_device *net);
int m_can_class_register(struct m_can_classdev *cdev); int m_can_class_register(struct m_can_classdev *cdev);
void m_can_class_unregister(struct m_can_classdev *cdev); void m_can_class_unregister(struct m_can_classdev *cdev);
int m_can_class_get_clocks(struct m_can_classdev *cdev); int m_can_class_get_clocks(struct m_can_classdev *cdev);
......
...@@ -67,32 +67,36 @@ static int m_can_plat_probe(struct platform_device *pdev) ...@@ -67,32 +67,36 @@ static int m_can_plat_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv) {
return -ENOMEM; ret = -ENOMEM;
goto probe_fail;
}
mcan_class->device_data = priv; mcan_class->device_data = priv;
m_can_class_get_clocks(mcan_class); ret = m_can_class_get_clocks(mcan_class);
if (ret)
goto probe_fail;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "m_can"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "m_can");
addr = devm_ioremap_resource(&pdev->dev, res); addr = devm_ioremap_resource(&pdev->dev, res);
irq = platform_get_irq_byname(pdev, "int0"); irq = platform_get_irq_byname(pdev, "int0");
if (IS_ERR(addr) || irq < 0) { if (IS_ERR(addr) || irq < 0) {
ret = -EINVAL; ret = -EINVAL;
goto failed_ret; goto probe_fail;
} }
/* message ram could be shared */ /* message ram could be shared */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
if (!res) { if (!res) {
ret = -ENODEV; ret = -ENODEV;
goto failed_ret; goto probe_fail;
} }
mram_addr = devm_ioremap(&pdev->dev, res->start, resource_size(res)); mram_addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!mram_addr) { if (!mram_addr) {
ret = -ENOMEM; ret = -ENOMEM;
goto failed_ret; goto probe_fail;
} }
priv->base = addr; priv->base = addr;
...@@ -111,9 +115,10 @@ static int m_can_plat_probe(struct platform_device *pdev) ...@@ -111,9 +115,10 @@ static int m_can_plat_probe(struct platform_device *pdev)
m_can_init_ram(mcan_class); m_can_init_ram(mcan_class);
ret = m_can_class_register(mcan_class); return m_can_class_register(mcan_class);
failed_ret: probe_fail:
m_can_class_free_dev(mcan_class->net);
return ret; return ret;
} }
...@@ -134,6 +139,8 @@ static int m_can_plat_remove(struct platform_device *pdev) ...@@ -134,6 +139,8 @@ static int m_can_plat_remove(struct platform_device *pdev)
m_can_class_unregister(mcan_class); m_can_class_unregister(mcan_class);
m_can_class_free_dev(mcan_class->net);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
return 0; return 0;
......
...@@ -440,14 +440,18 @@ static int tcan4x5x_can_probe(struct spi_device *spi) ...@@ -440,14 +440,18 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
return -ENOMEM; return -ENOMEM;
priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv) {
return -ENOMEM; ret = -ENOMEM;
goto out_m_can_class_free_dev;
}
priv->power = devm_regulator_get_optional(&spi->dev, "vsup"); priv->power = devm_regulator_get_optional(&spi->dev, "vsup");
if (PTR_ERR(priv->power) == -EPROBE_DEFER) if (PTR_ERR(priv->power) == -EPROBE_DEFER) {
return -EPROBE_DEFER; ret = -EPROBE_DEFER;
else goto out_m_can_class_free_dev;
} else {
priv->power = NULL; priv->power = NULL;
}
mcan_class->device_data = priv; mcan_class->device_data = priv;
...@@ -460,8 +464,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi) ...@@ -460,8 +464,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
} }
/* Sanity check */ /* Sanity check */
if (freq < 20000000 || freq > TCAN4X5X_EXT_CLK_DEF) if (freq < 20000000 || freq > TCAN4X5X_EXT_CLK_DEF) {
return -ERANGE; ret = -ERANGE;
goto out_m_can_class_free_dev;
}
priv->reg_offset = TCAN4X5X_MCAN_OFFSET; priv->reg_offset = TCAN4X5X_MCAN_OFFSET;
priv->mram_start = TCAN4X5X_MRAM_START; priv->mram_start = TCAN4X5X_MRAM_START;
...@@ -487,6 +493,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi) ...@@ -487,6 +493,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
priv->regmap = devm_regmap_init(&spi->dev, &tcan4x5x_bus, priv->regmap = devm_regmap_init(&spi->dev, &tcan4x5x_bus,
&spi->dev, &tcan4x5x_regmap); &spi->dev, &tcan4x5x_regmap);
if (IS_ERR(priv->regmap)) {
ret = PTR_ERR(priv->regmap);
goto out_clk;
}
ret = tcan4x5x_power_enable(priv->power, 1); ret = tcan4x5x_power_enable(priv->power, 1);
if (ret) if (ret)
...@@ -514,8 +524,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi) ...@@ -514,8 +524,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
clk_disable_unprepare(mcan_class->cclk); clk_disable_unprepare(mcan_class->cclk);
clk_disable_unprepare(mcan_class->hclk); clk_disable_unprepare(mcan_class->hclk);
} }
out_m_can_class_free_dev:
m_can_class_free_dev(mcan_class->net);
dev_err(&spi->dev, "Probe failed, err=%d\n", ret); dev_err(&spi->dev, "Probe failed, err=%d\n", ret);
return ret; return ret;
} }
...@@ -523,9 +535,11 @@ static int tcan4x5x_can_remove(struct spi_device *spi) ...@@ -523,9 +535,11 @@ static int tcan4x5x_can_remove(struct spi_device *spi)
{ {
struct tcan4x5x_priv *priv = spi_get_drvdata(spi); struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
m_can_class_unregister(priv->mcan_dev);
tcan4x5x_power_enable(priv->power, 0); tcan4x5x_power_enable(priv->power, 0);
m_can_class_unregister(priv->mcan_dev); m_can_class_free_dev(priv->mcan_dev->net);
return 0; return 0;
} }
......
...@@ -881,7 +881,8 @@ static int ti_hecc_probe(struct platform_device *pdev) ...@@ -881,7 +881,8 @@ static int ti_hecc_probe(struct platform_device *pdev)
priv->base = devm_platform_ioremap_resource_byname(pdev, "hecc"); priv->base = devm_platform_ioremap_resource_byname(pdev, "hecc");
if (IS_ERR(priv->base)) { if (IS_ERR(priv->base)) {
dev_err(&pdev->dev, "hecc ioremap failed\n"); dev_err(&pdev->dev, "hecc ioremap failed\n");
return PTR_ERR(priv->base); err = PTR_ERR(priv->base);
goto probe_exit_candev;
} }
/* handle hecc-ram memory */ /* handle hecc-ram memory */
...@@ -889,20 +890,22 @@ static int ti_hecc_probe(struct platform_device *pdev) ...@@ -889,20 +890,22 @@ static int ti_hecc_probe(struct platform_device *pdev)
"hecc-ram"); "hecc-ram");
if (IS_ERR(priv->hecc_ram)) { if (IS_ERR(priv->hecc_ram)) {
dev_err(&pdev->dev, "hecc-ram ioremap failed\n"); dev_err(&pdev->dev, "hecc-ram ioremap failed\n");
return PTR_ERR(priv->hecc_ram); err = PTR_ERR(priv->hecc_ram);
goto probe_exit_candev;
} }
/* handle mbx memory */ /* handle mbx memory */
priv->mbx = devm_platform_ioremap_resource_byname(pdev, "mbx"); priv->mbx = devm_platform_ioremap_resource_byname(pdev, "mbx");
if (IS_ERR(priv->mbx)) { if (IS_ERR(priv->mbx)) {
dev_err(&pdev->dev, "mbx ioremap failed\n"); dev_err(&pdev->dev, "mbx ioremap failed\n");
return PTR_ERR(priv->mbx); err = PTR_ERR(priv->mbx);
goto probe_exit_candev;
} }
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) { if (!irq) {
dev_err(&pdev->dev, "No irq resource\n"); dev_err(&pdev->dev, "No irq resource\n");
goto probe_exit; goto probe_exit_candev;
} }
priv->ndev = ndev; priv->ndev = ndev;
...@@ -966,7 +969,7 @@ static int ti_hecc_probe(struct platform_device *pdev) ...@@ -966,7 +969,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
clk_put(priv->clk); clk_put(priv->clk);
probe_exit_candev: probe_exit_candev:
free_candev(ndev); free_candev(ndev);
probe_exit:
return err; return err;
} }
......
...@@ -326,8 +326,6 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb, ...@@ -326,8 +326,6 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
if (!ctx) if (!ctx)
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
can_put_echo_skb(skb, priv->netdev, ctx->ndx);
if (cf->can_id & CAN_EFF_FLAG) { if (cf->can_id & CAN_EFF_FLAG) {
/* SIDH | SIDL | EIDH | EIDL /* SIDH | SIDL | EIDH | EIDL
* 28 - 21 | 20 19 18 x x x 17 16 | 15 - 8 | 7 - 0 * 28 - 21 | 20 19 18 x x x 17 16 | 15 - 8 | 7 - 0
...@@ -357,6 +355,8 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb, ...@@ -357,6 +355,8 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
if (cf->can_id & CAN_RTR_FLAG) if (cf->can_id & CAN_RTR_FLAG)
usb_msg.dlc |= MCBA_DLC_RTR_MASK; usb_msg.dlc |= MCBA_DLC_RTR_MASK;
can_put_echo_skb(skb, priv->netdev, ctx->ndx);
err = mcba_usb_xmit(priv, (struct mcba_usb_msg *)&usb_msg, ctx); err = mcba_usb_xmit(priv, (struct mcba_usb_msg *)&usb_msg, ctx);
if (err) if (err)
goto xmit_failed; goto xmit_failed;
......
...@@ -156,7 +156,7 @@ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time) ...@@ -156,7 +156,7 @@ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time)
if (time_ref->ts_dev_1 < time_ref->ts_dev_2) { if (time_ref->ts_dev_1 < time_ref->ts_dev_2) {
/* case when event time (tsw) wraps */ /* case when event time (tsw) wraps */
if (ts < time_ref->ts_dev_1) if (ts < time_ref->ts_dev_1)
delta_ts = 1 << time_ref->adapter->ts_used_bits; delta_ts = BIT_ULL(time_ref->adapter->ts_used_bits);
/* Otherwise, sync time counter (ts_dev_2) has wrapped: /* Otherwise, sync time counter (ts_dev_2) has wrapped:
* handle case when event time (tsn) hasn't. * handle case when event time (tsn) hasn't.
...@@ -168,7 +168,7 @@ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time) ...@@ -168,7 +168,7 @@ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time)
* tsn ts * tsn ts
*/ */
} else if (time_ref->ts_dev_1 < ts) { } else if (time_ref->ts_dev_1 < ts) {
delta_ts = -(1 << time_ref->adapter->ts_used_bits); delta_ts = -BIT_ULL(time_ref->adapter->ts_used_bits);
} }
/* add delay between last sync and event timestamps */ /* add delay between last sync and event timestamps */
......
...@@ -677,16 +677,25 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -677,16 +677,25 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
{ {
struct canfd_frame *cfd = (struct canfd_frame *)skb->data; struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CAN_MTU || if (unlikely(dev->type != ARPHRD_CAN || skb->len != CAN_MTU)) {
cfd->len > CAN_MAX_DLEN)) { pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n",
pr_warn_once("PF_CAN: dropped non conform CAN skbuf: dev type %d, len %d, datalen %d\n", dev->type, skb->len);
goto free_skb;
}
/* This check is made separately since cfd->len would be uninitialized if skb->len = 0. */
if (unlikely(cfd->len > CAN_MAX_DLEN)) {
pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d, datalen %d\n",
dev->type, skb->len, cfd->len); dev->type, skb->len, cfd->len);
kfree_skb(skb); goto free_skb;
return NET_RX_DROP;
} }
can_receive(skb, dev); can_receive(skb, dev);
return NET_RX_SUCCESS; return NET_RX_SUCCESS;
free_skb:
kfree_skb(skb);
return NET_RX_DROP;
} }
static int canfd_rcv(struct sk_buff *skb, struct net_device *dev, static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
...@@ -694,16 +703,25 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -694,16 +703,25 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
{ {
struct canfd_frame *cfd = (struct canfd_frame *)skb->data; struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CANFD_MTU || if (unlikely(dev->type != ARPHRD_CAN || skb->len != CANFD_MTU)) {
cfd->len > CANFD_MAX_DLEN)) { pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n",
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuf: dev type %d, len %d, datalen %d\n", dev->type, skb->len);
goto free_skb;
}
/* This check is made separately since cfd->len would be uninitialized if skb->len = 0. */
if (unlikely(cfd->len > CANFD_MAX_DLEN)) {
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d, datalen %d\n",
dev->type, skb->len, cfd->len); dev->type, skb->len, cfd->len);
kfree_skb(skb); goto free_skb;
return NET_RX_DROP;
} }
can_receive(skb, dev); can_receive(skb, dev);
return NET_RX_SUCCESS; return NET_RX_SUCCESS;
free_skb:
kfree_skb(skb);
return NET_RX_DROP;
} }
/* af_can protocol functions */ /* af_can protocol functions */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment