Commit bca69044 authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'linux-can-fixes-for-5.15-20211017' of...

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



Marc Kleine-Budde says:

====================
pull-request: can 2021-10-17

this is a pull request of 11 patches for net/master.

The first 4 patches are by Ziyang Xuan and Zhang Changzhong and fix 1
use after free and 3 standard conformance problems in the j1939 CAN
stack.

The next 2 patches are by Ziyang Xuan and fix 2 concurrency problems
in the ISOTP CAN stack.

Yoshihiro Shimoda's patch for the rcar_can fix suspend/resume on not
running CAN interfaces.

Aswath Govindraju's patch for the m_can driver fixes access for MMIO
devices.

Zheyu Ma contributes a patch for the peak_pci driver to fix a use
after free.

Stephane Grosjean's 2 patches fix CAN error state handling in the
peak_usb driver.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0a9bb11a 553715fe
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -32,8 +32,13 @@ static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg)
static int iomap_read_fifo(struct m_can_classdev *cdev, int offset, void *val, size_t val_count)
{
	struct m_can_plat_priv *priv = cdev_to_priv(cdev);
	void __iomem *src = priv->mram_base + offset;

	ioread32_rep(priv->mram_base + offset, val, val_count);
	while (val_count--) {
		*(unsigned int *)val = ioread32(src);
		val += 4;
		src += 4;
	}

	return 0;
}
@@ -51,8 +56,13 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
			    const void *val, size_t val_count)
{
	struct m_can_plat_priv *priv = cdev_to_priv(cdev);
	void __iomem *dst = priv->mram_base + offset;

	iowrite32_rep(priv->base + offset, val, val_count);
	while (val_count--) {
		iowrite32(*(unsigned int *)val, dst);
		val += 4;
		dst += 4;
	}

	return 0;
}
+12 −8
Original line number Diff line number Diff line
@@ -846,10 +846,12 @@ static int __maybe_unused rcar_can_suspend(struct device *dev)
	struct rcar_can_priv *priv = netdev_priv(ndev);
	u16 ctlr;

	if (netif_running(ndev)) {
	if (!netif_running(ndev))
		return 0;

	netif_stop_queue(ndev);
	netif_device_detach(ndev);
	}

	ctlr = readw(&priv->regs->ctlr);
	ctlr |= RCAR_CAN_CTLR_CANM_HALT;
	writew(ctlr, &priv->regs->ctlr);
@@ -868,6 +870,9 @@ static int __maybe_unused rcar_can_resume(struct device *dev)
	u16 ctlr;
	int err;

	if (!netif_running(ndev))
		return 0;

	err = clk_enable(priv->clk);
	if (err) {
		netdev_err(ndev, "clk_enable() failed, error %d\n", err);
@@ -881,10 +886,9 @@ static int __maybe_unused rcar_can_resume(struct device *dev)
	writew(ctlr, &priv->regs->ctlr);
	priv->can.state = CAN_STATE_ERROR_ACTIVE;

	if (netif_running(ndev)) {
	netif_device_attach(ndev);
	netif_start_queue(ndev);
	}

	return 0;
}

+4 −5
Original line number Diff line number Diff line
@@ -752,16 +752,15 @@ static void peak_pci_remove(struct pci_dev *pdev)
		struct net_device *prev_dev = chan->prev_dev;

		dev_info(&pdev->dev, "removing device %s\n", dev->name);
		/* do that only for first channel */
		if (!prev_dev && chan->pciec_card)
			peak_pciec_remove(chan->pciec_card);
		unregister_sja1000dev(dev);
		free_sja1000dev(dev);
		dev = prev_dev;

		if (!dev) {
			/* do that only for first channel */
			if (chan->pciec_card)
				peak_pciec_remove(chan->pciec_card);
		if (!dev)
			break;
		}
		priv = netdev_priv(dev);
		chan = priv->priv;
	}
