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