/* strtok corrupts the string, so we'll be using this copy instead. */ char str_copy[STR_MAX_LEN]; char *token; int error; if (strlen(str) + 1 > STR_MAX_LEN) { log_err("'%s' is too long for this poor, limited parser...", str); return -EINVAL; } strcpy(str_copy, str); token = strtok(str_copy, "/"); if (!token) { log_err("Cannot parse '%s' as a %s.", str, FORMAT); return -EINVAL; } error = str_to_addr4(token, &prefix_out->addr); if (error) return error; token = strtok(NULL, "/"); if (!token) { prefix_out->len = IPV4_MAX_PREFIX; return 0; } return str_to_u8(token, &prefix_out->len, 0, 32); /* Error msg already printed. */ } #undef STR_MAX_LEN #define STR_MAX_LEN (INET6_ADDRSTRLEN + 1 + 3) /* [addr + null chara] + / + pref len */ int str_to_prefix6(const char *str, struct ipv6_prefix *prefix_out) { const char *FORMAT = "<IPv6 address>[/<length>] (eg. 64:ff9b::/96)"; /* strtok corrupts the string, so we'll be using this copy instead. */ char str_copy[STR_MAX_LEN]; char *token; int error; if (strlen(str) + 1 > STR_MAX_LEN) { log_err("'%s' is too long for this poor, limited parser...", str); return -EINVAL; } strcpy(str_copy, str); token = strtok(str_copy, "/"); if (!token) { log_err("Cannot parse '%s' as a %s.", str, FORMAT); return -EINVAL; } error = str_to_addr6(token, &prefix_out->addr); if (error) return error; token = strtok(NULL, "/"); if (!token) { prefix_out->len = IPV6_MAX_PREFIX; return 0; } return str_to_u8(token, &prefix_out->len, 0, 128); /* Error msg already printed. */ }
/* Convert 'str_' (as described in the documentation for the "monitor" command * in the ovs-ofctl man page) into 'fmr'. */ void parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr, const char *str_) { static uint32_t id; char *string = xstrdup(str_); char *save_ptr = NULL; char *name; fmr->id = id++; fmr->flags = (NXFMF_INITIAL | NXFMF_ADD | NXFMF_DELETE | NXFMF_MODIFY | NXFMF_OWN | NXFMF_ACTIONS); fmr->out_port = OFPP_NONE; fmr->table_id = 0xff; match_init_catchall(&fmr->match); for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { const struct protocol *p; if (!strcmp(name, "!initial")) { fmr->flags &= ~NXFMF_INITIAL; } else if (!strcmp(name, "!add")) { fmr->flags &= ~NXFMF_ADD; } else if (!strcmp(name, "!delete")) { fmr->flags &= ~NXFMF_DELETE; } else if (!strcmp(name, "!modify")) { fmr->flags &= ~NXFMF_MODIFY; } else if (!strcmp(name, "!actions")) { fmr->flags &= ~NXFMF_ACTIONS; } else if (!strcmp(name, "!own")) { fmr->flags &= ~NXFMF_OWN; } else if (parse_protocol(name, &p)) { match_set_dl_type(&fmr->match, htons(p->dl_type)); if (p->nw_proto) { match_set_nw_proto(&fmr->match, p->nw_proto); } } else { char *value; value = strtok_r(NULL, ", \t\r\n", &save_ptr); if (!value) { ovs_fatal(0, "%s: field %s missing value", str_, name); } if (!strcmp(name, "table")) { fmr->table_id = str_to_u8(value, name); } else if (!strcmp(name, "out_port")) { fmr->out_port = u16_to_ofp(atoi(value)); } else if (mf_from_name(name)) { parse_field(mf_from_name(name), value, &fmr->match); } else { ovs_fatal(0, "%s: unknown keyword %s", str_, name); } } } free(string); }
static int set_general_u8(struct arguments *args, enum general_module module, __u8 type, char *value, __u8 min, __u8 max) { __u8 tmp; int error; error = str_to_u8(value, &tmp, min, max); if (error) return error; return set_general_arg(args, module, type, sizeof(tmp), &tmp); }
/** * Load subnet array. * @param[in] cfg Config section. * @param[in] option Option name. * @param[in,out] array Resulting array. * @return <0 - error. 0 - success. >0 - not found. */ static int zcfg_load_subnet_list(const config_setting_t *option, zsubnet_group_t *array) { utarray_init(array, &ut_ip_range_icd); if (!option) { return 1; } if (CONFIG_TYPE_LIST != option->type) { return -1; } int count = config_setting_length(option); for (int i = 0; i < count; i++) { ip_range_t range; char ip_str[INET_ADDRSTRLEN]; const char *item = config_setting_get_string_elem(option, i); const char *cidr_pos = strchr(item, '/'); // search CIDR, and make sure, that ip part is not bigger than buffer size if (cidr_pos && (((size_t) (cidr_pos - item) < sizeof(ip_str)))) { strncpy(ip_str, item, cidr_pos - item); ip_str[cidr_pos - item] = '\0'; struct in_addr ip_addr; if (0 < inet_pton(AF_INET, ip_str, &ip_addr)) { uint8_t cidr = 0; if ((0 == str_to_u8(cidr_pos + 1, &cidr)) && (cidr <= CIDR_MAX)) { range.ip_start = ntohl(ip_addr.s_addr); range.ip_end = IP_RANGE_END(range.ip_start, cidr); utarray_push_back(array, &range); continue; } } } // error handler ZLOG(LOG_ERR, "config:%s:%s: invalid subnet: %s", option->parent->name, option->name, item); utarray_done(array); return -1; } if (count) { utarray_sort(array, ip_range_cmp); } return 0; }
static void parse_named_instruction(enum ovs_instruction_type type, char *arg, struct ofpbuf *ofpacts) { enum ofperr error; switch (type) { case OVSINST_OFPIT11_APPLY_ACTIONS: NOT_REACHED(); /* This case is handled by str_to_inst_ofpacts() */ break; case OVSINST_OFPIT11_WRITE_ACTIONS: /* XXX */ ovs_fatal(0, "instruction write-actions is not supported yet"); break; case OVSINST_OFPIT11_CLEAR_ACTIONS: ofpact_put_CLEAR_ACTIONS(ofpacts); break; case OVSINST_OFPIT13_METER: ofpact_put_METER(ofpacts)->meter_id = str_to_u32(arg); break; case OVSINST_OFPIT11_WRITE_METADATA: parse_metadata(ofpacts, arg); break; case OVSINST_OFPIT11_GOTO_TABLE: { struct ofpact_goto_table *ogt = ofpact_put_GOTO_TABLE(ofpacts); char *table_s = strsep(&arg, ","); if (!table_s || !table_s[0]) { ovs_fatal(0, "instruction goto-table needs table id"); } ogt->table_id = str_to_u8(table_s, "table"); break; } } /* If write_metadata is specified as an action AND an instruction, ofpacts could be invalid. */ error = ofpacts_verify(ofpacts->data, ofpacts->size); if (error) { ovs_fatal(0, "Incorrect instruction ordering"); } }
int str_to_prefix(const char *str, struct ipv6_prefix *prefix_out) { const char *FORMAT = "<IPv6 address>/<length> (eg. 64:ff9b::/96)"; /* [addr + null chara] + / + pref len */ const unsigned int STR_MAX_LEN = INET6_ADDRSTRLEN + 1 + 3; /* strtok corrupts the string, so we'll be using this copy instead. */ char str_copy[STR_MAX_LEN]; char *token; __u8 valid_lengths[] = POOL6_PREFIX_LENGTHS; int valid_lengths_size = sizeof(valid_lengths) / sizeof(valid_lengths[0]); int i; int error; if (strlen(str) + 1 > STR_MAX_LEN) { log_err(ERR_PARSE_PREFIX, "'%s' is too long for this poor, limited parser...", str); return -EINVAL; } strcpy(str_copy, str); token = strtok(str_copy, "/"); if (!token) { log_err(ERR_PARSE_PREFIX, "Cannot parse '%s' as a %s.", str, FORMAT); return -EINVAL; } error = str_to_addr6(token, &prefix_out->address); if (error) return error; token = strtok(NULL, "/"); if (!token) { log_err(ERR_PARSE_PREFIX, "'%s' does not seem to contain a mask (format: %s).", str, FORMAT); return -EINVAL; } error = str_to_u8(token, &prefix_out->len, 0, 0xFF); if (error) return error; /* Error msg already printed. */ for (i = 0; i < valid_lengths_size; i++) if (prefix_out->len == valid_lengths[i]) return 0; log_err(ERR_PREF_LEN_RANGE, "%u is not a valid prefix length.", prefix_out->len); return -EINVAL; }
/*! * \brief Parse NSEC3 parameters and fill structure with NSEC3 parameters. */ static bool parse_nsec3_params(dnssec_nsec3_params_t *params, const char *salt_str, const char *algorithm_str, const char *iterations_str) { uint8_t algorithm = 0; int r = str_to_u8(algorithm_str, &algorithm); if (r != DNSSEC_EOK) { error("Invalid algorithm number."); return false; } uint16_t iterations = 0; r = str_to_u16(iterations_str, &iterations); if (r != DNSSEC_EOK) { error("Invalid iteration count, %s.", dnssec_strerror(r)); return false; } dnssec_binary_t salt = { 0 }; r = str_to_salt(salt_str, &salt); if (r != DNSSEC_EOK) { error("Invalid salt, %s.", dnssec_strerror(r)); return false; } if (salt.size > UINT8_MAX) { error("Invalid salt, maximum length is %d bytes.", UINT8_MAX); dnssec_binary_free(&salt); return false; } params->algorithm = algorithm; params->iterations = iterations; params->salt = salt; params->flags = 0; return true; }
bool str_to_prefix(const char *str, struct ipv6_prefix *prefix_out) { const char *FORMAT = "<IPv6 address>/<length> (eg. 64:ff9b::/96)"; const int STR_MAX_LEN = INET6_ADDRSTRLEN + 1 + 3; // [addr + null chara] + / + prefix len char str_copy[STR_MAX_LEN]; // strtok corrupts the string, so we'll be using this copy instead. char *token; __u8 valid_lengths[] = POOL6_PREFIX_LENGTHS; int valid_lengths_size = sizeof(valid_lengths) / sizeof((valid_lengths)[0]); int i; if (strlen(str) + 1 > STR_MAX_LEN) { printf("Error: '%s' is too long for this poor, limited parser...\n", str); return false; } strcpy(str_copy, str); token = strtok(str_copy, "/"); if (!token || !str_to_addr6(token, &prefix_out->address)) { printf("Error: Cannot parse '%s' as a %s.\n", str, FORMAT); return false; } token = strtok(NULL, "/"); if (!token) { printf("Error: '%s' does not seem to contain a mask (format: %s).\n", str, FORMAT); return false; } if (!str_to_u8(token, &prefix_out->len, 0, 0xFF)) return false; // Error msg already printed. for (i = 0; i < valid_lengths_size; i++) if (prefix_out->len == valid_lengths[i]) return true; printf("Error: %u is not a valid prefix length.\n", prefix_out->len); return false; }
/* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man * page) into 'fm' for sending the specified flow_mod 'command' to a switch. * If 'actions' is specified, an action must be in 'string' and may be expanded * or reallocated. * * To parse syntax for an OFPT_FLOW_MOD (or NXT_FLOW_MOD), use an OFPFC_* * constant for 'command'. To parse syntax for an OFPST_FLOW or * OFPST_AGGREGATE (or NXST_FLOW or NXST_AGGREGATE), use -1 for 'command'. */ void parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, bool verbose) { enum { F_OUT_PORT = 1 << 0, F_ACTIONS = 1 << 1, F_TIMEOUT = 1 << 3, F_PRIORITY = 1 << 4, F_FLAGS = 1 << 5, } fields; char *string = xstrdup(str_); char *save_ptr = NULL; char *act_str = NULL; char *name; switch (command) { case -1: fields = F_OUT_PORT; break; case OFPFC_ADD: fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; case OFPFC_DELETE: fields = F_OUT_PORT; break; case OFPFC_DELETE_STRICT: fields = F_OUT_PORT | F_PRIORITY; break; case OFPFC_MODIFY: fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; case OFPFC_MODIFY_STRICT: fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; default: NOT_REACHED(); } match_init_catchall(&fm->match); fm->priority = OFP_DEFAULT_PRIORITY; fm->cookie = htonll(0); fm->cookie_mask = htonll(0); if (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT) { /* For modify, by default, don't update the cookie. */ fm->new_cookie = htonll(UINT64_MAX); } else{ fm->new_cookie = htonll(0); } fm->table_id = 0xff; fm->command = command; fm->idle_timeout = OFP_FLOW_PERMANENT; fm->hard_timeout = OFP_FLOW_PERMANENT; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_ANY; fm->flags = 0; if (fields & F_ACTIONS) { act_str = strstr(string, "action"); if (!act_str) { ofp_fatal(str_, verbose, "must specify an action"); } *act_str = '\0'; act_str = strchr(act_str + 1, '='); if (!act_str) { ofp_fatal(str_, verbose, "must specify an action"); } act_str++; } for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { const struct protocol *p; if (parse_protocol(name, &p)) { match_set_dl_type(&fm->match, htons(p->dl_type)); if (p->nw_proto) { match_set_nw_proto(&fm->match, p->nw_proto); } } else if (fields & F_FLAGS && !strcmp(name, "send_flow_rem")) { fm->flags |= OFPFF_SEND_FLOW_REM; } else if (fields & F_FLAGS && !strcmp(name, "check_overlap")) { fm->flags |= OFPFF_CHECK_OVERLAP; } else if (fields & F_FLAGS && !strcmp(name, "reset_counts")) { fm->flags |= OFPFF12_RESET_COUNTS; } else if (fields & F_FLAGS && !strcmp(name, "no_packet_counts")) { fm->flags |= OFPFF13_NO_PKT_COUNTS; } else if (fields & F_FLAGS && !strcmp(name, "no_byte_counts")) { fm->flags |= OFPFF13_NO_BYT_COUNTS; } else { char *value; value = strtok_r(NULL, ", \t\r\n", &save_ptr); if (!value) { ofp_fatal(str_, verbose, "field %s missing value", name); } if (!strcmp(name, "table")) { fm->table_id = str_to_u8(value, name); } else if (!strcmp(name, "out_port")) { if (!ofputil_port_from_string(value, &fm->out_port)) { ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port", name); } } else if (fields & F_PRIORITY && !strcmp(name, "priority")) { fm->priority = str_to_u16(value, name); } else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) { fm->idle_timeout = str_to_u16(value, name); } else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) { fm->hard_timeout = str_to_u16(value, name); } else if (!strcmp(name, "cookie")) { char *mask = strchr(value, '/'); if (mask) { /* A mask means we're searching for a cookie. */ if (command == OFPFC_ADD) { ofp_fatal(str_, verbose, "flow additions cannot use " "a cookie mask"); } *mask = '\0'; fm->cookie = htonll(str_to_u64(value)); fm->cookie_mask = htonll(str_to_u64(mask+1)); } else { /* No mask means that the cookie is being set. */ if (command != OFPFC_ADD && command != OFPFC_MODIFY && command != OFPFC_MODIFY_STRICT) { ofp_fatal(str_, verbose, "cannot set cookie"); } fm->new_cookie = htonll(str_to_u64(value)); } } else if (mf_from_name(name)) { parse_field(mf_from_name(name), value, &fm->match); } else if (!strcmp(name, "duration") || !strcmp(name, "n_packets") || !strcmp(name, "n_bytes") || !strcmp(name, "idle_age") || !strcmp(name, "hard_age")) { /* Ignore these, so that users can feed the output of * "ovs-ofctl dump-flows" back into commands that parse * flows. */ } else { ofp_fatal(str_, verbose, "unknown keyword %s", name); } } } if (!fm->cookie_mask && fm->new_cookie == htonll(UINT64_MAX) && (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT)) { /* On modifies without a mask, we are supposed to add a flow if * one does not exist. If a cookie wasn't been specified, use a * default of zero. */ fm->new_cookie = htonll(0); } if (fields & F_ACTIONS) { struct ofpbuf ofpacts; enum ofperr err; ofpbuf_init(&ofpacts, 32); str_to_inst_ofpacts(act_str, &ofpacts); fm->ofpacts_len = ofpacts.size; fm->ofpacts = ofpbuf_steal_data(&ofpacts); err = ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow, OFPP_MAX, 0); if (err) { exit(EXIT_FAILURE); } } else { fm->ofpacts_len = 0; fm->ofpacts = NULL; } free(string); }
/* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man * page) into 'mm' for sending the specified meter_mod 'command' to a switch. */ void parse_ofp_meter_mod_str(struct ofputil_meter_mod *mm, const char *str_, int command, bool verbose) { enum { F_METER = 1 << 0, F_FLAGS = 1 << 1, F_BANDS = 1 << 2, } fields; char *string = xstrdup(str_); char *save_ptr = NULL; char *band_str = NULL; char *name; switch (command) { case -1: fields = F_METER; break; case OFPMC13_ADD: fields = F_METER | F_FLAGS | F_BANDS; break; case OFPMC13_DELETE: fields = F_METER; break; case OFPMC13_MODIFY: fields = F_METER | F_FLAGS | F_BANDS; break; default: NOT_REACHED(); } mm->command = command; mm->meter.meter_id = 0; mm->meter.flags = 0; if (fields & F_BANDS) { band_str = strstr(string, "band"); if (!band_str) { ofp_fatal(str_, verbose, "must specify bands"); } *band_str = '\0'; band_str = strchr(band_str + 1, '='); if (!band_str) { ofp_fatal(str_, verbose, "must specify bands"); } band_str++; } for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { if (fields & F_FLAGS && !strcmp(name, "kbps")) { mm->meter.flags |= OFPMF13_KBPS; } else if (fields & F_FLAGS && !strcmp(name, "pktps")) { mm->meter.flags |= OFPMF13_PKTPS; } else if (fields & F_FLAGS && !strcmp(name, "burst")) { mm->meter.flags |= OFPMF13_BURST; } else if (fields & F_FLAGS && !strcmp(name, "stats")) { mm->meter.flags |= OFPMF13_STATS; } else { char *value; value = strtok_r(NULL, ", \t\r\n", &save_ptr); if (!value) { ofp_fatal(str_, verbose, "field %s missing value", name); } if (!strcmp(name, "meter")) { if (!strcmp(value, "all")) { mm->meter.meter_id = OFPM13_ALL; } else if (!strcmp(value, "controller")) { mm->meter.meter_id = OFPM13_CONTROLLER; } else if (!strcmp(value, "slowpath")) { mm->meter.meter_id = OFPM13_SLOWPATH; } else { mm->meter.meter_id = str_to_u32(value); if (mm->meter.meter_id > OFPM13_MAX) { ofp_fatal(str_, verbose, "invalid value for %s", name); } } } else { ofp_fatal(str_, verbose, "unknown keyword %s", name); } } } if (fields & F_METER && !mm->meter.meter_id) { ofp_fatal(str_, verbose, "must specify 'meter'"); } if (fields & F_FLAGS && !mm->meter.flags) { ofp_fatal(str_, verbose, "meter must specify either 'kbps' or 'pktps'"); } if (fields & F_BANDS) { struct ofpbuf bands; uint16_t n_bands = 0; struct ofputil_meter_band *band = NULL; int i; ofpbuf_init(&bands, 64); for (name = strtok_r(band_str, "=, \t\r\n", &save_ptr); name; name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { char *value; value = strtok_r(NULL, ", \t\r\n", &save_ptr); if (!value) { ofp_fatal(str_, verbose, "field %s missing value", name); } if (!strcmp(name, "type")) { /* Start a new band */ band = ofpbuf_put_zeros(&bands, sizeof *band); n_bands++; if (!strcmp(value, "drop")) { band->type = OFPMBT13_DROP; } else if (!strcmp(value, "dscp_remark")) { band->type = OFPMBT13_DSCP_REMARK; } else { ofp_fatal(str_, verbose, "field %s unknown value %s", name, value); } } else if (!band || !band->type) { ofp_fatal(str_, verbose, "band must start with the 'type' keyword"); } else if (!strcmp(name, "rate")) { band->rate = str_to_u32(value); } else if (!strcmp(name, "burst_size")) { band->burst_size = str_to_u32(value); } else if (!strcmp(name, "prec_level")) { band->prec_level = str_to_u8(value, name); } else { ofp_fatal(str_, verbose, "unknown keyword %s", name); } } /* validate bands */ if (!n_bands) { ofp_fatal(str_, verbose, "meter must have bands"); } mm->meter.n_bands = n_bands; mm->meter.bands = ofpbuf_steal_data(&bands); for (i = 0; i < n_bands; ++i) { band = &mm->meter.bands[i]; if (!band->type) { ofp_fatal(str_, verbose, "band must have 'type'"); } if (band->type == OFPMBT13_DSCP_REMARK) { if (!band->prec_level) { ofp_fatal(str_, verbose, "'dscp_remark' band must have" " 'prec_level'"); } } else { if (band->prec_level) { ofp_fatal(str_, verbose, "Only 'dscp_remark' band may have" " 'prec_level'"); } } if (!band->rate) { ofp_fatal(str_, verbose, "band must have 'rate'"); } if (mm->meter.flags & OFPMF13_BURST) { if (!band->burst_size) { ofp_fatal(str_, verbose, "band must have 'burst_size' " "when 'burst' flag is set"); } } else { if (band->burst_size) { ofp_fatal(str_, verbose, "band may have 'burst_size' only " "when 'burst' flag is set"); } } } } else { mm->meter.n_bands = 0; mm->meter.bands = NULL; } free(string); }
/* * PARSER. Field 2 in ARGP. */ static int parse_opt(int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; int error = 0; __u16 temp; switch (key) { case ARGP_POOL6: arguments->mode = MODE_POOL6; break; case ARGP_POOL4: arguments->mode = MODE_POOL4; break; case ARGP_BIB: arguments->mode = MODE_BIB; break; case ARGP_SESSION: arguments->mode = MODE_SESSION; break; case ARGP_FILTERING: arguments->mode = MODE_FILTERING; break; case ARGP_TRANSLATE: arguments->mode = MODE_TRANSLATE; break; case ARGP_DISPLAY: arguments->operation = OP_DISPLAY; break; case ARGP_ADD: arguments->operation = OP_ADD; break; case ARGP_REMOVE: arguments->operation = OP_REMOVE; break; case ARGP_UDP: arguments->udp = true; break; case ARGP_TCP: arguments->tcp = true; break; case ARGP_ICMP: arguments->icmp = true; break; case ARGP_ADDRESS: error = str_to_addr4(arg, &arguments->pool4_addr); arguments->pool4_addr_set = true; break; case ARGP_PREFIX: error = str_to_prefix(arg, &arguments->pool6_prefix); arguments->pool6_prefix_set = true; break; // case ARGP_STATIC: // arguments->static_entries = true; // break; // case ARGP_DYNAMIC: // arguments->dynamic_entries = true; // break; // // case ARGP_IPV6: // error = str_to_addr6_port(arg, &arguments->bib_addr6); // arguments->bib_addr6_set = true; // break; // case ARGP_IPV4: // error = str_to_addr4_port(arg, &arguments->bib_addr4); // arguments->bib_addr4_set = true; // break; case ARGP_REMOTE6: error = str_to_addr6_port(arg, &arguments->session_pair6.remote); arguments->session_pair6_remote_set = true; break; case ARGP_LOCAL6: error = str_to_addr6_port(arg, &arguments->session_pair6.local); arguments->session_pair6_local_set = true; break; case ARGP_LOCAL4: error = str_to_addr4_port(arg, &arguments->session_pair4.local); arguments->session_pair4_local_set = true; break; case ARGP_REMOTE4: error = str_to_addr4_port(arg, &arguments->session_pair4.remote); arguments->session_pair4_remote_set = true; break; case ARGP_DROP_ADDR: arguments->mode = MODE_FILTERING; arguments->operation |= DROP_BY_ADDR_MASK; error = str_to_bool(arg, &arguments->filtering.drop_by_addr); break; case ARGP_DROP_INFO: arguments->mode = MODE_FILTERING; arguments->operation |= DROP_ICMP6_INFO_MASK; error = str_to_bool(arg, &arguments->filtering.drop_icmp6_info); break; // case ARGP_DROP_TCP: // arguments->mode = MODE_FILTERING; // arguments->operation |= DROP_EXTERNAL_TCP_MASK; // error = str_to_bool(arg, &arguments->filtering.drop_external_tcp); // break; case ARGP_UDP_TO: arguments->mode = MODE_FILTERING; arguments->operation |= UDP_TIMEOUT_MASK; error = str_to_u16(arg, &temp, UDP_MIN, 0xFFFF); arguments->filtering.to.udp = temp; break; case ARGP_ICMP_TO: arguments->mode = MODE_FILTERING; arguments->operation |= ICMP_TIMEOUT_MASK; error = str_to_u16(arg, &temp, 0, 0xFFFF); arguments->filtering.to.icmp = temp; break; case ARGP_TCP_TO: arguments->mode = MODE_FILTERING; arguments->operation |= TCP_EST_TIMEOUT_MASK; error = str_to_u16(arg, &temp, TCP_EST, 0xFFFF); arguments->filtering.to.tcp_est = temp; break; case ARGP_TCP_TRANS_TO: arguments->mode = MODE_FILTERING; arguments->operation |= TCP_TRANS_TIMEOUT_MASK; error = str_to_u16(arg, &temp, TCP_TRANS, 0xFFFF); arguments->filtering.to.tcp_trans = temp; break; case ARGP_HEAD: arguments->mode = MODE_TRANSLATE; arguments->operation |= SKB_HEAD_ROOM_MASK; error = str_to_u16(arg, &arguments->translate.skb_head_room, 0, 0xFFFF); break; case ARGP_TAIL: arguments->mode = MODE_TRANSLATE; arguments->operation |= SKB_TAIL_ROOM_MASK; error = str_to_u16(arg, &arguments->translate.skb_tail_room, 0, 0xFFFF); break; case ARGP_RESET_TCLASS: arguments->mode = MODE_TRANSLATE; arguments->operation |= RESET_TCLASS_MASK; error = str_to_bool(arg, &arguments->translate.reset_traffic_class); break; case ARGP_RESET_TOS: arguments->mode = MODE_TRANSLATE; arguments->operation |= RESET_TOS_MASK; error = str_to_bool(arg, &arguments->translate.reset_tos); break; case ARGP_NEW_TOS: arguments->mode = MODE_TRANSLATE; arguments->operation |= NEW_TOS_MASK; error = str_to_u8(arg, &arguments->translate.new_tos, 0, 0xFF); break; case ARGP_DF: arguments->mode = MODE_TRANSLATE; arguments->operation |= DF_ALWAYS_ON_MASK; error = str_to_bool(arg, &arguments->translate.df_always_on); break; case ARGP_BUILD_ID: arguments->mode = MODE_TRANSLATE; arguments->operation |= BUILD_IPV4_ID_MASK; error = str_to_bool(arg, &arguments->translate.build_ipv4_id); break; case ARGP_LOWER_MTU_FAIL: arguments->mode = MODE_TRANSLATE; arguments->operation |= LOWER_MTU_FAIL_MASK; error = str_to_bool(arg, &arguments->translate.lower_mtu_fail); break; case ARGP_NEXT_MTU6: arguments->mode = MODE_TRANSLATE; arguments->operation |= IPV6_NEXTHOP_MTU_MASK; error = str_to_u16(arg, &arguments->translate.ipv6_nexthop_mtu, 0, 0xFFFF); break; case ARGP_NEXT_MTU4: arguments->mode = MODE_TRANSLATE; arguments->operation |= IPV4_NEXTHOP_MTU_MASK; error = str_to_u16(arg, &arguments->translate.ipv4_nexthop_mtu, 0, 0xFFFF); break; case ARGP_PLATEAUS: arguments->mode = MODE_TRANSLATE; arguments->operation |= MTU_PLATEAUS_MASK; error = str_to_u16_array(arg, &arguments->translate.mtu_plateaus, &arguments->translate.mtu_plateau_count); break; default: return ARGP_ERR_UNKNOWN; } return error; }