aboutsummaryrefslogtreecommitdiffstats
path: root/net/can
diff options
context:
space:
mode:
Diffstat (limited to 'net/can')
-rw-r--r--net/can/Kconfig11
-rw-r--r--net/can/Makefile3
-rw-r--r--net/can/raw.c763
3 files changed, 777 insertions, 0 deletions
diff --git a/net/can/Kconfig b/net/can/Kconfig
index 8b92790747e5..4718d1f50ab3 100644
--- a/net/can/Kconfig
+++ b/net/can/Kconfig
@@ -15,3 +15,14 @@ menuconfig CAN
15 15
16 If you want CAN support you should say Y here and also to the 16 If you want CAN support you should say Y here and also to the
17 specific driver for your controller(s) below. 17 specific driver for your controller(s) below.
18
19config CAN_RAW
20 tristate "Raw CAN Protocol (raw access with CAN-ID filtering)"
21 depends on CAN
22 default N
23 ---help---
24 The raw CAN protocol option offers access to the CAN bus via
25 the BSD socket API. You probably want to use the raw socket in
26 most cases where no higher level protocol is being used. The raw
27 socket has several filter options e.g. ID masking / error frames.
28 To receive/send raw CAN messages, use AF_CAN with protocol CAN_RAW.
diff --git a/net/can/Makefile b/net/can/Makefile
index 4c7563c2ccb2..86f1cf21fce4 100644
--- a/net/can/Makefile
+++ b/net/can/Makefile
@@ -4,3 +4,6 @@
4 4
5obj-$(CONFIG_CAN) += can.o 5obj-$(CONFIG_CAN) += can.o
6can-objs := af_can.o proc.o 6can-objs := af_can.o proc.o
7
8obj-$(CONFIG_CAN_RAW) += can-raw.o
9can-raw-objs := raw.o
diff --git a/net/can/raw.c b/net/can/raw.c
new file mode 100644
index 000000000000..aeefd1419d00
--- /dev/null
+++ b/net/can/raw.c
@@ -0,0 +1,763 @@
1/*
2 * raw.c - Raw sockets for protocol family CAN
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/uio.h>
47#include <linux/net.h>
48#include <linux/netdevice.h>
49#include <linux/socket.h>
50#include <linux/if_arp.h>
51#include <linux/skbuff.h>
52#include <linux/can.h>
53#include <linux/can/core.h>
54#include <linux/can/raw.h>
55#include <net/sock.h>
56#include <net/net_namespace.h>
57
58#define CAN_RAW_VERSION CAN_VERSION
59static __initdata const char banner[] =
60 KERN_INFO "can: raw protocol (rev " CAN_RAW_VERSION ")\n";
61
62MODULE_DESCRIPTION("PF_CAN raw protocol");
63MODULE_LICENSE("Dual BSD/GPL");
64MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
65
66#define MASK_ALL 0
67
68/*
69 * A raw socket has a list of can_filters attached to it, each receiving
70 * the CAN frames matching that filter. If the filter list is empty,
71 * no CAN frames will be received by the socket. The default after
72 * opening the socket, is to have one filter which receives all frames.
73 * The filter list is allocated dynamically with the exception of the
74 * list containing only one item. This common case is optimized by
75 * storing the single filter in dfilter, to avoid using dynamic memory.
76 */
77
78struct raw_sock {
79 struct sock sk;
80 int bound;
81 int ifindex;
82 struct notifier_block notifier;
83 int loopback;
84 int recv_own_msgs;
85 int count; /* number of active filters */
86 struct can_filter dfilter; /* default/single filter */
87 struct can_filter *filter; /* pointer to filter(s) */
88 can_err_mask_t err_mask;
89};
90
91static inline struct raw_sock *raw_sk(const struct sock *sk)
92{
93 return (struct raw_sock *)sk;
94}
95
96static void raw_rcv(struct sk_buff *skb, void *data)
97{
98 struct sock *sk = (struct sock *)data;
99 struct raw_sock *ro = raw_sk(sk);
100 struct sockaddr_can *addr;
101 int error;
102
103 if (!ro->recv_own_msgs) {
104 /* check the received tx sock reference */
105 if (skb->sk == sk) {
106 kfree_skb(skb);
107 return;
108 }
109 }
110
111 /*
112 * Put the datagram to the queue so that raw_recvmsg() can
113 * get it from there. We need to pass the interface index to
114 * raw_recvmsg(). We pass a whole struct sockaddr_can in skb->cb
115 * containing the interface index.
116 */
117
118 BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct sockaddr_can));
119 addr = (struct sockaddr_can *)skb->cb;
120 memset(addr, 0, sizeof(*addr));
121 addr->can_family = AF_CAN;
122 addr->can_ifindex = skb->dev->ifindex;
123
124 error = sock_queue_rcv_skb(sk, skb);
125 if (error < 0)
126 kfree_skb(skb);
127}
128
129static int raw_enable_filters(struct net_device *dev, struct sock *sk,
130 struct can_filter *filter,
131 int count)
132{
133 int err = 0;
134 int i;
135
136 for (i = 0; i < count; i++) {
137 err = can_rx_register(dev, filter[i].can_id,
138 filter[i].can_mask,
139 raw_rcv, sk, "raw");
140 if (err) {
141 /* clean up successfully registered filters */
142 while (--i >= 0)
143 can_rx_unregister(dev, filter[i].can_id,
144 filter[i].can_mask,
145 raw_rcv, sk);
146 break;
147 }
148 }
149
150 return err;
151}
152
153static int raw_enable_errfilter(struct net_device *dev, struct sock *sk,
154 can_err_mask_t err_mask)
155{
156 int err = 0;
157
158 if (err_mask)
159 err = can_rx_register(dev, 0, err_mask | CAN_ERR_FLAG,
160 raw_rcv, sk, "raw");
161
162 return err;
163}
164
165static void raw_disable_filters(struct net_device *dev, struct sock *sk,
166 struct can_filter *filter,
167 int count)
168{
169 int i;
170
171 for (i = 0; i < count; i++)
172 can_rx_unregister(dev, filter[i].can_id, filter[i].can_mask,
173 raw_rcv, sk);
174}
175
176static inline void raw_disable_errfilter(struct net_device *dev,
177 struct sock *sk,
178 can_err_mask_t err_mask)
179
180{
181 if (err_mask)
182 can_rx_unregister(dev, 0, err_mask | CAN_ERR_FLAG,
183 raw_rcv, sk);
184}
185
186static inline void raw_disable_allfilters(struct net_device *dev,
187 struct sock *sk)
188{
189 struct raw_sock *ro = raw_sk(sk);
190
191 raw_disable_filters(dev, sk, ro->filter, ro->count);
192 raw_disable_errfilter(dev, sk, ro->err_mask);
193}
194
195static int raw_enable_allfilters(struct net_device *dev, struct sock *sk)
196{
197 struct raw_sock *ro = raw_sk(sk);
198 int err;
199
200 err = raw_enable_filters(dev, sk, ro->filter, ro->count);
201 if (!err) {
202 err = raw_enable_errfilter(dev, sk, ro->err_mask);
203 if (err)
204 raw_disable_filters(dev, sk, ro->filter, ro->count);
205 }
206
207 return err;
208}
209
210static int raw_notifier(struct notifier_block *nb,
211 unsigned long msg, void *data)
212{
213 struct net_device *dev = (struct net_device *)data;
214 struct raw_sock *ro = container_of(nb, struct raw_sock, notifier);
215 struct sock *sk = &ro->sk;
216
217 if (dev->nd_net != &init_net)
218 return NOTIFY_DONE;
219
220 if (dev->type != ARPHRD_CAN)
221 return NOTIFY_DONE;
222
223 if (ro->ifindex != dev->ifindex)
224 return NOTIFY_DONE;
225
226 switch (msg) {
227
228 case NETDEV_UNREGISTER:
229 lock_sock(sk);
230 /* remove current filters & unregister */
231 if (ro->bound)
232 raw_disable_allfilters(dev, sk);
233
234 if (ro->count > 1)
235 kfree(ro->filter);
236
237 ro->ifindex = 0;
238 ro->bound = 0;
239 ro->count = 0;
240 release_sock(sk);
241
242 sk->sk_err = ENODEV;
243 if (!sock_flag(sk, SOCK_DEAD))
244 sk->sk_error_report(sk);
245 break;
246
247 case NETDEV_DOWN:
248 sk->sk_err = ENETDOWN;
249 if (!sock_flag(sk, SOCK_DEAD))
250 sk->sk_error_report(sk);
251 break;
252 }
253
254 return NOTIFY_DONE;
255}
256
257static int raw_init(struct sock *sk)
258{
259 struct raw_sock *ro = raw_sk(sk);
260
261 ro->bound = 0;
262 ro->ifindex = 0;
263
264 /* set default filter to single entry dfilter */
265 ro->dfilter.can_id = 0;
266 ro->dfilter.can_mask = MASK_ALL;
267 ro->filter = &ro->dfilter;
268 ro->count = 1;
269
270 /* set default loopback behaviour */
271 ro->loopback = 1;
272 ro->recv_own_msgs = 0;
273
274 /* set notifier */
275 ro->notifier.notifier_call = raw_notifier;
276
277 register_netdevice_notifier(&ro->notifier);
278
279 return 0;
280}
281
282static int raw_release(struct socket *sock)
283{
284 struct sock *sk = sock->sk;
285 struct raw_sock *ro = raw_sk(sk);
286
287 unregister_netdevice_notifier(&ro->notifier);
288
289 lock_sock(sk);
290
291 /* remove current filters & unregister */
292 if (ro->bound) {
293 if (ro->ifindex) {
294 struct net_device *dev;
295
296 dev = dev_get_by_index(&init_net, ro->ifindex);
297 if (dev) {
298 raw_disable_allfilters(dev, sk);
299 dev_put(dev);
300 }
301 } else
302 raw_disable_allfilters(NULL, sk);
303 }
304
305 if (ro->count > 1)
306 kfree(ro->filter);
307
308 ro->ifindex = 0;
309 ro->bound = 0;
310 ro->count = 0;
311
312 release_sock(sk);
313 sock_put(sk);
314
315 return 0;
316}
317
318static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
319{
320 struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
321 struct sock *sk = sock->sk;
322 struct raw_sock *ro = raw_sk(sk);
323 int ifindex;
324 int err = 0;
325 int notify_enetdown = 0;
326
327 if (len < sizeof(*addr))
328 return -EINVAL;
329
330 lock_sock(sk);
331
332 if (ro->bound && addr->can_ifindex == ro->ifindex)
333 goto out;
334
335 if (addr->can_ifindex) {
336 struct net_device *dev;
337
338 dev = dev_get_by_index(&init_net, addr->can_ifindex);
339 if (!dev) {
340 err = -ENODEV;
341 goto out;
342 }
343 if (dev->type != ARPHRD_CAN) {
344 dev_put(dev);
345 err = -ENODEV;
346 goto out;
347 }
348 if (!(dev->flags & IFF_UP))
349 notify_enetdown = 1;
350
351 ifindex = dev->ifindex;
352
353 /* filters set by default/setsockopt */
354 err = raw_enable_allfilters(dev, sk);
355 dev_put(dev);
356
357 } else {
358 ifindex = 0;
359
360 /* filters set by default/setsockopt */
361 err = raw_enable_allfilters(NULL, sk);
362 }
363
364 if (!err) {
365 if (ro->bound) {
366 /* unregister old filters */
367 if (ro->ifindex) {
368 struct net_device *dev;
369
370 dev = dev_get_by_index(&init_net, ro->ifindex);
371 if (dev) {
372 raw_disable_allfilters(dev, sk);
373 dev_put(dev);
374 }
375 } else
376 raw_disable_allfilters(NULL, sk);
377 }
378 ro->ifindex = ifindex;
379 ro->bound = 1;
380 }
381
382 out:
383 release_sock(sk);
384
385 if (notify_enetdown) {
386 sk->sk_err = ENETDOWN;
387 if (!sock_flag(sk, SOCK_DEAD))
388 sk->sk_error_report(sk);
389 }
390
391 return err;
392}
393
394static int raw_getname(struct socket *sock, struct sockaddr *uaddr,
395 int *len, int peer)
396{
397 struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
398 struct sock *sk = sock->sk;
399 struct raw_sock *ro = raw_sk(sk);
400
401 if (peer)
402 return -EOPNOTSUPP;
403
404 addr->can_family = AF_CAN;
405 addr->can_ifindex = ro->ifindex;
406
407 *len = sizeof(*addr);
408
409 return 0;
410}
411
412static int raw_setsockopt(struct socket *sock, int level, int optname,
413 char __user *optval, int optlen)
414{
415 struct sock *sk = sock->sk;
416 struct raw_sock *ro = raw_sk(sk);
417 struct can_filter *filter = NULL; /* dyn. alloc'ed filters */
418 struct can_filter sfilter; /* single filter */
419 struct net_device *dev = NULL;
420 can_err_mask_t err_mask = 0;
421 int count = 0;
422 int err = 0;
423
424 if (level != SOL_CAN_RAW)
425 return -EINVAL;
426 if (optlen < 0)
427 return -EINVAL;
428
429 switch (optname) {
430
431 case CAN_RAW_FILTER:
432 if (optlen % sizeof(struct can_filter) != 0)
433 return -EINVAL;
434
435 count = optlen / sizeof(struct can_filter);
436
437 if (count > 1) {
438 /* filter does not fit into dfilter => alloc space */
439 filter = kmalloc(optlen, GFP_KERNEL);
440 if (!filter)
441 return -ENOMEM;
442
443 err = copy_from_user(filter, optval, optlen);
444 if (err) {
445 kfree(filter);
446 return err;
447 }
448 } else if (count == 1) {
449 err = copy_from_user(&sfilter, optval, optlen);
450 if (err)
451 return err;
452 }
453
454 lock_sock(sk);
455
456 if (ro->bound && ro->ifindex)
457 dev = dev_get_by_index(&init_net, ro->ifindex);
458
459 if (ro->bound) {
460 /* (try to) register the new filters */
461 if (count == 1)
462 err = raw_enable_filters(dev, sk, &sfilter, 1);
463 else
464 err = raw_enable_filters(dev, sk, filter,
465 count);
466 if (err) {
467 if (count > 1)
468 kfree(filter);
469
470 goto out_fil;
471 }
472
473 /* remove old filter registrations */
474 raw_disable_filters(dev, sk, ro->filter, ro->count);
475 }
476
477 /* remove old filter space */
478 if (ro->count > 1)
479 kfree(ro->filter);
480
481 /* link new filters to the socket */
482 if (count == 1) {
483 /* copy filter data for single filter */
484 ro->dfilter = sfilter;
485 filter = &ro->dfilter;
486 }
487 ro->filter = filter;
488 ro->count = count;
489
490 out_fil:
491 if (dev)
492 dev_put(dev);
493
494 release_sock(sk);
495
496 break;
497
498 case CAN_RAW_ERR_FILTER:
499 if (optlen != sizeof(err_mask))
500 return -EINVAL;
501
502 err = copy_from_user(&err_mask, optval, optlen);
503 if (err)
504 return err;
505
506 err_mask &= CAN_ERR_MASK;
507
508 lock_sock(sk);
509
510 if (ro->bound && ro->ifindex)
511 dev = dev_get_by_index(&init_net, ro->ifindex);
512
513 /* remove current error mask */
514 if (ro->bound) {
515 /* (try to) register the new err_mask */
516 err = raw_enable_errfilter(dev, sk, err_mask);
517
518 if (err)
519 goto out_err;
520
521 /* remove old err_mask registration */
522 raw_disable_errfilter(dev, sk, ro->err_mask);
523 }
524
525 /* link new err_mask to the socket */
526 ro->err_mask = err_mask;
527
528 out_err:
529 if (dev)
530 dev_put(dev);
531
532 release_sock(sk);
533
534 break;
535
536 case CAN_RAW_LOOPBACK:
537 if (optlen != sizeof(ro->loopback))
538 return -EINVAL;
539
540 err = copy_from_user(&ro->loopback, optval, optlen);
541
542 break;
543
544 case CAN_RAW_RECV_OWN_MSGS:
545 if (optlen != sizeof(ro->recv_own_msgs))
546 return -EINVAL;
547
548 err = copy_from_user(&ro->recv_own_msgs, optval, optlen);
549
550 break;
551
552 default:
553 return -ENOPROTOOPT;
554 }
555 return err;
556}
557
558static int raw_getsockopt(struct socket *sock, int level, int optname,
559 char __user *optval, int __user *optlen)
560{
561 struct sock *sk = sock->sk;
562 struct raw_sock *ro = raw_sk(sk);
563 int len;
564 void *val;
565 int err = 0;
566
567 if (level != SOL_CAN_RAW)
568 return -EINVAL;
569 if (get_user(len, optlen))
570 return -EFAULT;
571 if (len < 0)
572 return -EINVAL;
573
574 switch (optname) {
575
576 case CAN_RAW_FILTER:
577 lock_sock(sk);
578 if (ro->count > 0) {
579 int fsize = ro->count * sizeof(struct can_filter);
580 if (len > fsize)
581 len = fsize;
582 err = copy_to_user(optval, ro->filter, len);
583 } else
584 len = 0;
585 release_sock(sk);
586
587 if (!err)
588 err = put_user(len, optlen);
589 return err;
590
591 case CAN_RAW_ERR_FILTER:
592 if (len > sizeof(can_err_mask_t))
593 len = sizeof(can_err_mask_t);
594 val = &ro->err_mask;
595 break;
596
597 case CAN_RAW_LOOPBACK:
598 if (len > sizeof(int))
599 len = sizeof(int);
600 val = &ro->loopback;
601 break;
602
603 case CAN_RAW_RECV_OWN_MSGS:
604 if (len > sizeof(int))
605 len = sizeof(int);
606 val = &ro->recv_own_msgs;
607 break;
608
609 default:
610 return -ENOPROTOOPT;
611 }
612
613 if (put_user(len, optlen))
614 return -EFAULT;
615 if (copy_to_user(optval, val, len))
616 return -EFAULT;
617 return 0;
618}
619
620static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
621 struct msghdr *msg, size_t size)
622{
623 struct sock *sk = sock->sk;
624 struct raw_sock *ro = raw_sk(sk);
625 struct sk_buff *skb;
626 struct net_device *dev;
627 int ifindex;
628 int err;
629
630 if (msg->msg_name) {
631 struct sockaddr_can *addr =
632 (struct sockaddr_can *)msg->msg_name;
633
634 if (addr->can_family != AF_CAN)
635 return -EINVAL;
636
637 ifindex = addr->can_ifindex;
638 } else
639 ifindex = ro->ifindex;
640
641 dev = dev_get_by_index(&init_net, ifindex);
642 if (!dev)
643 return -ENXIO;
644
645 skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT,
646 &err);
647 if (!skb) {
648 dev_put(dev);
649 return err;
650 }
651
652 err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
653 if (err < 0) {
654 kfree_skb(skb);
655 dev_put(dev);
656 return err;
657 }
658 skb->dev = dev;
659 skb->sk = sk;
660
661 err = can_send(skb, ro->loopback);
662
663 dev_put(dev);
664
665 if (err)
666 return err;
667
668 return size;
669}
670
671static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
672 struct msghdr *msg, size_t size, int flags)
673{
674 struct sock *sk = sock->sk;
675 struct sk_buff *skb;
676 int error = 0;
677 int noblock;
678
679 noblock = flags & MSG_DONTWAIT;
680 flags &= ~MSG_DONTWAIT;
681
682 skb = skb_recv_datagram(sk, flags, noblock, &error);
683 if (!skb)
684 return error;
685
686 if (size < skb->len)
687 msg->msg_flags |= MSG_TRUNC;
688 else
689 size = skb->len;
690
691 error = memcpy_toiovec(msg->msg_iov, skb->data, size);
692 if (error < 0) {
693 skb_free_datagram(sk, skb);
694 return error;
695 }
696
697 sock_recv_timestamp(msg, sk, skb);
698
699 if (msg->msg_name) {
700 msg->msg_namelen = sizeof(struct sockaddr_can);
701 memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
702 }
703
704 skb_free_datagram(sk, skb);
705
706 return size;
707}
708
709static struct proto_ops raw_ops __read_mostly = {
710 .family = PF_CAN,
711 .release = raw_release,
712 .bind = raw_bind,
713 .connect = sock_no_connect,
714 .socketpair = sock_no_socketpair,
715 .accept = sock_no_accept,
716 .getname = raw_getname,
717 .poll = datagram_poll,
718 .ioctl = NULL, /* use can_ioctl() from af_can.c */
719 .listen = sock_no_listen,
720 .shutdown = sock_no_shutdown,
721 .setsockopt = raw_setsockopt,
722 .getsockopt = raw_getsockopt,
723 .sendmsg = raw_sendmsg,
724 .recvmsg = raw_recvmsg,
725 .mmap = sock_no_mmap,
726 .sendpage = sock_no_sendpage,
727};
728
729static struct proto raw_proto __read_mostly = {
730 .name = "CAN_RAW",
731 .owner = THIS_MODULE,
732 .obj_size = sizeof(struct raw_sock),
733 .init = raw_init,
734};
735
736static struct can_proto raw_can_proto __read_mostly = {
737 .type = SOCK_RAW,
738 .protocol = CAN_RAW,
739 .capability = -1,
740 .ops = &raw_ops,
741 .prot = &raw_proto,
742};
743
744static __init int raw_module_init(void)
745{
746 int err;
747
748 printk(banner);
749
750 err = can_proto_register(&raw_can_proto);
751 if (err < 0)
752 printk(KERN_ERR "can: registration of raw protocol failed\n");
753
754 return err;
755}
756
757static __exit void raw_module_exit(void)
758{
759 can_proto_unregister(&raw_can_proto);
760}
761
762module_init(raw_module_init);
763module_exit(raw_module_exit);