42 #include <linux/module.h>
44 #include <linux/types.h>
45 #include <linux/list.h>
49 #include <linux/net.h>
50 #include <linux/netdevice.h>
51 #include <linux/if_arp.h>
60 #define CAN_GW_VERSION "20101209"
140 #define MODFUNC(func, op) static void func(struct can_frame *cf, \
141 struct cf_mod *mod) { op ; }
143 MODFUNC(mod_and_id,
cf->can_id &=
mod->modframe.and.can_id)
164 dst->can_id = src->can_id;
165 dst->can_dlc = src->can_dlc;
166 *(
u64 *)dst->data = *(
u64 *)src->data;
169 static int cgw_chk_csum_parms(
s8 fr,
s8 to,
s8 re)
180 if (fr > -9 && fr < 8 &&
188 static inline int calc_idx(
int idx,
int rx_dlc)
204 if (from < 0 || to < 0 || res < 0)
208 for (i = from; i <= to; i++)
211 for (i = from; i >= to; i--)
248 if (from < 0 || to < 0 || res < 0)
253 crc = crc8->
crctab[crc^cf->data[
i]];
256 crc = crc8->
crctab[crc^cf->data[
i]];
271 (cf->
can_id >> 8 & 0xFF)];
285 crc = crc8->
crctab[crc^cf->data[
i]];
299 (cf->
can_id >> 8 & 0xFF)];
312 crc = crc8->
crctab[crc^cf->data[
i]];
326 (cf->
can_id >> 8 & 0xFF)];
342 if (skb_mac_header_was_set(skb))
356 if (gwj->
mod.modfunc[0])
374 skb_set_mac_header(nskb, 8);
381 while (modidx < MAX_MODFUNCTIONS && gwj->
mod.modfunc[modidx])
382 (*gwj->
mod.modfunc[modidx++])(cf, &gwj->
mod);
386 if (gwj->
mod.csumfunc.crc8)
387 (*gwj->
mod.csumfunc.crc8)(cf, &gwj->
mod.csum.crc8);
389 if (gwj->
mod.csumfunc.xor)
390 (*gwj->
mod.csumfunc.xor)(cf, &gwj->
mod.csum.xor);
404 static inline int cgw_register_filter(
struct cgw_job *gwj)
407 gwj->
ccgw.filter.can_mask, can_can_gw_rcv,
411 static inline void cgw_unregister_filter(
struct cgw_job *gwj)
414 gwj->
ccgw.filter.can_mask, can_can_gw_rcv, gwj);
418 unsigned long msg,
void *data)
422 if (!net_eq(dev_net(dev), &
init_net))
437 hlist_del(&gwj->
list);
438 cgw_unregister_filter(gwj);
454 nlh = nlmsg_put(skb, pid, seq, type,
sizeof(*rtcan), flags);
458 rtcan = nlmsg_data(nlh);
477 if (gwj->
mod.modtype.and) {
479 mb.modtype = gwj->
mod.modtype.and;
484 if (gwj->
mod.modtype.or) {
486 mb.modtype = gwj->
mod.modtype.or;
491 if (gwj->
mod.modtype.xor) {
493 mb.modtype = gwj->
mod.modtype.xor;
498 if (gwj->
mod.modtype.set) {
500 mb.modtype = gwj->
mod.modtype.set;
505 if (gwj->
mod.csumfunc.crc8) {
507 &gwj->
mod.csum.crc8) < 0)
511 if (gwj->
mod.csumfunc.xor) {
513 &gwj->
mod.csum.xor) < 0)
519 if (gwj->
ccgw.filter.can_id || gwj->
ccgw.filter.can_mask) {
521 &gwj->
ccgw.filter) < 0)
532 return nlmsg_end(skb, nlh);
535 nlmsg_cancel(skb, nlh);
545 int s_idx = cb->
args[0];
548 hlist_for_each_entry_rcu(gwj, n, &cgw_list,
list) {
579 u8 gwtype,
void *gwtypeattr)
587 memset(mod, 0,
sizeof(*mod));
603 mod->
modfunc[modidx++] = mod_and_id;
606 mod->
modfunc[modidx++] = mod_and_dlc;
609 mod->
modfunc[modidx++] = mod_and_data;
619 mod->
modfunc[modidx++] = mod_or_id;
622 mod->
modfunc[modidx++] = mod_or_dlc;
625 mod->
modfunc[modidx++] = mod_or_data;
635 mod->
modfunc[modidx++] = mod_xor_id;
638 mod->
modfunc[modidx++] = mod_xor_dlc;
641 mod->
modfunc[modidx++] = mod_xor_data;
651 mod->
modfunc[modidx++] = mod_set_id;
654 mod->
modfunc[modidx++] = mod_set_dlc;
657 mod->
modfunc[modidx++] = mod_set_data;
680 mod->
csumfunc.crc8 = cgw_csum_crc8_rel;
682 mod->
csumfunc.crc8 = cgw_csum_crc8_pos;
684 mod->
csumfunc.crc8 = cgw_csum_crc8_neg;
704 mod->
csumfunc.xor = cgw_csum_xor_rel;
706 mod->
csumfunc.xor = cgw_csum_xor_pos;
708 mod->
csumfunc.xor = cgw_csum_xor_neg;
717 memset(ccgw, 0,
sizeof(*ccgw));
731 ccgw->
dst_idx = nla_get_u32(tb[CGW_DST_IF]);
754 if (nlmsg_len(nlh) <
sizeof(*r))
781 if (!gwj->
ccgw.src_idx || !gwj->
ccgw.dst_idx)
800 goto put_src_dst_out;
804 err = cgw_register_filter(gwj);
806 hlist_add_head_rcu(&gwj->
list, &cgw_list);
819 static void cgw_remove_all_jobs(
void)
827 hlist_del(&gwj->
list);
828 cgw_unregister_filter(gwj);
833 static int cgw_remove_job(
struct sk_buff *skb,
struct nlmsghdr *nlh,
void *arg)
842 if (nlmsg_len(nlh) <
sizeof(*r))
859 cgw_remove_all_jobs();
873 if (
memcmp(&gwj->
mod, &mod,
sizeof(mod)))
880 hlist_del(&gwj->
list);
881 cgw_unregister_filter(gwj);
890 static __init int cgw_module_init(
void)
901 notifier.notifier_call = cgw_notifier;
917 static __exit void cgw_module_exit(
void)
924 cgw_remove_all_jobs();