]> rtime.felk.cvut.cz Git - socketcan-devel.git/blob - kernel/2.6/drivers/net/can/vcan.c
merged branches/netlink in rev. 1037 back to trunk.
[socketcan-devel.git] / kernel / 2.6 / drivers / net / can / vcan.c
1 /*
2  * vcan.c - Virtual CAN interface
3  *
4  * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of Volkswagen nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * Alternatively, provided that this notice is retained in full, this
20  * software may be distributed under the terms of the GNU General
21  * Public License ("GPL") version 2, in which case the provisions of the
22  * GPL apply INSTEAD OF those given above.
23  *
24  * The provided data structures and external interfaces from this code
25  * are not restricted to be used by modules with a GPL compatible license.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38  * DAMAGE.
39  *
40  * Send feedback to <socketcan-users@lists.berlios.de>
41  *
42  */
43
44 #include <linux/module.h>
45 #include <linux/init.h>
46 #include <linux/version.h>
47 #include <linux/netdevice.h>
48 #include <linux/if_arp.h>
49 #include <linux/if_ether.h>
50 #include <socketcan/can.h>
51 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
52 #include <net/rtnetlink.h>
53 #endif
54
55 #include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
56 RCSID("$Id$");
57
58 static __initdata const char banner[] =
59         KERN_INFO "vcan: Virtual CAN interface driver\n";
60
61 MODULE_DESCRIPTION("virtual CAN interface");
62 MODULE_LICENSE("Dual BSD/GPL");
63 MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
64
65 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
66 static void *kzalloc(size_t size, unsigned int __nocast flags)
67 {
68         void *ret = kmalloc(size, flags);
69
70         if (ret)
71                 memset(ret, 0, size);
72
73         return ret;
74 }
75 #endif
76
77 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
78 static int numdev = 4; /* default number of virtual CAN interfaces */
79 module_param(numdev, int, S_IRUGO);
80 MODULE_PARM_DESC(numdev, "Number of virtual CAN devices");
81 #endif
82
83 /*
84  * CAN test feature:
85  * Enable the echo on driver level for testing the CAN core echo modes.
86  * See Documentation/networking/can.txt for details.
87  */
88
89 static int echo; /* echo testing. Default: 0 (Off) */
90 module_param(echo, bool, S_IRUGO);
91 MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
92
93 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
94 static struct net_device **vcan_devs; /* root pointer to netdevice structs */
95 #endif
96
97 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
98 #define PRIVSIZE sizeof(struct net_device_stats)
99 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
100 #define PRIVSIZE 0
101 #endif
102
103 static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
104 {
105 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
106         struct net_device_stats *stats = &dev->stats;
107 #else
108         struct net_device_stats *stats = netdev_priv(dev);
109 #endif
110
111         stats->rx_packets++;
112         stats->rx_bytes += skb->len;
113
114         skb->protocol  = htons(ETH_P_CAN);
115         skb->pkt_type  = PACKET_BROADCAST;
116         skb->dev       = dev;
117         skb->ip_summed = CHECKSUM_UNNECESSARY;
118
119         netif_rx(skb);
120 }
121
122 static int vcan_tx(struct sk_buff *skb, struct net_device *dev)
123 {
124 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
125         struct net_device_stats *stats = &dev->stats;
126 #else
127         struct net_device_stats *stats = netdev_priv(dev);
128 #endif
129         int loop;
130
131         stats->tx_packets++;
132         stats->tx_bytes += skb->len;
133
134         /* set flag whether this packet has to be looped back */
135         loop = skb->pkt_type == PACKET_LOOPBACK;
136
137         if (!echo) {
138                 /* no echo handling available inside this driver */
139
140                 if (loop) {
141                         /*
142                          * only count the packets here, because the
143                          * CAN core already did the echo for us
144                          */
145                         stats->rx_packets++;
146                         stats->rx_bytes += skb->len;
147                 }
148                 kfree_skb(skb);
149                 return NETDEV_TX_OK;
150         }
151
152         /* perform standard echo handling for CAN network interfaces */
153
154         if (loop) {
155                 struct sock *srcsk = skb->sk;
156
157                 skb = skb_share_check(skb, GFP_ATOMIC);
158                 if (!skb)
159                         return NETDEV_TX_OK;
160
161                 /* receive with packet counting */
162                 skb->sk = srcsk;
163                 vcan_rx(skb, dev);
164         } else {
165                 /* no looped packets => no counting */
166                 kfree_skb(skb);
167         }
168         return NETDEV_TX_OK;
169 }
170
171 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
172 static struct net_device_stats *vcan_get_stats(struct net_device *dev)
173 {
174         struct net_device_stats *stats = netdev_priv(dev);
175
176         return stats;
177 }
178 #endif
179 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
180 static const struct net_device_ops vcan_netdev_ops = {
181         .ndo_start_xmit = vcan_tx,
182 };
183 #endif
184
185 static void vcan_setup(struct net_device *dev)
186 {
187         dev->type               = ARPHRD_CAN;
188         dev->mtu                = sizeof(struct can_frame);
189         dev->hard_header_len    = 0;
190         dev->addr_len           = 0;
191         dev->tx_queue_len       = 0;
192         dev->flags              = IFF_NOARP;
193
194 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
195 #define IFF_ECHO IFF_LOOPBACK
196 #endif
197         /* set flags according to driver capabilities */
198         if (echo)
199                 dev->flags |= IFF_ECHO;
200
201 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
202         dev->netdev_ops         = &vcan_netdev_ops;
203 #else
204         dev->hard_start_xmit    = vcan_tx;
205 #endif
206 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
207         dev->destructor         = free_netdev;
208 #endif
209 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
210         dev->get_stats          = vcan_get_stats;
211 #endif
212 }
213
214 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
215 static struct rtnl_link_ops vcan_link_ops __read_mostly = {
216         .kind   = "vcan",
217         .setup  = vcan_setup,
218 };
219
220 static __init int vcan_init_module(void)
221 {
222         printk(banner);
223
224         if (echo)
225                 printk(KERN_INFO "vcan: enabled echo on driver level.\n");
226
227         return rtnl_link_register(&vcan_link_ops);
228 }
229
230 static __exit void vcan_cleanup_module(void)
231 {
232         rtnl_link_unregister(&vcan_link_ops);
233 }
234 #else
235 static __init int vcan_init_module(void)
236 {
237         int i, result;
238
239         printk(banner);
240
241         /* register at least one interface */
242         if (numdev < 1)
243                 numdev = 1;
244
245         printk(KERN_INFO
246                "vcan: registering %d virtual CAN interfaces. (echo %s)\n",
247                numdev, echo ? "enabled" : "disabled");
248
249         vcan_devs = kzalloc(numdev * sizeof(struct net_device *), GFP_KERNEL);
250         if (!vcan_devs) {
251                 printk(KERN_ERR "vcan: Can't allocate vcan devices array!\n");
252                 return -ENOMEM;
253         }
254
255         for (i = 0; i < numdev; i++) {
256                 vcan_devs[i] = alloc_netdev(PRIVSIZE, "vcan%d", vcan_setup);
257                 if (!vcan_devs[i]) {
258                         printk(KERN_ERR "vcan: error allocating net_device\n");
259                         result = -ENOMEM;
260                         goto out;
261                 }
262
263                 result = register_netdev(vcan_devs[i]);
264                 if (result < 0) {
265                         printk(KERN_ERR
266                                "vcan: error %d registering interface %s\n",
267                                result, vcan_devs[i]->name);
268                         free_netdev(vcan_devs[i]);
269                         vcan_devs[i] = NULL;
270                         goto out;
271                 }
272         }
273
274         return 0;
275
276  out:
277         for (i = 0; i < numdev; i++) {
278                 if (vcan_devs[i]) {
279                         unregister_netdev(vcan_devs[i]);
280                         free_netdev(vcan_devs[i]);
281                 }
282         }
283
284         kfree(vcan_devs);
285
286         return result;
287 }
288
289 static __exit void vcan_cleanup_module(void)
290 {
291         int i;
292
293         for (i = 0; i < numdev; i++) {
294                 if (vcan_devs[i]) {
295                         unregister_netdev(vcan_devs[i]);
296                         free_netdev(vcan_devs[i]);
297                 }
298         }
299
300         kfree(vcan_devs);
301 }
302 #endif
303
304 module_init(vcan_init_module);
305 module_exit(vcan_cleanup_module);