aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Hartkopp <socketcan@hartkopp.net>2012-06-13 14:41:31 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2012-06-19 15:40:08 -0400
commite2d265d3b587f5f6f8febc0222aace93302ff0be (patch)
tree36530611615f19f3591955de0517aaac7d1a1766
parent8b01939f358d680cea971151375268cfdb6b9635 (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.h3
-rw-r--r--net/can/raw.c50
2 files changed, 48 insertions, 5 deletions
diff --git a/include/linux/can/raw.h b/include/linux/can/raw.h
index 781f3a3701b..a814062b071 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 46cca3a91d1..3e9c89356a9 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) {