diff options
author | Oliver Hartkopp <socketcan@hartkopp.net> | 2012-06-13 14:33:02 -0400 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2012-06-19 15:40:01 -0400 |
commit | 8b01939f358d680cea971151375268cfdb6b9635 (patch) | |
tree | 96045ac486821ae2c94c075d5676649f48ed5e5d /net/can/af_can.c | |
parent | 7c9416365c60f150ef8961a2855fafbc7394ad6b (diff) |
canfd: add support for CAN FD in PF_CAN core
- handle ETH_P_CAN and ETH_P_CANFD skbuffs
- update sanity checks for CAN and CAN FD
- make sure the CAN frame can pass the selected CAN netdevice on send
- bump core version and abi version to indicate the new CAN FD support
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'net/can/af_can.c')
-rw-r--r-- | net/can/af_can.c | 109 |
1 files changed, 82 insertions, 27 deletions
diff --git a/net/can/af_can.c b/net/can/af_can.c index c96140a1458e..821022a7214f 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c | |||
@@ -221,30 +221,46 @@ static int can_create(struct net *net, struct socket *sock, int protocol, | |||
221 | * -ENOBUFS on full driver queue (see net_xmit_errno()) | 221 | * -ENOBUFS on full driver queue (see net_xmit_errno()) |
222 | * -ENOMEM when local loopback failed at calling skb_clone() | 222 | * -ENOMEM when local loopback failed at calling skb_clone() |
223 | * -EPERM when trying to send on a non-CAN interface | 223 | * -EPERM when trying to send on a non-CAN interface |
224 | * -EMSGSIZE CAN frame size is bigger than CAN interface MTU | ||
224 | * -EINVAL when the skb->data does not contain a valid CAN frame | 225 | * -EINVAL when the skb->data does not contain a valid CAN frame |
225 | */ | 226 | */ |
226 | int can_send(struct sk_buff *skb, int loop) | 227 | int can_send(struct sk_buff *skb, int loop) |
227 | { | 228 | { |
228 | struct sk_buff *newskb = NULL; | 229 | struct sk_buff *newskb = NULL; |
229 | struct can_frame *cf = (struct can_frame *)skb->data; | 230 | struct canfd_frame *cfd = (struct canfd_frame *)skb->data; |
230 | int err; | 231 | int err = -EINVAL; |
232 | |||
233 | if (skb->len == CAN_MTU) { | ||
234 | skb->protocol = htons(ETH_P_CAN); | ||
235 | if (unlikely(cfd->len > CAN_MAX_DLEN)) | ||
236 | goto inval_skb; | ||
237 | } else if (skb->len == CANFD_MTU) { | ||
238 | skb->protocol = htons(ETH_P_CANFD); | ||
239 | if (unlikely(cfd->len > CANFD_MAX_DLEN)) | ||
240 | goto inval_skb; | ||
241 | } else | ||
242 | goto inval_skb; | ||
231 | 243 | ||
232 | if (skb->len != sizeof(struct can_frame) || cf->can_dlc > 8) { | 244 | /* |
233 | kfree_skb(skb); | 245 | * Make sure the CAN frame can pass the selected CAN netdevice. |
234 | return -EINVAL; | 246 | * As structs can_frame and canfd_frame are similar, we can provide |
247 | * CAN FD frames to legacy CAN drivers as long as the length is <= 8 | ||
248 | */ | ||
249 | if (unlikely(skb->len > skb->dev->mtu && cfd->len > CAN_MAX_DLEN)) { | ||
250 | err = -EMSGSIZE; | ||
251 | goto inval_skb; | ||
235 | } | 252 | } |
236 | 253 | ||
237 | if (skb->dev->type != ARPHRD_CAN) { | 254 | if (unlikely(skb->dev->type != ARPHRD_CAN)) { |
238 | kfree_skb(skb); | 255 | err = -EPERM; |
239 | return -EPERM; | 256 | goto inval_skb; |
240 | } | 257 | } |
241 | 258 | ||
242 | if (!(skb->dev->flags & IFF_UP)) { | 259 | if (unlikely(!(skb->dev->flags & IFF_UP))) { |
243 | kfree_skb(skb); | 260 | err = -ENETDOWN; |
244 | return -ENETDOWN; | 261 | goto inval_skb; |
245 | } | 262 | } |
246 | 263 | ||
247 | skb->protocol = htons(ETH_P_CAN); | ||
248 | skb_reset_network_header(skb); | 264 | skb_reset_network_header(skb); |
249 | skb_reset_transport_header(skb); | 265 | skb_reset_transport_header(skb); |
250 | 266 | ||
@@ -301,6 +317,10 @@ int can_send(struct sk_buff *skb, int loop) | |||
301 | can_stats.tx_frames_delta++; | 317 | can_stats.tx_frames_delta++; |
302 | 318 | ||
303 | return 0; | 319 | return 0; |
320 | |||
321 | inval_skb: | ||
322 | kfree_skb(skb); | ||
323 | return err; | ||
304 | } | 324 | } |
305 | EXPORT_SYMBOL(can_send); | 325 | EXPORT_SYMBOL(can_send); |
306 | 326 | ||
@@ -633,24 +653,11 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb) | |||
633 | return matches; | 653 | return matches; |
634 | } | 654 | } |
635 | 655 | ||
636 | static int can_rcv(struct sk_buff *skb, struct net_device *dev, | 656 | static void can_receive(struct sk_buff *skb, struct net_device *dev) |
637 | struct packet_type *pt, struct net_device *orig_dev) | ||
638 | { | 657 | { |
639 | struct dev_rcv_lists *d; | 658 | struct dev_rcv_lists *d; |
640 | struct can_frame *cf = (struct can_frame *)skb->data; | ||
641 | int matches; | 659 | int matches; |
642 | 660 | ||
643 | if (!net_eq(dev_net(dev), &init_net)) | ||
644 | goto drop; | ||
645 | |||
646 | if (WARN_ONCE(dev->type != ARPHRD_CAN || | ||
647 | skb->len != sizeof(struct can_frame) || | ||
648 | cf->can_dlc > 8, | ||
649 | "PF_CAN: dropped non conform skbuf: " | ||
650 | "dev type %d, len %d, can_dlc %d\n", | ||
651 | dev->type, skb->len, cf->can_dlc)) | ||
652 | goto drop; | ||
653 | |||
654 | /* update statistics */ | 661 | /* update statistics */ |
655 | can_stats.rx_frames++; | 662 | can_stats.rx_frames++; |
656 | can_stats.rx_frames_delta++; | 663 | can_stats.rx_frames_delta++; |
@@ -674,7 +681,49 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, | |||
674 | can_stats.matches++; | 681 | can_stats.matches++; |
675 | can_stats.matches_delta++; | 682 | can_stats.matches_delta++; |
676 | } | 683 | } |
684 | } | ||
685 | |||
686 | static int can_rcv(struct sk_buff *skb, struct net_device *dev, | ||
687 | struct packet_type *pt, struct net_device *orig_dev) | ||
688 | { | ||
689 | struct canfd_frame *cfd = (struct canfd_frame *)skb->data; | ||
677 | 690 | ||
691 | if (unlikely(!net_eq(dev_net(dev), &init_net))) | ||
692 | goto drop; | ||
693 | |||
694 | if (WARN_ONCE(dev->type != ARPHRD_CAN || | ||
695 | skb->len != CAN_MTU || | ||
696 | cfd->len > CAN_MAX_DLEN, | ||
697 | "PF_CAN: dropped non conform CAN skbuf: " | ||
698 | "dev type %d, len %d, datalen %d\n", | ||
699 | dev->type, skb->len, cfd->len)) | ||
700 | goto drop; | ||
701 | |||
702 | can_receive(skb, dev); | ||
703 | return NET_RX_SUCCESS; | ||
704 | |||
705 | drop: | ||
706 | kfree_skb(skb); | ||
707 | return NET_RX_DROP; | ||
708 | } | ||
709 | |||
710 | static int canfd_rcv(struct sk_buff *skb, struct net_device *dev, | ||
711 | struct packet_type *pt, struct net_device *orig_dev) | ||
712 | { | ||
713 | struct canfd_frame *cfd = (struct canfd_frame *)skb->data; | ||
714 | |||
715 | if (unlikely(!net_eq(dev_net(dev), &init_net))) | ||
716 | goto drop; | ||
717 | |||
718 | if (WARN_ONCE(dev->type != ARPHRD_CAN || | ||
719 | skb->len != CANFD_MTU || | ||
720 | cfd->len > CANFD_MAX_DLEN, | ||
721 | "PF_CAN: dropped non conform CAN FD skbuf: " | ||
722 | "dev type %d, len %d, datalen %d\n", | ||
723 | dev->type, skb->len, cfd->len)) | ||
724 | goto drop; | ||
725 | |||
726 | can_receive(skb, dev); | ||
678 | return NET_RX_SUCCESS; | 727 | return NET_RX_SUCCESS; |
679 | 728 | ||
680 | drop: | 729 | drop: |
@@ -808,10 +857,14 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg, | |||
808 | 857 | ||
809 | static struct packet_type can_packet __read_mostly = { | 858 | static struct packet_type can_packet __read_mostly = { |
810 | .type = cpu_to_be16(ETH_P_CAN), | 859 | .type = cpu_to_be16(ETH_P_CAN), |
811 | .dev = NULL, | ||
812 | .func = can_rcv, | 860 | .func = can_rcv, |
813 | }; | 861 | }; |
814 | 862 | ||
863 | static struct packet_type canfd_packet __read_mostly = { | ||
864 | .type = cpu_to_be16(ETH_P_CANFD), | ||
865 | .func = canfd_rcv, | ||
866 | }; | ||
867 | |||
815 | static const struct net_proto_family can_family_ops = { | 868 | static const struct net_proto_family can_family_ops = { |
816 | .family = PF_CAN, | 869 | .family = PF_CAN, |
817 | .create = can_create, | 870 | .create = can_create, |
@@ -853,6 +906,7 @@ static __init int can_init(void) | |||
853 | sock_register(&can_family_ops); | 906 | sock_register(&can_family_ops); |
854 | register_netdevice_notifier(&can_netdev_notifier); | 907 | register_netdevice_notifier(&can_netdev_notifier); |
855 | dev_add_pack(&can_packet); | 908 | dev_add_pack(&can_packet); |
909 | dev_add_pack(&canfd_packet); | ||
856 | 910 | ||
857 | return 0; | 911 | return 0; |
858 | } | 912 | } |
@@ -867,6 +921,7 @@ static __exit void can_exit(void) | |||
867 | can_remove_proc(); | 921 | can_remove_proc(); |
868 | 922 | ||
869 | /* protocol unregister */ | 923 | /* protocol unregister */ |
924 | dev_remove_pack(&canfd_packet); | ||
870 | dev_remove_pack(&can_packet); | 925 | dev_remove_pack(&can_packet); |
871 | unregister_netdevice_notifier(&can_netdev_notifier); | 926 | unregister_netdevice_notifier(&can_netdev_notifier); |
872 | sock_unregister(PF_CAN); | 927 | sock_unregister(PF_CAN); |