/*
* gw.c - CAN frame Gateway/Router/Bridge with netlink interface
*
- * Copyright (c) 2002-2010 Volkswagen Group Electronic Research
+ * Copyright (c) 2011 Volkswagen Group Electronic Research
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include <socketcan/can/gw.h>
#include <net/rtnetlink.h>
#include <net/net_namespace.h>
+#include <net/sock.h>
#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
RCSID("$Id$");
-#define CAN_GW_VERSION "20101205"
+#define CAN_GW_VERSION "20101209"
static __initdata const char banner[] =
KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n";
static struct kmem_cache *cgw_cache __read_mostly;
-#define CGW_SK_MAGIC ((void *)(¬ifier))
-
/* structure that contains the (on-the-fly) CAN frame modifications */
struct cf_mod {
struct {
/* modification functions that are invoked in the hot path in can_can_gw_rcv */
-#define MODFUNC(func, op) static void func (struct can_frame *cf, \
- struct cf_mod *mod) { op ; }
+#define MODFUNC(func, op) static void func(struct can_frame *cf, \
+ struct cf_mod *mod) { op ; }
MODFUNC(mod_and_id, cf->can_id &= mod->modframe.and.can_id)
MODFUNC(mod_and_dlc, cf->can_dlc &= mod->modframe.and.can_dlc)
static int cgw_chk_csum_parms(s8 fr, s8 to, s8 re)
{
- /*
+ /*
* absolute dlc values 0 .. 7 => 0 .. 7, e.g. data [0]
* relative to received dlc -1 .. -8 :
- * e.g. for received dlc = 8
+ * e.g. for received dlc = 8
* -1 => index = 7 (data[7])
* -3 => index = 5 (data[5])
* -8 => index = 0 (data[0])
return 0;
else
return -EINVAL;
-}
+}
static inline int calc_idx(int idx, int rx_dlc)
{
if (from <= to) {
for (i = from; i <= to; i++)
- val ^= cf->data[i];
+ val ^= cf->data[i];
} else {
for (i = from; i >= to; i--)
- val ^= cf->data[i];
+ val ^= cf->data[i];
}
cf->data[res] = val;
struct sk_buff *nskb;
int modidx = 0;
- /* do not handle already routed frames */
- if (skb->sk == CGW_SK_MAGIC)
+ /* do not handle already routed frames - see comment below */
+ if (skb_mac_header_was_set(skb))
return;
if (!(gwj->dst.dev->flags & IFF_UP)) {
return;
}
- /* mark routed frames with a 'special' sk value */
- nskb->sk = CGW_SK_MAGIC;
+ /*
+ * Mark routed frames by setting some mac header length which is
+ * not relevant for the CAN frames located in the skb->data section.
+ *
+ * As dev->header_ops is not set in CAN netdevices no one is ever
+ * accessing the various header offsets in the CAN skbuffs anyway.
+ * E.g. using the packet socket to read CAN frames is still working.
+ */
+ skb_set_mac_header(nskb, 8);
nskb->dev = gwj->dst.dev;
/* pointer to modifiable CAN frame */
hlist_for_each_entry_safe(gwj, n, nx, &cgw_list, list) {
- if (gwj->src.dev == dev || gwj->dst.dev == dev) {
+ if (gwj->src.dev == dev || gwj->dst.dev == dev) {
hlist_del(&gwj->list);
cgw_unregister_filter(gwj);
kfree(gwj);
}
/* check for common and gwtype specific attributes */
-static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
+static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
u8 gwtype, void *gwtypeattr)
{
struct nlattr *tb[CGW_MAX+1];
int err = 0;
/* initialize modification & checksum data space */
- memset(mod, 0, sizeof(*mod));
+ memset(mod, 0, sizeof(*mod));
err = nlmsg_parse(nlh, sizeof(struct rtcanmsg), tb, CGW_MAX, NULL);
if (err < 0)
/* check CGW_TYPE_CAN_CAN specific attributes */
struct can_can_gw *ccgw = (struct can_can_gw *)gwtypeattr;
- memset(ccgw, 0, sizeof(*ccgw));
+ memset(ccgw, 0, sizeof(*ccgw));
/* check for can_filter in attributes */
if (tb[CGW_FILTER] &&
if (!gwj->src.dev)
goto out;
- if (gwj->src.dev->type != ARPHRD_CAN)
+ /* check for CAN netdev not using header_ops - see gw_rcv() */
+ if (gwj->src.dev->type != ARPHRD_CAN || gwj->src.dev->header_ops)
goto put_src_out;
gwj->dst.dev = dev_get_by_index(&init_net, gwj->ccgw.dst_idx);
if (!gwj->dst.dev)
goto put_src_out;
- if (gwj->dst.dev->type != ARPHRD_CAN)
+ /* check for CAN netdev not using header_ops - see gw_rcv() */
+ if (gwj->dst.dev->type != ARPHRD_CAN || gwj->dst.dev->header_ops)
goto put_src_dst_out;
-
+
ASSERT_RTNL();
err = cgw_register_filter(gwj);