0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include <linux/module.h>
0043 #include <linux/init.h>
0044 #include <linux/types.h>
0045 #include <linux/kernel.h>
0046 #include <linux/list.h>
0047 #include <linux/spinlock.h>
0048 #include <linux/rcupdate.h>
0049 #include <linux/rculist.h>
0050 #include <linux/net.h>
0051 #include <linux/netdevice.h>
0052 #include <linux/if_arp.h>
0053 #include <linux/skbuff.h>
0054 #include <linux/can.h>
0055 #include <linux/can/core.h>
0056 #include <linux/can/skb.h>
0057 #include <linux/can/gw.h>
0058 #include <net/rtnetlink.h>
0059 #include <net/net_namespace.h>
0060 #include <net/sock.h>
0061
0062 #define CAN_GW_NAME "can-gw"
0063
0064 MODULE_DESCRIPTION("PF_CAN netlink gateway");
0065 MODULE_LICENSE("Dual BSD/GPL");
0066 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
0067 MODULE_ALIAS(CAN_GW_NAME);
0068
0069 #define CGW_MIN_HOPS 1
0070 #define CGW_MAX_HOPS 6
0071 #define CGW_DEFAULT_HOPS 1
0072
0073 static unsigned int max_hops __read_mostly = CGW_DEFAULT_HOPS;
0074 module_param(max_hops, uint, 0444);
0075 MODULE_PARM_DESC(max_hops,
0076 "maximum " CAN_GW_NAME " routing hops for CAN frames "
0077 "(valid values: " __stringify(CGW_MIN_HOPS) "-"
0078 __stringify(CGW_MAX_HOPS) " hops, "
0079 "default: " __stringify(CGW_DEFAULT_HOPS) ")");
0080
0081 static struct notifier_block notifier;
0082 static struct kmem_cache *cgw_cache __read_mostly;
0083
0084
0085 struct cf_mod {
0086 struct {
0087 struct canfd_frame and;
0088 struct canfd_frame or;
0089 struct canfd_frame xor;
0090 struct canfd_frame set;
0091 } modframe;
0092 struct {
0093 u8 and;
0094 u8 or;
0095 u8 xor;
0096 u8 set;
0097 } modtype;
0098 void (*modfunc[MAX_MODFUNCTIONS])(struct canfd_frame *cf,
0099 struct cf_mod *mod);
0100
0101
0102 struct {
0103 struct cgw_csum_xor xor;
0104 struct cgw_csum_crc8 crc8;
0105 } csum;
0106 struct {
0107 void (*xor)(struct canfd_frame *cf,
0108 struct cgw_csum_xor *xor);
0109 void (*crc8)(struct canfd_frame *cf,
0110 struct cgw_csum_crc8 *crc8);
0111 } csumfunc;
0112 u32 uid;
0113 };
0114
0115
0116
0117
0118
0119
0120 struct can_can_gw {
0121 struct can_filter filter;
0122 int src_idx;
0123 int dst_idx;
0124 };
0125
0126
0127 struct cgw_job {
0128 struct hlist_node list;
0129 struct rcu_head rcu;
0130 u32 handled_frames;
0131 u32 dropped_frames;
0132 u32 deleted_frames;
0133 struct cf_mod mod;
0134 union {
0135
0136 struct net_device *dev;
0137 } src;
0138 union {
0139
0140 struct net_device *dev;
0141 } dst;
0142 union {
0143 struct can_can_gw ccgw;
0144
0145 };
0146 u8 gwtype;
0147 u8 limit_hops;
0148 u16 flags;
0149 };
0150
0151
0152
0153 #define MODFUNC(func, op) static void func(struct canfd_frame *cf, \
0154 struct cf_mod *mod) { op ; }
0155
0156 MODFUNC(mod_and_id, cf->can_id &= mod->modframe.and.can_id)
0157 MODFUNC(mod_and_len, cf->len &= mod->modframe.and.len)
0158 MODFUNC(mod_and_flags, cf->flags &= mod->modframe.and.flags)
0159 MODFUNC(mod_and_data, *(u64 *)cf->data &= *(u64 *)mod->modframe.and.data)
0160 MODFUNC(mod_or_id, cf->can_id |= mod->modframe.or.can_id)
0161 MODFUNC(mod_or_len, cf->len |= mod->modframe.or.len)
0162 MODFUNC(mod_or_flags, cf->flags |= mod->modframe.or.flags)
0163 MODFUNC(mod_or_data, *(u64 *)cf->data |= *(u64 *)mod->modframe.or.data)
0164 MODFUNC(mod_xor_id, cf->can_id ^= mod->modframe.xor.can_id)
0165 MODFUNC(mod_xor_len, cf->len ^= mod->modframe.xor.len)
0166 MODFUNC(mod_xor_flags, cf->flags ^= mod->modframe.xor.flags)
0167 MODFUNC(mod_xor_data, *(u64 *)cf->data ^= *(u64 *)mod->modframe.xor.data)
0168 MODFUNC(mod_set_id, cf->can_id = mod->modframe.set.can_id)
0169 MODFUNC(mod_set_len, cf->len = mod->modframe.set.len)
0170 MODFUNC(mod_set_flags, cf->flags = mod->modframe.set.flags)
0171 MODFUNC(mod_set_data, *(u64 *)cf->data = *(u64 *)mod->modframe.set.data)
0172
0173 static void mod_and_fddata(struct canfd_frame *cf, struct cf_mod *mod)
0174 {
0175 int i;
0176
0177 for (i = 0; i < CANFD_MAX_DLEN; i += 8)
0178 *(u64 *)(cf->data + i) &= *(u64 *)(mod->modframe.and.data + i);
0179 }
0180
0181 static void mod_or_fddata(struct canfd_frame *cf, struct cf_mod *mod)
0182 {
0183 int i;
0184
0185 for (i = 0; i < CANFD_MAX_DLEN; i += 8)
0186 *(u64 *)(cf->data + i) |= *(u64 *)(mod->modframe.or.data + i);
0187 }
0188
0189 static void mod_xor_fddata(struct canfd_frame *cf, struct cf_mod *mod)
0190 {
0191 int i;
0192
0193 for (i = 0; i < CANFD_MAX_DLEN; i += 8)
0194 *(u64 *)(cf->data + i) ^= *(u64 *)(mod->modframe.xor.data + i);
0195 }
0196
0197 static void mod_set_fddata(struct canfd_frame *cf, struct cf_mod *mod)
0198 {
0199 memcpy(cf->data, mod->modframe.set.data, CANFD_MAX_DLEN);
0200 }
0201
0202
0203 static void mod_retrieve_ccdlc(struct canfd_frame *cf)
0204 {
0205 struct can_frame *ccf = (struct can_frame *)cf;
0206
0207
0208 if (ccf->len != CAN_MAX_DLEN)
0209 return;
0210
0211
0212 if (ccf->len8_dlc > CAN_MAX_DLEN && ccf->len8_dlc <= CAN_MAX_RAW_DLC)
0213 ccf->len = ccf->len8_dlc;
0214 }
0215
0216
0217 static void mod_store_ccdlc(struct canfd_frame *cf)
0218 {
0219 struct can_frame *ccf = (struct can_frame *)cf;
0220
0221
0222 ccf->len8_dlc = 0;
0223
0224
0225 if (ccf->len <= CAN_MAX_DLEN)
0226 return;
0227
0228
0229 if (ccf->len > CAN_MAX_RAW_DLC)
0230 return;
0231
0232
0233 ccf->len8_dlc = ccf->len;
0234 ccf->len = CAN_MAX_DLEN;
0235 }
0236
0237 static void mod_and_ccdlc(struct canfd_frame *cf, struct cf_mod *mod)
0238 {
0239 mod_retrieve_ccdlc(cf);
0240 mod_and_len(cf, mod);
0241 mod_store_ccdlc(cf);
0242 }
0243
0244 static void mod_or_ccdlc(struct canfd_frame *cf, struct cf_mod *mod)
0245 {
0246 mod_retrieve_ccdlc(cf);
0247 mod_or_len(cf, mod);
0248 mod_store_ccdlc(cf);
0249 }
0250
0251 static void mod_xor_ccdlc(struct canfd_frame *cf, struct cf_mod *mod)
0252 {
0253 mod_retrieve_ccdlc(cf);
0254 mod_xor_len(cf, mod);
0255 mod_store_ccdlc(cf);
0256 }
0257
0258 static void mod_set_ccdlc(struct canfd_frame *cf, struct cf_mod *mod)
0259 {
0260 mod_set_len(cf, mod);
0261 mod_store_ccdlc(cf);
0262 }
0263
0264 static void canframecpy(struct canfd_frame *dst, struct can_frame *src)
0265 {
0266
0267
0268
0269
0270
0271 dst->can_id = src->can_id;
0272 dst->len = src->len;
0273 *(u64 *)dst->data = *(u64 *)src->data;
0274 }
0275
0276 static void canfdframecpy(struct canfd_frame *dst, struct canfd_frame *src)
0277 {
0278
0279
0280
0281
0282
0283 dst->can_id = src->can_id;
0284 dst->flags = src->flags;
0285 dst->len = src->len;
0286 memcpy(dst->data, src->data, CANFD_MAX_DLEN);
0287 }
0288
0289 static int cgw_chk_csum_parms(s8 fr, s8 to, s8 re, struct rtcanmsg *r)
0290 {
0291 s8 dlen = CAN_MAX_DLEN;
0292
0293 if (r->flags & CGW_FLAGS_CAN_FD)
0294 dlen = CANFD_MAX_DLEN;
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304 if (fr >= -dlen && fr < dlen &&
0305 to >= -dlen && to < dlen &&
0306 re >= -dlen && re < dlen)
0307 return 0;
0308 else
0309 return -EINVAL;
0310 }
0311
0312 static inline int calc_idx(int idx, int rx_len)
0313 {
0314 if (idx < 0)
0315 return rx_len + idx;
0316 else
0317 return idx;
0318 }
0319
0320 static void cgw_csum_xor_rel(struct canfd_frame *cf, struct cgw_csum_xor *xor)
0321 {
0322 int from = calc_idx(xor->from_idx, cf->len);
0323 int to = calc_idx(xor->to_idx, cf->len);
0324 int res = calc_idx(xor->result_idx, cf->len);
0325 u8 val = xor->init_xor_val;
0326 int i;
0327
0328 if (from < 0 || to < 0 || res < 0)
0329 return;
0330
0331 if (from <= to) {
0332 for (i = from; i <= to; i++)
0333 val ^= cf->data[i];
0334 } else {
0335 for (i = from; i >= to; i--)
0336 val ^= cf->data[i];
0337 }
0338
0339 cf->data[res] = val;
0340 }
0341
0342 static void cgw_csum_xor_pos(struct canfd_frame *cf, struct cgw_csum_xor *xor)
0343 {
0344 u8 val = xor->init_xor_val;
0345 int i;
0346
0347 for (i = xor->from_idx; i <= xor->to_idx; i++)
0348 val ^= cf->data[i];
0349
0350 cf->data[xor->result_idx] = val;
0351 }
0352
0353 static void cgw_csum_xor_neg(struct canfd_frame *cf, struct cgw_csum_xor *xor)
0354 {
0355 u8 val = xor->init_xor_val;
0356 int i;
0357
0358 for (i = xor->from_idx; i >= xor->to_idx; i--)
0359 val ^= cf->data[i];
0360
0361 cf->data[xor->result_idx] = val;
0362 }
0363
0364 static void cgw_csum_crc8_rel(struct canfd_frame *cf,
0365 struct cgw_csum_crc8 *crc8)
0366 {
0367 int from = calc_idx(crc8->from_idx, cf->len);
0368 int to = calc_idx(crc8->to_idx, cf->len);
0369 int res = calc_idx(crc8->result_idx, cf->len);
0370 u8 crc = crc8->init_crc_val;
0371 int i;
0372
0373 if (from < 0 || to < 0 || res < 0)
0374 return;
0375
0376 if (from <= to) {
0377 for (i = crc8->from_idx; i <= crc8->to_idx; i++)
0378 crc = crc8->crctab[crc ^ cf->data[i]];
0379 } else {
0380 for (i = crc8->from_idx; i >= crc8->to_idx; i--)
0381 crc = crc8->crctab[crc ^ cf->data[i]];
0382 }
0383
0384 switch (crc8->profile) {
0385 case CGW_CRC8PRF_1U8:
0386 crc = crc8->crctab[crc ^ crc8->profile_data[0]];
0387 break;
0388
0389 case CGW_CRC8PRF_16U8:
0390 crc = crc8->crctab[crc ^ crc8->profile_data[cf->data[1] & 0xF]];
0391 break;
0392
0393 case CGW_CRC8PRF_SFFID_XOR:
0394 crc = crc8->crctab[crc ^ (cf->can_id & 0xFF) ^
0395 (cf->can_id >> 8 & 0xFF)];
0396 break;
0397 }
0398
0399 cf->data[crc8->result_idx] = crc ^ crc8->final_xor_val;
0400 }
0401
0402 static void cgw_csum_crc8_pos(struct canfd_frame *cf,
0403 struct cgw_csum_crc8 *crc8)
0404 {
0405 u8 crc = crc8->init_crc_val;
0406 int i;
0407
0408 for (i = crc8->from_idx; i <= crc8->to_idx; i++)
0409 crc = crc8->crctab[crc ^ cf->data[i]];
0410
0411 switch (crc8->profile) {
0412 case CGW_CRC8PRF_1U8:
0413 crc = crc8->crctab[crc ^ crc8->profile_data[0]];
0414 break;
0415
0416 case CGW_CRC8PRF_16U8:
0417 crc = crc8->crctab[crc ^ crc8->profile_data[cf->data[1] & 0xF]];
0418 break;
0419
0420 case CGW_CRC8PRF_SFFID_XOR:
0421 crc = crc8->crctab[crc ^ (cf->can_id & 0xFF) ^
0422 (cf->can_id >> 8 & 0xFF)];
0423 break;
0424 }
0425
0426 cf->data[crc8->result_idx] = crc ^ crc8->final_xor_val;
0427 }
0428
0429 static void cgw_csum_crc8_neg(struct canfd_frame *cf,
0430 struct cgw_csum_crc8 *crc8)
0431 {
0432 u8 crc = crc8->init_crc_val;
0433 int i;
0434
0435 for (i = crc8->from_idx; i >= crc8->to_idx; i--)
0436 crc = crc8->crctab[crc ^ cf->data[i]];
0437
0438 switch (crc8->profile) {
0439 case CGW_CRC8PRF_1U8:
0440 crc = crc8->crctab[crc ^ crc8->profile_data[0]];
0441 break;
0442
0443 case CGW_CRC8PRF_16U8:
0444 crc = crc8->crctab[crc ^ crc8->profile_data[cf->data[1] & 0xF]];
0445 break;
0446
0447 case CGW_CRC8PRF_SFFID_XOR:
0448 crc = crc8->crctab[crc ^ (cf->can_id & 0xFF) ^
0449 (cf->can_id >> 8 & 0xFF)];
0450 break;
0451 }
0452
0453 cf->data[crc8->result_idx] = crc ^ crc8->final_xor_val;
0454 }
0455
0456
0457 static void can_can_gw_rcv(struct sk_buff *skb, void *data)
0458 {
0459 struct cgw_job *gwj = (struct cgw_job *)data;
0460 struct canfd_frame *cf;
0461 struct sk_buff *nskb;
0462 int modidx = 0;
0463
0464
0465 if (gwj->flags & CGW_FLAGS_CAN_FD) {
0466 if (skb->len != CANFD_MTU)
0467 return;
0468 } else {
0469 if (skb->len != CAN_MTU)
0470 return;
0471 }
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484 #define cgw_hops(skb) ((skb)->csum_start)
0485
0486 BUG_ON(skb->ip_summed != CHECKSUM_UNNECESSARY);
0487
0488 if (cgw_hops(skb) >= max_hops) {
0489
0490 gwj->deleted_frames++;
0491 return;
0492 }
0493
0494 if (!(gwj->dst.dev->flags & IFF_UP)) {
0495 gwj->dropped_frames++;
0496 return;
0497 }
0498
0499
0500 if (!(gwj->flags & CGW_FLAGS_CAN_IIF_TX_OK) &&
0501 can_skb_prv(skb)->ifindex == gwj->dst.dev->ifindex)
0502 return;
0503
0504
0505
0506
0507
0508
0509 if (gwj->mod.modfunc[0])
0510 nskb = skb_copy(skb, GFP_ATOMIC);
0511 else
0512 nskb = skb_clone(skb, GFP_ATOMIC);
0513
0514 if (!nskb) {
0515 gwj->dropped_frames++;
0516 return;
0517 }
0518
0519
0520 cgw_hops(nskb) = cgw_hops(skb) + 1;
0521
0522
0523 if (gwj->limit_hops && cgw_hops(nskb) == 1)
0524 cgw_hops(nskb) = max_hops - gwj->limit_hops + 1;
0525
0526 nskb->dev = gwj->dst.dev;
0527
0528
0529 cf = (struct canfd_frame *)nskb->data;
0530
0531
0532 while (modidx < MAX_MODFUNCTIONS && gwj->mod.modfunc[modidx])
0533 (*gwj->mod.modfunc[modidx++])(cf, &gwj->mod);
0534
0535
0536 if (modidx) {
0537
0538 int max_len = nskb->len - offsetof(struct canfd_frame, data);
0539
0540
0541 if (cf->len > max_len) {
0542
0543 gwj->deleted_frames++;
0544 kfree_skb(nskb);
0545 return;
0546 }
0547
0548
0549 if (gwj->mod.csumfunc.crc8)
0550 (*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8);
0551
0552 if (gwj->mod.csumfunc.xor)
0553 (*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor);
0554 }
0555
0556
0557 if (!(gwj->flags & CGW_FLAGS_CAN_SRC_TSTAMP))
0558 nskb->tstamp = 0;
0559
0560
0561 if (can_send(nskb, gwj->flags & CGW_FLAGS_CAN_ECHO))
0562 gwj->dropped_frames++;
0563 else
0564 gwj->handled_frames++;
0565 }
0566
0567 static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj)
0568 {
0569 return can_rx_register(net, gwj->src.dev, gwj->ccgw.filter.can_id,
0570 gwj->ccgw.filter.can_mask, can_can_gw_rcv,
0571 gwj, "gw", NULL);
0572 }
0573
0574 static inline void cgw_unregister_filter(struct net *net, struct cgw_job *gwj)
0575 {
0576 can_rx_unregister(net, gwj->src.dev, gwj->ccgw.filter.can_id,
0577 gwj->ccgw.filter.can_mask, can_can_gw_rcv, gwj);
0578 }
0579
0580 static void cgw_job_free_rcu(struct rcu_head *rcu_head)
0581 {
0582 struct cgw_job *gwj = container_of(rcu_head, struct cgw_job, rcu);
0583
0584 kmem_cache_free(cgw_cache, gwj);
0585 }
0586
0587 static int cgw_notifier(struct notifier_block *nb,
0588 unsigned long msg, void *ptr)
0589 {
0590 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
0591 struct net *net = dev_net(dev);
0592
0593 if (dev->type != ARPHRD_CAN)
0594 return NOTIFY_DONE;
0595
0596 if (msg == NETDEV_UNREGISTER) {
0597 struct cgw_job *gwj = NULL;
0598 struct hlist_node *nx;
0599
0600 ASSERT_RTNL();
0601
0602 hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
0603 if (gwj->src.dev == dev || gwj->dst.dev == dev) {
0604 hlist_del(&gwj->list);
0605 cgw_unregister_filter(net, gwj);
0606 call_rcu(&gwj->rcu, cgw_job_free_rcu);
0607 }
0608 }
0609 }
0610
0611 return NOTIFY_DONE;
0612 }
0613
0614 static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
0615 u32 pid, u32 seq, int flags)
0616 {
0617 struct rtcanmsg *rtcan;
0618 struct nlmsghdr *nlh;
0619
0620 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtcan), flags);
0621 if (!nlh)
0622 return -EMSGSIZE;
0623
0624 rtcan = nlmsg_data(nlh);
0625 rtcan->can_family = AF_CAN;
0626 rtcan->gwtype = gwj->gwtype;
0627 rtcan->flags = gwj->flags;
0628
0629
0630
0631 if (gwj->handled_frames) {
0632 if (nla_put_u32(skb, CGW_HANDLED, gwj->handled_frames) < 0)
0633 goto cancel;
0634 }
0635
0636 if (gwj->dropped_frames) {
0637 if (nla_put_u32(skb, CGW_DROPPED, gwj->dropped_frames) < 0)
0638 goto cancel;
0639 }
0640
0641 if (gwj->deleted_frames) {
0642 if (nla_put_u32(skb, CGW_DELETED, gwj->deleted_frames) < 0)
0643 goto cancel;
0644 }
0645
0646
0647
0648 if (gwj->limit_hops) {
0649 if (nla_put_u8(skb, CGW_LIM_HOPS, gwj->limit_hops) < 0)
0650 goto cancel;
0651 }
0652
0653 if (gwj->flags & CGW_FLAGS_CAN_FD) {
0654 struct cgw_fdframe_mod mb;
0655
0656 if (gwj->mod.modtype.and) {
0657 memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf));
0658 mb.modtype = gwj->mod.modtype.and;
0659 if (nla_put(skb, CGW_FDMOD_AND, sizeof(mb), &mb) < 0)
0660 goto cancel;
0661 }
0662
0663 if (gwj->mod.modtype.or) {
0664 memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf));
0665 mb.modtype = gwj->mod.modtype.or;
0666 if (nla_put(skb, CGW_FDMOD_OR, sizeof(mb), &mb) < 0)
0667 goto cancel;
0668 }
0669
0670 if (gwj->mod.modtype.xor) {
0671 memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf));
0672 mb.modtype = gwj->mod.modtype.xor;
0673 if (nla_put(skb, CGW_FDMOD_XOR, sizeof(mb), &mb) < 0)
0674 goto cancel;
0675 }
0676
0677 if (gwj->mod.modtype.set) {
0678 memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf));
0679 mb.modtype = gwj->mod.modtype.set;
0680 if (nla_put(skb, CGW_FDMOD_SET, sizeof(mb), &mb) < 0)
0681 goto cancel;
0682 }
0683 } else {
0684 struct cgw_frame_mod mb;
0685
0686 if (gwj->mod.modtype.and) {
0687 memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf));
0688 mb.modtype = gwj->mod.modtype.and;
0689 if (nla_put(skb, CGW_MOD_AND, sizeof(mb), &mb) < 0)
0690 goto cancel;
0691 }
0692
0693 if (gwj->mod.modtype.or) {
0694 memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf));
0695 mb.modtype = gwj->mod.modtype.or;
0696 if (nla_put(skb, CGW_MOD_OR, sizeof(mb), &mb) < 0)
0697 goto cancel;
0698 }
0699
0700 if (gwj->mod.modtype.xor) {
0701 memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf));
0702 mb.modtype = gwj->mod.modtype.xor;
0703 if (nla_put(skb, CGW_MOD_XOR, sizeof(mb), &mb) < 0)
0704 goto cancel;
0705 }
0706
0707 if (gwj->mod.modtype.set) {
0708 memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf));
0709 mb.modtype = gwj->mod.modtype.set;
0710 if (nla_put(skb, CGW_MOD_SET, sizeof(mb), &mb) < 0)
0711 goto cancel;
0712 }
0713 }
0714
0715 if (gwj->mod.uid) {
0716 if (nla_put_u32(skb, CGW_MOD_UID, gwj->mod.uid) < 0)
0717 goto cancel;
0718 }
0719
0720 if (gwj->mod.csumfunc.crc8) {
0721 if (nla_put(skb, CGW_CS_CRC8, CGW_CS_CRC8_LEN,
0722 &gwj->mod.csum.crc8) < 0)
0723 goto cancel;
0724 }
0725
0726 if (gwj->mod.csumfunc.xor) {
0727 if (nla_put(skb, CGW_CS_XOR, CGW_CS_XOR_LEN,
0728 &gwj->mod.csum.xor) < 0)
0729 goto cancel;
0730 }
0731
0732 if (gwj->gwtype == CGW_TYPE_CAN_CAN) {
0733 if (gwj->ccgw.filter.can_id || gwj->ccgw.filter.can_mask) {
0734 if (nla_put(skb, CGW_FILTER, sizeof(struct can_filter),
0735 &gwj->ccgw.filter) < 0)
0736 goto cancel;
0737 }
0738
0739 if (nla_put_u32(skb, CGW_SRC_IF, gwj->ccgw.src_idx) < 0)
0740 goto cancel;
0741
0742 if (nla_put_u32(skb, CGW_DST_IF, gwj->ccgw.dst_idx) < 0)
0743 goto cancel;
0744 }
0745
0746 nlmsg_end(skb, nlh);
0747 return 0;
0748
0749 cancel:
0750 nlmsg_cancel(skb, nlh);
0751 return -EMSGSIZE;
0752 }
0753
0754
0755 static int cgw_dump_jobs(struct sk_buff *skb, struct netlink_callback *cb)
0756 {
0757 struct net *net = sock_net(skb->sk);
0758 struct cgw_job *gwj = NULL;
0759 int idx = 0;
0760 int s_idx = cb->args[0];
0761
0762 rcu_read_lock();
0763 hlist_for_each_entry_rcu(gwj, &net->can.cgw_list, list) {
0764 if (idx < s_idx)
0765 goto cont;
0766
0767 if (cgw_put_job(skb, gwj, RTM_NEWROUTE,
0768 NETLINK_CB(cb->skb).portid,
0769 cb->nlh->nlmsg_seq, NLM_F_MULTI) < 0)
0770 break;
0771 cont:
0772 idx++;
0773 }
0774 rcu_read_unlock();
0775
0776 cb->args[0] = idx;
0777
0778 return skb->len;
0779 }
0780
0781 static const struct nla_policy cgw_policy[CGW_MAX + 1] = {
0782 [CGW_MOD_AND] = { .len = sizeof(struct cgw_frame_mod) },
0783 [CGW_MOD_OR] = { .len = sizeof(struct cgw_frame_mod) },
0784 [CGW_MOD_XOR] = { .len = sizeof(struct cgw_frame_mod) },
0785 [CGW_MOD_SET] = { .len = sizeof(struct cgw_frame_mod) },
0786 [CGW_CS_XOR] = { .len = sizeof(struct cgw_csum_xor) },
0787 [CGW_CS_CRC8] = { .len = sizeof(struct cgw_csum_crc8) },
0788 [CGW_SRC_IF] = { .type = NLA_U32 },
0789 [CGW_DST_IF] = { .type = NLA_U32 },
0790 [CGW_FILTER] = { .len = sizeof(struct can_filter) },
0791 [CGW_LIM_HOPS] = { .type = NLA_U8 },
0792 [CGW_MOD_UID] = { .type = NLA_U32 },
0793 [CGW_FDMOD_AND] = { .len = sizeof(struct cgw_fdframe_mod) },
0794 [CGW_FDMOD_OR] = { .len = sizeof(struct cgw_fdframe_mod) },
0795 [CGW_FDMOD_XOR] = { .len = sizeof(struct cgw_fdframe_mod) },
0796 [CGW_FDMOD_SET] = { .len = sizeof(struct cgw_fdframe_mod) },
0797 };
0798
0799
0800 static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
0801 u8 gwtype, void *gwtypeattr, u8 *limhops)
0802 {
0803 struct nlattr *tb[CGW_MAX + 1];
0804 struct rtcanmsg *r = nlmsg_data(nlh);
0805 int modidx = 0;
0806 int err = 0;
0807
0808
0809 memset(mod, 0, sizeof(*mod));
0810
0811 err = nlmsg_parse_deprecated(nlh, sizeof(struct rtcanmsg), tb,
0812 CGW_MAX, cgw_policy, NULL);
0813 if (err < 0)
0814 return err;
0815
0816 if (tb[CGW_LIM_HOPS]) {
0817 *limhops = nla_get_u8(tb[CGW_LIM_HOPS]);
0818
0819 if (*limhops < 1 || *limhops > max_hops)
0820 return -EINVAL;
0821 }
0822
0823
0824 if (r->flags & CGW_FLAGS_CAN_FD) {
0825 struct cgw_fdframe_mod mb;
0826
0827 if (tb[CGW_FDMOD_AND]) {
0828 nla_memcpy(&mb, tb[CGW_FDMOD_AND], CGW_FDMODATTR_LEN);
0829
0830 canfdframecpy(&mod->modframe.and, &mb.cf);
0831 mod->modtype.and = mb.modtype;
0832
0833 if (mb.modtype & CGW_MOD_ID)
0834 mod->modfunc[modidx++] = mod_and_id;
0835
0836 if (mb.modtype & CGW_MOD_LEN)
0837 mod->modfunc[modidx++] = mod_and_len;
0838
0839 if (mb.modtype & CGW_MOD_FLAGS)
0840 mod->modfunc[modidx++] = mod_and_flags;
0841
0842 if (mb.modtype & CGW_MOD_DATA)
0843 mod->modfunc[modidx++] = mod_and_fddata;
0844 }
0845
0846 if (tb[CGW_FDMOD_OR]) {
0847 nla_memcpy(&mb, tb[CGW_FDMOD_OR], CGW_FDMODATTR_LEN);
0848
0849 canfdframecpy(&mod->modframe.or, &mb.cf);
0850 mod->modtype.or = mb.modtype;
0851
0852 if (mb.modtype & CGW_MOD_ID)
0853 mod->modfunc[modidx++] = mod_or_id;
0854
0855 if (mb.modtype & CGW_MOD_LEN)
0856 mod->modfunc[modidx++] = mod_or_len;
0857
0858 if (mb.modtype & CGW_MOD_FLAGS)
0859 mod->modfunc[modidx++] = mod_or_flags;
0860
0861 if (mb.modtype & CGW_MOD_DATA)
0862 mod->modfunc[modidx++] = mod_or_fddata;
0863 }
0864
0865 if (tb[CGW_FDMOD_XOR]) {
0866 nla_memcpy(&mb, tb[CGW_FDMOD_XOR], CGW_FDMODATTR_LEN);
0867
0868 canfdframecpy(&mod->modframe.xor, &mb.cf);
0869 mod->modtype.xor = mb.modtype;
0870
0871 if (mb.modtype & CGW_MOD_ID)
0872 mod->modfunc[modidx++] = mod_xor_id;
0873
0874 if (mb.modtype & CGW_MOD_LEN)
0875 mod->modfunc[modidx++] = mod_xor_len;
0876
0877 if (mb.modtype & CGW_MOD_FLAGS)
0878 mod->modfunc[modidx++] = mod_xor_flags;
0879
0880 if (mb.modtype & CGW_MOD_DATA)
0881 mod->modfunc[modidx++] = mod_xor_fddata;
0882 }
0883
0884 if (tb[CGW_FDMOD_SET]) {
0885 nla_memcpy(&mb, tb[CGW_FDMOD_SET], CGW_FDMODATTR_LEN);
0886
0887 canfdframecpy(&mod->modframe.set, &mb.cf);
0888 mod->modtype.set = mb.modtype;
0889
0890 if (mb.modtype & CGW_MOD_ID)
0891 mod->modfunc[modidx++] = mod_set_id;
0892
0893 if (mb.modtype & CGW_MOD_LEN)
0894 mod->modfunc[modidx++] = mod_set_len;
0895
0896 if (mb.modtype & CGW_MOD_FLAGS)
0897 mod->modfunc[modidx++] = mod_set_flags;
0898
0899 if (mb.modtype & CGW_MOD_DATA)
0900 mod->modfunc[modidx++] = mod_set_fddata;
0901 }
0902 } else {
0903 struct cgw_frame_mod mb;
0904
0905 if (tb[CGW_MOD_AND]) {
0906 nla_memcpy(&mb, tb[CGW_MOD_AND], CGW_MODATTR_LEN);
0907
0908 canframecpy(&mod->modframe.and, &mb.cf);
0909 mod->modtype.and = mb.modtype;
0910
0911 if (mb.modtype & CGW_MOD_ID)
0912 mod->modfunc[modidx++] = mod_and_id;
0913
0914 if (mb.modtype & CGW_MOD_DLC)
0915 mod->modfunc[modidx++] = mod_and_ccdlc;
0916
0917 if (mb.modtype & CGW_MOD_DATA)
0918 mod->modfunc[modidx++] = mod_and_data;
0919 }
0920
0921 if (tb[CGW_MOD_OR]) {
0922 nla_memcpy(&mb, tb[CGW_MOD_OR], CGW_MODATTR_LEN);
0923
0924 canframecpy(&mod->modframe.or, &mb.cf);
0925 mod->modtype.or = mb.modtype;
0926
0927 if (mb.modtype & CGW_MOD_ID)
0928 mod->modfunc[modidx++] = mod_or_id;
0929
0930 if (mb.modtype & CGW_MOD_DLC)
0931 mod->modfunc[modidx++] = mod_or_ccdlc;
0932
0933 if (mb.modtype & CGW_MOD_DATA)
0934 mod->modfunc[modidx++] = mod_or_data;
0935 }
0936
0937 if (tb[CGW_MOD_XOR]) {
0938 nla_memcpy(&mb, tb[CGW_MOD_XOR], CGW_MODATTR_LEN);
0939
0940 canframecpy(&mod->modframe.xor, &mb.cf);
0941 mod->modtype.xor = mb.modtype;
0942
0943 if (mb.modtype & CGW_MOD_ID)
0944 mod->modfunc[modidx++] = mod_xor_id;
0945
0946 if (mb.modtype & CGW_MOD_DLC)
0947 mod->modfunc[modidx++] = mod_xor_ccdlc;
0948
0949 if (mb.modtype & CGW_MOD_DATA)
0950 mod->modfunc[modidx++] = mod_xor_data;
0951 }
0952
0953 if (tb[CGW_MOD_SET]) {
0954 nla_memcpy(&mb, tb[CGW_MOD_SET], CGW_MODATTR_LEN);
0955
0956 canframecpy(&mod->modframe.set, &mb.cf);
0957 mod->modtype.set = mb.modtype;
0958
0959 if (mb.modtype & CGW_MOD_ID)
0960 mod->modfunc[modidx++] = mod_set_id;
0961
0962 if (mb.modtype & CGW_MOD_DLC)
0963 mod->modfunc[modidx++] = mod_set_ccdlc;
0964
0965 if (mb.modtype & CGW_MOD_DATA)
0966 mod->modfunc[modidx++] = mod_set_data;
0967 }
0968 }
0969
0970
0971 if (modidx) {
0972 if (tb[CGW_CS_CRC8]) {
0973 struct cgw_csum_crc8 *c = nla_data(tb[CGW_CS_CRC8]);
0974
0975 err = cgw_chk_csum_parms(c->from_idx, c->to_idx,
0976 c->result_idx, r);
0977 if (err)
0978 return err;
0979
0980 nla_memcpy(&mod->csum.crc8, tb[CGW_CS_CRC8],
0981 CGW_CS_CRC8_LEN);
0982
0983
0984
0985
0986 if (c->from_idx < 0 || c->to_idx < 0 ||
0987 c->result_idx < 0)
0988 mod->csumfunc.crc8 = cgw_csum_crc8_rel;
0989 else if (c->from_idx <= c->to_idx)
0990 mod->csumfunc.crc8 = cgw_csum_crc8_pos;
0991 else
0992 mod->csumfunc.crc8 = cgw_csum_crc8_neg;
0993 }
0994
0995 if (tb[CGW_CS_XOR]) {
0996 struct cgw_csum_xor *c = nla_data(tb[CGW_CS_XOR]);
0997
0998 err = cgw_chk_csum_parms(c->from_idx, c->to_idx,
0999 c->result_idx, r);
1000 if (err)
1001 return err;
1002
1003 nla_memcpy(&mod->csum.xor, tb[CGW_CS_XOR],
1004 CGW_CS_XOR_LEN);
1005
1006
1007
1008
1009 if (c->from_idx < 0 || c->to_idx < 0 ||
1010 c->result_idx < 0)
1011 mod->csumfunc.xor = cgw_csum_xor_rel;
1012 else if (c->from_idx <= c->to_idx)
1013 mod->csumfunc.xor = cgw_csum_xor_pos;
1014 else
1015 mod->csumfunc.xor = cgw_csum_xor_neg;
1016 }
1017
1018 if (tb[CGW_MOD_UID])
1019 nla_memcpy(&mod->uid, tb[CGW_MOD_UID], sizeof(u32));
1020 }
1021
1022 if (gwtype == CGW_TYPE_CAN_CAN) {
1023
1024 struct can_can_gw *ccgw = (struct can_can_gw *)gwtypeattr;
1025
1026 memset(ccgw, 0, sizeof(*ccgw));
1027
1028
1029 if (tb[CGW_FILTER])
1030 nla_memcpy(&ccgw->filter, tb[CGW_FILTER],
1031 sizeof(struct can_filter));
1032
1033 err = -ENODEV;
1034
1035
1036 if (!tb[CGW_SRC_IF] || !tb[CGW_DST_IF])
1037 return err;
1038
1039 ccgw->src_idx = nla_get_u32(tb[CGW_SRC_IF]);
1040 ccgw->dst_idx = nla_get_u32(tb[CGW_DST_IF]);
1041
1042
1043 if (!ccgw->src_idx && !ccgw->dst_idx)
1044 return 0;
1045
1046
1047 if (!ccgw->src_idx || !ccgw->dst_idx)
1048 return err;
1049 }
1050
1051
1052
1053 return 0;
1054 }
1055
1056 static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
1057 struct netlink_ext_ack *extack)
1058 {
1059 struct net *net = sock_net(skb->sk);
1060 struct rtcanmsg *r;
1061 struct cgw_job *gwj;
1062 struct cf_mod mod;
1063 struct can_can_gw ccgw;
1064 u8 limhops = 0;
1065 int err = 0;
1066
1067 if (!netlink_capable(skb, CAP_NET_ADMIN))
1068 return -EPERM;
1069
1070 if (nlmsg_len(nlh) < sizeof(*r))
1071 return -EINVAL;
1072
1073 r = nlmsg_data(nlh);
1074 if (r->can_family != AF_CAN)
1075 return -EPFNOSUPPORT;
1076
1077
1078 if (r->gwtype != CGW_TYPE_CAN_CAN)
1079 return -EINVAL;
1080
1081 err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops);
1082 if (err < 0)
1083 return err;
1084
1085 if (mod.uid) {
1086 ASSERT_RTNL();
1087
1088
1089 hlist_for_each_entry(gwj, &net->can.cgw_list, list) {
1090 if (gwj->mod.uid != mod.uid)
1091 continue;
1092
1093
1094 if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw)))
1095 return -EINVAL;
1096
1097
1098 local_bh_disable();
1099 memcpy(&gwj->mod, &mod, sizeof(mod));
1100 local_bh_enable();
1101 return 0;
1102 }
1103 }
1104
1105
1106 if (!ccgw.src_idx || !ccgw.dst_idx)
1107 return -ENODEV;
1108
1109 gwj = kmem_cache_alloc(cgw_cache, GFP_KERNEL);
1110 if (!gwj)
1111 return -ENOMEM;
1112
1113 gwj->handled_frames = 0;
1114 gwj->dropped_frames = 0;
1115 gwj->deleted_frames = 0;
1116 gwj->flags = r->flags;
1117 gwj->gwtype = r->gwtype;
1118 gwj->limit_hops = limhops;
1119
1120
1121 memcpy(&gwj->mod, &mod, sizeof(mod));
1122 memcpy(&gwj->ccgw, &ccgw, sizeof(ccgw));
1123
1124 err = -ENODEV;
1125
1126 gwj->src.dev = __dev_get_by_index(net, gwj->ccgw.src_idx);
1127
1128 if (!gwj->src.dev)
1129 goto out;
1130
1131 if (gwj->src.dev->type != ARPHRD_CAN)
1132 goto out;
1133
1134 gwj->dst.dev = __dev_get_by_index(net, gwj->ccgw.dst_idx);
1135
1136 if (!gwj->dst.dev)
1137 goto out;
1138
1139 if (gwj->dst.dev->type != ARPHRD_CAN)
1140 goto out;
1141
1142 ASSERT_RTNL();
1143
1144 err = cgw_register_filter(net, gwj);
1145 if (!err)
1146 hlist_add_head_rcu(&gwj->list, &net->can.cgw_list);
1147 out:
1148 if (err)
1149 kmem_cache_free(cgw_cache, gwj);
1150
1151 return err;
1152 }
1153
1154 static void cgw_remove_all_jobs(struct net *net)
1155 {
1156 struct cgw_job *gwj = NULL;
1157 struct hlist_node *nx;
1158
1159 ASSERT_RTNL();
1160
1161 hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
1162 hlist_del(&gwj->list);
1163 cgw_unregister_filter(net, gwj);
1164 call_rcu(&gwj->rcu, cgw_job_free_rcu);
1165 }
1166 }
1167
1168 static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
1169 struct netlink_ext_ack *extack)
1170 {
1171 struct net *net = sock_net(skb->sk);
1172 struct cgw_job *gwj = NULL;
1173 struct hlist_node *nx;
1174 struct rtcanmsg *r;
1175 struct cf_mod mod;
1176 struct can_can_gw ccgw;
1177 u8 limhops = 0;
1178 int err = 0;
1179
1180 if (!netlink_capable(skb, CAP_NET_ADMIN))
1181 return -EPERM;
1182
1183 if (nlmsg_len(nlh) < sizeof(*r))
1184 return -EINVAL;
1185
1186 r = nlmsg_data(nlh);
1187 if (r->can_family != AF_CAN)
1188 return -EPFNOSUPPORT;
1189
1190
1191 if (r->gwtype != CGW_TYPE_CAN_CAN)
1192 return -EINVAL;
1193
1194 err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops);
1195 if (err < 0)
1196 return err;
1197
1198
1199 if (!ccgw.src_idx && !ccgw.dst_idx) {
1200 cgw_remove_all_jobs(net);
1201 return 0;
1202 }
1203
1204 err = -EINVAL;
1205
1206 ASSERT_RTNL();
1207
1208
1209 hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
1210 if (gwj->flags != r->flags)
1211 continue;
1212
1213 if (gwj->limit_hops != limhops)
1214 continue;
1215
1216
1217 if (gwj->mod.uid || mod.uid) {
1218 if (gwj->mod.uid != mod.uid)
1219 continue;
1220 } else {
1221
1222 if (memcmp(&gwj->mod, &mod, sizeof(mod)))
1223 continue;
1224 }
1225
1226
1227 if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw)))
1228 continue;
1229
1230 hlist_del(&gwj->list);
1231 cgw_unregister_filter(net, gwj);
1232 call_rcu(&gwj->rcu, cgw_job_free_rcu);
1233 err = 0;
1234 break;
1235 }
1236
1237 return err;
1238 }
1239
1240 static int __net_init cangw_pernet_init(struct net *net)
1241 {
1242 INIT_HLIST_HEAD(&net->can.cgw_list);
1243 return 0;
1244 }
1245
1246 static void __net_exit cangw_pernet_exit_batch(struct list_head *net_list)
1247 {
1248 struct net *net;
1249
1250 rtnl_lock();
1251 list_for_each_entry(net, net_list, exit_list)
1252 cgw_remove_all_jobs(net);
1253 rtnl_unlock();
1254 }
1255
1256 static struct pernet_operations cangw_pernet_ops = {
1257 .init = cangw_pernet_init,
1258 .exit_batch = cangw_pernet_exit_batch,
1259 };
1260
1261 static __init int cgw_module_init(void)
1262 {
1263 int ret;
1264
1265
1266 max_hops = clamp_t(unsigned int, max_hops, CGW_MIN_HOPS, CGW_MAX_HOPS);
1267
1268 pr_info("can: netlink gateway - max_hops=%d\n", max_hops);
1269
1270 ret = register_pernet_subsys(&cangw_pernet_ops);
1271 if (ret)
1272 return ret;
1273
1274 ret = -ENOMEM;
1275 cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job),
1276 0, 0, NULL);
1277 if (!cgw_cache)
1278 goto out_cache_create;
1279
1280
1281 notifier.notifier_call = cgw_notifier;
1282 ret = register_netdevice_notifier(¬ifier);
1283 if (ret)
1284 goto out_register_notifier;
1285
1286 ret = rtnl_register_module(THIS_MODULE, PF_CAN, RTM_GETROUTE,
1287 NULL, cgw_dump_jobs, 0);
1288 if (ret)
1289 goto out_rtnl_register1;
1290
1291 ret = rtnl_register_module(THIS_MODULE, PF_CAN, RTM_NEWROUTE,
1292 cgw_create_job, NULL, 0);
1293 if (ret)
1294 goto out_rtnl_register2;
1295 ret = rtnl_register_module(THIS_MODULE, PF_CAN, RTM_DELROUTE,
1296 cgw_remove_job, NULL, 0);
1297 if (ret)
1298 goto out_rtnl_register3;
1299
1300 return 0;
1301
1302 out_rtnl_register3:
1303 rtnl_unregister(PF_CAN, RTM_NEWROUTE);
1304 out_rtnl_register2:
1305 rtnl_unregister(PF_CAN, RTM_GETROUTE);
1306 out_rtnl_register1:
1307 unregister_netdevice_notifier(¬ifier);
1308 out_register_notifier:
1309 kmem_cache_destroy(cgw_cache);
1310 out_cache_create:
1311 unregister_pernet_subsys(&cangw_pernet_ops);
1312
1313 return ret;
1314 }
1315
1316 static __exit void cgw_module_exit(void)
1317 {
1318 rtnl_unregister_all(PF_CAN);
1319
1320 unregister_netdevice_notifier(¬ifier);
1321
1322 unregister_pernet_subsys(&cangw_pernet_ops);
1323 rcu_barrier();
1324
1325 kmem_cache_destroy(cgw_cache);
1326 }
1327
1328 module_init(cgw_module_init);
1329 module_exit(cgw_module_exit);