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

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
...@@ -32,8 +32,13 @@ static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg) ...@@ -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) 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); 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; return 0;
} }
...@@ -51,8 +56,13 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset, ...@@ -51,8 +56,13 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
const void *val, size_t val_count) const void *val, size_t val_count)
{ {
struct m_can_plat_priv *priv = cdev_to_priv(cdev); 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; return 0;
} }
......
...@@ -846,10 +846,12 @@ static int __maybe_unused rcar_can_suspend(struct device *dev) ...@@ -846,10 +846,12 @@ static int __maybe_unused rcar_can_suspend(struct device *dev)
struct rcar_can_priv *priv = netdev_priv(ndev); struct rcar_can_priv *priv = netdev_priv(ndev);
u16 ctlr; u16 ctlr;
if (netif_running(ndev)) { if (!netif_running(ndev))
netif_stop_queue(ndev); return 0;
netif_device_detach(ndev);
} netif_stop_queue(ndev);
netif_device_detach(ndev);
ctlr = readw(&priv->regs->ctlr); ctlr = readw(&priv->regs->ctlr);
ctlr |= RCAR_CAN_CTLR_CANM_HALT; ctlr |= RCAR_CAN_CTLR_CANM_HALT;
writew(ctlr, &priv->regs->ctlr); writew(ctlr, &priv->regs->ctlr);
...@@ -868,6 +870,9 @@ static int __maybe_unused rcar_can_resume(struct device *dev) ...@@ -868,6 +870,9 @@ static int __maybe_unused rcar_can_resume(struct device *dev)
u16 ctlr; u16 ctlr;
int err; int err;
if (!netif_running(ndev))
return 0;
err = clk_enable(priv->clk); err = clk_enable(priv->clk);
if (err) { if (err) {
netdev_err(ndev, "clk_enable() failed, error %d\n", 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) ...@@ -881,10 +886,9 @@ static int __maybe_unused rcar_can_resume(struct device *dev)
writew(ctlr, &priv->regs->ctlr); writew(ctlr, &priv->regs->ctlr);
priv->can.state = CAN_STATE_ERROR_ACTIVE; priv->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_running(ndev)) { netif_device_attach(ndev);
netif_device_attach(ndev); netif_start_queue(ndev);
netif_start_queue(ndev);
}
return 0; return 0;
} }
......
...@@ -752,16 +752,15 @@ static void peak_pci_remove(struct pci_dev *pdev) ...@@ -752,16 +752,15 @@ static void peak_pci_remove(struct pci_dev *pdev)
struct net_device *prev_dev = chan->prev_dev; struct net_device *prev_dev = chan->prev_dev;
dev_info(&pdev->dev, "removing device %s\n", dev->name); 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); unregister_sja1000dev(dev);
free_sja1000dev(dev); free_sja1000dev(dev);
dev = prev_dev; dev = prev_dev;
if (!dev) { if (!dev)
/* do that only for first channel */
if (chan->pciec_card)
peak_pciec_remove(chan->pciec_card);
break; break;
}
priv = netdev_priv(dev); priv = netdev_priv(dev);
chan = priv->priv; chan = priv->priv;
} }
......
...@@ -551,11 +551,10 @@ static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if, ...@@ -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) { } else if (sm->channel_p_w_b & PUCAN_BUS_WARNING) {
new_state = CAN_STATE_ERROR_WARNING; new_state = CAN_STATE_ERROR_WARNING;
} else { } else {
/* no error bit (so, no error skb, back to active state) */ /* back to (or still in) ERROR_ACTIVE state */
dev->can.state = CAN_STATE_ERROR_ACTIVE; new_state = CAN_STATE_ERROR_ACTIVE;
pdev->bec.txerr = 0; pdev->bec.txerr = 0;
pdev->bec.rxerr = 0; pdev->bec.rxerr = 0;
return 0;
} }
/* state hasn't changed */ /* state hasn't changed */
...@@ -568,8 +567,7 @@ static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if, ...@@ -568,8 +567,7 @@ static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if,
/* allocate an skb to store the error frame */ /* allocate an skb to store the error frame */
skb = alloc_can_err_skb(netdev, &cf); skb = alloc_can_err_skb(netdev, &cf);
if (skb) can_change_state(netdev, cf, tx_state, rx_state);
can_change_state(netdev, cf, tx_state, rx_state);
/* things must be done even in case of OOM */ /* things must be done even in case of OOM */
if (new_state == CAN_STATE_BUS_OFF) if (new_state == CAN_STATE_BUS_OFF)
......
...@@ -121,7 +121,7 @@ enum { ...@@ -121,7 +121,7 @@ enum {
struct tpcon { struct tpcon {
int idx; int idx;
int len; int len;
u8 state; u32 state;
u8 bs; u8 bs;
u8 sn; u8 sn;
u8 ll_dl; u8 ll_dl;
...@@ -848,6 +848,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) ...@@ -848,6 +848,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct isotp_sock *so = isotp_sk(sk); struct isotp_sock *so = isotp_sk(sk);
u32 old_state = so->tx.state;
struct sk_buff *skb; struct sk_buff *skb;
struct net_device *dev; struct net_device *dev;
struct canfd_frame *cf; struct canfd_frame *cf;
...@@ -860,45 +861,55 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) ...@@ -860,45 +861,55 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
/* we do not support multiple buffers - for now */ /* we do not support multiple buffers - for now */
if (so->tx.state != ISOTP_IDLE || wq_has_sleeper(&so->wait)) { if (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE ||
if (msg->msg_flags & MSG_DONTWAIT) wq_has_sleeper(&so->wait)) {
return -EAGAIN; if (msg->msg_flags & MSG_DONTWAIT) {
err = -EAGAIN;
goto err_out;
}
/* wait for complete transmission of current pdu */ /* 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) if (!size || size > MAX_MSG_LENGTH) {
return -EINVAL; err = -EINVAL;
goto err_out;
}
/* take care of a potential SF_DL ESC offset for TX_DL > 8 */ /* take care of a potential SF_DL ESC offset for TX_DL > 8 */
off = (so->tx.ll_dl > CAN_MAX_DLEN) ? 1 : 0; off = (so->tx.ll_dl > CAN_MAX_DLEN) ? 1 : 0;
/* does the given data fit into a single frame for SF_BROADCAST? */ /* does the given data fit into a single frame for SF_BROADCAST? */
if ((so->opt.flags & CAN_ISOTP_SF_BROADCAST) && if ((so->opt.flags & CAN_ISOTP_SF_BROADCAST) &&
(size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off)) (size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off)) {
return -EINVAL; err = -EINVAL;
goto err_out;
}
err = memcpy_from_msg(so->tx.buf, msg, size); err = memcpy_from_msg(so->tx.buf, msg, size);
if (err < 0) if (err < 0)
return err; goto err_out;
dev = dev_get_by_index(sock_net(sk), so->ifindex); dev = dev_get_by_index(sock_net(sk), so->ifindex);
if (!dev) if (!dev) {
return -ENXIO; err = -ENXIO;
goto err_out;
}
skb = sock_alloc_send_skb(sk, so->ll.mtu + sizeof(struct can_skb_priv), skb = sock_alloc_send_skb(sk, so->ll.mtu + sizeof(struct can_skb_priv),
msg->msg_flags & MSG_DONTWAIT, &err); msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb) { if (!skb) {
dev_put(dev); dev_put(dev);
return err; goto err_out;
} }
can_skb_reserve(skb); can_skb_reserve(skb);
can_skb_prv(skb)->ifindex = dev->ifindex; can_skb_prv(skb)->ifindex = dev->ifindex;
can_skb_prv(skb)->skbcnt = 0; can_skb_prv(skb)->skbcnt = 0;
so->tx.state = ISOTP_SENDING;
so->tx.len = size; so->tx.len = size;
so->tx.idx = 0; so->tx.idx = 0;
...@@ -954,7 +965,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) ...@@ -954,7 +965,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
if (err) { if (err) {
pr_notice_once("can-isotp: %s: can_send_ret %pe\n", pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
__func__, ERR_PTR(err)); __func__, ERR_PTR(err));
return err; goto err_out;
} }
if (wait_tx_done) { if (wait_tx_done) {
...@@ -963,6 +974,13 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) ...@@ -963,6 +974,13 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
} }
return 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, static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
......
...@@ -330,6 +330,7 @@ int j1939_session_activate(struct j1939_session *session); ...@@ -330,6 +330,7 @@ int j1939_session_activate(struct j1939_session *session);
void j1939_tp_schedule_txtimer(struct j1939_session *session, int msec); void j1939_tp_schedule_txtimer(struct j1939_session *session, int msec);
void j1939_session_timers_cancel(struct j1939_session *session); void j1939_session_timers_cancel(struct j1939_session *session);
#define J1939_MIN_TP_PACKET_SIZE 9
#define J1939_MAX_TP_PACKET_SIZE (7 * 0xff) #define J1939_MAX_TP_PACKET_SIZE (7 * 0xff)
#define J1939_MAX_ETP_PACKET_SIZE (7 * 0x00ffffff) #define J1939_MAX_ETP_PACKET_SIZE (7 * 0x00ffffff)
......
...@@ -249,11 +249,14 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev) ...@@ -249,11 +249,14 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev)
struct j1939_priv *priv, *priv_new; struct j1939_priv *priv, *priv_new;
int ret; int ret;
priv = j1939_priv_get_by_ndev(ndev); spin_lock(&j1939_netdev_lock);
priv = j1939_priv_get_by_ndev_locked(ndev);
if (priv) { if (priv) {
kref_get(&priv->rx_kref); kref_get(&priv->rx_kref);
spin_unlock(&j1939_netdev_lock);
return priv; return priv;
} }
spin_unlock(&j1939_netdev_lock);
priv = j1939_priv_create(ndev); priv = j1939_priv_create(ndev);
if (!priv) if (!priv)
...@@ -269,10 +272,10 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev) ...@@ -269,10 +272,10 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev)
/* Someone was faster than us, use their priv and roll /* Someone was faster than us, use their priv and roll
* back our's. * back our's.
*/ */
kref_get(&priv_new->rx_kref);
spin_unlock(&j1939_netdev_lock); spin_unlock(&j1939_netdev_lock);
dev_put(ndev); dev_put(ndev);
kfree(priv); kfree(priv);
kref_get(&priv_new->rx_kref);
return priv_new; return priv_new;
} }
j1939_priv_set(ndev, priv); j1939_priv_set(ndev, priv);
......
...@@ -1237,12 +1237,11 @@ static enum hrtimer_restart j1939_tp_rxtimer(struct hrtimer *hrtimer) ...@@ -1237,12 +1237,11 @@ static enum hrtimer_restart j1939_tp_rxtimer(struct hrtimer *hrtimer)
session->err = -ETIME; session->err = -ETIME;
j1939_session_deactivate(session); j1939_session_deactivate(session);
} else { } else {
netdev_alert(priv->ndev, "%s: 0x%p: rx timeout, send abort\n",
__func__, session);
j1939_session_list_lock(session->priv); j1939_session_list_lock(session->priv);
if (session->state >= J1939_SESSION_ACTIVE && if (session->state >= J1939_SESSION_ACTIVE &&
session->state < J1939_SESSION_ACTIVE_MAX) { session->state < J1939_SESSION_ACTIVE_MAX) {
netdev_alert(priv->ndev, "%s: 0x%p: rx timeout, send abort\n",
__func__, session);
j1939_session_get(session); j1939_session_get(session);
hrtimer_start(&session->rxtimer, hrtimer_start(&session->rxtimer,
ms_to_ktime(J1939_XTP_ABORT_TIMEOUT_MS), ms_to_ktime(J1939_XTP_ABORT_TIMEOUT_MS),
...@@ -1609,6 +1608,8 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv, ...@@ -1609,6 +1608,8 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv,
abort = J1939_XTP_ABORT_FAULT; abort = J1939_XTP_ABORT_FAULT;
else if (len > priv->tp_max_packet_size) else if (len > priv->tp_max_packet_size)
abort = J1939_XTP_ABORT_RESOURCE; abort = J1939_XTP_ABORT_RESOURCE;
else if (len < J1939_MIN_TP_PACKET_SIZE)
abort = J1939_XTP_ABORT_FAULT;
} }
if (abort != J1939_XTP_NO_ABORT) { if (abort != J1939_XTP_NO_ABORT) {
...@@ -1789,6 +1790,7 @@ static void j1939_xtp_rx_dpo(struct j1939_priv *priv, struct sk_buff *skb, ...@@ -1789,6 +1790,7 @@ static void j1939_xtp_rx_dpo(struct j1939_priv *priv, struct sk_buff *skb,
static void j1939_xtp_rx_dat_one(struct j1939_session *session, static void j1939_xtp_rx_dat_one(struct j1939_session *session,
struct sk_buff *skb) struct sk_buff *skb)
{ {
enum j1939_xtp_abort abort = J1939_XTP_ABORT_FAULT;
struct j1939_priv *priv = session->priv; struct j1939_priv *priv = session->priv;
struct j1939_sk_buff_cb *skcb, *se_skcb; struct j1939_sk_buff_cb *skcb, *se_skcb;
struct sk_buff *se_skb = NULL; struct sk_buff *se_skb = NULL;
...@@ -1803,9 +1805,11 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session, ...@@ -1803,9 +1805,11 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
skcb = j1939_skb_to_cb(skb); skcb = j1939_skb_to_cb(skb);
dat = skb->data; dat = skb->data;
if (skb->len <= 1) if (skb->len != 8) {
/* makes no sense */ /* makes no sense */
abort = J1939_XTP_ABORT_UNEXPECTED_DATA;
goto out_session_cancel; goto out_session_cancel;
}
switch (session->last_cmd) { switch (session->last_cmd) {
case 0xff: case 0xff:
...@@ -1904,7 +1908,7 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session, ...@@ -1904,7 +1908,7 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
out_session_cancel: out_session_cancel:
kfree_skb(se_skb); kfree_skb(se_skb);
j1939_session_timers_cancel(session); j1939_session_timers_cancel(session);
j1939_session_cancel(session, J1939_XTP_ABORT_FAULT); j1939_session_cancel(session, abort);
j1939_session_put(session); j1939_session_put(session);
} }
......
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