aboutsummaryrefslogtreecommitdiffstats
path: root/net/can/af_can.c
diff options
context:
space:
mode:
authorOliver Hartkopp <socketcan@hartkopp.net>2012-06-13 14:33:02 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2012-06-19 15:40:01 -0400
commit8b01939f358d680cea971151375268cfdb6b9635 (patch)
tree96045ac486821ae2c94c075d5676649f48ed5e5d /net/can/af_can.c
parent7c9416365c60f150ef8961a2855fafbc7394ad6b (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.c109
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 */
226int can_send(struct sk_buff *skb, int loop) 227int 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
321inval_skb:
322 kfree_skb(skb);
323 return err;
304} 324}
305EXPORT_SYMBOL(can_send); 325EXPORT_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
636static int can_rcv(struct sk_buff *skb, struct net_device *dev, 656static 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
686static 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
705drop:
706 kfree_skb(skb);
707 return NET_RX_DROP;
708}
709
710static 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
680drop: 729drop:
@@ -808,10 +857,14 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
808 857
809static struct packet_type can_packet __read_mostly = { 858static 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
863static struct packet_type canfd_packet __read_mostly = {
864 .type = cpu_to_be16(ETH_P_CANFD),
865 .func = canfd_rcv,
866};
867
815static const struct net_proto_family can_family_ops = { 868static 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);