]> rtime.felk.cvut.cz Git - socketcan-devel.git/blobdiff - can-utils/cangw.c
Rework of help text.
[socketcan-devel.git] / can-utils / cangw.c
index 5e1ddc580c72bd3609a30568ff88263fd12f624e..a3681cf13e8246f9ed67c5ca639550a20ecfcf27 100644 (file)
@@ -50,6 +50,7 @@
 #include <libgen.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 #include <sys/socket.h>
 #include <net/if.h>
 #include <linux/netlink.h>
@@ -94,13 +95,47 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
        return 0;
 }
 
+void printfilter(const void *data)
+{
+       struct can_filter *filter = (struct can_filter *)data;
+
+       printf("-f %03X:%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(":%03X.%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)             [not yet implemented]\n");
-       fprintf(stderr, "           -F (flush - delete all rules)  [not yet implemented]\n");
-       fprintf(stderr, "           -L (list all rules)            [not yet implemented]\n");
+       fprintf(stderr, "           -D (delete a rule)\n");
+       fprintf(stderr, "           -F (flush / delete all rules)\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");
@@ -118,10 +153,10 @@ void print_usage(char *prg)
        fprintf(stderr, " - <can_id> is an u32 value containing the CAN Identifier\n");
        fprintf(stderr, " - <can_dlc> is an u8 value containing the data length code (0 .. 8)\n");
        fprintf(stderr, " - <can_data> is always eight(!) u8 values containing the CAN frames data\n");
-       fprintf(stderr, "The instructions are performed in the order 'AND' -> 'OR' -> 'XOR' -> 'SET'\n");
+       fprintf(stderr, "The max. four modifications are performed in the order AND -> OR -> XOR -> SET\n");
        fprintf(stderr, "\n");
        fprintf(stderr, "Example:\n");
-       fprintf(stderr, "%s -A -s can0 -d vcan3 -f 123:C00007FF -m SET:IL:80000333.4.1122334455667788\n", prg);
+       fprintf(stderr, "%s -A -s can0 -d vcan3 -e -f 123:C00007FF -m SET:IL:333.4.1122334455667788\n", prg);
        fprintf(stderr, "\n");
 }
 
@@ -208,12 +243,23 @@ int main(int argc, char **argv)
        int have_filter = 0;
 
        struct {
-               struct nlmsghdr n;
-               struct rtcanmsg r;
+               struct nlmsghdr nh;
+               struct rtcanmsg rtcan;
                char buf[200];
 
        } 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;
 
@@ -247,19 +293,19 @@ int main(int argc, char **argv)
                        break;
 
                case 's':
-                       req.r.src_ifindex = if_nametoindex(optarg);
+                       req.rtcan.src_ifindex = if_nametoindex(optarg);
                        break;
 
                case 'd':
-                       req.r.dst_ifindex = if_nametoindex(optarg);
+                       req.rtcan.dst_ifindex = if_nametoindex(optarg);
                        break;
 
                case 't':
-                       req.r.can_txflags |= CAN_GW_TXFLAGS_SRC_TSTAMP;
+                       req.rtcan.can_txflags |= CAN_GW_TXFLAGS_SRC_TSTAMP;
                        break;
 
                case 'e':
-                       req.r.can_txflags |= CAN_GW_TXFLAGS_ECHO;
+                       req.rtcan.can_txflags |= CAN_GW_TXFLAGS_ECHO;
                        break;
 
                case 'f':
@@ -294,8 +340,13 @@ int main(int argc, char **argv)
                }
        }
 
-       if ((argc - optind != 0) || (cmd == UNSPEC) ||
-           (!req.r.src_ifindex) || (!req.r.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);
        }
@@ -305,8 +356,26 @@ int main(int argc, char **argv)
        switch (cmd) {
 
        case ADD:
-               req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
-               req.n.nlmsg_type  = RTM_NEWROUTE;
+               req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+               req.nh.nlmsg_type  = RTM_NEWROUTE;
+               break;
+
+       case DEL:
+               req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+               req.nh.nlmsg_type  = RTM_DELROUTE;
+               break;
+
+       case FLUSH:
+               req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+               req.nh.nlmsg_type  = RTM_DELROUTE;
+               /* if_index set to 0 => remove all entries */
+               req.rtcan.src_ifindex  = 0;
+               req.rtcan.dst_ifindex  = 0;
+               break;
+
+       case LIST:
+               req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+               req.nh.nlmsg_type  = RTM_GETROUTE;
                break;
 
        default:
@@ -315,34 +384,144 @@ int main(int argc, char **argv)
                break;
        }
 
-       req.n.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtcanmsg));
-       req.n.nlmsg_seq   = 0;
+       req.nh.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtcanmsg));
+       req.nh.nlmsg_seq   = 0;
 
-       req.r.can_family  = AF_CAN;
+       req.rtcan.can_family  = AF_CAN;
 
        /* add new attributes here */
 
        if (have_filter)
-               addattr_l(&req.n, sizeof(req), CGW_FILTER, &filter, sizeof(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++)
-               addattr_l(&req.n, sizeof(req), modmsg[i].instruction, &modmsg[i], CGW_MODATTR_LEN);
+               addattr_l(&req.nh, sizeof(req), modmsg[i].instruction, &modmsg[i], CGW_MODATTR_LEN);
 
        memset(&nladdr, 0, sizeof(nladdr));
        nladdr.nl_family = AF_NETLINK;
        nladdr.nl_pid    = 0;
        nladdr.nl_groups = 0;
 
-       err = sendto(s, &req, req.n.nlmsg_len, 0,
+       err = sendto(s, &req, req.nh.nlmsg_len, 0,
                     (struct sockaddr*)&nladdr, sizeof(nladdr));
+       if (err < 0) {
+               perror("netlink sendto");
+               return err;
+       }
+
+       /* clean netlink receive buffer */
+       bzero(rxbuf, sizeof(rxbuf));
+
+       if (cmd != LIST) {
+
+               /*
+                * cmd == ADD || cmd == DEL || cmd == FLUSH
+                *
+                * Parse the requested netlink acknowledge return values.
+                */
+
+               err = recv(s, &rxbuf, sizeof(rxbuf), 0);
+               if (err < 0) {
+                       perror("netlink recv");
+                       return err;
+               }
+               nlh = (struct nlmsghdr *)rxbuf;
+               if (nlh->nlmsg_type != NLMSG_ERROR) {
+                       fprintf(stderr, "unexpected netlink answer of type %d\n", nlh->nlmsg_type);
+                       return -EINVAL;
+               }
+               rte = (struct nlmsgerr *)NLMSG_DATA(nlh);
+               err = rte->error;
+               if (err < 0)
+                       fprintf(stderr, "netlink error %d (%s)\n", err, strerror(abs(err)));
+
+       } else {
 
-       if (err < 0)
-               perror("PF_CAN netlink gateway answered ");
+               /* cmd == LIST */
+
+               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);