Skip to content

Commit

Permalink
can: cangw: introduce optional uid to reference created routing jobs
Browse files Browse the repository at this point in the history
Similar to referencing iptables rules by their line number this UID allows to
reference created routing jobs, e.g. to alter configured data modifications.

The UID is an optional non-zero value which can be provided at routing job
creation time. When the UID is set the UID replaces the data modification
configuration as job identification attribute e.g. at job removal time.

Signed-off-by: Oliver Hartkopp <[email protected]>
Signed-off-by: Marc Kleine-Budde <[email protected]>
  • Loading branch information
hartkopp authored and marckleinebudde committed Jun 9, 2015
1 parent 3d5db5e commit dd895d7
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 12 deletions.
5 changes: 5 additions & 0 deletions include/uapi/linux/can/gw.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ enum {
CGW_FILTER, /* specify struct can_filter on source CAN device */
CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */
CGW_LIM_HOPS, /* limit the number of hops of this specific rule */
CGW_MOD_UID, /* user defined identifier for modification updates */
__CGW_MAX
};

Expand Down Expand Up @@ -162,6 +163,10 @@ enum {
* load time of the can-gw module). This value is used to reduce the number of
* possible hops for this gateway rule to a value smaller then max_hops.
*
* CGW_MOD_UID (length 4 bytes):
* Optional non-zero user defined routing job identifier to alter existing
* modification settings at runtime.
*
* CGW_CS_XOR (length 4 bytes):
* Set a simple XOR checksum starting with an initial value into
* data[result-idx] using data[start-idx] .. data[end-idx]
Expand Down
68 changes: 56 additions & 12 deletions net/can/gw.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ struct cf_mod {
void (*xor)(struct can_frame *cf, struct cgw_csum_xor *xor);
void (*crc8)(struct can_frame *cf, struct cgw_csum_crc8 *crc8);
} csumfunc;
u32 uid;
};


Expand Down Expand Up @@ -548,6 +549,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
goto cancel;
}

if (gwj->mod.uid) {
if (nla_put_u32(skb, CGW_MOD_UID, gwj->mod.uid) < 0)
goto cancel;
}

if (gwj->mod.csumfunc.crc8) {
if (nla_put(skb, CGW_CS_CRC8, CGW_CS_CRC8_LEN,
&gwj->mod.csum.crc8) < 0)
Expand Down Expand Up @@ -619,6 +625,7 @@ static const struct nla_policy cgw_policy[CGW_MAX+1] = {
[CGW_DST_IF] = { .type = NLA_U32 },
[CGW_FILTER] = { .len = sizeof(struct can_filter) },
[CGW_LIM_HOPS] = { .type = NLA_U8 },
[CGW_MOD_UID] = { .type = NLA_U32 },
};

/* check for common and gwtype specific attributes */
Expand Down Expand Up @@ -761,6 +768,10 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
else
mod->csumfunc.xor = cgw_csum_xor_neg;
}

if (tb[CGW_MOD_UID]) {
nla_memcpy(&mod->uid, tb[CGW_MOD_UID], sizeof(u32));
}
}

if (gwtype == CGW_TYPE_CAN_CAN) {
Expand Down Expand Up @@ -802,6 +813,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct rtcanmsg *r;
struct cgw_job *gwj;
struct cf_mod mod;
struct can_can_gw ccgw;
u8 limhops = 0;
int err = 0;

Expand All @@ -819,6 +832,36 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
if (r->gwtype != CGW_TYPE_CAN_CAN)
return -EINVAL;

err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops);
if (err < 0)
return err;

if (mod.uid) {

ASSERT_RTNL();

/* check for updating an existing job with identical uid */
hlist_for_each_entry(gwj, &cgw_list, list) {

if (gwj->mod.uid != mod.uid)
continue;

/* interfaces & filters must be identical */
if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw)))
return -EINVAL;

/* update modifications with disabled softirq & quit */
local_bh_disable();
memcpy(&gwj->mod, &mod, sizeof(mod));
local_bh_enable();
return 0;
}
}

/* ifindex == 0 is not allowed for job creation */
if (!ccgw.src_idx || !ccgw.dst_idx)
return -ENODEV;

gwj = kmem_cache_alloc(cgw_cache, GFP_KERNEL);
if (!gwj)
return -ENOMEM;
Expand All @@ -828,18 +871,14 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
gwj->deleted_frames = 0;
gwj->flags = r->flags;
gwj->gwtype = r->gwtype;
gwj->limit_hops = limhops;

err = cgw_parse_attr(nlh, &gwj->mod, CGW_TYPE_CAN_CAN, &gwj->ccgw,
&limhops);
if (err < 0)
goto out;
/* insert already parsed information */
memcpy(&gwj->mod, &mod, sizeof(mod));
memcpy(&gwj->ccgw, &ccgw, sizeof(ccgw));

err = -ENODEV;

/* ifindex == 0 is not allowed for job creation */
if (!gwj->ccgw.src_idx || !gwj->ccgw.dst_idx)
goto out;

gwj->src.dev = __dev_get_by_index(&init_net, gwj->ccgw.src_idx);

if (!gwj->src.dev)
Expand All @@ -856,8 +895,6 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
if (gwj->dst.dev->type != ARPHRD_CAN)
goto out;

gwj->limit_hops = limhops;

ASSERT_RTNL();

err = cgw_register_filter(gwj);
Expand Down Expand Up @@ -931,8 +968,15 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
if (gwj->limit_hops != limhops)
continue;

if (memcmp(&gwj->mod, &mod, sizeof(mod)))
continue;
/* we have a match when uid is enabled and identical */
if (gwj->mod.uid || mod.uid) {
if (gwj->mod.uid != mod.uid)
continue;
} else {
/* no uid => check for identical modifications */
if (memcmp(&gwj->mod, &mod, sizeof(mod)))
continue;
}

/* if (r->gwtype == CGW_TYPE_CAN_CAN) - is made sure here */
if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw)))
Expand Down

0 comments on commit dd895d7

Please sign in to comment.