+3 −5
Original line number Diff line number Diff line
@@ -551,11 +551,10 @@ static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if,
	} else if (sm->channel_p_w_b & PUCAN_BUS_WARNING) {
		new_state = CAN_STATE_ERROR_WARNING;
	} else {
		/* no error bit (so, no error skb, back to active state) */
		dev->can.state = CAN_STATE_ERROR_ACTIVE;
		/* back to (or still in) ERROR_ACTIVE state */
		new_state = CAN_STATE_ERROR_ACTIVE;
		pdev->bec.txerr = 0;
		pdev->bec.rxerr = 0;
		return 0;
	}

	/* state hasn't changed */
@@ -568,7 +567,6 @@ static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if,

	/* allocate an skb to store the error frame */
	skb = alloc_can_err_skb(netdev, &cf);
	if (skb)
	can_change_state(netdev, cf, tx_state, rx_state);

	/* things must be done even in case of OOM */
+33 −15
Original line number Diff line number Diff line
@@ -121,7 +121,7 @@ enum {
struct tpcon {
	int idx;
	int len;
	u8 state;
	u32 state;
	u8 bs;
	u8 sn;
	u8 ll_dl;
@@ -848,6 +848,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
{
	struct sock *sk = sock->sk;
	struct isotp_sock *so = isotp_sk(sk);
	u32 old_state = so->tx.state;
	struct sk_buff *skb;
	struct net_device *dev;
	struct canfd_frame *cf;
@@ -860,45 +861,55 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
		return -EADDRNOTAVAIL;

	/* we do not support multiple buffers - for now */
	if (so->tx.state != ISOTP_IDLE || wq_has_sleeper(&so->wait)) {
		if (msg->msg_flags & MSG_DONTWAIT)
			return -EAGAIN;
	if (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE ||
	    wq_has_sleeper(&so->wait)) {
		if (msg->msg_flags & MSG_DONTWAIT) {
			err = -EAGAIN;
			goto err_out;
		}

		/* wait for complete transmission of current pdu */
		wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
		err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
		if (err)
			goto err_out;
	}

	if (!size || size > MAX_MSG_LENGTH)
		return -EINVAL;
	if (!size || size > MAX_MSG_LENGTH) {
		err = -EINVAL;
		goto err_out;
	}

	/* take care of a potential SF_DL ESC offset for TX_DL > 8 */
	off = (so->tx.ll_dl > CAN_MAX_DLEN) ? 1 : 0;

	/* does the given data fit into a single frame for SF_BROADCAST? */
	if ((so->opt.flags & CAN_ISOTP_SF_BROADCAST) &&
	    (size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off))
		return -EINVAL;
	    (size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off)) {
		err = -EINVAL;
		goto err_out;
	}

	err = memcpy_from_msg(so->tx.buf, msg, size);
	if (err < 0)
		return err;
		goto err_out;

	dev = dev_get_by_index(sock_net(sk), so->ifindex);
	if (!dev)
		return -ENXIO;
	if (!dev) {
		err = -ENXIO;
		goto err_out;
	}

	skb = sock_alloc_send_skb(sk, so->ll.mtu + sizeof(struct can_skb_priv),
				  msg->msg_flags & MSG_DONTWAIT, &err);
	if (!skb) {
		dev_put(dev);
		return err;
		goto err_out;
	}

	can_skb_reserve(skb);
	can_skb_prv(skb)->ifindex = dev->ifindex;
	can_skb_prv(skb)->skbcnt = 0;

	so->tx.state = ISOTP_SENDING;
	so->tx.len = size;
	so->tx.idx = 0;

@@ -954,7 +965,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
	if (err) {
		pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
			       __func__, ERR_PTR(err));
		return err;
		goto err_out;
	}

	if (wait_tx_done) {
@@ -963,6 +974,13 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
	}

	return size;

err_out:
	so->tx.state = old_state;
	if (so->tx.state == ISOTP_IDLE)
		wake_up_interruptible(&so->wait);

	return err;
}

static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
Loading