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

Merge tag 'linux-can-fixes-for-5.13-20210616' of...

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

Marc Kleine-Budde says:

====================
pull-request: can 2021-06-16

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

The first patch is by Oleksij Rempel and fixes a Use-after-Free found
by syzbot in the j1939 stack.

The next patch is by Tetsuo Handa and fixes hung task detected by
syzbot in the bcm, raw and isotp protocols.

Norbert Slusarek's patch fixes a infoleak in bcm's struct
bcm_msg_head.

Pavel Skripkin's patch fixes a memory leak in the mcba_usb driver.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d8e29730 91c02557
...@@ -82,6 +82,8 @@ struct mcba_priv { ...@@ -82,6 +82,8 @@ struct mcba_priv {
bool can_ka_first_pass; bool can_ka_first_pass;
bool can_speed_check; bool can_speed_check;
atomic_t free_ctx_cnt; atomic_t free_ctx_cnt;
void *rxbuf[MCBA_MAX_RX_URBS];
dma_addr_t rxbuf_dma[MCBA_MAX_RX_URBS];
}; };
/* CAN frame */ /* CAN frame */
...@@ -633,6 +635,7 @@ static int mcba_usb_start(struct mcba_priv *priv) ...@@ -633,6 +635,7 @@ static int mcba_usb_start(struct mcba_priv *priv)
for (i = 0; i < MCBA_MAX_RX_URBS; i++) { for (i = 0; i < MCBA_MAX_RX_URBS; i++) {
struct urb *urb = NULL; struct urb *urb = NULL;
u8 *buf; u8 *buf;
dma_addr_t buf_dma;
/* create a URB, and a buffer for it */ /* create a URB, and a buffer for it */
urb = usb_alloc_urb(0, GFP_KERNEL); urb = usb_alloc_urb(0, GFP_KERNEL);
...@@ -642,7 +645,7 @@ static int mcba_usb_start(struct mcba_priv *priv) ...@@ -642,7 +645,7 @@ static int mcba_usb_start(struct mcba_priv *priv)
} }
buf = usb_alloc_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE, buf = usb_alloc_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
GFP_KERNEL, &urb->transfer_dma); GFP_KERNEL, &buf_dma);
if (!buf) { if (!buf) {
netdev_err(netdev, "No memory left for USB buffer\n"); netdev_err(netdev, "No memory left for USB buffer\n");
usb_free_urb(urb); usb_free_urb(urb);
...@@ -661,11 +664,14 @@ static int mcba_usb_start(struct mcba_priv *priv) ...@@ -661,11 +664,14 @@ static int mcba_usb_start(struct mcba_priv *priv)
if (err) { if (err) {
usb_unanchor_urb(urb); usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE, usb_free_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
buf, urb->transfer_dma); buf, buf_dma);
usb_free_urb(urb); usb_free_urb(urb);
break; break;
} }
priv->rxbuf[i] = buf;
priv->rxbuf_dma[i] = buf_dma;
/* Drop reference, USB core will take care of freeing it */ /* Drop reference, USB core will take care of freeing it */
usb_free_urb(urb); usb_free_urb(urb);
} }
...@@ -708,7 +714,14 @@ static int mcba_usb_open(struct net_device *netdev) ...@@ -708,7 +714,14 @@ static int mcba_usb_open(struct net_device *netdev)
static void mcba_urb_unlink(struct mcba_priv *priv) static void mcba_urb_unlink(struct mcba_priv *priv)
{ {
int i;
usb_kill_anchored_urbs(&priv->rx_submitted); usb_kill_anchored_urbs(&priv->rx_submitted);
for (i = 0; i < MCBA_MAX_RX_URBS; ++i)
usb_free_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
priv->rxbuf[i], priv->rxbuf_dma[i]);
usb_kill_anchored_urbs(&priv->tx_submitted); usb_kill_anchored_urbs(&priv->tx_submitted);
} }
......
...@@ -125,7 +125,7 @@ struct bcm_sock { ...@@ -125,7 +125,7 @@ struct bcm_sock {
struct sock sk; struct sock sk;
int bound; int bound;
int ifindex; int ifindex;
struct notifier_block notifier; struct list_head notifier;
struct list_head rx_ops; struct list_head rx_ops;
struct list_head tx_ops; struct list_head tx_ops;
unsigned long dropped_usr_msgs; unsigned long dropped_usr_msgs;
...@@ -133,6 +133,10 @@ struct bcm_sock { ...@@ -133,6 +133,10 @@ struct bcm_sock {
char procname [32]; /* inode number in decimal with \0 */ char procname [32]; /* inode number in decimal with \0 */
}; };
static LIST_HEAD(bcm_notifier_list);
static DEFINE_SPINLOCK(bcm_notifier_lock);
static struct bcm_sock *bcm_busy_notifier;
static inline struct bcm_sock *bcm_sk(const struct sock *sk) static inline struct bcm_sock *bcm_sk(const struct sock *sk)
{ {
return (struct bcm_sock *)sk; return (struct bcm_sock *)sk;
...@@ -402,6 +406,7 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer) ...@@ -402,6 +406,7 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
if (!op->count && (op->flags & TX_COUNTEVT)) { if (!op->count && (op->flags & TX_COUNTEVT)) {
/* create notification to user */ /* create notification to user */
memset(&msg_head, 0, sizeof(msg_head));
msg_head.opcode = TX_EXPIRED; msg_head.opcode = TX_EXPIRED;
msg_head.flags = op->flags; msg_head.flags = op->flags;
msg_head.count = op->count; msg_head.count = op->count;
...@@ -439,6 +444,7 @@ static void bcm_rx_changed(struct bcm_op *op, struct canfd_frame *data) ...@@ -439,6 +444,7 @@ static void bcm_rx_changed(struct bcm_op *op, struct canfd_frame *data)
/* this element is not throttled anymore */ /* this element is not throttled anymore */
data->flags &= (BCM_CAN_FLAGS_MASK|RX_RECV); data->flags &= (BCM_CAN_FLAGS_MASK|RX_RECV);
memset(&head, 0, sizeof(head));
head.opcode = RX_CHANGED; head.opcode = RX_CHANGED;
head.flags = op->flags; head.flags = op->flags;
head.count = op->count; head.count = op->count;
...@@ -560,6 +566,7 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer) ...@@ -560,6 +566,7 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
} }
/* create notification to user */ /* create notification to user */
memset(&msg_head, 0, sizeof(msg_head));
msg_head.opcode = RX_TIMEOUT; msg_head.opcode = RX_TIMEOUT;
msg_head.flags = op->flags; msg_head.flags = op->flags;
msg_head.count = op->count; msg_head.count = op->count;
...@@ -1378,20 +1385,15 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) ...@@ -1378,20 +1385,15 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
/* /*
* notification handler for netdevice status changes * notification handler for netdevice status changes
*/ */
static int bcm_notifier(struct notifier_block *nb, unsigned long msg, static void bcm_notify(struct bcm_sock *bo, unsigned long msg,
void *ptr) struct net_device *dev)
{ {
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct bcm_sock *bo = container_of(nb, struct bcm_sock, notifier);
struct sock *sk = &bo->sk; struct sock *sk = &bo->sk;
struct bcm_op *op; struct bcm_op *op;
int notify_enodev = 0; int notify_enodev = 0;
if (!net_eq(dev_net(dev), sock_net(sk))) if (!net_eq(dev_net(dev), sock_net(sk)))
return NOTIFY_DONE; return;
if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
switch (msg) { switch (msg) {
...@@ -1426,7 +1428,28 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg, ...@@ -1426,7 +1428,28 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
sk->sk_error_report(sk); sk->sk_error_report(sk);
} }
} }
}
static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
return NOTIFY_DONE;
if (unlikely(bcm_busy_notifier)) /* Check for reentrant bug. */
return NOTIFY_DONE;
spin_lock(&bcm_notifier_lock);
list_for_each_entry(bcm_busy_notifier, &bcm_notifier_list, notifier) {
spin_unlock(&bcm_notifier_lock);
bcm_notify(bcm_busy_notifier, msg, dev);
spin_lock(&bcm_notifier_lock);
}
bcm_busy_notifier = NULL;
spin_unlock(&bcm_notifier_lock);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -1446,9 +1469,9 @@ static int bcm_init(struct sock *sk) ...@@ -1446,9 +1469,9 @@ static int bcm_init(struct sock *sk)
INIT_LIST_HEAD(&bo->rx_ops); INIT_LIST_HEAD(&bo->rx_ops);
/* set notifier */ /* set notifier */
bo->notifier.notifier_call = bcm_notifier; spin_lock(&bcm_notifier_lock);
list_add_tail(&bo->notifier, &bcm_notifier_list);
register_netdevice_notifier(&bo->notifier); spin_unlock(&bcm_notifier_lock);
return 0; return 0;
} }
...@@ -1471,7 +1494,14 @@ static int bcm_release(struct socket *sock) ...@@ -1471,7 +1494,14 @@ static int bcm_release(struct socket *sock)
/* remove bcm_ops, timer, rx_unregister(), etc. */ /* remove bcm_ops, timer, rx_unregister(), etc. */
unregister_netdevice_notifier(&bo->notifier); spin_lock(&bcm_notifier_lock);
while (bcm_busy_notifier == bo) {
spin_unlock(&bcm_notifier_lock);
schedule_timeout_uninterruptible(1);
spin_lock(&bcm_notifier_lock);
}
list_del(&bo->notifier);
spin_unlock(&bcm_notifier_lock);
lock_sock(sk); lock_sock(sk);
...@@ -1692,6 +1722,10 @@ static struct pernet_operations canbcm_pernet_ops __read_mostly = { ...@@ -1692,6 +1722,10 @@ static struct pernet_operations canbcm_pernet_ops __read_mostly = {
.exit = canbcm_pernet_exit, .exit = canbcm_pernet_exit,
}; };
static struct notifier_block canbcm_notifier = {
.notifier_call = bcm_notifier
};
static int __init bcm_module_init(void) static int __init bcm_module_init(void)
{ {
int err; int err;
...@@ -1705,12 +1739,14 @@ static int __init bcm_module_init(void) ...@@ -1705,12 +1739,14 @@ static int __init bcm_module_init(void)
} }
register_pernet_subsys(&canbcm_pernet_ops); register_pernet_subsys(&canbcm_pernet_ops);
register_netdevice_notifier(&canbcm_notifier);
return 0; return 0;
} }
static void __exit bcm_module_exit(void) static void __exit bcm_module_exit(void)
{ {
can_proto_unregister(&bcm_can_proto); can_proto_unregister(&bcm_can_proto);
unregister_netdevice_notifier(&canbcm_notifier);
unregister_pernet_subsys(&canbcm_pernet_ops); unregister_pernet_subsys(&canbcm_pernet_ops);
} }
......
...@@ -143,10 +143,14 @@ struct isotp_sock { ...@@ -143,10 +143,14 @@ struct isotp_sock {
u32 force_tx_stmin; u32 force_tx_stmin;
u32 force_rx_stmin; u32 force_rx_stmin;
struct tpcon rx, tx; struct tpcon rx, tx;
struct notifier_block notifier; struct list_head notifier;
wait_queue_head_t wait; wait_queue_head_t wait;
}; };
static LIST_HEAD(isotp_notifier_list);
static DEFINE_SPINLOCK(isotp_notifier_lock);
static struct isotp_sock *isotp_busy_notifier;
static inline struct isotp_sock *isotp_sk(const struct sock *sk) static inline struct isotp_sock *isotp_sk(const struct sock *sk)
{ {
return (struct isotp_sock *)sk; return (struct isotp_sock *)sk;
...@@ -1013,7 +1017,14 @@ static int isotp_release(struct socket *sock) ...@@ -1013,7 +1017,14 @@ static int isotp_release(struct socket *sock)
/* wait for complete transmission of current pdu */ /* wait for complete transmission of current pdu */
wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE); wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
unregister_netdevice_notifier(&so->notifier); spin_lock(&isotp_notifier_lock);
while (isotp_busy_notifier == so) {
spin_unlock(&isotp_notifier_lock);
schedule_timeout_uninterruptible(1);
spin_lock(&isotp_notifier_lock);
}
list_del(&so->notifier);
spin_unlock(&isotp_notifier_lock);
lock_sock(sk); lock_sock(sk);
...@@ -1317,21 +1328,16 @@ static int isotp_getsockopt(struct socket *sock, int level, int optname, ...@@ -1317,21 +1328,16 @@ static int isotp_getsockopt(struct socket *sock, int level, int optname,
return 0; return 0;
} }
static int isotp_notifier(struct notifier_block *nb, unsigned long msg, static void isotp_notify(struct isotp_sock *so, unsigned long msg,
void *ptr) struct net_device *dev)
{ {
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct isotp_sock *so = container_of(nb, struct isotp_sock, notifier);
struct sock *sk = &so->sk; struct sock *sk = &so->sk;
if (!net_eq(dev_net(dev), sock_net(sk))) if (!net_eq(dev_net(dev), sock_net(sk)))
return NOTIFY_DONE; return;
if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
if (so->ifindex != dev->ifindex) if (so->ifindex != dev->ifindex)
return NOTIFY_DONE; return;
switch (msg) { switch (msg) {
case NETDEV_UNREGISTER: case NETDEV_UNREGISTER:
...@@ -1357,7 +1363,28 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg, ...@@ -1357,7 +1363,28 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
sk->sk_error_report(sk); sk->sk_error_report(sk);
break; break;
} }
}
static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
return NOTIFY_DONE;
if (unlikely(isotp_busy_notifier)) /* Check for reentrant bug. */
return NOTIFY_DONE;
spin_lock(&isotp_notifier_lock);
list_for_each_entry(isotp_busy_notifier, &isotp_notifier_list, notifier) {
spin_unlock(&isotp_notifier_lock);
isotp_notify(isotp_busy_notifier, msg, dev);
spin_lock(&isotp_notifier_lock);
}
isotp_busy_notifier = NULL;
spin_unlock(&isotp_notifier_lock);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -1394,8 +1421,9 @@ static int isotp_init(struct sock *sk) ...@@ -1394,8 +1421,9 @@ static int isotp_init(struct sock *sk)
init_waitqueue_head(&so->wait); init_waitqueue_head(&so->wait);
so->notifier.notifier_call = isotp_notifier; spin_lock(&isotp_notifier_lock);
register_netdevice_notifier(&so->notifier); list_add_tail(&so->notifier, &isotp_notifier_list);
spin_unlock(&isotp_notifier_lock);
return 0; return 0;
} }
...@@ -1442,6 +1470,10 @@ static const struct can_proto isotp_can_proto = { ...@@ -1442,6 +1470,10 @@ static const struct can_proto isotp_can_proto = {
.prot = &isotp_proto, .prot = &isotp_proto,
}; };
static struct notifier_block canisotp_notifier = {
.notifier_call = isotp_notifier
};
static __init int isotp_module_init(void) static __init int isotp_module_init(void)
{ {
int err; int err;
...@@ -1451,6 +1483,8 @@ static __init int isotp_module_init(void) ...@@ -1451,6 +1483,8 @@ static __init int isotp_module_init(void)
err = can_proto_register(&isotp_can_proto); err = can_proto_register(&isotp_can_proto);
if (err < 0) if (err < 0)
pr_err("can: registration of isotp protocol failed\n"); pr_err("can: registration of isotp protocol failed\n");
else
register_netdevice_notifier(&canisotp_notifier);
return err; return err;
} }
...@@ -1458,6 +1492,7 @@ static __init int isotp_module_init(void) ...@@ -1458,6 +1492,7 @@ static __init int isotp_module_init(void)
static __exit void isotp_module_exit(void) static __exit void isotp_module_exit(void)
{ {
can_proto_unregister(&isotp_can_proto); can_proto_unregister(&isotp_can_proto);
unregister_netdevice_notifier(&canisotp_notifier);
} }
module_init(isotp_module_init); module_init(isotp_module_init);
......
...@@ -330,6 +330,9 @@ static void j1939_session_skb_drop_old(struct j1939_session *session) ...@@ -330,6 +330,9 @@ static void j1939_session_skb_drop_old(struct j1939_session *session)
if ((do_skcb->offset + do_skb->len) < offset_start) { if ((do_skcb->offset + do_skb->len) < offset_start) {
__skb_unlink(do_skb, &session->skb_queue); __skb_unlink(do_skb, &session->skb_queue);
/* drop ref taken in j1939_session_skb_queue() */
skb_unref(do_skb);
kfree_skb(do_skb); kfree_skb(do_skb);
} }
spin_unlock_irqrestore(&session->skb_queue.lock, flags); spin_unlock_irqrestore(&session->skb_queue.lock, flags);
...@@ -349,12 +352,13 @@ void j1939_session_skb_queue(struct j1939_session *session, ...@@ -349,12 +352,13 @@ void j1939_session_skb_queue(struct j1939_session *session,
skcb->flags |= J1939_ECU_LOCAL_SRC; skcb->flags |= J1939_ECU_LOCAL_SRC;
skb_get(skb);
skb_queue_tail(&session->skb_queue, skb); skb_queue_tail(&session->skb_queue, skb);
} }
static struct static struct
sk_buff *j1939_session_skb_find_by_offset(struct j1939_session *session, sk_buff *j1939_session_skb_get_by_offset(struct j1939_session *session,
unsigned int offset_start) unsigned int offset_start)
{ {
struct j1939_priv *priv = session->priv; struct j1939_priv *priv = session->priv;
struct j1939_sk_buff_cb *do_skcb; struct j1939_sk_buff_cb *do_skcb;
...@@ -371,6 +375,10 @@ sk_buff *j1939_session_skb_find_by_offset(struct j1939_session *session, ...@@ -371,6 +375,10 @@ sk_buff *j1939_session_skb_find_by_offset(struct j1939_session *session,
skb = do_skb; skb = do_skb;
} }
} }
if (skb)
skb_get(skb);
spin_unlock_irqrestore(&session->skb_queue.lock, flags); spin_unlock_irqrestore(&session->skb_queue.lock, flags);
if (!skb) if (!skb)
...@@ -381,12 +389,12 @@ sk_buff *j1939_session_skb_find_by_offset(struct j1939_session *session, ...@@ -381,12 +389,12 @@ sk_buff *j1939_session_skb_find_by_offset(struct j1939_session *session,
return skb; return skb;
} }
static struct sk_buff *j1939_session_skb_find(struct j1939_session *session) static struct sk_buff *j1939_session_skb_get(struct j1939_session *session)
{ {
unsigned int offset_start; unsigned int offset_start;
offset_start = session->pkt.dpo * 7; offset_start = session->pkt.dpo * 7;
return j1939_session_skb_find_by_offset(session, offset_start); return j1939_session_skb_get_by_offset(session, offset_start);
} }
/* see if we are receiver /* see if we are receiver
...@@ -776,7 +784,7 @@ static int j1939_session_tx_dat(struct j1939_session *session) ...@@ -776,7 +784,7 @@ static int j1939_session_tx_dat(struct j1939_session *session)
int ret = 0; int ret = 0;
u8 dat[8]; u8 dat[8];
se_skb = j1939_session_skb_find_by_offset(session, session->pkt.tx * 7); se_skb = j1939_session_skb_get_by_offset(session, session->pkt.tx * 7);
if (!se_skb) if (!se_skb)
return -ENOBUFS; return -ENOBUFS;
...@@ -801,7 +809,8 @@ static int j1939_session_tx_dat(struct j1939_session *session) ...@@ -801,7 +809,8 @@ static int j1939_session_tx_dat(struct j1939_session *session)
netdev_err_once(priv->ndev, netdev_err_once(priv->ndev,
"%s: 0x%p: requested data outside of queued buffer: offset %i, len %i, pkt.tx: %i\n", "%s: 0x%p: requested data outside of queued buffer: offset %i, len %i, pkt.tx: %i\n",
__func__, session, skcb->offset, se_skb->len , session->pkt.tx); __func__, session, skcb->offset, se_skb->len , session->pkt.tx);
return -EOVERFLOW; ret = -EOVERFLOW;
goto out_free;
} }
if (!len) { if (!len) {
...@@ -835,6 +844,12 @@ static int j1939_session_tx_dat(struct j1939_session *session) ...@@ -835,6 +844,12 @@ static int j1939_session_tx_dat(struct j1939_session *session)
if (pkt_done) if (pkt_done)
j1939_tp_set_rxtimeout(session, 250); j1939_tp_set_rxtimeout(session, 250);
out_free:
if (ret)
kfree_skb(se_skb);
else
consume_skb(se_skb);
return ret; return ret;
} }
...@@ -1007,7 +1022,7 @@ static int j1939_xtp_txnext_receiver(struct j1939_session *session) ...@@ -1007,7 +1022,7 @@ static int j1939_xtp_txnext_receiver(struct j1939_session *session)
static int j1939_simple_txnext(struct j1939_session *session) static int j1939_simple_txnext(struct j1939_session *session)
{ {
struct j1939_priv *priv = session->priv; struct j1939_priv *priv = session->priv;
struct sk_buff *se_skb = j1939_session_skb_find(session); struct sk_buff *se_skb = j1939_session_skb_get(session);
struct sk_buff *skb; struct sk_buff *skb;
int ret; int ret;
...@@ -1015,8 +1030,10 @@ static int j1939_simple_txnext(struct j1939_session *session) ...@@ -1015,8 +1030,10 @@ static int j1939_simple_txnext(struct j1939_session *session)
return 0; return 0;
skb = skb_clone(se_skb, GFP_ATOMIC); skb = skb_clone(se_skb, GFP_ATOMIC);
if (!skb) if (!skb) {
return -ENOMEM; ret = -ENOMEM;
goto out_free;
}
can_skb_set_owner(skb, se_skb->sk); can_skb_set_owner(skb, se_skb->sk);
...@@ -1024,12 +1041,18 @@ static int j1939_simple_txnext(struct j1939_session *session) ...@@ -1024,12 +1041,18 @@ static int j1939_simple_txnext(struct j1939_session *session)
ret = j1939_send_one(priv, skb); ret = j1939_send_one(priv, skb);
if (ret) if (ret)
return ret; goto out_free;
j1939_sk_errqueue(session, J1939_ERRQUEUE_SCHED); j1939_sk_errqueue(session, J1939_ERRQUEUE_SCHED);
j1939_sk_queue_activate_next(session); j1939_sk_queue_activate_next(session);
return 0; out_free:
if (ret)
kfree_skb(se_skb);
else
consume_skb(se_skb);
return ret;
} }
static bool j1939_session_deactivate_locked(struct j1939_session *session) static bool j1939_session_deactivate_locked(struct j1939_session *session)
...@@ -1170,9 +1193,10 @@ static void j1939_session_completed(struct j1939_session *session) ...@@ -1170,9 +1193,10 @@ static void j1939_session_completed(struct j1939_session *session)
struct sk_buff *skb; struct sk_buff *skb;
if (!session->transmission) { if (!session->transmission) {
skb = j1939_session_skb_find(session); skb = j1939_session_skb_get(session);
/* distribute among j1939 receivers */ /* distribute among j1939 receivers */
j1939_sk_recv(session->priv, skb); j1939_sk_recv(session->priv, skb);
consume_skb(skb);
} }
j1939_session_deactivate_activate_next(session); j1939_session_deactivate_activate_next(session);
...@@ -1744,7 +1768,7 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session, ...@@ -1744,7 +1768,7 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
{ {
struct j1939_priv *priv = session->priv; struct j1939_priv *priv = session->priv;
struct j1939_sk_buff_cb *skcb; struct j1939_sk_buff_cb *skcb;
struct sk_buff *se_skb; struct sk_buff *se_skb = NULL;
const u8 *dat; const u8 *dat;
u8 *tpdat; u8 *tpdat;
int offset; int offset;
...@@ -1786,7 +1810,7 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session, ...@@ -1786,7 +1810,7 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
goto out_session_cancel; goto out_session_cancel;
} }
se_skb = j1939_session_skb_find_by_offset(session, packet * 7); se_skb = j1939_session_skb_get_by_offset(session, packet * 7);
if (!se_skb) { if (!se_skb) {
netdev_warn(priv->ndev, "%s: 0x%p: no skb found\n", __func__, netdev_warn(priv->ndev, "%s: 0x%p: no skb found\n", __func__,
session); session);
...@@ -1848,11 +1872,13 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session, ...@@ -1848,11 +1872,13 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
j1939_tp_set_rxtimeout(session, 250); j1939_tp_set_rxtimeout(session, 250);
} }
session->last_cmd = 0xff; session->last_cmd = 0xff;
consume_skb(se_skb);
j1939_session_put(session); j1939_session_put(session);
return; return;
out_session_cancel: out_session_cancel:
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, J1939_XTP_ABORT_FAULT);
j1939_session_put(session); j1939_session_put(session);
......
...@@ -83,7 +83,7 @@ struct raw_sock { ...@@ -83,7 +83,7 @@ struct raw_sock {
struct sock sk; struct sock sk;
int bound; int bound;
int ifindex; int ifindex;
struct notifier_block notifier; struct list_head notifier;
int loopback; int loopback;
int recv_own_msgs; int recv_own_msgs;
int fd_frames; int fd_frames;
...@@ -95,6 +95,10 @@ struct raw_sock { ...@@ -95,6 +95,10 @@ struct raw_sock {
struct uniqframe __percpu *uniq; struct uniqframe __percpu *uniq;
}; };
static LIST_HEAD(raw_notifier_list);
static DEFINE_SPINLOCK(raw_notifier_lock);
static struct raw_sock *raw_busy_notifier;
/* Return pointer to store the extra msg flags for raw_recvmsg(). /* Return pointer to store the extra msg flags for raw_recvmsg().
* We use the space of one unsigned int beyond the 'struct sockaddr_can' * We use the space of one unsigned int beyond the 'struct sockaddr_can'
* in skb->cb. * in skb->cb.
...@@ -263,21 +267,16 @@ static int raw_enable_allfilters(struct net *net, struct net_device *dev, ...@@ -263,21 +267,16 @@ static int raw_enable_allfilters(struct net *net, struct net_device *dev,
return err; return err;
} }
static int raw_notifier(struct notifier_block *nb, static void raw_notify(struct raw_sock *ro, unsigned long msg,
unsigned long msg, void *ptr) struct net_device *dev)
{ {
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct raw_sock *ro = container_of(nb, struct raw_sock, notifier);
struct sock *sk = &ro->sk; struct sock *sk = &ro->sk;
if (!net_eq(dev_net(dev), sock_net(sk))) if (!net_eq(dev_net(dev), sock_net(sk)))
return NOTIFY_DONE; return;
if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
if (ro->ifindex != dev->ifindex) if (ro->ifindex != dev->ifindex)
return NOTIFY_DONE; return;
switch (msg) { switch (msg) {
case NETDEV_UNREGISTER: case NETDEV_UNREGISTER:
...@@ -305,7 +304,28 @@ static int raw_notifier(struct notifier_block *nb, ...@@ -305,7 +304,28 @@ static int raw_notifier(struct notifier_block *nb,
sk->sk_error_report(sk); sk->sk_error_report(sk);
break; break;
} }
}
static int raw_notifier(struct notifier_block *nb, unsigned long msg,
void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
return NOTIFY_DONE;
if (unlikely(raw_busy_notifier)) /* Check for reentrant bug. */
return NOTIFY_DONE;
spin_lock(&raw_notifier_lock);
list_for_each_entry(raw_busy_notifier, &raw_notifier_list, notifier) {
spin_unlock(&raw_notifier_lock);
raw_notify(raw_busy_notifier, msg, dev);
spin_lock(&raw_notifier_lock);
}
raw_busy_notifier = NULL;
spin_unlock(&raw_notifier_lock);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -334,9 +354,9 @@ static int raw_init(struct sock *sk) ...@@ -334,9 +354,9 @@ static int raw_init(struct sock *sk)
return -ENOMEM; return -ENOMEM;
/* set notifier */ /* set notifier */
ro->notifier.notifier_call = raw_notifier; spin_lock(&raw_notifier_lock);
list_add_tail(&ro->notifier, &raw_notifier_list);
register_netdevice_notifier(&ro->notifier); spin_unlock(&raw_notifier_lock);
return 0; return 0;
} }
...@@ -351,7 +371,14 @@ static int raw_release(struct socket *sock) ...@@ -351,7 +371,14 @@ static int raw_release(struct socket *sock)
ro = raw_sk(sk); ro = raw_sk(sk);
unregister_netdevice_notifier(&ro->notifier); spin_lock(&raw_notifier_lock);
while (raw_busy_notifier == ro) {
spin_unlock(&raw_notifier_lock);
schedule_timeout_uninterruptible(1);
spin_lock(&raw_notifier_lock);
}
list_del(&ro->notifier);
spin_unlock(&raw_notifier_lock);
lock_sock(sk); lock_sock(sk);
...@@ -889,6 +916,10 @@ static const struct can_proto raw_can_proto = { ...@@ -889,6 +916,10 @@ static const struct can_proto raw_can_proto = {
.prot = &raw_proto, .prot = &raw_proto,
}; };
static struct notifier_block canraw_notifier = {
.notifier_call = raw_notifier
};
static __init int raw_module_init(void) static __init int raw_module_init(void)
{ {
int err; int err;
...@@ -898,6 +929,8 @@ static __init int raw_module_init(void) ...@@ -898,6 +929,8 @@ static __init int raw_module_init(void)
err = can_proto_register(&raw_can_proto); err = can_proto_register(&raw_can_proto);
if (err < 0) if (err < 0)
pr_err("can: registration of raw protocol failed\n"); pr_err("can: registration of raw protocol failed\n");
else
register_netdevice_notifier(&canraw_notifier);
return err; return err;
} }
...@@ -905,6 +938,7 @@ static __init int raw_module_init(void) ...@@ -905,6 +938,7 @@ static __init int raw_module_init(void)
static __exit void raw_module_exit(void) static __exit void raw_module_exit(void)
{ {
can_proto_unregister(&raw_can_proto); can_proto_unregister(&raw_can_proto);
unregister_netdevice_notifier(&canraw_notifier);
} }
module_init(raw_module_init); module_init(raw_module_init);
......
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