aboutsummaryrefslogtreecommitdiff
path: root/net/can/af_can.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/can/af_can.c')
-rw-r--r--net/can/af_can.c299
1 files changed, 193 insertions, 106 deletions
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 702be5a2c95..ce82337521f 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -38,11 +38,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#include <linux/module.h>
+#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/slab.h>
@@ -58,12 +57,14 @@
#include <linux/skbuff.h>
#include <linux/can.h>
#include <linux/can/core.h>
+#include <linux/can/skb.h>
+#include <linux/ratelimit.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include "af_can.h"
-static __initdata const char banner[] = KERN_INFO
+static __initconst const char banner[] = KERN_INFO
"can: controller area network core (" CAN_VERSION_STRING ")\n";
MODULE_DESCRIPTION("Controller Area Network PF_CAN core");
@@ -84,8 +85,8 @@ static DEFINE_SPINLOCK(can_rcvlists_lock);
static struct kmem_cache *rcv_cache __read_mostly;
/* 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 */
@@ -95,7 +96,7 @@ struct s_pstats can_pstats; /* receive list 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;
@@ -108,17 +109,36 @@ static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return -ENOIOCTLCMD;
}
}
+EXPORT_SYMBOL(can_ioctl);
static void can_sock_destruct(struct sock *sk)
{
skb_queue_purge(&sk->sk_receive_queue);
}
+static const struct can_proto *can_get_proto(int protocol)
+{
+ const struct can_proto *cp;
+
+ rcu_read_lock();
+ cp = rcu_dereference(proto_tab[protocol]);
+ if (cp && !try_module_get(cp->prot->owner))
+ cp = NULL;
+ rcu_read_unlock();
+
+ return cp;
+}
+
+static inline void can_put_proto(const struct can_proto *cp)
+{
+ module_put(cp->prot->owner);
+}
+
static int can_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
struct sock *sk;
- struct can_proto *cp;
+ const struct can_proto *cp;
int err = 0;
sock->state = SS_UNCONNECTED;
@@ -129,9 +149,12 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
if (!net_eq(net, &init_net))
return -EAFNOSUPPORT;
+ cp = can_get_proto(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);
/*
@@ -139,25 +162,21 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
* return the error code immediately. Below we will
* return -EPROTONOSUPPORT
*/
- if (err && printk_ratelimit())
- printk(KERN_ERR "can: request_module "
+ if (err)
+ printk_ratelimited(KERN_ERR "can: request_module "
"(can-proto-%d) failed.\n", protocol);
+
+ cp = can_get_proto(protocol);
}
#endif
- spin_lock(&proto_tab_lock);
- cp = proto_tab[protocol];
- if (cp && !try_module_get(cp->prot->owner))
- cp = NULL;
- spin_unlock(&proto_tab_lock);
-
/* check for available protocol and correct usage */
if (!cp)
return -EPROTONOSUPPORT;
if (cp->type != sock->type) {
- err = -EPROTONOSUPPORT;
+ err = -EPROTOTYPE;
goto errout;
}
@@ -182,7 +201,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
}
errout:
- module_put(cp->prot->owner);
+ can_put_proto(cp);
return err;
}
@@ -203,30 +222,46 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
* -ENOBUFS on full driver queue (see net_xmit_errno())
* -ENOMEM when local loopback failed at calling skb_clone()
* -EPERM when trying to send on a non-CAN interface
+ * -EMSGSIZE CAN frame size is bigger than CAN interface MTU
* -EINVAL when the skb->data does not contain a valid CAN frame
*/
int can_send(struct sk_buff *skb, int loop)
{
struct sk_buff *newskb = NULL;
- struct can_frame *cf = (struct can_frame *)skb->data;
- int err;
+ struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+ int err = -EINVAL;
+
+ if (skb->len == CAN_MTU) {
+ skb->protocol = htons(ETH_P_CAN);
+ if (unlikely(cfd->len > CAN_MAX_DLEN))
+ goto inval_skb;
+ } else if (skb->len == CANFD_MTU) {
+ skb->protocol = htons(ETH_P_CANFD);
+ if (unlikely(cfd->len > CANFD_MAX_DLEN))
+ goto inval_skb;
+ } else
+ goto inval_skb;
- if (skb->len != sizeof(struct can_frame) || cf->can_dlc > 8) {
- kfree_skb(skb);
- return -EINVAL;
+ /*
+ * Make sure the CAN frame can pass the selected CAN netdevice.
+ * As structs can_frame and canfd_frame are similar, we can provide
+ * CAN FD frames to legacy CAN drivers as long as the length is <= 8
+ */
+ if (unlikely(skb->len > skb->dev->mtu && cfd->len > CAN_MAX_DLEN)) {
+ err = -EMSGSIZE;
+ goto inval_skb;
}
- if (skb->dev->type != ARPHRD_CAN) {
- kfree_skb(skb);
- return -EPERM;
+ if (unlikely(skb->dev->type != ARPHRD_CAN)) {
+ err = -EPERM;
+ goto inval_skb;
}
- if (!(skb->dev->flags & IFF_UP)) {
- kfree_skb(skb);
- return -ENETDOWN;
+ if (unlikely(!(skb->dev->flags & IFF_UP))) {
+ err = -ENETDOWN;
+ goto inval_skb;
}
- skb->protocol = htons(ETH_P_CAN);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
@@ -256,7 +291,7 @@ int can_send(struct sk_buff *skb, int loop)
return -ENOMEM;
}
- newskb->sk = skb->sk;
+ can_skb_set_owner(newskb, skb->sk);
newskb->ip_summed = CHECKSUM_UNNECESSARY;
newskb->pkt_type = PACKET_BROADCAST;
}
@@ -283,6 +318,10 @@ int can_send(struct sk_buff *skb, int loop)
can_stats.tx_frames_delta++;
return 0;
+
+inval_skb:
+ kfree_skb(skb);
+ return err;
}
EXPORT_SYMBOL(can_send);
@@ -299,6 +338,29 @@ static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
}
/**
+ * effhash - hash function for 29 bit CAN identifier reduction
+ * @can_id: 29 bit CAN identifier
+ *
+ * Description:
+ * To reduce the linear traversal in one linked list of _single_ EFF CAN
+ * frame subscriptions the 29 bit identifier is mapped to 10 bits.
+ * (see CAN_EFF_RCV_HASH_BITS definition)
+ *
+ * Return:
+ * Hash value from 0x000 - 0x3FF ( enforced by CAN_EFF_RCV_HASH_BITS mask )
+ */
+static unsigned int effhash(canid_t can_id)
+{
+ unsigned int hash;
+
+ hash = can_id;
+ hash ^= can_id >> CAN_EFF_RCV_HASH_BITS;
+ hash ^= can_id >> (2 * CAN_EFF_RCV_HASH_BITS);
+
+ return hash & ((1 << CAN_EFF_RCV_HASH_BITS) - 1);
+}
+
+/**
* find_rcv_list - determine optimal filterlist inside device filter struct
* @can_id: pointer to CAN identifier of a given can_filter
* @mask: pointer to CAN mask of a given can_filter
@@ -317,8 +379,8 @@ static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
* relevant bits for the filter.
*
* The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
- * filter for error frames (CAN_ERR_FLAG bit set in mask). For error frames
- * there is a special filterlist and a special rx path filter handling.
+ * filter for error messages (CAN_ERR_FLAG bit set in mask). For error msg
+ * frames there is a special filterlist and a special rx path filter handling.
*
* Return:
* Pointer to optimal filterlist for the given can_id/mask pair.
@@ -330,7 +392,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
{
canid_t inv = *can_id & CAN_INV_FILTER; /* save flag before masking */
- /* filter for error frames in extra filterlist */
+ /* filter for error message frames in extra filterlist */
if (*mask & CAN_ERR_FLAG) {
/* clear CAN_ERR_FLAG in filter entry */
*mask &= CAN_ERR_MASK;
@@ -361,10 +423,8 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
!(*can_id & CAN_RTR_FLAG)) {
if (*can_id & CAN_EFF_FLAG) {
- if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS)) {
- /* RFC: a future use-case for hash-tables? */
- return &d->rx[RX_EFF];
- }
+ if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS))
+ return &d->rx_eff[effhash(*can_id)];
} else {
if (*mask == (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS))
return &d->rx_sff[*can_id];
@@ -382,7 +442,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
* @mask: CAN mask (see description)
* @func: callback function on filter match
* @data: returned parameter for callback function
- * @ident: string for calling module indentification
+ * @ident: string for calling module identification
*
* Description:
* Invokes the callback function with the received sk_buff and the given
@@ -391,7 +451,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
* <received_can_id> & mask == can_id & mask
*
* The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
- * filter for error frames (CAN_ERR_FLAG bit set in mask).
+ * filter for error message frames (CAN_ERR_FLAG bit set in mask).
*
* The provided pointer to the sk_buff is guaranteed to be valid as long as
* the callback function is running. The callback function must *not* free
@@ -478,7 +538,6 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
{
struct receiver *r = NULL;
struct hlist_head *rl;
- struct hlist_node *next;
struct dev_rcv_lists *d;
if (dev && dev->type != ARPHRD_CAN)
@@ -488,7 +547,7 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
d = find_dev_rcv_lists(dev);
if (!d) {
- printk(KERN_ERR "BUG: receive list not found for "
+ pr_err("BUG: receive list not found for "
"dev %s, id %03X, mask %03X\n",
DNAME(dev), can_id, mask);
goto out;
@@ -502,23 +561,20 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
* been registered before.
*/
- hlist_for_each_entry_rcu(r, next, rl, list) {
+ hlist_for_each_entry_rcu(r, rl, list) {
if (r->can_id == can_id && r->mask == mask &&
r->func == func && r->data == data)
break;
}
/*
- * Check for bugs in CAN protocol implementations:
- * If no matching list item was found, the list cursor variable next
- * will be NULL, while r will point to the last item of the list.
+ * Check for bugs in CAN protocol implementations using af_can.c:
+ * 'r' will be NULL if no matching list item was found for removal.
*/
- if (!next) {
- printk(KERN_ERR "BUG: receive list entry not found for "
- "dev %s, id %03X, mask %03X\n",
- DNAME(dev), can_id, mask);
- r = NULL;
+ if (!r) {
+ WARN(1, "BUG: receive list entry not found for dev %s, "
+ "id %03X, mask %03X\n", DNAME(dev), can_id, mask);
goto out;
}
@@ -552,7 +608,6 @@ static inline void deliver(struct sk_buff *skb, struct receiver *r)
static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
{
struct receiver *r;
- struct hlist_node *n;
int matches = 0;
struct can_frame *cf = (struct can_frame *)skb->data;
canid_t can_id = cf->can_id;
@@ -561,8 +616,8 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
return 0;
if (can_id & CAN_ERR_FLAG) {
- /* check for error frame entries only */
- hlist_for_each_entry_rcu(r, n, &d->rx[RX_ERR], list) {
+ /* check for error message frame entries only */
+ hlist_for_each_entry_rcu(r, &d->rx[RX_ERR], list) {
if (can_id & r->mask) {
deliver(skb, r);
matches++;
@@ -572,13 +627,13 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
}
/* check for unfiltered entries */
- hlist_for_each_entry_rcu(r, n, &d->rx[RX_ALL], list) {
+ hlist_for_each_entry_rcu(r, &d->rx[RX_ALL], list) {
deliver(skb, r);
matches++;
}
/* check for can_id/mask entries */
- hlist_for_each_entry_rcu(r, n, &d->rx[RX_FIL], list) {
+ hlist_for_each_entry_rcu(r, &d->rx[RX_FIL], list) {
if ((can_id & r->mask) == r->can_id) {
deliver(skb, r);
matches++;
@@ -586,7 +641,7 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
}
/* check for inverted can_id/mask entries */
- hlist_for_each_entry_rcu(r, n, &d->rx[RX_INV], list) {
+ hlist_for_each_entry_rcu(r, &d->rx[RX_INV], list) {
if ((can_id & r->mask) != r->can_id) {
deliver(skb, r);
matches++;
@@ -598,7 +653,7 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
return matches;
if (can_id & CAN_EFF_FLAG) {
- hlist_for_each_entry_rcu(r, n, &d->rx[RX_EFF], list) {
+ hlist_for_each_entry_rcu(r, &d->rx_eff[effhash(can_id)], list) {
if (r->can_id == can_id) {
deliver(skb, r);
matches++;
@@ -606,7 +661,7 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
}
} else {
can_id &= CAN_SFF_MASK;
- hlist_for_each_entry_rcu(r, n, &d->rx_sff[can_id], list) {
+ hlist_for_each_entry_rcu(r, &d->rx_sff[can_id], list) {
deliver(skb, r);
matches++;
}
@@ -615,24 +670,11 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
return matches;
}
-static int can_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
+static void can_receive(struct sk_buff *skb, struct net_device *dev)
{
struct dev_rcv_lists *d;
- struct can_frame *cf = (struct can_frame *)skb->data;
int matches;
- if (!net_eq(dev_net(dev), &init_net))
- goto drop;
-
- if (WARN_ONCE(dev->type != ARPHRD_CAN ||
- skb->len != sizeof(struct can_frame) ||
- cf->can_dlc > 8,
- "PF_CAN: dropped non conform skbuf: "
- "dev type %d, len %d, can_dlc %d\n",
- dev->type, skb->len, cf->can_dlc))
- goto drop;
-
/* update statistics */
can_stats.rx_frames++;
can_stats.rx_frames_delta++;
@@ -656,7 +698,49 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
can_stats.matches++;
can_stats.matches_delta++;
}
+}
+
+static int can_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
+{
+ struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+
+ if (unlikely(!net_eq(dev_net(dev), &init_net)))
+ goto drop;
+ if (WARN_ONCE(dev->type != ARPHRD_CAN ||
+ skb->len != CAN_MTU ||
+ cfd->len > CAN_MAX_DLEN,
+ "PF_CAN: dropped non conform CAN skbuf: "
+ "dev type %d, len %d, datalen %d\n",
+ dev->type, skb->len, cfd->len))
+ goto drop;
+
+ can_receive(skb, dev);
+ return NET_RX_SUCCESS;
+
+drop:
+ kfree_skb(skb);
+ return NET_RX_DROP;
+}
+
+static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
+{
+ struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+
+ if (unlikely(!net_eq(dev_net(dev), &init_net)))
+ goto drop;
+
+ if (WARN_ONCE(dev->type != ARPHRD_CAN ||
+ skb->len != CANFD_MTU ||
+ cfd->len > CANFD_MAX_DLEN,
+ "PF_CAN: dropped non conform CAN FD skbuf: "
+ "dev type %d, len %d, datalen %d\n",
+ dev->type, skb->len, cfd->len))
+ goto drop;
+
+ can_receive(skb, dev);
return NET_RX_SUCCESS;
drop:
@@ -678,14 +762,13 @@ drop:
* -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;
if (proto < 0 || proto >= CAN_NPROTO) {
- printk(KERN_ERR "can: protocol number %d out of range\n",
- proto);
+ pr_err("can: protocol number %d out of range\n", proto);
return -EINVAL;
}
@@ -693,19 +776,15 @@ int can_proto_register(struct can_proto *cp)
if (err < 0)
return err;
- spin_lock(&proto_tab_lock);
+ mutex_lock(&proto_tab_lock);
+
if (proto_tab[proto]) {
- printk(KERN_ERR "can: protocol %d already registered\n",
- proto);
+ pr_err("can: protocol %d already registered\n", proto);
err = -EBUSY;
- } else {
- proto_tab[proto] = cp;
+ } else
+ RCU_INIT_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 (err < 0)
proto_unregister(cp->prot);
@@ -718,17 +797,16 @@ EXPORT_SYMBOL(can_proto_register);
* 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_INIT_POINTER(proto_tab[proto], NULL);
+ mutex_unlock(&proto_tab_lock);
+
+ synchronize_rcu();
proto_unregister(cp->prot);
}
@@ -738,9 +816,9 @@ EXPORT_SYMBOL(can_proto_unregister);
* af_can notifier to create/remove CAN netdevice specific structs
*/
static int can_notifier(struct notifier_block *nb, unsigned long msg,
- void *data)
+ void *ptr)
{
- struct net_device *dev = (struct net_device *)data;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct dev_rcv_lists *d;
if (!net_eq(dev_net(dev), &init_net))
@@ -755,11 +833,8 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
/* create new dev_rcv_lists for this device */
d = kzalloc(sizeof(*d), GFP_KERNEL);
- if (!d) {
- printk(KERN_ERR
- "can: allocation of receive list failed\n");
+ if (!d)
return NOTIFY_DONE;
- }
BUG_ON(dev->ml_priv);
dev->ml_priv = d;
@@ -777,8 +852,8 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
dev->ml_priv = NULL;
}
} else
- printk(KERN_ERR "can: notifier: receive list not "
- "found for dev %s\n", dev->name);
+ pr_err("can: notifier: receive list not found for dev "
+ "%s\n", dev->name);
spin_unlock(&can_rcvlists_lock);
@@ -794,10 +869,14 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
static struct packet_type can_packet __read_mostly = {
.type = cpu_to_be16(ETH_P_CAN),
- .dev = NULL,
.func = can_rcv,
};
+static struct packet_type canfd_packet __read_mostly = {
+ .type = cpu_to_be16(ETH_P_CANFD),
+ .func = canfd_rcv,
+};
+
static const struct net_proto_family can_family_ops = {
.family = PF_CAN,
.create = can_create,
@@ -811,6 +890,12 @@ static struct notifier_block can_netdev_notifier __read_mostly = {
static __init int can_init(void)
{
+ /* check for correct padding to be able to use the structs similarly */
+ BUILD_BUG_ON(offsetof(struct can_frame, can_dlc) !=
+ offsetof(struct canfd_frame, len) ||
+ offsetof(struct can_frame, data) !=
+ offsetof(struct canfd_frame, data));
+
printk(banner);
memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list));
@@ -833,6 +918,7 @@ static __init int can_init(void)
sock_register(&can_family_ops);
register_netdevice_notifier(&can_netdev_notifier);
dev_add_pack(&can_packet);
+ dev_add_pack(&canfd_packet);
return 0;
}
@@ -842,11 +928,12 @@ static __exit void can_exit(void)
struct net_device *dev;
if (stats_timer)
- del_timer(&can_stattimer);
+ del_timer_sync(&can_stattimer);
can_remove_proc();
/* protocol unregister */
+ dev_remove_pack(&canfd_packet);
dev_remove_pack(&can_packet);
unregister_netdevice_notifier(&can_netdev_notifier);
sock_unregister(PF_CAN);
@@ -854,7 +941,7 @@ static __exit void can_exit(void)
/* remove created dev_rcv_lists from still registered CAN devices */
rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) {
- if (dev->type == ARPHRD_CAN && dev->ml_priv){
+ if (dev->type == ARPHRD_CAN && dev->ml_priv) {
struct dev_rcv_lists *d = dev->ml_priv;