static int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *args) { int opnd; struct bstr *a; struct tcf_meta_hdr meta_hdr; unsigned long lvalue = 0, rvalue = 0; memset(&meta_hdr, 0, sizeof(meta_hdr)); if (args == NULL) return PARSE_ERR(args, "meta: missing arguments"); if (!bstrcmp(args, "list")) { list_meta_ids(stderr); return -1; } a = parse_object(args, args, &meta_hdr.left, &lvalue, NULL); if (a == PARSE_FAILURE) return -1; else if (a == NULL) return PARSE_ERR(args, "meta: missing operand"); if (!bstrcmp(a, "eq")) opnd = TCF_EM_OPND_EQ; else if (!bstrcmp(a, "gt")) opnd = TCF_EM_OPND_GT; else if (!bstrcmp(a, "lt")) opnd = TCF_EM_OPND_LT; else return PARSE_ERR(a, "meta: invalid operand"); meta_hdr.left.op = (__u8) opnd; if (a->next == NULL) return PARSE_ERR(args, "meta: missing rvalue"); a = bstr_next(a); a = parse_object(args, a, &meta_hdr.right, &rvalue, &meta_hdr.left); if (a == PARSE_FAILURE) return -1; else if (a != NULL) return PARSE_ERR(a, "meta: unexpected trailer"); addraw_l(n, MAX_MSG, hdr, sizeof(*hdr)); addattr_l(n, MAX_MSG, TCA_EM_META_HDR, &meta_hdr, sizeof(meta_hdr)); dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left); dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right); return 0; }
static int ipset_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *args) { struct xt_set_info set_info = {}; int ret; #define PARSE_ERR(CARG, FMT, ARGS...) \ em_parse_error(EINVAL, args, CARG, &ipset_ematch_util, FMT, ##ARGS) if (args == NULL) return PARSE_ERR(args, "ipset: missing set name"); if (args->len >= IPSET_MAXNAMELEN) return PARSE_ERR(args, "ipset: set name too long (max %u)", IPSET_MAXNAMELEN - 1); ret = get_set_byname(args->data, &set_info); if (ret < 0) return PARSE_ERR(args, "ipset: unknown set name '%s'", args->data); if (args->next == NULL) return PARSE_ERR(args, "ipset: missing set flags"); args = bstr_next(args); if (parse_dirs(args->data, &set_info)) return PARSE_ERR(args, "ipset: error parsing set flags"); if (args->next) { args = bstr_next(args); return PARSE_ERR(args, "ipset: unknown parameter"); } addraw_l(n, MAX_MSG, hdr, sizeof(*hdr)); addraw_l(n, MAX_MSG, &set_info, sizeof(set_info)); #undef PARSE_ERR return 0; }
static int parse_tree(struct nlmsghdr *n, struct ematch *tree) { int index = 1; struct ematch *t; for (t = tree; t; t = t->next) { struct rtattr *tail = NLMSG_TAIL(n); struct tcf_ematch_hdr hdr = { .flags = t->relation }; if (t->inverted) hdr.flags |= TCF_EM_INVERT; addattr_l(n, MAX_MSG, index++, NULL, 0); if (t->child) { __u32 r = t->child_ref; addraw_l(n, MAX_MSG, &hdr, sizeof(hdr)); addraw_l(n, MAX_MSG, &r, sizeof(r)); } else { int num = 0, err; char buf[64]; struct ematch_util *e; if (t->args == NULL) return -1; strncpy(buf, (char*) t->args->data, sizeof(buf)-1); e = get_ematch_kind(buf); if (e == NULL) { fprintf(stderr, "Unknown ematch \"%s\"\n", buf); return -1; } err = lookup_map_id(buf, &num, EMATCH_MAP); if (err < 0) { if (err == -ENOENT) map_warning(e->kind_num, buf); return err; } hdr.kind = num; if (e->parse_eopt(n, &hdr, t->args->next) < 0) return -1; } tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail; } return 0; } static int flatten_tree(struct ematch *head, struct ematch *tree) { int i, count = 0; struct ematch *t; for (;;) { count++; if (tree->child) { for (t = head; t->next; t = t->next); t->next = tree->child; count += flatten_tree(head, tree->child); } if (tree->relation == 0) break; tree = tree->next; } for (i = 0, t = head; t; t = t->next, i++) t->index = i; for (t = head; t; t = t->next) if (t->child) t->child_ref = t->child->index; return count; }
static int nbyte_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *args) { struct bstr *a; struct bstr *needle = args; unsigned long offset = 0, layer = TCF_LAYER_NETWORK; int offset_present = 0; struct tcf_em_nbyte nb; memset(&nb, 0, sizeof(nb)); #define PARSE_ERR(CARG, FMT, ARGS...) \ em_parse_error(EINVAL, args, CARG, &nbyte_ematch_util, FMT ,##ARGS) if (args == NULL) return PARSE_ERR(args, "nbyte: missing arguments"); if (needle->len <= 0) return PARSE_ERR(args, "nbyte: needle length is 0"); for (a = bstr_next(args); a; a = bstr_next(a)) { if (!bstrcmp(a, "at")) { if (a->next == NULL) return PARSE_ERR(a, "nbyte: missing argument"); a = bstr_next(a); offset = bstrtoul(a); if (offset == ULONG_MAX) return PARSE_ERR(a, "nbyte: invalid offset, " \ "must be numeric"); offset_present = 1; } else if (!bstrcmp(a, "layer")) { if (a->next == NULL) return PARSE_ERR(a, "nbyte: missing argument"); a = bstr_next(a); layer = parse_layer(a); if (layer == INT_MAX) { layer = bstrtoul(a); if (layer == ULONG_MAX) return PARSE_ERR(a, "nbyte: invalid " \ "layer"); } if (layer > TCF_LAYER_MAX) return PARSE_ERR(a, "nbyte: illegal layer, " \ "must be in 0..%d", TCF_LAYER_MAX); } else return PARSE_ERR(a, "nbyte: unknown parameter"); } if (offset_present == 0) return PARSE_ERR(a, "nbyte: offset required"); nb.len = needle->len; nb.layer = (__u8) layer; nb.off = (__u16) offset; addraw_l(n, MAX_MSG, hdr, sizeof(*hdr)); addraw_l(n, MAX_MSG, &nb, sizeof(nb)); addraw_l(n, MAX_MSG, needle->data, needle->len); #undef PARSE_ERR return 0; }
/* Add/Delete IP route to/from a specific interface */ static int netlink_route(ip_route_t *iproute, int cmd) { int status = 1; struct { struct nlmsghdr n; struct rtmsg r; char buf[RTM_SIZE]; } req; char buf[RTA_SIZE]; struct rtattr *rta = (void*)buf; memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); if (cmd == IPROUTE_DEL) { req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELROUTE; } else { req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; if (cmd == IPROUTE_REPLACE) req.n.nlmsg_flags |= NLM_F_REPLACE; req.n.nlmsg_type = RTM_NEWROUTE; } rta->rta_type = RTA_METRICS; rta->rta_len = RTA_LENGTH(0); req.r.rtm_family = iproute->family; if (iproute->table < 256) req.r.rtm_table = iproute->table; else { req.r.rtm_table = RT_TABLE_UNSPEC; addattr32(&req.n, sizeof(req), RTA_TABLE, iproute->table); } if (cmd == IPROUTE_DEL) { req.r.rtm_scope = RT_SCOPE_NOWHERE; if (iproute->mask & IPROUTE_BIT_TYPE) req.r.rtm_type = iproute->type; } else { req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_type = iproute->type; } if (iproute->mask & IPROUTE_BIT_PROTOCOL) req.r.rtm_protocol = iproute->protocol; if (iproute->mask & IPROUTE_BIT_SCOPE) req.r.rtm_scope = iproute->scope; if (iproute->dst) { req.r.rtm_dst_len = iproute->dst->ifa.ifa_prefixlen; add_addr2req(&req.n, sizeof(req), RTA_DST, iproute->dst); } if (iproute->src) { req.r.rtm_src_len = iproute->src->ifa.ifa_prefixlen; add_addr2req(&req.n, sizeof(req), RTA_SRC, iproute->src); } if (iproute->pref_src) add_addr2req(&req.n, sizeof(req), RTA_PREFSRC, iproute->pref_src); //#ifdef _HAVE_RTA_NEWDST_ // if (iproute->as_to) // add_addr2req(&req.n, sizeof(req), RTA_NEWDST, iproute->as_to); //#endif if (iproute->via) { if (iproute->via->ifa.ifa_family == iproute->family) add_addr2req(&req.n, sizeof(req), RTA_GATEWAY, iproute->via); #ifdef _HAVE_RTA_VIA_ else add_addr_fam2req(&req.n, sizeof(req), RTA_VIA, iproute->via); #endif } #ifdef _HAVE_RTA_ENCAP_ if (iproute->encap.type != LWTUNNEL_ENCAP_NONE) { char encap_buf[ENCAP_RTA_SIZE]; struct rtattr *encap_rta = (void *)encap_buf; encap_rta->rta_type = RTA_ENCAP; encap_rta->rta_len = RTA_LENGTH(0); add_encap(encap_rta, sizeof(encap_buf), &iproute->encap); if (encap_rta->rta_len > RTA_LENGTH(0)) addraw_l(&req.n, sizeof(encap_buf), RTA_DATA(encap_rta), RTA_PAYLOAD(encap_rta)); } #endif if (iproute->mask & IPROUTE_BIT_DSFIELD) req.r.rtm_tos = iproute->tos; if (iproute->oif) addattr32(&req.n, sizeof(req), RTA_OIF, iproute->oif->ifindex); if (iproute->mask & IPROUTE_BIT_METRIC) addattr32(&req.n, sizeof(req), RTA_PRIORITY, iproute->metric); req.r.rtm_flags = iproute->flags; if (iproute->realms) addattr32(&req.n, sizeof(req), RTA_FLOW, iproute->realms); #ifdef _HAVE_RTA_EXPIRES_ if (iproute->mask & IPROUTE_BIT_EXPIRES) addattr32(&req.n, sizeof(req), RTA_EXPIRES, iproute->expires); #endif #ifdef RTAX_CC_ALGO if (iproute->congctl) rta_addattr_l(rta, sizeof(buf), RTAX_CC_ALGO, iproute->congctl, strlen(iproute->congctl)); #endif if (iproute->mask & IPROUTE_BIT_RTT) rta_addattr32(rta, sizeof(buf), RTAX_RTT, iproute->rtt); if (iproute->mask & IPROUTE_BIT_RTTVAR) rta_addattr32(rta, sizeof(buf), RTAX_RTTVAR, iproute->rttvar); if (iproute->mask & IPROUTE_BIT_RTO_MIN) rta_addattr32(rta, sizeof(buf), RTAX_RTO_MIN, iproute->rto_min); #ifdef RTAX_FEATURES if (iproute->features) rta_addattr32(rta, sizeof(buf), RTAX_FEATURES, iproute->features); #endif if (iproute->mask & IPROUTE_BIT_MTU) rta_addattr32(rta, sizeof(buf), RTAX_MTU, iproute->mtu); if (iproute->mask & IPROUTE_BIT_WINDOW) rta_addattr32(rta, sizeof(buf), RTAX_WINDOW, iproute->window); if (iproute->mask & IPROUTE_BIT_SSTHRESH) rta_addattr32(rta, sizeof(buf), RTAX_SSTHRESH, iproute->ssthresh); if (iproute->mask & IPROUTE_BIT_CWND) rta_addattr32(rta, sizeof(buf), RTAX_CWND, iproute->cwnd); if (iproute->mask & IPROUTE_BIT_ADVMSS) rta_addattr32(rta, sizeof(buf), RTAX_ADVMSS, iproute->advmss); if (iproute->mask & IPROUTE_BIT_REORDERING) rta_addattr32(rta, sizeof(buf), RTAX_REORDERING, iproute->reordering); if (iproute->mask & IPROUTE_BIT_HOPLIMIT) rta_addattr32(rta, sizeof(buf), RTAX_HOPLIMIT, iproute->hoplimit); if (iproute->mask & IPROUTE_BIT_INITCWND) rta_addattr32(rta, sizeof(buf), RTAX_INITCWND, iproute->initcwnd); #ifdef RTAX_INITRWND if (iproute->mask & IPROUTE_BIT_INITRWND) rta_addattr32(rta, sizeof(buf), RTAX_INITRWND, iproute->initrwnd); #endif #ifdef RTAX_QUICKACK if (iproute->mask & IPROUTE_BIT_QUICKACK) rta_addattr32(rta, sizeof(buf), RTAX_QUICKACK, iproute->quickack); #endif #ifdef _HAVE_RTA_PREF_ if (iproute->mask & IPROUTE_BIT_PREF) addattr8(&req.n, sizeof(req), RTA_PREF, iproute->pref); #endif if (rta->rta_len > RTA_LENGTH(0)) { if (iproute->lock) rta_addattr32(rta, sizeof(buf), RTAX_LOCK, iproute->lock); addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(rta), RTA_PAYLOAD(rta)); } if (!LIST_ISEMPTY(iproute->nhs)) add_nexthops(iproute, &req.n, &req.r); #ifdef DEBUG_NETLINK_MSG size_t i, j; uint8_t *p; char lbuf[3072]; char *op = lbuf; log_message(LOG_INFO, "rtmsg buffer used %lu, rtattr buffer used %d", req.n.nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)), rta->rta_len); op += snprintf(op, sizeof(lbuf) - (op - lbuf), "nlmsghdr %p(%u):", &req.n, req.n.nlmsg_len); for (i = 0, p = (uint8_t*)&req.n; i < sizeof(struct nlmsghdr); i++) op += snprintf(op, sizeof(lbuf) - (op - lbuf), " %2.2hhx", *(p++)); log_message(LOG_INFO, "%s\n", lbuf); op = lbuf; op += snprintf(op, sizeof(lbuf) - (op - lbuf), "rtmsg %p(%lu):", &req.r, req.n.nlmsg_len - sizeof(struct nlmsghdr)); for (i = 0, p = (uint8_t*)&req.r; i < + req.n.nlmsg_len - sizeof(struct nlmsghdr); i++) op += snprintf(op, sizeof(lbuf) - (op - lbuf), " %2.2hhx", *(p++)); for (j = 0; lbuf + j < op; j+= MAX_LOG_MSG) log_message(LOG_INFO, "%.*\n", MAX_LOG_MSG, lbuf+j); #endif /* This returns ESRCH if the address of via address doesn't exist */ /* ENETDOWN if dev p33p1.40 for example is down */ if (netlink_talk(&nl_cmd, &req.n) < 0) { #ifdef _HAVE_RTA_EXPIRES_ /* If an expiry was set on the route, it may have disappeared already */ if (cmd != IPADDRESS_DEL || !(iproute->mask & IPROUTE_BIT_EXPIRES)) #endif status = -1; } return status; }
static int cmp_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *args) { struct bstr *a; int align, opnd = 0; unsigned long offset = 0, layer = TCF_LAYER_NETWORK, mask = 0, value = 0; int offset_present = 0, value_present = 0; struct tcf_em_cmp cmp; memset(&cmp, 0, sizeof(cmp)); #define PARSE_ERR(CARG, FMT, ARGS...) \ em_parse_error(EINVAL, args, CARG, &cmp_ematch_util, FMT ,##ARGS) if (args == NULL) return PARSE_ERR(args, "cmp: missing arguments"); if (!bstrcmp(args, "u8")) align = TCF_EM_ALIGN_U8; else if (!bstrcmp(args, "u16")) align = TCF_EM_ALIGN_U16; else if (!bstrcmp(args, "u32")) align = TCF_EM_ALIGN_U32; else return PARSE_ERR(args, "cmp: invalid alignment"); for (a = bstr_next(args); a; a = bstr_next(a)) { if (!bstrcmp(a, "at")) { if (a->next == NULL) return PARSE_ERR(a, "cmp: missing argument"); a = bstr_next(a); offset = bstrtoul(a); if (offset == ULONG_MAX) return PARSE_ERR(a, "cmp: invalid offset, " \ "must be numeric"); offset_present = 1; } else if (!bstrcmp(a, "layer")) { if (a->next == NULL) return PARSE_ERR(a, "cmp: missing argument"); a = bstr_next(a); layer = parse_layer(a); if (layer == INT_MAX) { layer = bstrtoul(a); if (layer == ULONG_MAX) return PARSE_ERR(a, "cmp: invalid " \ "layer"); } if (layer > TCF_LAYER_MAX) return PARSE_ERR(a, "cmp: illegal layer, " \ "must be in 0..%d", TCF_LAYER_MAX); } else if (!bstrcmp(a, "mask")) { if (a->next == NULL) return PARSE_ERR(a, "cmp: missing argument"); a = bstr_next(a); mask = bstrtoul(a); if (mask == ULONG_MAX) return PARSE_ERR(a, "cmp: invalid mask"); } else if (!bstrcmp(a, "trans")) { cmp.flags |= TCF_EM_CMP_TRANS; } else if (!bstrcmp(a, "eq") || !bstrcmp(a, "gt") || !bstrcmp(a, "lt")) { if (!bstrcmp(a, "eq")) opnd = TCF_EM_OPND_EQ; else if (!bstrcmp(a, "gt")) opnd = TCF_EM_OPND_GT; else if (!bstrcmp(a, "lt")) opnd = TCF_EM_OPND_LT; if (a->next == NULL) return PARSE_ERR(a, "cmp: missing argument"); a = bstr_next(a); value = bstrtoul(a); if (value == ULONG_MAX) return PARSE_ERR(a, "cmp: invalid value"); value_present = 1; } else return PARSE_ERR(a, "nbyte: unknown parameter"); } if (offset_present == 0 || value_present == 0) return PARSE_ERR(a, "cmp: offset and value required"); cmp.val = (__u32) value; cmp.mask = (__u32) mask; cmp.off = (__u16) offset; cmp.align = (__u8) align; cmp.layer = (__u8) layer; cmp.opnd = (__u8) opnd; addraw_l(n, MAX_MSG, hdr, sizeof(*hdr)); addraw_l(n, MAX_MSG, &cmp, sizeof(cmp)); #undef PARSE_ERR return 0; }
static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *args) { struct bstr *a; int align, nh_len; unsigned long key, mask, offmask = 0, offset; struct tc_u32_key u_key; memset(&u_key, 0, sizeof(u_key)); #define PARSE_ERR(CARG, FMT, ARGS...) \ em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT ,##ARGS) if (args == NULL) return PARSE_ERR(args, "u32: missing arguments"); if (!bstrcmp(args, "u8")) align = 1; else if (!bstrcmp(args, "u16")) align = 2; else if (!bstrcmp(args, "u32")) align = 4; else return PARSE_ERR(args, "u32: invalid alignment"); a = bstr_next(args); if (a == NULL) return PARSE_ERR(a, "u32: missing key"); key = bstrtoul(a); if (key == ULONG_MAX) return PARSE_ERR(a, "u32: invalid key, must be numeric"); a = bstr_next(a); if (a == NULL) return PARSE_ERR(a, "u32: missing mask"); mask = bstrtoul(a); if (mask == ULONG_MAX) return PARSE_ERR(a, "u32: invalid mask, must be numeric"); a = bstr_next(a); if (a == NULL || bstrcmp(a, "at") != 0) return PARSE_ERR(a, "u32: missing \"at\""); a = bstr_next(a); if (a == NULL) return PARSE_ERR(a, "u32: missing offset"); nh_len = strlen("nexthdr+"); if (a->len > nh_len && !memcmp(a->data, "nexthdr+", nh_len)) { char buf[a->len - nh_len + 1]; offmask = -1; memcpy(buf, a->data + nh_len, a->len - nh_len); offset = strtoul(buf, NULL, 0); } else if (!bstrcmp(a, "nexthdr+")) { a = bstr_next(a); if (a == NULL) return PARSE_ERR(a, "u32: missing offset"); offset = bstrtoul(a); } else offset = bstrtoul(a); if (offset == ULONG_MAX) return PARSE_ERR(a, "u32: invalid offset"); if (a->next) return PARSE_ERR(a->next, "u32: unexpected trailer"); switch (align) { case 1: if (key > 0xFF) return PARSE_ERR(a, "Illegal key (>0xFF)"); if (mask > 0xFF) return PARSE_ERR(a, "Illegal mask (>0xFF)"); key <<= 24 - ((offset & 3) * 8); mask <<= 24 - ((offset & 3) * 8); offset &= ~3; break; case 2: if (key > 0xFFFF) return PARSE_ERR(a, "Illegal key (>0xFFFF)"); if (mask > 0xFFFF) return PARSE_ERR(a, "Illegal mask (>0xFFFF)"); if ((offset & 3) == 0) { key <<= 16; mask <<= 16; } offset &= ~3; break; } key = htonl(key); mask = htonl(mask); if (offset % 4) return PARSE_ERR(a, "u32: invalid offset alignment, " \ "must be aligned to 4."); key &= mask; u_key.mask = mask; u_key.val = key; u_key.off = offset; u_key.offmask = offmask; addraw_l(n, MAX_MSG, hdr, sizeof(*hdr)); addraw_l(n, MAX_MSG, &u_key, sizeof(u_key)); #undef PARSE_ERR return 0; }
static int canid_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *args) { int iseff = 0; int ret = 0; struct rules rules = { .rules_capacity = 25, /* Denominator of EM_CANID_RULES_MAX Will be multiplied by 2 to calculate the size for realloc() */ .rules_cnt = 0 }; #define PARSE_ERR(CARG, FMT, ARGS...) \ em_parse_error(EINVAL, args, CARG, &canid_ematch_util, FMT, ##ARGS) if (args == NULL) return PARSE_ERR(args, "canid: missing arguments"); rules.rules_raw = malloc(sizeof(struct can_filter) * rules.rules_capacity); memset(rules.rules_raw, 0, sizeof(struct can_filter) * rules.rules_capacity); do { if (!bstrcmp(args, "sff")) { iseff = 0; } else if (!bstrcmp(args, "eff")) { iseff = 1; } else { ret = PARSE_ERR(args, "canid: invalid key"); goto exit; } args = bstr_next(args); if (args == NULL) { ret = PARSE_ERR(args, "canid: missing argument"); goto exit; } ret = canid_parse_rule(&rules, args, iseff); if (ret == -1) { ret = PARSE_ERR(args, "canid: Improperly formed CAN ID & mask\n"); goto exit; } else if (ret == -2) { ret = PARSE_ERR(args, "canid: Too many arguments on input\n"); goto exit; } } while ((args = bstr_next(args)) != NULL); addraw_l(n, MAX_MSG, hdr, sizeof(*hdr)); addraw_l(n, MAX_MSG, rules.rules_raw, sizeof(struct can_filter) * rules.rules_cnt); #undef PARSE_ERR exit: free(rules.rules_raw); return ret; } static int canid_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data, int data_len) { struct can_filter *conf = data; /* Array with rules */ int rules_count; int i; rules_count = data_len / sizeof(struct can_filter); for (i = 0; i < rules_count; i++) { struct can_filter *pcfltr = &conf[i]; if (pcfltr->can_id & CAN_EFF_FLAG) { if (pcfltr->can_mask == (CAN_EFF_FLAG | CAN_EFF_MASK)) fprintf(fd, "eff 0x%"PRIX32, pcfltr->can_id & CAN_EFF_MASK); else fprintf(fd, "eff 0x%"PRIX32":0x%"PRIX32, pcfltr->can_id & CAN_EFF_MASK, pcfltr->can_mask & CAN_EFF_MASK); } else { if (pcfltr->can_mask == (CAN_EFF_FLAG | CAN_SFF_MASK)) fprintf(fd, "sff 0x%"PRIX32, pcfltr->can_id & CAN_SFF_MASK); else fprintf(fd, "sff 0x%"PRIX32":0x%"PRIX32, pcfltr->can_id & CAN_SFF_MASK, pcfltr->can_mask & CAN_SFF_MASK); } if ((i + 1) < rules_count) fprintf(fd, " "); } return 0; } struct ematch_util canid_ematch_util = { .kind = "canid", .kind_num = TCF_EM_CANID, .parse_eopt = canid_parse_eopt, .print_eopt = canid_print_eopt, .print_usage = canid_print_usage };