diff options
| author | Oliver Hartkopp <socketcan@hartkopp.net> | 2012-06-13 14:41:31 -0400 |
|---|---|---|
| committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2012-06-19 15:40:08 -0400 |
| commit | e2d265d3b587f5f6f8febc0222aace93302ff0be (patch) | |
| tree | 36530611615f19f3591955de0517aaac7d1a1766 | |
| parent | 8b01939f358d680cea971151375268cfdb6b9635 (diff) | |
canfd: add support for CAN FD in CAN_RAW sockets
- introduce a new sockopt CAN_RAW_FD_FRAMES to allow CAN FD frames
- handle CAN frames and CAN FD frames simultaneously when enabled
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
| -rw-r--r-- | include/linux/can/raw.h | 3 | ||||
| -rw-r--r-- | net/can/raw.c | 50 |
2 files changed, 48 insertions, 5 deletions
diff --git a/include/linux/can/raw.h b/include/linux/can/raw.h index 781f3a3701be..a814062b0719 100644 --- a/include/linux/can/raw.h +++ b/include/linux/can/raw.h | |||
| @@ -23,7 +23,8 @@ enum { | |||
| 23 | CAN_RAW_FILTER = 1, /* set 0 .. n can_filter(s) */ | 23 | CAN_RAW_FILTER = 1, /* set 0 .. n can_filter(s) */ |
| 24 | CAN_RAW_ERR_FILTER, /* set filter for error frames */ | 24 | CAN_RAW_ERR_FILTER, /* set filter for error frames */ |
| 25 | CAN_RAW_LOOPBACK, /* local loopback (default:on) */ | 25 | CAN_RAW_LOOPBACK, /* local loopback (default:on) */ |
| 26 | CAN_RAW_RECV_OWN_MSGS /* receive my own msgs (default:off) */ | 26 | CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */ |
| 27 | CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ | ||
| 27 | }; | 28 | }; |
| 28 | 29 | ||
| 29 | #endif | 30 | #endif |
diff --git a/net/can/raw.c b/net/can/raw.c index 46cca3a91d19..3e9c89356a93 100644 --- a/net/can/raw.c +++ b/net/can/raw.c | |||
| @@ -82,6 +82,7 @@ struct raw_sock { | |||
| 82 | struct notifier_block notifier; | 82 | struct notifier_block notifier; |
| 83 | int loopback; | 83 | int loopback; |
| 84 | int recv_own_msgs; | 84 | int recv_own_msgs; |
| 85 | int fd_frames; | ||
| 85 | int count; /* number of active filters */ | 86 | int count; /* number of active filters */ |
| 86 | struct can_filter dfilter; /* default/single filter */ | 87 | struct can_filter dfilter; /* default/single filter */ |
| 87 | struct can_filter *filter; /* pointer to filter(s) */ | 88 | struct can_filter *filter; /* pointer to filter(s) */ |
| @@ -119,6 +120,14 @@ static void raw_rcv(struct sk_buff *oskb, void *data) | |||
| 119 | if (!ro->recv_own_msgs && oskb->sk == sk) | 120 | if (!ro->recv_own_msgs && oskb->sk == sk) |
| 120 | return; | 121 | return; |
| 121 | 122 | ||
| 123 | /* do not pass frames with DLC > 8 to a legacy socket */ | ||
| 124 | if (!ro->fd_frames) { | ||
| 125 | struct canfd_frame *cfd = (struct canfd_frame *)oskb->data; | ||
| 126 | |||
| 127 | if (unlikely(cfd->len > CAN_MAX_DLEN)) | ||
| 128 | return; | ||
| 129 | } | ||
| 130 | |||
| 122 | /* clone the given skb to be able to enqueue it into the rcv queue */ | 131 | /* clone the given skb to be able to enqueue it into the rcv queue */ |
| 123 | skb = skb_clone(oskb, GFP_ATOMIC); | 132 | skb = skb_clone(oskb, GFP_ATOMIC); |
| 124 | if (!skb) | 133 | if (!skb) |
| @@ -291,6 +300,7 @@ static int raw_init(struct sock *sk) | |||
| 291 | /* set default loopback behaviour */ | 300 | /* set default loopback behaviour */ |
| 292 | ro->loopback = 1; | 301 | ro->loopback = 1; |
| 293 | ro->recv_own_msgs = 0; | 302 | ro->recv_own_msgs = 0; |
| 303 | ro->fd_frames = 0; | ||
| 294 | 304 | ||
| 295 | /* set notifier */ | 305 | /* set notifier */ |
| 296 | ro->notifier.notifier_call = raw_notifier; | 306 | ro->notifier.notifier_call = raw_notifier; |
| @@ -569,6 +579,15 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, | |||
| 569 | 579 | ||
| 570 | break; | 580 | break; |
| 571 | 581 | ||
| 582 | case CAN_RAW_FD_FRAMES: | ||
| 583 | if (optlen != sizeof(ro->fd_frames)) | ||
| 584 | return -EINVAL; | ||
| 585 | |||
| 586 | if (copy_from_user(&ro->fd_frames, optval, optlen)) | ||
| 587 | return -EFAULT; | ||
| 588 | |||
| 589 | break; | ||
| 590 | |||
| 572 | default: | 591 | default: |
| 573 | return -ENOPROTOOPT; | 592 | return -ENOPROTOOPT; |
| 574 | } | 593 | } |
| @@ -627,6 +646,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, | |||
| 627 | val = &ro->recv_own_msgs; | 646 | val = &ro->recv_own_msgs; |
| 628 | break; | 647 | break; |
| 629 | 648 | ||
| 649 | case CAN_RAW_FD_FRAMES: | ||
| 650 | if (len > sizeof(int)) | ||
| 651 | len = sizeof(int); | ||
| 652 | val = &ro->fd_frames; | ||
| 653 | break; | ||
| 654 | |||
| 630 | default: | 655 | default: |
| 631 | return -ENOPROTOOPT; | 656 | return -ENOPROTOOPT; |
| 632 | } | 657 | } |
| @@ -662,8 +687,13 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 662 | } else | 687 | } else |
| 663 | ifindex = ro->ifindex; | 688 | ifindex = ro->ifindex; |
| 664 | 689 | ||
| 665 | if (size != sizeof(struct can_frame)) | 690 | if (ro->fd_frames) { |
| 666 | return -EINVAL; | 691 | if (unlikely(size != CANFD_MTU && size != CAN_MTU)) |
| 692 | return -EINVAL; | ||
| 693 | } else { | ||
| 694 | if (unlikely(size != CAN_MTU)) | ||
| 695 | return -EINVAL; | ||
| 696 | } | ||
| 667 | 697 | ||
| 668 | dev = dev_get_by_index(&init_net, ifindex); | 698 | dev = dev_get_by_index(&init_net, ifindex); |
| 669 | if (!dev) | 699 | if (!dev) |
| @@ -705,7 +735,9 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 705 | struct msghdr *msg, size_t size, int flags) | 735 | struct msghdr *msg, size_t size, int flags) |
| 706 | { | 736 | { |
| 707 | struct sock *sk = sock->sk; | 737 | struct sock *sk = sock->sk; |
| 738 | struct raw_sock *ro = raw_sk(sk); | ||
| 708 | struct sk_buff *skb; | 739 | struct sk_buff *skb; |
| 740 | int rxmtu; | ||
| 709 | int err = 0; | 741 | int err = 0; |
| 710 | int noblock; | 742 | int noblock; |
| 711 | 743 | ||
| @@ -716,10 +748,20 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 716 | if (!skb) | 748 | if (!skb) |
| 717 | return err; | 749 | return err; |
| 718 | 750 | ||
| 719 | if (size < skb->len) | 751 | /* |
| 752 | * when serving a legacy socket the DLC <= 8 is already checked inside | ||
| 753 | * raw_rcv(). Now check if we need to pass a canfd_frame to a legacy | ||
| 754 | * socket and cut the possible CANFD_MTU/CAN_MTU length to CAN_MTU | ||
| 755 | */ | ||
| 756 | if (!ro->fd_frames) | ||
| 757 | rxmtu = CAN_MTU; | ||
| 758 | else | ||
| 759 | rxmtu = skb->len; | ||
| 760 | |||
| 761 | if (size < rxmtu) | ||
| 720 | msg->msg_flags |= MSG_TRUNC; | 762 | msg->msg_flags |= MSG_TRUNC; |
| 721 | else | 763 | else |
| 722 | size = skb->len; | 764 | size = rxmtu; |
| 723 | 765 | ||
| 724 | err = memcpy_toiovec(msg->msg_iov, skb->data, size); | 766 | err = memcpy_toiovec(msg->msg_iov, skb->data, size); |
| 725 | if (err < 0) { | 767 | if (err < 0) { |
