| .. | .. |
|---|
| 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 | } |
|---|
| .. | .. |
|---|
| 1301 | 1313 | /* no bound device as default => check msg_name */ |
|---|
| 1302 | 1314 | DECLARE_SOCKADDR(struct sockaddr_can *, addr, msg->msg_name); |
|---|
| 1303 | 1315 | |
|---|
| 1304 | | - if (msg->msg_namelen < sizeof(*addr)) |
|---|
| 1316 | + if (msg->msg_namelen < BCM_MIN_NAMELEN) |
|---|
| 1305 | 1317 | return -EINVAL; |
|---|
| 1306 | 1318 | |
|---|
| 1307 | 1319 | if (addr->can_family != AF_CAN) |
|---|
| .. | .. |
|---|
| 1570 | 1582 | struct net *net = sock_net(sk); |
|---|
| 1571 | 1583 | int ret = 0; |
|---|
| 1572 | 1584 | |
|---|
| 1573 | | - if (len < sizeof(*addr)) |
|---|
| 1585 | + if (len < BCM_MIN_NAMELEN) |
|---|
| 1574 | 1586 | return -EINVAL; |
|---|
| 1575 | 1587 | |
|---|
| 1576 | 1588 | lock_sock(sk); |
|---|
| .. | .. |
|---|
| 1652 | 1664 | sock_recv_ts_and_drops(msg, sk, skb); |
|---|
| 1653 | 1665 | |
|---|
| 1654 | 1666 | if (msg->msg_name) { |
|---|
| 1655 | | - __sockaddr_check_size(sizeof(struct sockaddr_can)); |
|---|
| 1656 | | - msg->msg_namelen = sizeof(struct sockaddr_can); |
|---|
| 1667 | + __sockaddr_check_size(BCM_MIN_NAMELEN); |
|---|
| 1668 | + msg->msg_namelen = BCM_MIN_NAMELEN; |
|---|
| 1657 | 1669 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); |
|---|
| 1658 | 1670 | } |
|---|
| 1659 | 1671 | |
|---|
| 1660 | 1672 | skb_free_datagram(sk, skb); |
|---|
| 1661 | 1673 | |
|---|
| 1662 | 1674 | return size; |
|---|
| 1675 | +} |
|---|
| 1676 | + |
|---|
| 1677 | +static int bcm_sock_no_ioctlcmd(struct socket *sock, unsigned int cmd, |
|---|
| 1678 | + unsigned long arg) |
|---|
| 1679 | +{ |
|---|
| 1680 | + /* no ioctls for socket layer -> hand it down to NIC layer */ |
|---|
| 1681 | + return -ENOIOCTLCMD; |
|---|
| 1663 | 1682 | } |
|---|
| 1664 | 1683 | |
|---|
| 1665 | 1684 | static const struct proto_ops bcm_ops = { |
|---|
| .. | .. |
|---|
| 1671 | 1690 | .accept = sock_no_accept, |
|---|
| 1672 | 1691 | .getname = sock_no_getname, |
|---|
| 1673 | 1692 | .poll = datagram_poll, |
|---|
| 1674 | | - .ioctl = can_ioctl, /* use can_ioctl() from af_can.c */ |
|---|
| 1693 | + .ioctl = bcm_sock_no_ioctlcmd, |
|---|
| 1694 | + .gettstamp = sock_gettstamp, |
|---|
| 1675 | 1695 | .listen = sock_no_listen, |
|---|
| 1676 | 1696 | .shutdown = sock_no_shutdown, |
|---|
| 1677 | | - .setsockopt = sock_no_setsockopt, |
|---|
| 1678 | | - .getsockopt = sock_no_getsockopt, |
|---|
| 1679 | 1697 | .sendmsg = bcm_sendmsg, |
|---|
| 1680 | 1698 | .recvmsg = bcm_recvmsg, |
|---|
| 1681 | 1699 | .mmap = sock_no_mmap, |
|---|
| .. | .. |
|---|
| 1728 | 1746 | { |
|---|
| 1729 | 1747 | int err; |
|---|
| 1730 | 1748 | |
|---|
| 1731 | | - pr_info("can: broadcast manager protocol (rev " CAN_BCM_VERSION " t)\n"); |
|---|
| 1749 | + pr_info("can: broadcast manager protocol\n"); |
|---|
| 1732 | 1750 | |
|---|
| 1733 | 1751 | err = can_proto_register(&bcm_can_proto); |
|---|
| 1734 | 1752 | if (err < 0) { |
|---|