return 0;
}
+void printfilter(const void *data)
+{
+ struct can_filter *filter = (struct can_filter *)data;
+
+ printf("-f %X:%X ", filter->can_id, filter->can_mask);
+}
+
+void printmod(const char *type, const void *data)
+{
+ struct modattr mod;
+ int i;
+
+ memcpy (&mod, data, CGW_MODATTR_LEN);
+
+ printf("-m %s:", type);
+
+ if (mod.modtype & CGW_MOD_ID)
+ printf("I");
+
+ if (mod.modtype & CGW_MOD_DLC)
+ printf("L");
+
+ if (mod.modtype & CGW_MOD_DATA)
+ printf("D");
+
+ printf(":%X.%X.", mod.cf.can_id, mod.cf.can_dlc);
+
+ for (i = 0; i < 8; i++)
+ printf("%02X", mod.cf.data[i]);
+
+ printf(" ");
+}
+
+
void print_usage(char *prg)
{
fprintf(stderr, "\nUsage: %s [options]\n\n", prg);
fprintf(stderr, "Commands: -A (add a new rule)\n");
fprintf(stderr, " -D (delete a rule)\n");
fprintf(stderr, " -F (flush - delete all rules) [not yet implemented]\n");
- fprintf(stderr, " -L (list all rules) [not yet implemented]\n");
+ fprintf(stderr, " -L (list all rules)\n");
fprintf(stderr, "Mandatory: -s <src_dev> (source netdevice)\n");
fprintf(stderr, " -d <dst_dev> (destination netdevice)\n");
fprintf(stderr, "Options: -t (preserve src_dev rx timestamp)\n");
} req;
char rxbuf[8192]; /* netlink receive buffer */
+ char ifname[IF_NAMESIZE]; /* internface name for if_indextoname() */
struct nlmsghdr *nlh;
struct nlmsgerr *rte;
+ struct rtcanmsg *rtc;
+ struct rtattr *rta;
+ __u32 handled = 0;
+ __u32 dropped = 0;
+ int rtlen;
+ int len;
struct can_filter filter;
struct sockaddr_nl nladdr;
}
}
- if ((argc - optind != 0) || (cmd == UNSPEC) ||
- (!req.rtcan.src_ifindex) || (!req.rtcan.dst_ifindex)) {
+ if ((argc - optind != 0) || (cmd == UNSPEC)) {
+ print_usage(basename(argv[0]));
+ exit(1);
+ }
+
+ if ((cmd == ADD || cmd == DEL) &&
+ ((!req.rtcan.src_ifindex) || (!req.rtcan.dst_ifindex))) {
print_usage(basename(argv[0]));
exit(1);
}
req.nh.nlmsg_type = RTM_DELROUTE;
break;
+ case LIST:
+ req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ req.nh.nlmsg_type = RTM_GETROUTE;
+ break;
+
default:
printf("This function is not yet implemented.\n");
exit(1);
if (have_filter)
addattr_l(&req.nh, sizeof(req), CGW_FILTER, &filter, sizeof(filter));
- // a better example code
- // modmsg.modtype = CGW_MOD_ID;
- // addattr_l(&req.n, sizeof(req), CGW_MOD_SET, &modmsg, CGW_MODATTR_LEN);
+ /*
+ * a better example code
+ * modmsg.modtype = CGW_MOD_ID;
+ * addattr_l(&req.n, sizeof(req), CGW_MOD_SET, &modmsg, CGW_MODATTR_LEN);
+ */
/* add up to CGW_MOD_FUNCS modification definitions */
for (i = 0; i < modidx; i++)
return err;
}
- // clean netlink receive buffer
+ /* clean netlink receive buffer */
bzero(rxbuf, sizeof(rxbuf));
if (cmd == ADD || cmd == DEL) {
err = rte->error;
if (err < 0)
fprintf(stderr, "netlink error %d (%s)\n", err, strerror(abs(err)));
+
+ } else {
+
+ /* cmd == LIST (for now) */
+
+ while (1) {
+ len = recv(s, &rxbuf, sizeof(rxbuf), 0);
+ if (len < 0) {
+ perror("netlink recv");
+ return len;
+ }
+ nlh = (struct nlmsghdr *)rxbuf;
+ if (nlh->nlmsg_type == NLMSG_DONE)
+ break;
+
+ rtc = (struct rtcanmsg *)NLMSG_DATA(nlh);
+ if (rtc->can_family != AF_CAN) {
+ printf("received msg from unknown family %d\n", rtc->can_family);
+ return -EINVAL;
+ }
+
+ /*
+ * print list in a representation that
+ * can be used directly for start scripts
+ */
+
+ printf("%s -A ", basename(argv[0]));
+ printf("-s %s ", if_indextoname(rtc->src_ifindex, ifname));
+ printf("-d %s ", if_indextoname(rtc->dst_ifindex, ifname));
+
+ if (rtc->can_txflags & CAN_GW_TXFLAGS_ECHO)
+ printf("-e ");
+
+ if (rtc->can_txflags & CAN_GW_TXFLAGS_SRC_TSTAMP)
+ printf("-t ");
+
+ /* check for attributes */
+ rta = (struct rtattr *) RTM_RTA(rtc);
+ rtlen = RTM_PAYLOAD(nlh);
+ for(;RTA_OK(rta, rtlen);rta=RTA_NEXT(rta,rtlen))
+ {
+ switch(rta->rta_type) {
+
+ case CGW_FILTER:
+ printfilter(RTA_DATA(rta));
+ break;
+
+ case CGW_MOD_AND:
+ printmod("AND", RTA_DATA(rta));
+ break;
+
+ case CGW_MOD_OR:
+ printmod("OR", RTA_DATA(rta));
+ break;
+
+ case CGW_MOD_XOR:
+ printmod("XOR", RTA_DATA(rta));
+ break;
+
+ case CGW_MOD_SET:
+ printmod("SET", RTA_DATA(rta));
+ break;
+
+ case CGW_HANDLED:
+ handled = *(__u32 *)RTA_DATA(rta);
+ break;
+
+ case CGW_DROPPED:
+ dropped = *(__u32 *)RTA_DATA(rta);
+ break;
+
+ default:
+ printf("Unknown attribute %d!", rta->rta_type);
+ return -EINVAL;
+ break;
+ }
+ }
+
+ printf("# %d handled %d dropped\n", handled, dropped); /* end of entry */
+ }
}
close(s);
#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
RCSID("$Id$");
-#define CAN_GW_VERSION "20100218"
+#define CAN_GW_VERSION "20100222"
static __initdata const char banner[] =
KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n";
struct can_frame xor;
struct can_frame set;
} modframe;
+ struct {
+ u8 and;
+ u8 or;
+ u8 xor;
+ u8 set;
+ } modtype;
void (*modfunc[MAX_MODFUNCTIONS])(struct can_frame *cf,
struct can_can_gw *mod);
};
if (skb->sk == GW_SK_MAGIC)
return;
- if (!netif_running(gwj->dst_dev)) {
+ if (!(gwj->dst_dev->flags & IFF_UP)) {
gwj->dropped_frames++;
return;
}
return NOTIFY_DONE;
}
-/*
- * Dump information about all ports, in response to GETROUTE
- */
+static int gw_put_job(struct sk_buff *skb, struct gw_job *gwj)
+{
+ struct {
+ struct can_frame cf;
+ u8 modtype;
+ } __attribute__((packed)) mb;
+
+ struct rtcanmsg *rtcan;
+ struct nlmsghdr *nlh = nlmsg_put(skb, 0, 0, 0, sizeof(*rtcan), 0);
+ if (!nlh)
+ return -EMSGSIZE;
+
+ rtcan = nlmsg_data(nlh);
+ rtcan->can_family = AF_CAN;
+ rtcan->src_ifindex = gwj->src_dev->ifindex;
+ rtcan->dst_ifindex = gwj->dst_dev->ifindex;
+ rtcan->can_txflags = 0;
+
+ if (gwj->flags & CAN_TX_ECHO)
+ rtcan->can_txflags |= CAN_GW_TXFLAGS_ECHO;
+
+ if (gwj->flags & CAN_TX_SRC_TSTAMP)
+ rtcan->can_txflags |= CAN_GW_TXFLAGS_SRC_TSTAMP;
+
+ /* check non default settings of attributes */
+ if (gwj->handled_frames) {
+ if (nla_put_u32(skb, CGW_HANDLED, gwj->handled_frames) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(u32));
+ }
+
+ if (gwj->dropped_frames) {
+ if (nla_put_u32(skb, CGW_DROPPED, gwj->dropped_frames) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(u32));
+ }
+
+ if (gwj->ccgw.filter.can_id || gwj->ccgw.filter.can_mask) {
+ if (nla_put(skb, CGW_FILTER, sizeof(struct can_filter),
+ &gwj->ccgw.filter) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN +
+ NLA_ALIGN(sizeof(struct can_filter));
+ }
+
+ if (gwj->ccgw.modtype.and) {
+ memcpy(&mb.cf, &gwj->ccgw.modframe.and, sizeof(mb.cf));
+ mb.modtype = gwj->ccgw.modtype.and;
+ if (nla_put(skb, CGW_MOD_AND, sizeof(mb), &mb) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(mb));
+ }
+
+ if (gwj->ccgw.modtype.or) {
+ memcpy(&mb.cf, &gwj->ccgw.modframe.or, sizeof(mb.cf));
+ mb.modtype = gwj->ccgw.modtype.or;
+ if (nla_put(skb, CGW_MOD_OR, sizeof(mb), &mb) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(mb));
+ }
+
+ if (gwj->ccgw.modtype.xor) {
+ memcpy(&mb.cf, &gwj->ccgw.modframe.xor, sizeof(mb.cf));
+ mb.modtype = gwj->ccgw.modtype.xor;
+ if (nla_put(skb, CGW_MOD_XOR, sizeof(mb), &mb) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(mb));
+ }
+
+ if (gwj->ccgw.modtype.set) {
+ memcpy(&mb.cf, &gwj->ccgw.modframe.set, sizeof(mb.cf));
+ mb.modtype = gwj->ccgw.modtype.set;
+ if (nla_put(skb, CGW_MOD_SET, sizeof(mb), &mb) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(mb));
+ }
+
+ return skb->len;
+
+cancel:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+}
+
+/* Dump information about all CAN gateway jobs, in response to RTM_GETROUTE */
static int gw_dump_jobs(struct sk_buff *skb, struct netlink_callback *cb)
{
- printk(KERN_INFO "%s (TODO)\n", __FUNCTION__);
+ struct gw_job *gwj = NULL;
+ struct hlist_node *n;
+ int idx = 0;
+ int ret = 0;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(gwj, n, &can_gw_list, list) {
+ if (idx >= cb->args[0]) {
+ ret = gw_put_job(skb, gwj);
+ if (ret > 0)
+ cb->args[0]++;
+ break;
+ }
+ idx++;
+ }
+ rcu_read_unlock();
- return 0;
+ return ret;
}
/* check for attributes / filters for the CAN->CAN gateway */
nla_memcpy(&mb, tb[CGW_MOD_AND], CGW_MODATTR_LEN);
canframecpy(&ccgw->modframe.and, &mb.cf);
+ ccgw->modtype.and = mb.modtype;
if (mb.modtype & CGW_MOD_ID)
ccgw->modfunc[modidx++] = mod_and_id;
nla_memcpy(&mb, tb[CGW_MOD_OR], CGW_MODATTR_LEN);
canframecpy(&ccgw->modframe.or, &mb.cf);
+ ccgw->modtype.or = mb.modtype;
if (mb.modtype & CGW_MOD_ID)
ccgw->modfunc[modidx++] = mod_or_id;
nla_memcpy(&mb, tb[CGW_MOD_XOR], CGW_MODATTR_LEN);
canframecpy(&ccgw->modframe.xor, &mb.cf);
+ ccgw->modtype.xor = mb.modtype;
if (mb.modtype & CGW_MOD_ID)
ccgw->modfunc[modidx++] = mod_xor_id;
nla_memcpy(&mb, tb[CGW_MOD_SET], CGW_MODATTR_LEN);
canframecpy(&ccgw->modframe.set, &mb.cf);
+ ccgw->modtype.set = mb.modtype;
if (mb.modtype & CGW_MOD_ID)
ccgw->modfunc[modidx++] = mod_set_id;
struct gw_job *gwj;
int err = 0;
- printk(KERN_INFO "%s: len %d attrlen %d\n", __FUNCTION__,
- nlmsg_len(nlh), nlmsg_attrlen(nlh, sizeof(*r)));
-
if (nlmsg_len(nlh) < sizeof(*r))
return -EINVAL;
goto put_src_dst_fail;
}
+ gwj->handled_frames = 0;
+ gwj->dropped_frames = 0;
gwj->flags = 0;
if (r->can_txflags & CAN_GW_TXFLAGS_ECHO)
if (err)
goto fail;
- printk(KERN_INFO "%s: added entry %p\n", __FUNCTION__, gwj);
-
return 0;
put_src_dst_fail:
u32 flags = 0;
int err = 0;
- printk(KERN_INFO "%s: len %d attrlen %d\n", __FUNCTION__,
- nlmsg_len(nlh), nlmsg_attrlen(nlh, sizeof(*r)));
-
if (nlmsg_len(nlh) < sizeof(*r))
return -EINVAL;
can_gw_unregister_filter(gwj);
kfree(gwj);
err = 0;
- printk(KERN_INFO "%s: removed entry %p\n", __FUNCTION__, gwj);
break;
}