1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44#include <linux/module.h>
45#include <linux/init.h>
46#include <linux/netdevice.h>
47#include <linux/if_arp.h>
48#include <linux/if_ether.h>
49#include <linux/can.h>
50#include <net/rtnetlink.h>
51
52static __initdata const char banner[] =
53 KERN_INFO "vcan: Virtual CAN interface driver\n";
54
55MODULE_DESCRIPTION("virtual CAN interface");
56MODULE_LICENSE("Dual BSD/GPL");
57MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
58
59
60
61
62
63
64
65
66static int echo;
67module_param(echo, bool, S_IRUGO);
68MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
69
70
71static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
72{
73 struct net_device_stats *stats = &dev->stats;
74
75 stats->rx_packets++;
76 stats->rx_bytes += skb->len;
77
78 skb->protocol = htons(ETH_P_CAN);
79 skb->pkt_type = PACKET_BROADCAST;
80 skb->dev = dev;
81 skb->ip_summed = CHECKSUM_UNNECESSARY;
82
83 netif_rx_ni(skb);
84}
85
86static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
87{
88 struct net_device_stats *stats = &dev->stats;
89 int loop;
90
91 stats->tx_packets++;
92 stats->tx_bytes += skb->len;
93
94
95 loop = skb->pkt_type == PACKET_LOOPBACK;
96
97 if (!echo) {
98
99
100 if (loop) {
101
102
103
104
105 stats->rx_packets++;
106 stats->rx_bytes += skb->len;
107 }
108 kfree_skb(skb);
109 return NETDEV_TX_OK;
110 }
111
112
113
114 if (loop) {
115 struct sock *srcsk = skb->sk;
116
117 skb = skb_share_check(skb, GFP_ATOMIC);
118 if (!skb)
119 return NETDEV_TX_OK;
120
121
122 skb->sk = srcsk;
123 vcan_rx(skb, dev);
124 } else {
125
126 kfree_skb(skb);
127 }
128 return NETDEV_TX_OK;
129}
130
131static const struct net_device_ops vcan_netdev_ops = {
132 .ndo_start_xmit = vcan_tx,
133};
134
135static void vcan_setup(struct net_device *dev)
136{
137 dev->type = ARPHRD_CAN;
138 dev->mtu = sizeof(struct can_frame);
139 dev->hard_header_len = 0;
140 dev->addr_len = 0;
141 dev->tx_queue_len = 0;
142 dev->flags = IFF_NOARP;
143
144
145 if (echo)
146 dev->flags |= IFF_ECHO;
147
148 dev->netdev_ops = &vcan_netdev_ops;
149 dev->destructor = free_netdev;
150}
151
152static struct rtnl_link_ops vcan_link_ops __read_mostly = {
153 .kind = "vcan",
154 .setup = vcan_setup,
155};
156
157static __init int vcan_init_module(void)
158{
159 printk(banner);
160
161 if (echo)
162 printk(KERN_INFO "vcan: enabled echo on driver level.\n");
163
164 return rtnl_link_register(&vcan_link_ops);
165}
166
167static __exit void vcan_cleanup_module(void)
168{
169 rtnl_link_unregister(&vcan_link_ops);
170}
171
172module_init(vcan_init_module);
173module_exit(vcan_cleanup_module);
174