Back to home page

OSCL-LXR

 
 

    


0001 /* vcan.c - Virtual CAN interface
0002  *
0003  * Copyright (c) 2002-2017 Volkswagen Group Electronic Research
0004  * All rights reserved.
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  * 3. Neither the name of Volkswagen nor the names of its contributors
0015  *    may be used to endorse or promote products derived from this software
0016  *    without specific prior written permission.
0017  *
0018  * Alternatively, provided that this notice is retained in full, this
0019  * software may be distributed under the terms of the GNU General
0020  * Public License ("GPL") version 2, in which case the provisions of the
0021  * GPL apply INSTEAD OF those given above.
0022  *
0023  * The provided data structures and external interfaces from this code
0024  * are not restricted to be used by modules with a GPL compatible license.
0025  *
0026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0027  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0030  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
0037  * DAMAGE.
0038  *
0039  */
0040 
0041 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0042 
0043 #include <linux/ethtool.h>
0044 #include <linux/module.h>
0045 #include <linux/init.h>
0046 #include <linux/netdevice.h>
0047 #include <linux/if_arp.h>
0048 #include <linux/if_ether.h>
0049 #include <linux/can.h>
0050 #include <linux/can/can-ml.h>
0051 #include <linux/can/dev.h>
0052 #include <linux/can/skb.h>
0053 #include <linux/slab.h>
0054 #include <net/rtnetlink.h>
0055 
0056 #define DRV_NAME "vcan"
0057 
0058 MODULE_DESCRIPTION("virtual CAN interface");
0059 MODULE_LICENSE("Dual BSD/GPL");
0060 MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
0061 MODULE_ALIAS_RTNL_LINK(DRV_NAME);
0062 
0063 /* CAN test feature:
0064  * Enable the echo on driver level for testing the CAN core echo modes.
0065  * See Documentation/networking/can.rst for details.
0066  */
0067 
0068 static bool echo; /* echo testing. Default: 0 (Off) */
0069 module_param(echo, bool, 0444);
0070 MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
0071 
0072 static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
0073 {
0074     struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
0075     struct net_device_stats *stats = &dev->stats;
0076 
0077     stats->rx_packets++;
0078     stats->rx_bytes += cfd->len;
0079 
0080     skb->pkt_type  = PACKET_BROADCAST;
0081     skb->dev       = dev;
0082     skb->ip_summed = CHECKSUM_UNNECESSARY;
0083 
0084     netif_rx(skb);
0085 }
0086 
0087 static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
0088 {
0089     struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
0090     struct net_device_stats *stats = &dev->stats;
0091     int loop, len;
0092 
0093     if (can_dropped_invalid_skb(dev, skb))
0094         return NETDEV_TX_OK;
0095 
0096     len = cfd->can_id & CAN_RTR_FLAG ? 0 : cfd->len;
0097     stats->tx_packets++;
0098     stats->tx_bytes += len;
0099 
0100     /* set flag whether this packet has to be looped back */
0101     loop = skb->pkt_type == PACKET_LOOPBACK;
0102 
0103     skb_tx_timestamp(skb);
0104 
0105     if (!echo) {
0106         /* no echo handling available inside this driver */
0107         if (loop) {
0108             /* only count the packets here, because the
0109              * CAN core already did the echo for us
0110              */
0111             stats->rx_packets++;
0112             stats->rx_bytes += len;
0113         }
0114         consume_skb(skb);
0115         return NETDEV_TX_OK;
0116     }
0117 
0118     /* perform standard echo handling for CAN network interfaces */
0119 
0120     if (loop) {
0121         skb = can_create_echo_skb(skb);
0122         if (!skb)
0123             return NETDEV_TX_OK;
0124 
0125         /* receive with packet counting */
0126         vcan_rx(skb, dev);
0127     } else {
0128         /* no looped packets => no counting */
0129         consume_skb(skb);
0130     }
0131     return NETDEV_TX_OK;
0132 }
0133 
0134 static int vcan_change_mtu(struct net_device *dev, int new_mtu)
0135 {
0136     /* Do not allow changing the MTU while running */
0137     if (dev->flags & IFF_UP)
0138         return -EBUSY;
0139 
0140     if (new_mtu != CAN_MTU && new_mtu != CANFD_MTU)
0141         return -EINVAL;
0142 
0143     dev->mtu = new_mtu;
0144     return 0;
0145 }
0146 
0147 static const struct net_device_ops vcan_netdev_ops = {
0148     .ndo_start_xmit = vcan_tx,
0149     .ndo_change_mtu = vcan_change_mtu,
0150 };
0151 
0152 static const struct ethtool_ops vcan_ethtool_ops = {
0153     .get_ts_info = ethtool_op_get_ts_info,
0154 };
0155 
0156 static void vcan_setup(struct net_device *dev)
0157 {
0158     dev->type       = ARPHRD_CAN;
0159     dev->mtu        = CANFD_MTU;
0160     dev->hard_header_len    = 0;
0161     dev->addr_len       = 0;
0162     dev->tx_queue_len   = 0;
0163     dev->flags      = IFF_NOARP;
0164     can_set_ml_priv(dev, netdev_priv(dev));
0165 
0166     /* set flags according to driver capabilities */
0167     if (echo)
0168         dev->flags |= IFF_ECHO;
0169 
0170     dev->netdev_ops     = &vcan_netdev_ops;
0171     dev->ethtool_ops    = &vcan_ethtool_ops;
0172     dev->needs_free_netdev  = true;
0173 }
0174 
0175 static struct rtnl_link_ops vcan_link_ops __read_mostly = {
0176     .kind = DRV_NAME,
0177     .priv_size = sizeof(struct can_ml_priv),
0178     .setup = vcan_setup,
0179 };
0180 
0181 static __init int vcan_init_module(void)
0182 {
0183     pr_info("Virtual CAN interface driver\n");
0184 
0185     if (echo)
0186         pr_info("enabled echo on driver level.\n");
0187 
0188     return rtnl_link_register(&vcan_link_ops);
0189 }
0190 
0191 static __exit void vcan_cleanup_module(void)
0192 {
0193     rtnl_link_unregister(&vcan_link_ops);
0194 }
0195 
0196 module_init(vcan_init_module);
0197 module_exit(vcan_cleanup_module);