#endif
/* table of registered CAN protocols */
-static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly;
-static DEFINE_SPINLOCK(proto_tab_lock);
+static const struct can_proto *proto_tab[CAN_NPROTO] __read_mostly;
+static DEFINE_MUTEX(proto_tab_lock);
struct timer_list can_stattimer; /* timer for statistics update */
struct s_stats can_stats; /* packet statistics */
* af_can socket functions
*/
-static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
#endif
}
}
+EXPORT_SYMBOL(can_ioctl);
static void can_sock_destruct(struct sock *sk)
{
#endif
}
+static const struct can_proto *can_try_module_get(int protocol)
+{
+ const struct can_proto *cp;
+
+ rcu_read_lock();
+ cp = rcu_dereference(proto_tab[protocol]);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+ if (cp && !try_module_get(cp->prot->owner))
+ cp = NULL;
+#else
+ if (cp && !try_module_get(cp->owner))
+ cp = NULL;
+#endif
+ rcu_read_unlock();
+
+ return cp;
+}
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
static int can_create(struct net *net, struct socket *sock, int protocol, int kern)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
#endif
{
struct sock *sk;
- struct can_proto *cp;
+ const struct can_proto *cp;
int err = 0;
sock->state = SS_UNCONNECTED;
return -EAFNOSUPPORT;
#endif
+ cp = can_try_module_get(protocol);
+
#ifdef CONFIG_MODULES
- /* try to load protocol module kernel is modular */
- if (!proto_tab[protocol]) {
+ if (!cp) {
+ /* try to load protocol module if kernel is modular */
+
err = request_module("can-proto-%d", protocol);
/*
if (err && printk_ratelimit())
printk(KERN_ERR "can: request_module "
"(can-proto-%d) failed.\n", protocol);
- }
-#endif
- spin_lock(&proto_tab_lock);
- cp = proto_tab[protocol];
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
- if (cp && !try_module_get(cp->prot->owner))
- cp = NULL;
-#else
- if (cp && !try_module_get(cp->owner))
- cp = NULL;
+ cp = can_try_module_get(protocol);
+ }
#endif
- spin_unlock(&proto_tab_lock);
/* check for available protocol and correct usage */
return -EPROTONOSUPPORT;
if (cp->type != sock->type) {
- err = -EPROTONOSUPPORT;
+ err = -EPROTOTYPE;
goto errout;
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
if (cp->capability >= 0 && !capable(cp->capability)) {
err = -EPERM;
goto errout;
}
-
+#endif
sock->ops = cp->ops;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
* -EBUSY protocol already in use
* -ENOBUF if proto_register() fails
*/
-int can_proto_register(struct can_proto *cp)
+int can_proto_register(const struct can_proto *cp)
{
int proto = cp->protocol;
int err = 0;
return err;
#endif
- spin_lock(&proto_tab_lock);
+ mutex_lock(&proto_tab_lock);
+
if (proto_tab[proto]) {
printk(KERN_ERR "can: protocol %d already registered\n",
proto);
err = -EBUSY;
- } else {
- proto_tab[proto] = cp;
+ } else
+ rcu_assign_pointer(proto_tab[proto], cp);
- /* use generic ioctl function if not defined by module */
- if (!cp->ops->ioctl)
- cp->ops->ioctl = can_ioctl;
- }
- spin_unlock(&proto_tab_lock);
+ mutex_unlock(&proto_tab_lock);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
if (err < 0)
* can_proto_unregister - unregister CAN transport protocol
* @cp: pointer to CAN protocol structure
*/
-void can_proto_unregister(struct can_proto *cp)
+void can_proto_unregister(const struct can_proto *cp)
{
int proto = cp->protocol;
- spin_lock(&proto_tab_lock);
- if (!proto_tab[proto]) {
- printk(KERN_ERR "BUG: can: protocol %d is not registered\n",
- proto);
- }
- proto_tab[proto] = NULL;
- spin_unlock(&proto_tab_lock);
+ mutex_lock(&proto_tab_lock);
+ BUG_ON(proto_tab[proto] != cp);
+ rcu_assign_pointer(proto_tab[proto], NULL);
+ mutex_unlock(&proto_tab_lock);
+
+ synchronize_rcu();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
proto_unregister(cp->prot);