]> rtime.felk.cvut.cz Git - socketcan-devel.git/blob - kernel/2.6/can/vcan.c
fix version code.
[socketcan-devel.git] / kernel / 2.6 / can / vcan.c
1 /*
2  * vcan.c
3  *
4  * Copyright (c) 2002-2005 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, the following disclaimer and
12  *    the referenced file 'COPYING'.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of Volkswagen nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * Alternatively, provided that this notice is retained in full, this
21  * software may be distributed under the terms of the GNU General
22  * Public License ("GPL") version 2 as distributed in the 'COPYING'
23  * file from the main directory of the linux kernel source.
24  *
25  * The provided data structures and external interfaces from this code
26  * are not restricted to be used by modules with a GPL compatible license.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39  * DAMAGE.
40  *
41  * Send feedback to <llcf@volkswagen.de>
42  *
43  */
44
45 #include <linux/module.h>
46 #include <linux/init.h>
47 #include <linux/netdevice.h>
48 #include <linux/if_arp.h>
49
50 #include "af_can.h"
51 #include "version.h"
52
53 RCSID("$Id: vcan.c,v 2.0 2006/04/13 10:37:20 ethuerm Exp $");
54
55
56 #define NAME "VCAN loopback interface for LLCF"
57 static __initdata const char banner[] = BANNER(NAME);
58
59 MODULE_DESCRIPTION(NAME);
60 MODULE_LICENSE("Dual BSD/GPL");
61 MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
62
63 #ifdef DEBUG
64 static int debug = 0;
65 module_param(debug, int, S_IRUGO);
66 #define DBG(args...)       (debug & 1 ? \
67                                (printk(KERN_DEBUG "VCAN %s: ", __func__), \
68                                 printk(args)) : 0)
69 #define DBG_FRAME(args...) (debug & 2 ? can_debug_cframe(args) : 0)
70 #define DBG_SKB(skb)       (debug & 4 ? can_debug_skb(skb) : 0)
71 #else
72 #define DBG(args...)
73 #define DBG_FRAME(args...)
74 #define DBG_SKB(skb)
75 #endif
76
77 /* This 'undef' makes the vcan a kind of NULL device.  Since LLCF v0.6  */
78 /* the local loopback is implemented in af_can.c for all interfaces.    */
79 #undef  DO_LOOPBACK
80
81 #define NDEVICES 4
82
83 static struct net_device *vcan_devs[NDEVICES];
84
85 static int vcan_open(struct net_device *dev)
86 {
87     DBG("%s: interface up\n", dev->name);
88
89     netif_start_queue(dev);
90     return 0;
91 }
92
93 static int vcan_stop(struct net_device *dev)
94 {
95     DBG("%s: interface down\n", dev->name);
96
97     netif_stop_queue(dev);
98     return 0;
99 }
100
101 #ifdef DO_LOOPBACK
102
103 static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
104 {
105     struct net_device_stats *stats = netdev_priv(dev);
106     stats->rx_packets++;
107     stats->rx_bytes += skb->len;
108
109     skb->protocol  = htons(ETH_P_CAN);
110     skb->dev       = dev;
111     skb->ip_summed = CHECKSUM_UNNECESSARY;
112
113     DBG("received skbuff on interface %d\n", dev->ifindex);
114     DBG_SKB(skb);
115
116     netif_rx(skb);
117 }
118
119 #endif
120
121
122 static int vcan_tx(struct sk_buff *skb, struct net_device *dev)
123 {
124     struct net_device_stats *stats = netdev_priv(dev);
125
126     DBG("sending skbuff on interface %s\n", dev->name);
127     DBG_SKB(skb);
128     DBG_FRAME("VCAN: transmit CAN frame", (struct can_frame *)skb->data);
129
130 #ifdef DO_LOOPBACK
131     if (atomic_read(&skb->users) != 1) {
132         struct sk_buff *old_skb = skb;
133         skb = skb_clone(old_skb, GFP_ATOMIC);
134         DBG("  freeing old skbuff %p, using new skbuff %p\n", old_skb, skb);
135         kfree_skb(old_skb);
136         if (!skb) {
137             return 0;
138         }
139     } else
140         skb_orphan(skb);
141 #endif
142
143     stats->tx_packets++;
144     stats->tx_bytes += skb->len;
145 #ifdef DO_LOOPBACK
146     vcan_rx(skb, dev);
147 #else
148     stats->rx_packets++;
149     stats->rx_bytes += skb->len;
150     kfree_skb(skb);
151 #endif
152     return 0;
153 }
154
155 static int vcan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
156 {
157     return -EOPNOTSUPP;
158 }
159
160 static int vcan_rebuild_header(struct sk_buff *skb)
161 {
162     DBG("called on skbuff %p\n", skb);
163     DBG_SKB(skb);
164     return 0;
165 }
166
167 static int vcan_header(struct sk_buff *skb, struct net_device *dev,
168                        unsigned short type, void *daddr, void *saddr,
169                        unsigned int len)
170 {
171     DBG("called skbuff %p device %p\n", skb, dev);
172     DBG_SKB(skb);
173     return 0;
174 }
175
176
177 static struct net_device_stats *vcan_get_stats(struct net_device *dev)
178 {
179     struct net_device_stats *stats = netdev_priv(dev);
180     return stats;
181 }
182
183 static void vcan_init(struct net_device *dev)
184 {
185     DBG("dev %s\n", dev->name);
186
187     ether_setup(dev);
188
189     memset(dev->priv, 0, sizeof(struct net_device_stats));
190
191     dev->open              = vcan_open;
192     dev->stop              = vcan_stop;
193     dev->set_config        = NULL;
194     dev->hard_start_xmit   = vcan_tx;
195     dev->do_ioctl          = vcan_ioctl;
196     dev->get_stats         = vcan_get_stats;
197
198     dev->mtu               = sizeof(struct can_frame);
199     dev->flags             = IFF_LOOPBACK;
200     dev->hard_header       = vcan_header;
201     dev->rebuild_header    = vcan_rebuild_header;
202     dev->hard_header_cache = NULL;
203     dev->type              = ARPHRD_LOOPBACK;
204
205     SET_MODULE_OWNER(dev);
206 }
207
208 static __init int vcan_init_module(void)
209 {
210     int i, ndev = 0, result;
211
212     printk(banner);
213
214     for (i = 0; i < NDEVICES; i++) {
215         if (!(vcan_devs[i] = alloc_netdev(sizeof(struct net_device_stats),
216                                           "vcan%d", vcan_init)))
217             printk(KERN_ERR "vcan: error allocating net_device\n");
218         else if (result = register_netdev(vcan_devs[i])) {
219             printk(KERN_ERR "vcan: error %d registering interface %s\n",
220                    result, vcan_devs[i]->name);
221             free_netdev(vcan_devs[i]);
222         } else {
223             DBG("successfully registered interface %s\n", vcan_devs[i]->name);
224             ndev++;
225         }
226     }
227     return ndev ? 0 : -ENODEV;
228 }
229
230 static __exit void vcan_cleanup_module(void)
231 {
232     int i;
233     for (i = 0; i < NDEVICES; i++) {
234         unregister_netdev(vcan_devs[i]);
235         free_netdev(vcan_devs[i]);
236     }
237 }
238
239 module_init(vcan_init_module);
240 module_exit(vcan_cleanup_module);