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; }
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 inline struct bstr * parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj, unsigned long *dst, struct tcf_meta_val *left) { struct meta_entry *entry; unsigned long num; struct bstr *a; if (arg->quoted) { obj->kind = TCF_META_TYPE_VAR << 12; obj->kind |= TCF_META_ID_VALUE; *dst = (unsigned long) arg; return bstr_next(arg); } num = bstrtoul(arg); if (num != ULONG_MAX) { obj->kind = TCF_META_TYPE_INT << 12; obj->kind |= TCF_META_ID_VALUE; *dst = (unsigned long) num; return bstr_next(arg); } entry = lookup_meta_entry(arg); if (entry == NULL) { PARSE_ERR(arg, "meta: unknown meta id\n"); return PARSE_FAILURE; } obj->kind = entry->id | (map_type(entry->mask[0]) << 12); if (left) { struct tcf_meta_val *right = obj; if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind)) goto compatible; if (can_adopt(left) && !can_adopt(right)) { if (is_compatible(left, right)) left->kind = overwrite_type(left, right); else goto not_compatible; } else if (can_adopt(right) && !can_adopt(left)) { if (is_compatible(right, left)) right->kind = overwrite_type(right, left); else goto not_compatible; } else if (can_adopt(left) && can_adopt(right)) { if (is_compatible(left, right)) left->kind = overwrite_type(left, right); else if (is_compatible(right, left)) right->kind = overwrite_type(right, left); else goto not_compatible; } else goto not_compatible; } compatible: a = bstr_next(arg); while(a) { if (!bstrcmp(a, "shift")) { unsigned long shift; if (a->next == NULL) { PARSE_ERR(a, "meta: missing argument"); return PARSE_FAILURE; } a = bstr_next(a); shift = bstrtoul(a); if (shift == ULONG_MAX) { PARSE_ERR(a, "meta: invalid shift, must " \ "be numeric"); return PARSE_FAILURE; } obj->shift = (__u8) shift; a = bstr_next(a); } else if (!bstrcmp(a, "mask")) { unsigned long mask; if (a->next == NULL) { PARSE_ERR(a, "meta: missing argument"); return PARSE_FAILURE; } a = bstr_next(a); mask = bstrtoul(a); if (mask == ULONG_MAX) { PARSE_ERR(a, "meta: invalid mask, must be " \ "numeric"); return PARSE_FAILURE; } *dst = (unsigned long) mask; a = bstr_next(a); } else break; } return a; not_compatible: PARSE_ERR(arg, "lvalue and rvalue are not compatible."); return PARSE_FAILURE; }
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; }