[PATCH] can: ip: support hw-filter setting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Oliver Hartkopp <socketcan@xxxxxxxxxxxx>

Signed-off-by: Oliver Hartkopp <socketcan@xxxxxxxxxxxx>
---

Just for refernce, this patch can be used on latest iproute2 when
testing the hardware filtering support. It is based on
https://marc.info/?l=linux-can&m=151949929522529 but rebased to latest
master, where other new flags have been introduced.

 include/uapi/linux/can/netlink.h |  1 +
 ip/iplink_can.c                  | 82 +++++++++++++++++++++++++++++---
 2 files changed, 77 insertions(+), 6 deletions(-)

diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h
index 8ec98c21..0f6d0bf6 100644
--- a/include/uapi/linux/can/netlink.h
+++ b/include/uapi/linux/can/netlink.h
@@ -138,6 +138,7 @@ enum {
 	IFLA_CAN_BITRATE_MAX,
 	IFLA_CAN_TDC,
 	IFLA_CAN_CTRLMODE_EXT,
+	IFLA_CAN_HW_FILTER,
 
 	/* add new constants above here */
 	__IFLA_CAN_MAX,
diff --git a/ip/iplink_can.c b/ip/iplink_can.c
index f2967db5..e0b5c8fc 100644
--- a/ip/iplink_can.c
+++ b/ip/iplink_can.c
@@ -8,13 +8,20 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
+#include <linux/can.h>
 #include <linux/can/netlink.h>
 
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
 
+#define CAN_HW_FILTER_MAX 200
+#define CAN_NLMAXLEN (2*sizeof(struct can_bittiming) + \
+		      sizeof(struct can_ctrlmode) + \
+		      CAN_HW_FILTER_MAX*sizeof(struct can_filter))
+
 static void print_usage(FILE *f)
 {
 	fprintf(f,
@@ -42,6 +49,8 @@ static void print_usage(FILE *f)
 		"\n"
 		"\t[ termination { 0..65535 } ]\n"
 		"\n"
+		"\t[ hw-filter can_id:can_mask[,can_id:can_mask]+ ]\n"
+		"\n"
 		"\tWhere: BITRATE	:= { NUMBER in bps }\n"
 		"\t	  SAMPLE-POINT	:= { 0.000..0.999 }\n"
 		"\t	  TQ		:= { NUMBER in ns }\n"
@@ -263,14 +272,14 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
 		} else if (matches(*argv, "restart") == 0) {
 			__u32 val = 1;
 
-			addattr32(n, 1024, IFLA_CAN_RESTART, val);
+			addattr32(n, CAN_NLMAXLEN, IFLA_CAN_RESTART, val);
 		} else if (matches(*argv, "restart-ms") == 0) {
 			__u32 val;
 
 			NEXT_ARG();
 			if (get_u32(&val, *argv, 0))
 				invarg("invalid \"restart-ms\" value\n", *argv);
-			addattr32(n, 1024, IFLA_CAN_RESTART_MS, val);
+			addattr32(n, CAN_NLMAXLEN, IFLA_CAN_RESTART_MS, val);
 		} else if (matches(*argv, "termination") == 0) {
 			__u16 val;
 
@@ -278,7 +287,68 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
 			if (get_u16(&val, *argv, 0))
 				invarg("invalid \"termination\" value\n",
 				       *argv);
-			addattr16(n, 1024, IFLA_CAN_TERMINATION, val);
+			addattr16(n, CAN_NLMAXLEN, IFLA_CAN_TERMINATION, val);
+		} else if (matches(*argv, "hw-filter") == 0) {
+			struct can_filter cfi;
+			struct can_filter *cfi_msg;
+			char *ptr, *nptr;
+			unsigned int num_cfi = 0;
+			unsigned int i = 0;
+
+			NEXT_ARG();
+
+			/* dry run to get the number of valid filters */
+			ptr = *argv;
+			if (sscanf(ptr, "%x:%x", &cfi.can_id, &cfi.can_mask) == 2)
+				num_cfi++;
+			else
+				invarg("invalid \"hw-filter\" value\n", *argv);
+
+			nptr = strchr(ptr, ','); /* check for next filter */
+			while (nptr && num_cfi < CAN_HW_FILTER_MAX) {
+
+				ptr = nptr+1; /* hop behind the ',' */
+				nptr = strchr(ptr, ','); /* update exit condition */
+
+				if (sscanf(ptr, "%x:%x", &cfi.can_id, &cfi.can_mask) == 2)
+					num_cfi++;
+				else
+					invarg("invalid \"hw-filter\" value\n", *argv);
+			}
+
+			cfi_msg = malloc(num_cfi * sizeof(cfi));
+			if (!cfi_msg) {
+				perror("CAN hw-filter malloc");
+				return -ENOMEM;
+			}
+
+			/* second run to really fill the filter message */
+			ptr = *argv;
+			if (sscanf(ptr, "%x:%x", &cfi_msg[i].can_id, &cfi_msg[i].can_mask) == 2)
+				i++;
+			else
+				invarg("invalid \"hw-filter\" value\n", *argv);
+
+			nptr = strchr(ptr, ','); /* check for next filter */
+			while (nptr && i < CAN_HW_FILTER_MAX) {
+
+				ptr = nptr+1; /* hop behind the ',' */
+				nptr = strchr(ptr, ','); /* update exit condition */
+
+				if (sscanf(ptr, "%x:%x", &cfi_msg[i].can_id, &cfi_msg[i].can_mask) == 2)
+					i++;
+				else
+					invarg("invalid \"hw-filter\" value\n", *argv);
+			}
+
+			/* double check the second scan result */
+			if (num_cfi != i) {
+				printf("CAN hw-filter: second filter scan failed.\n");
+				return -EINVAL;
+			}
+
+			addattr_l(n, CAN_NLMAXLEN, IFLA_CAN_HW_FILTER, cfi_msg, num_cfi * sizeof(cfi));
+			free(cfi_msg);
 		} else if (matches(*argv, "help") == 0) {
 			usage();
 			return -1;
@@ -291,11 +361,11 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
 	}
 
 	if (bt.bitrate || bt.tq)
-		addattr_l(n, 1024, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
+		addattr_l(n, CAN_NLMAXLEN, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
 	if (dbt.bitrate || dbt.tq)
-		addattr_l(n, 1024, IFLA_CAN_DATA_BITTIMING, &dbt, sizeof(dbt));
+		addattr_l(n, CAN_NLMAXLEN, IFLA_CAN_DATA_BITTIMING, &dbt, sizeof(dbt));
 	if (cm.mask)
-		addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));
+		addattr_l(n, CAN_NLMAXLEN, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));
 
 	if (tdcv != -1 || tdco != -1 || tdcf != -1) {
 		tdc = addattr_nest(n, 1024, IFLA_CAN_TDC | NLA_F_NESTED);
-- 
2.41.0




[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux