.. | .. |
---|
| 1 | +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) |
---|
1 | 2 | /* |
---|
2 | 3 | * bcm.c - Broadcast Manager to filter/send (cyclic) CAN content |
---|
3 | 4 | * |
---|
.. | .. |
---|
80 | 81 | (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG) : \ |
---|
81 | 82 | (CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG)) |
---|
82 | 83 | |
---|
83 | | -#define CAN_BCM_VERSION "20170425" |
---|
84 | | - |
---|
85 | 84 | MODULE_DESCRIPTION("PF_CAN broadcast manager protocol"); |
---|
86 | 85 | MODULE_LICENSE("Dual BSD/GPL"); |
---|
87 | 86 | MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>"); |
---|
88 | 87 | MODULE_ALIAS("can-proto-2"); |
---|
| 88 | + |
---|
| 89 | +#define BCM_MIN_NAMELEN CAN_REQUIRED_SIZE(struct sockaddr_can, can_ifindex) |
---|
89 | 90 | |
---|
90 | 91 | /* |
---|
91 | 92 | * easy access to the first 64 bit of can(fd)_frame payload. cp->data is |
---|
.. | .. |
---|
99 | 100 | |
---|
100 | 101 | struct bcm_op { |
---|
101 | 102 | struct list_head list; |
---|
| 103 | + struct rcu_head rcu; |
---|
102 | 104 | int ifindex; |
---|
103 | 105 | canid_t can_id; |
---|
104 | 106 | u32 flags; |
---|
.. | .. |
---|
272 | 274 | struct sk_buff *skb; |
---|
273 | 275 | struct net_device *dev; |
---|
274 | 276 | struct canfd_frame *cf = op->frames + op->cfsiz * op->currframe; |
---|
| 277 | + int err; |
---|
275 | 278 | |
---|
276 | 279 | /* no target device? => exit */ |
---|
277 | 280 | if (!op->ifindex) |
---|
.. | .. |
---|
296 | 299 | /* send with loopback */ |
---|
297 | 300 | skb->dev = dev; |
---|
298 | 301 | can_skb_set_owner(skb, op->sk); |
---|
299 | | - can_send(skb, 1); |
---|
| 302 | + err = can_send(skb, 1); |
---|
| 303 | + if (!err) |
---|
| 304 | + op->frames_abs++; |
---|
300 | 305 | |
---|
301 | | - /* update statistics */ |
---|
302 | 306 | op->currframe++; |
---|
303 | | - op->frames_abs++; |
---|
304 | 307 | |
---|
305 | 308 | /* reached last frame? */ |
---|
306 | 309 | if (op->currframe >= op->nframes) |
---|
.. | .. |
---|
717 | 720 | return NULL; |
---|
718 | 721 | } |
---|
719 | 722 | |
---|
720 | | -static void bcm_remove_op(struct bcm_op *op) |
---|
| 723 | +static void bcm_free_op_rcu(struct rcu_head *rcu_head) |
---|
721 | 724 | { |
---|
722 | | - hrtimer_cancel(&op->timer); |
---|
723 | | - hrtimer_cancel(&op->thrtimer); |
---|
| 725 | + struct bcm_op *op = container_of(rcu_head, struct bcm_op, rcu); |
---|
724 | 726 | |
---|
725 | 727 | if ((op->frames) && (op->frames != &op->sframe)) |
---|
726 | 728 | kfree(op->frames); |
---|
.. | .. |
---|
729 | 731 | kfree(op->last_frames); |
---|
730 | 732 | |
---|
731 | 733 | kfree(op); |
---|
| 734 | +} |
---|
| 735 | + |
---|
| 736 | +static void bcm_remove_op(struct bcm_op *op) |
---|
| 737 | +{ |
---|
| 738 | + hrtimer_cancel(&op->timer); |
---|
| 739 | + hrtimer_cancel(&op->thrtimer); |
---|
| 740 | + |
---|
| 741 | + call_rcu(&op->rcu, bcm_free_op_rcu); |
---|
732 | 742 | } |
---|
733 | 743 | |
---|
734 | 744 | static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op) |
---|
.. | .. |
---|
755 | 765 | list_for_each_entry_safe(op, n, ops, list) { |
---|
756 | 766 | if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) && |
---|
757 | 767 | (op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) { |
---|
| 768 | + |
---|
| 769 | + /* disable automatic timer on frame reception */ |
---|
| 770 | + op->flags |= RX_NO_AUTOTIMER; |
---|
758 | 771 | |
---|
759 | 772 | /* |
---|
760 | 773 | * Don't care if we're bound or not (due to netdev |
---|
.. | .. |
---|
784 | 797 | bcm_rx_handler, op); |
---|
785 | 798 | |
---|
786 | 799 | list_del(&op->list); |
---|
787 | | - synchronize_rcu(); |
---|
788 | 800 | bcm_remove_op(op); |
---|
789 | 801 | return 1; /* done */ |
---|
790 | 802 | } |
---|
.. | .. |
---|
924 | 936 | |
---|
925 | 937 | cf = op->frames + op->cfsiz * i; |
---|
926 | 938 | err = memcpy_from_msg((u8 *)cf, msg, op->cfsiz); |
---|
| 939 | + if (err < 0) |
---|
| 940 | + goto free_op; |
---|
927 | 941 | |
---|
928 | 942 | if (op->flags & CAN_FD_FRAME) { |
---|
929 | 943 | if (cf->len > 64) |
---|
.. | .. |
---|
933 | 947 | err = -EINVAL; |
---|
934 | 948 | } |
---|
935 | 949 | |
---|
936 | | - if (err < 0) { |
---|
937 | | - if (op->frames != &op->sframe) |
---|
938 | | - kfree(op->frames); |
---|
939 | | - kfree(op); |
---|
940 | | - return err; |
---|
941 | | - } |
---|
| 950 | + if (err < 0) |
---|
| 951 | + goto free_op; |
---|
942 | 952 | |
---|
943 | 953 | if (msg_head->flags & TX_CP_CAN_ID) { |
---|
944 | 954 | /* copy can_id into frame */ |
---|
.. | .. |
---|
1009 | 1019 | bcm_tx_start_timer(op); |
---|
1010 | 1020 | |
---|
1011 | 1021 | return msg_head->nframes * op->cfsiz + MHSIZ; |
---|
| 1022 | + |
---|
| 1023 | +free_op: |
---|
| 1024 | + if (op->frames != &op->sframe) |
---|
| 1025 | + kfree(op->frames); |
---|
| 1026 | + kfree(op); |
---|
| 1027 | + return err; |
---|
1012 | 1028 | } |
---|
1013 | 1029 | |
---|
1014 | 1030 | /* |
---|
.. | .. |
---|
1301 | 1317 | /* no bound device as default => check msg_name */ |
---|
1302 | 1318 | DECLARE_SOCKADDR(struct sockaddr_can *, addr, msg->msg_name); |
---|
1303 | 1319 | |
---|
1304 | | - if (msg->msg_namelen < sizeof(*addr)) |
---|
| 1320 | + if (msg->msg_namelen < BCM_MIN_NAMELEN) |
---|
1305 | 1321 | return -EINVAL; |
---|
1306 | 1322 | |
---|
1307 | 1323 | if (addr->can_family != AF_CAN) |
---|
.. | .. |
---|
1505 | 1521 | |
---|
1506 | 1522 | lock_sock(sk); |
---|
1507 | 1523 | |
---|
| 1524 | +#if IS_ENABLED(CONFIG_PROC_FS) |
---|
| 1525 | + /* remove procfs entry */ |
---|
| 1526 | + if (net->can.bcmproc_dir && bo->bcm_proc_read) |
---|
| 1527 | + remove_proc_entry(bo->procname, net->can.bcmproc_dir); |
---|
| 1528 | +#endif /* CONFIG_PROC_FS */ |
---|
| 1529 | + |
---|
1508 | 1530 | list_for_each_entry_safe(op, next, &bo->tx_ops, list) |
---|
1509 | 1531 | bcm_remove_op(op); |
---|
1510 | 1532 | |
---|
.. | .. |
---|
1540 | 1562 | list_for_each_entry_safe(op, next, &bo->rx_ops, list) |
---|
1541 | 1563 | bcm_remove_op(op); |
---|
1542 | 1564 | |
---|
1543 | | -#if IS_ENABLED(CONFIG_PROC_FS) |
---|
1544 | | - /* remove procfs entry */ |
---|
1545 | | - if (net->can.bcmproc_dir && bo->bcm_proc_read) |
---|
1546 | | - remove_proc_entry(bo->procname, net->can.bcmproc_dir); |
---|
1547 | | -#endif /* CONFIG_PROC_FS */ |
---|
1548 | | - |
---|
1549 | 1565 | /* remove device reference */ |
---|
1550 | 1566 | if (bo->bound) { |
---|
1551 | 1567 | bo->bound = 0; |
---|
.. | .. |
---|
1570 | 1586 | struct net *net = sock_net(sk); |
---|
1571 | 1587 | int ret = 0; |
---|
1572 | 1588 | |
---|
1573 | | - if (len < sizeof(*addr)) |
---|
| 1589 | + if (len < BCM_MIN_NAMELEN) |
---|
1574 | 1590 | return -EINVAL; |
---|
1575 | 1591 | |
---|
1576 | 1592 | lock_sock(sk); |
---|
.. | .. |
---|
1652 | 1668 | sock_recv_ts_and_drops(msg, sk, skb); |
---|
1653 | 1669 | |
---|
1654 | 1670 | if (msg->msg_name) { |
---|
1655 | | - __sockaddr_check_size(sizeof(struct sockaddr_can)); |
---|
1656 | | - msg->msg_namelen = sizeof(struct sockaddr_can); |
---|
| 1671 | + __sockaddr_check_size(BCM_MIN_NAMELEN); |
---|
| 1672 | + msg->msg_namelen = BCM_MIN_NAMELEN; |
---|
1657 | 1673 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); |
---|
1658 | 1674 | } |
---|
1659 | 1675 | |
---|
1660 | 1676 | skb_free_datagram(sk, skb); |
---|
1661 | 1677 | |
---|
1662 | 1678 | return size; |
---|
| 1679 | +} |
---|
| 1680 | + |
---|
| 1681 | +static int bcm_sock_no_ioctlcmd(struct socket *sock, unsigned int cmd, |
---|
| 1682 | + unsigned long arg) |
---|
| 1683 | +{ |
---|
| 1684 | + /* no ioctls for socket layer -> hand it down to NIC layer */ |
---|
| 1685 | + return -ENOIOCTLCMD; |
---|
1663 | 1686 | } |
---|
1664 | 1687 | |
---|
1665 | 1688 | static const struct proto_ops bcm_ops = { |
---|
.. | .. |
---|
1671 | 1694 | .accept = sock_no_accept, |
---|
1672 | 1695 | .getname = sock_no_getname, |
---|
1673 | 1696 | .poll = datagram_poll, |
---|
1674 | | - .ioctl = can_ioctl, /* use can_ioctl() from af_can.c */ |
---|
| 1697 | + .ioctl = bcm_sock_no_ioctlcmd, |
---|
| 1698 | + .gettstamp = sock_gettstamp, |
---|
1675 | 1699 | .listen = sock_no_listen, |
---|
1676 | 1700 | .shutdown = sock_no_shutdown, |
---|
1677 | | - .setsockopt = sock_no_setsockopt, |
---|
1678 | | - .getsockopt = sock_no_getsockopt, |
---|
1679 | 1701 | .sendmsg = bcm_sendmsg, |
---|
1680 | 1702 | .recvmsg = bcm_recvmsg, |
---|
1681 | 1703 | .mmap = sock_no_mmap, |
---|
.. | .. |
---|
1728 | 1750 | { |
---|
1729 | 1751 | int err; |
---|
1730 | 1752 | |
---|
1731 | | - pr_info("can: broadcast manager protocol (rev " CAN_BCM_VERSION " t)\n"); |
---|
| 1753 | + pr_info("can: broadcast manager protocol\n"); |
---|
1732 | 1754 | |
---|
1733 | 1755 | err = can_proto_register(&bcm_can_proto); |
---|
1734 | 1756 | if (err < 0) { |
---|