]> rtime.felk.cvut.cz Git - socketcan-devel.git/blob - kernel/2.6/drivers/net/can/vcan.c
reorganized kernel include files:
[socketcan-devel.git] / kernel / 2.6 / drivers / net / 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 <socketcan-users@lists.berlios.de>
42  *
43  */
44
45 #include <linux/config.h>
46 #include <linux/module.h>
47 #include <linux/init.h>
48 #include <linux/netdevice.h>
49 #include <linux/if_arp.h>
50
51 #include <linux/can.h>
52 #include <linux/can/version.h>
53
54 RCSID("$Id$");
55
56
57 #define NAME "VCAN loopback interface for LLCF"
58 static __initdata const char banner[] = BANNER(NAME);
59
60 MODULE_DESCRIPTION(NAME);
61 MODULE_LICENSE("Dual BSD/GPL");
62 MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
63
64 #ifdef CONFIG_CAN_DEBUG_DEVICES
65 static int debug = 0;
66 module_param(debug, int, S_IRUGO);
67 #define DBG(args...)       (debug & 1 ? \
68                                (printk(KERN_DEBUG "VCAN %s: ", __func__), \
69                                 printk(args)) : 0)
70 #define DBG_FRAME(args...) (debug & 2 ? can_debug_cframe(args) : 0)
71 #define DBG_SKB(skb)       (debug & 4 ? can_debug_skb(skb) : 0)
72 #else
73 #define DBG(args...)
74 #define DBG_FRAME(args...)
75 #define DBG_SKB(skb)
76 #endif
77
78 /* This 'undef' makes the vcan a kind of NULL device.  Since LLCF v0.6  */
79 /* the local loopback is implemented in af_can.c for all interfaces.    */
80 #undef  DO_LOOPBACK
81
82 #define NDEVICES 4
83
84 static struct net_device *vcan_devs[NDEVICES];
85
86 static int vcan_open(struct net_device *dev)
87 {
88         DBG("%s: interface up\n", dev->name);
89
90         netif_start_queue(dev);
91         return 0;
92 }
93
94 static int vcan_stop(struct net_device *dev)
95 {
96         DBG("%s: interface down\n", dev->name);
97
98         netif_stop_queue(dev);
99         return 0;
100 }
101
102 #ifdef DO_LOOPBACK
103
104 static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
105 {
106         struct net_device_stats *stats = netdev_priv(dev);
107         stats->rx_packets++;
108         stats->rx_bytes += skb->len;
109
110         skb->protocol  = htons(ETH_P_CAN);
111         skb->dev       = dev;
112         skb->ip_summed = CHECKSUM_UNNECESSARY;
113
114         DBG("received skbuff on interface %d\n", dev->ifindex);
115         DBG_SKB(skb);
116
117         netif_rx(skb);
118 }
119
120 #endif
121
122
123 static int vcan_tx(struct sk_buff *skb, struct net_device *dev)
124 {
125         struct net_device_stats *stats = netdev_priv(dev);
126
127         DBG("sending skbuff on interface %s\n", dev->name);
128         DBG_SKB(skb);
129         DBG_FRAME("VCAN: transmit CAN frame", (struct can_frame *)skb->data);
130
131 #ifdef DO_LOOPBACK
132         if (atomic_read(&skb->users) != 1) {
133                 struct sk_buff *old_skb = skb;
134                 skb = skb_clone(old_skb, GFP_ATOMIC);
135                 DBG("  freeing old skbuff %p, using new skbuff %p\n",
136                     old_skb, skb);
137                 kfree_skb(old_skb);
138                 if (!skb) {
139                         return 0;
140                 }
141         } else
142                 skb_orphan(skb);
143 #endif
144
145         stats->tx_packets++;
146         stats->tx_bytes += skb->len;
147 #ifdef DO_LOOPBACK
148         vcan_rx(skb, dev);
149 #else
150         stats->rx_packets++;
151         stats->rx_bytes += skb->len;
152         kfree_skb(skb);
153 #endif
154         return 0;
155 }
156
157 static int vcan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
158 {
159         return -EOPNOTSUPP;
160 }
161
162 static int vcan_rebuild_header(struct sk_buff *skb)
163 {
164         DBG("called on skbuff %p\n", skb);
165         DBG_SKB(skb);
166         return 0;
167 }
168
169 static int vcan_header(struct sk_buff *skb, struct net_device *dev,
170                        unsigned short type, void *daddr, void *saddr,
171                        unsigned int len)
172 {
173         DBG("called skbuff %p device %p\n", skb, dev);
174         DBG_SKB(skb);
175         return 0;
176 }
177
178
179 static struct net_device_stats *vcan_get_stats(struct net_device *dev)
180 {
181         struct net_device_stats *stats = netdev_priv(dev);
182         return stats;
183 }
184
185 static void vcan_init(struct net_device *dev)
186 {
187         DBG("dev %s\n", dev->name);
188
189         ether_setup(dev);
190
191         memset(dev->priv, 0, sizeof(struct net_device_stats));
192
193         dev->open              = vcan_open;
194         dev->stop              = vcan_stop;
195         dev->set_config        = NULL;
196         dev->hard_start_xmit   = vcan_tx;
197         dev->do_ioctl          = vcan_ioctl;
198         dev->get_stats         = vcan_get_stats;
199
200         dev->mtu               = sizeof(struct can_frame);
201         dev->flags             = IFF_LOOPBACK;
202         dev->hard_header       = vcan_header;
203         dev->rebuild_header    = vcan_rebuild_header;
204         dev->hard_header_cache = NULL;
205         dev->type              = ARPHRD_LOOPBACK;
206
207         SET_MODULE_OWNER(dev);
208 }
209
210 static __init int vcan_init_module(void)
211 {
212         int i, ndev = 0, result;
213
214         printk(banner);
215
216         for (i = 0; i < NDEVICES; i++) {
217                 if (!(vcan_devs[i] = alloc_netdev(sizeof(struct net_device_stats),
218                                                   "vcan%d", vcan_init)))
219                         printk(KERN_ERR "vcan: error allocating net_device\n");
220                 else if ((result = register_netdev(vcan_devs[i])) < 0) {
221                         printk(KERN_ERR "vcan: error %d registering interface %s\n",
222                                result, vcan_devs[i]->name);
223                         free_netdev(vcan_devs[i]);
224                 } else {
225                         DBG("successfully registered interface %s\n",
226                             vcan_devs[i]->name);
227                         ndev++;
228                 }
229         }
230         return ndev ? 0 : -ENODEV;
231 }
232
233 static __exit void vcan_cleanup_module(void)
234 {
235         int i;
236         for (i = 0; i < NDEVICES; i++) {
237                 unregister_netdev(vcan_devs[i]);
238                 free_netdev(vcan_devs[i]);
239         }
240 }
241
242 module_init(vcan_init_module);
243 module_exit(vcan_cleanup_module);