Ejemplo n.º 1
0
/*
 * Parse numbers
 */
static int
string_to_number_ll(struct ipset_session *session,
		    const char *str, 
		    unsigned long long min,
		    unsigned long long max,
		    unsigned long long *ret)
{
	unsigned long long number = 0;
	char *end;

	/* Handle hex, octal, etc. */
	errno = 0;
	number = strtoull(str, &end, 0);
	if (*end == '\0' && end != str && errno != ERANGE) {
		/* we parsed a number, let's see if we want this */
		if (min <= number && (!max || number <= max)) {
			*ret = number;
			return 0;
		} else
			errno = ERANGE;
	}
	if (errno == ERANGE && max)
		return syntax_err("'%s' is out of range %llu-%llu",
				  str, min, max);
	else if (errno == ERANGE)
		return syntax_err("'%s' is out of range %llu-%llu",
				  str, min, ULLONG_MAX);
	else
		return syntax_err("'%s' is invalid as number", str);
}
Ejemplo n.º 2
0
Tuple remove_duplicate_labels(Tuple label_list)
											/*;remove_duplicate_labels*/
{
	Tuple new_label_list = tup_new(0), label_id_set = tup_new(0);
	Fortup ft1, ft2;
	Node tmp_node, tmp_node2, node, label;

	FORTUP(tmp_node = (Node), label_list, ft1);
	    if (N_KIND((node = tmp_node)) == as_simple_name) {
			if (in_label_set(node, label_id_set))
				syntax_err(SPAN(node),"Duplicate label name");
			else {
				/* new_label_list = concatl(new_label_list,initlist(node)); */
				label_id_set = tup_with(label_id_set, (char *)node);
			}
			new_label_list = tup_with(new_label_list, (char *)node);
		}
		else {
			FORTUP(tmp_node2 = (Node), N_LIST(node), ft2);
		    	label = tmp_node2;
				if (in_label_set(label,label_id_set))
					syntax_err(SPAN(label),"Duplicate label name");
				else
					label_id_set = tup_with(label_id_set, (char *)label);
			ENDFORTUP(ft2);
		}
	ENDFORTUP(ft1)
/*
	if (label_id_set != (struct two_pool *)0)
		TFREE(label_id_set->link,label_id_set);
	if (label_list != (struct two_pool *)0)
		TFREE(label_list->link,label_list);
*/
	return(new_label_list);
}
Ejemplo n.º 3
0
// Obtain the name of the RegMask for an InstructForm
const char *ArchDesc::reg_mask(InstructForm &inForm) {
  const char *result = inForm.reduce_result();

  if (result == NULL) {
    syntax_err(inForm._linenum,
               "Did not find result operand or RegMask"
               " for this instruction: %s",
               inForm._ident);
    abort();
  }

  // Instructions producing 'Universe' use RegMask::Empty
  if( strcmp(result,"Universe")==0 ) {
    return "RegMask::Empty";
  }

  // Lookup this result operand and get its register class
  Form *form = (Form*)_globalNames[result];
  if (form == NULL) {
    syntax_err(inForm._linenum,
               "Did not find result operand for result: %s", result);
    abort();
  }
  OperandForm *oper = form->is_operand();
  if (oper == NULL) {
    syntax_err(inForm._linenum, "Form is not an OperandForm:");
    form->dump();
    abort();
  }
  return reg_mask( *oper );
}
Ejemplo n.º 4
0
/**
 * ipset_parse_iptimeout - parse IPv4|IPv6 address and timeout
 * @session: session structure
 * @opt: option kind of the data
 * @str: string to parse
 *
 * Parse string as an IPv4|IPv6 address and timeout parameter.
 * If family is not set yet in the data blob, INET is assumed.
 * The value is stored in the data blob of the session.
 *
 * Compatibility parser.
 *
 * Returns 0 on success or a negative error code.
 */
int
ipset_parse_iptimeout(struct ipset_session *session,
		      enum ipset_opt opt, const char *str)
{
	char *tmp, *saved, *a;
	int err;

	assert(session);
	assert(opt == IPSET_OPT_IP);
	assert(str);

	/* IP,timeout */
	if (ipset_data_flags_test(ipset_session_data(session),
				  IPSET_FLAG(IPSET_OPT_TIMEOUT)))
		return syntax_err("mixed syntax, timeout already specified");
		 
	tmp = saved = strdup(str);	
	if (saved == NULL)
		return ipset_err(session,
				 "Cannot allocate memory to duplicate %s.",
				 str);

	a = elem_separator(tmp);
	if (a == NULL) {
		free(saved);
		return syntax_err("Missing separator from %s", str);
	}
	*a++ = '\0';
	err = parse_ip(session, opt, tmp, IPADDR_ANY);
	if (!err)
		err = ipset_parse_uint32(session, IPSET_OPT_TIMEOUT, a);

	free(saved);
	return err;
}
Ejemplo n.º 5
0
/**
 * ipset_parse_family - parse INET|INET6 family names
 * @session: session structure
 * @opt: option kind of the data
 * @str: string to parse
 *
 * Parse string as an INET|INET6 family name.
 * The value is stored in the data blob of the session.
 *
 * Returns 0 on success or a negative error code.
 */
int
ipset_parse_family(struct ipset_session *session,
		   enum ipset_opt opt, const char *str)
{
	struct ipset_data *data;
	uint8_t family;
	
	assert(session);
	assert(opt == IPSET_OPT_FAMILY);
	assert(str);

	data = ipset_session_data(session);
	if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_FAMILY)))
		syntax_err("protocol family may not be specified "
			   "multiple times");

	if (STREQ(str, "inet") || STREQ(str, "ipv4") || STREQ(str, "-4"))
		family = AF_INET;
	else if (STREQ(str, "inet6") || STREQ(str, "ipv6") || STREQ(str, "-6"))
		family = AF_INET6;
	else if (STREQ(str, "any") || STREQ(str, "unspec"))
		family = AF_UNSPEC;
	else
		return syntax_err("unknown INET family %s", str);
				
	return ipset_data_set(data, opt, &family);
}
Ejemplo n.º 6
0
// Build MatchList structures for instructions
void ArchDesc::inspectInstructions() {

  // Iterate through all instructions
  _instructions.reset();
  InstructForm *instr;
  for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {
    // Construct list of top-level operands (components)
    instr->build_components();

    // Ensure that match field is defined.
    if ( instr->_matrule == NULL )  continue;

    MatchRule &mrule = *instr->_matrule;
    Predicate *pred  =  instr->build_predicate();

    // Grab the machine type of the operand
    const char  *rootOp    = instr->_ident;
    mrule._machType  = rootOp;

    // Cost for this match
    const char *costStr = instr->cost();
    const char *defaultCost =
      ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;
    const char *cost    =  costStr? costStr : defaultCost;

    // Find result type for match
    const char *result  = instr->reduce_result();

    if ( (instr->is_ideal_branch() && instr->label_position() == -1) ||
	 (!instr->is_ideal_branch() && instr->label_position() != -1)) {
      syntax_err(instr->_linenum, "%s: Only branches to a label are supported\n", rootOp);
    }

    Attribute *attr = instr->_attribs;
    while (attr != NULL) {
      if (strcmp(attr->_ident,"ins_short_branch") == 0 &&
          attr->int_val(*this) != 0) {
        if (!instr->is_ideal_branch() || instr->label_position() == -1) {
          syntax_err(instr->_linenum, "%s: Only short branch to a label is supported\n", rootOp);
        }
        instr->set_short_branch(true);
      } else if (strcmp(attr->_ident,"ins_alignment") == 0 &&
          attr->int_val(*this) != 0) {
        instr->set_alignment(attr->int_val(*this));
      }
      attr = (Attribute *)attr->_next;
    }

    if (!instr->is_short_branch()) {
      buildMatchList(instr->_matrule, result, mrule._machType, pred, cost);
    }
  }
}
Ejemplo n.º 7
0
void check_choices(Node alt_node, char *source)	/*;check_choices*/
{
	Tuple choice_list, others_indices = tup_new(0);
	Node tmp_node, tmp_node2, last_alt = (Node) 0;
	Fortup ft1, ft2;
	int choice_flag = 0;

	FORTUP(tmp_node = (Node), N_LIST(alt_node), ft1);
	    if (N_KIND(tmp_node) != as_pragma) {
			choice_list = N_LIST(N_AST1(tmp_node));
			if (tup_size(choice_list) > 1) {
				FORTUP(tmp_node2 = (Node), choice_list, ft2);
					if (N_KIND(tmp_node2) == as_others
					  || N_KIND(tmp_node2) == as_others_choice) {
						char msg[90];

						sprintf(msg,"The choice OTHERS must appear alone in %s",
						  source);
						syntax_err(SPAN(tmp_node2),msg);
						choice_flag = 1;
						break;
					}
				ENDFORTUP(ft2);
			}
		   	if (!choice_flag) {
				if (N_KIND((Node)choice_list[1]) == as_others
				  || N_KIND((Node)choice_list[1]) == as_others_choice)
					others_indices = tup_with(others_indices, (char *)tmp_node);
			}
			else
				choice_flag = 0;
			last_alt = tmp_node;
		}
	ENDFORTUP(ft1);

	FORTUP(tmp_node = (Node), others_indices, ft1); {
		Node choice;
		char msg[90];

		if (tmp_node == last_alt)
			continue;
		choice = (Node)N_LIST(N_AST1(tmp_node))[1];
		sprintf(msg,"The choice OTHERS must appear last in %s",source);
		syntax_err(SPAN(choice),msg);
	} ENDFORTUP(ft1);
/*
	if (others_indices != (struct two_pool *)0 )
		TFREE(others_indices->link,others_indices);
*/
}
Ejemplo n.º 8
0
/**
 * ipset_parse_netmask - parse string as a CIDR netmask value
 * @session: session structure
 * @opt: option kind of the data
 * @str: string to parse
 *
 * Parse string as a CIDR netmask value, depending on family type.
 * If family is not set yet, INET is assumed.
 * The value is stored in the data blob of the session.
 *
 * Returns 0 on success or a negative error code.
 */
int
ipset_parse_netmask(struct ipset_session *session,
		    enum ipset_opt opt, const char *str)
{
	uint8_t family, cidr;
	struct ipset_data *data;
	int err = 0;
	
	assert(session);
	assert(opt == IPSET_OPT_NETMASK);
	assert(str);

	data = ipset_session_data(session);
	family = ipset_data_family(data);
	if (family == AF_UNSPEC) {
		family = AF_INET;
		ipset_data_set(data, IPSET_OPT_FAMILY, &family);
	}

	err = string_to_cidr(session, str,
			     family == AF_INET ? 1 : 4, 
			     family == AF_INET ? 31 : 124,
			     &cidr);

	if (err)
		return syntax_err("netmask is out of the inclusive range "
				  "of %u-%u",
				  family == AF_INET ? 1 : 4,
				  family == AF_INET ? 31 : 124);

	return ipset_data_set(data, opt, &cidr);
}
Ejemplo n.º 9
0
/**
 * ipset_parse_ether - parse ethernet address
 * @session: session structure
 * @opt: option kind of the data
 * @str: string to parse
 *
 * Parse string as an ethernet address. The parsed ethernet
 * address is stored in the data blob of the session.
 *
 * Returns 0 on success or a negative error code.
 */
int
ipset_parse_ether(struct ipset_session *session,
		  enum ipset_opt opt, const char *str)
{
	unsigned int i = 0;
	unsigned char ether[ETH_ALEN];
	
	assert(session);
	assert(opt == IPSET_OPT_ETHER);
	assert(str);

	if (strlen(str) != ETH_ALEN * 3 - 1)
		goto error;

	for (i = 0; i < ETH_ALEN; i++) {
		long number;
		char *end;

		number = strtol(str + i * 3, &end, 16);

		if (end == str + i * 3 + 2
		    && (*end == ':' || *end == '\0')
		    && number >= 0 && number <= 255)
			ether[i] = number;
		else
			goto error;
	}
	return ipset_session_data_set(session, opt, ether);

error:
	return syntax_err("cannot parse '%s' as ethernet address", str);
}
Ejemplo n.º 10
0
static int
get_addrinfo(struct ipset_session *session,
	     enum ipset_opt opt,
	     const char *str,
	     struct addrinfo **info,
	     uint8_t family)
{
        struct addrinfo *i;
	size_t addrlen = family == AF_INET ? sizeof(struct sockaddr_in)
					   : sizeof(struct sockaddr_in6);
        int found, err = 0;

	if ((*info = call_getaddrinfo(session, str, family)) == NULL) {
		syntax_err("cannot parse %s: resolving to %s address failed",
			   str, family == AF_INET ? "IPv4" : "IPv6");
		return EINVAL;
	}

	for (i = *info, found = 0; i != NULL; i = i->ai_next) {
		if (i->ai_family != family || i->ai_addrlen != addrlen)
			continue;
		if (found == 0) {
			if (family == AF_INET) {
				/* Workaround: direct cast increases required alignment on Sparc */
				const struct sockaddr_in *saddr = (void *)i->ai_addr;
				err = ipset_session_data_set(session, opt, &saddr->sin_addr);
			} else {
				/* Workaround: direct cast increases required alignment on Sparc */
				const struct sockaddr_in6 *saddr = (void *)i->ai_addr;
				err = ipset_session_data_set(session, opt, &saddr->sin6_addr);
			}
		} else if (found == 1) {
			ipset_warn(session,
				   "%s resolves to multiple addresses: "
				   "using only the first one returned "
				   "by the resolver",
				   str);
		}
		found++;
	}
	if (found == 0)
		return syntax_err("cannot parse %s: "
				  "%s address could not be resolved",
				  str, family == AF_INET ? "IPv4" : "IPv6");
	return err;
}
Ejemplo n.º 11
0
static int
string_to_cidr(struct ipset_session *session,
	       const char *str, uint8_t min, uint8_t max, uint8_t *ret)
{
	int err = string_to_u8(session, str, ret);
	
	if (!err && (*ret < min || *ret > max))
		return syntax_err("'%s' is out of range %u-%u",
				  str, min, max);

	return err;
}
Ejemplo n.º 12
0
/**
 * ipset_parse_name_compat - parse setname as element
 * @session: session structure
 * @opt: option kind of the data
 * @str: string to parse
 *
 * Parse string as a setname or a setname element to add to a set.
 * The pattern "setname,before|after,setname" is recognized and
 * parsed.
 * The value is stored in the data blob of the session.
 *
 * Returns 0 on success or a negative error code.
 */
int
ipset_parse_name_compat(struct ipset_session *session,
			enum ipset_opt opt, const char *str)
{
	char *saved;
	char *a = NULL, *b = NULL, *tmp;
	int err, before = 0;
	const char *sep = IPSET_ELEM_SEPARATOR;
	struct ipset_data *data;

	assert(session);
	assert(opt == IPSET_OPT_NAME);
	assert(str);

	data = ipset_session_data(session);
	if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_NAMEREF)))
		syntax_err("mixed syntax, before|after option already used");

	tmp = saved = strdup(str);	
	if (saved == NULL)
		return ipset_err(session,
				 "Cannot allocate memory to duplicate %s.",
				 str);
	if ((a = elem_separator(tmp)) != NULL) {
		/* setname,[before|after,setname */
		*a++ = '\0';
		if ((b = elem_separator(a)) != NULL)
			*b++ = '\0';
		if (b == NULL
		    || !(STREQ(a, "before") || STREQ(a, "after"))) {
			err = ipset_err(session, "you must specify elements "
					"as setname%s[before|after]%ssetname",
					sep, sep);
			goto out;
		}
		before = STREQ(a, "before");
	}
	check_setname(tmp, saved);
	if ((err = ipset_data_set(data, opt, tmp)) != 0 || b == NULL)
		goto out;

	check_setname(b, saved);
	if ((err = ipset_data_set(data,
				  IPSET_OPT_NAMEREF, b)) != 0)
		goto out;

	if (before)
		err = ipset_data_set(data, IPSET_OPT_BEFORE, &before);

out:
	free(saved);
	return err;
}
Ejemplo n.º 13
0
/**
 * ipset_parse_ipnet - parse IPv4|IPv6 address or address/cidr pattern
 * @session: session structure
 * @opt: option kind of the data
 * @str: string to parse
 *
 * Parse string as an IPv4|IPv6 address or address/cidr pattern.
 * If family is not set yet in the data blob, INET is assumed.
 * The value is stored in the data blob of the session.
 *
 * Returns 0 on success or a negative error code.
 */
int
ipset_parse_ipnet(struct ipset_session *session,
		  enum ipset_opt opt, const char *str)
{
	assert(session);
	assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
	assert(str);

	if (range_separator(str))
		return syntax_err("IP address or IP/cidr must be specified: %s",
				  str);
	return parse_ip(session, opt, str, IPADDR_ANY);
}
Ejemplo n.º 14
0
/**
 * ipset_parse_proto - parse protocol name
 * @session: session structure
 * @opt: option kind of the data
 * @str: string to parse
 *
 * Parse string as a protocol name.
 * The parsed protocol is stored in the data blob of the session.
 *
 * Returns 0 on success or a negative error code.
 */
int
ipset_parse_proto(struct ipset_session *session,
		  enum ipset_opt opt, const char *str)
{
	const struct protoent *protoent;
	uint8_t proto = 0;

	assert(session);
	assert(opt == IPSET_OPT_PROTO);
	assert(str);
	
	protoent = getprotobyname(strcasecmp(str, "icmpv6") == 0
				  ? "ipv6-icmp" : str);
	if (protoent == NULL)
		return syntax_err("cannot parse '%s' "
				  "as a protocol name", str);
	proto = protoent->p_proto;
	if (!proto)
		return syntax_err("Unsupported protocol '%s'", str);
	
	return ipset_session_data_set(session, opt, &proto);
}
Ejemplo n.º 15
0
/*
 * Parse TCP service names or port numbers
 */
static int
parse_portname(struct ipset_session *session, const char *str,
	       uint16_t *port, const char *proto)
{
	struct servent *service;

	if ((service = getservbyname(str, proto)) != NULL) {
		*port = ntohs((uint16_t) service->s_port);
		return 0;
	}
	
	return syntax_err("cannot parse '%s' as a %s port", str, proto);
}
Ejemplo n.º 16
0
void check_discrete_range(Node discrete_range) /*;check_discrete_range*/
{
	/* Check whether a discrete range node is valid. */

	switch (N_KIND(discrete_range))
	{
	case as_range_expression :
#define name (N_AST1(discrete_range))
		if (!check_expanded_name(name))
			syntax_err(SPAN(discrete_range),
			  "Invalid discrete_range specification");
		else
			N_KIND(discrete_range) = as_name;
		break;
#undef name
	case as_range_attribute :
	case as_subtype :
		break;
	default :
		syntax_err(SPAN(discrete_range),
		  "Invalid discrete_range specification");
	}
}
Ejemplo n.º 17
0
static int
parse_ip(struct ipset_session *session,
	 enum ipset_opt opt, const char *str, enum ipaddr_type addrtype)
{
	struct ipset_data *data = ipset_session_data(session);
	uint8_t family = ipset_data_family(data);

	if (family == AF_UNSPEC) {
		family = AF_INET;
		ipset_data_set(data, IPSET_OPT_FAMILY, &family);
	}

	switch (addrtype) {
	case IPADDR_PLAIN:
		if (range_separator(str)
		    || (cidr_separator(str) && !cidr_hostaddr(str, family)))
			return syntax_err("plain IP address must be supplied: %s",
					  str);
		break;
	case IPADDR_NET:
		if (!cidr_separator(str) || range_separator(str))
			return syntax_err("IP/netblock must be supplied: %s",
					  str);
		break;
	case IPADDR_RANGE:
		if (!range_separator(str) || cidr_separator(str))
			return syntax_err("IP-IP range must supplied: %s",
					  str);
		break;
	case IPADDR_ANY:
	default:
		break;
	}

	return parse_ipaddr(session, opt, str, family);
}
Ejemplo n.º 18
0
// Convert a register class name to its register mask.
const char *ArchDesc::reg_class_to_reg_mask(const char *rc_name) {
  const char *reg_mask = "RegMask::Empty";

  if( _register ) {
    RegClass *reg_class  = _register->getRegClass(rc_name);
    if (reg_class == NULL) {
      syntax_err(0, "Use of an undefined register class %s", rc_name);
      return reg_mask;
    }

    // Construct the name of the register mask.
    reg_mask = getRegMask(rc_name);
  }

  return reg_mask;
}
Ejemplo n.º 19
0
// Obtain the name of the RegMask for an OperandForm
const char *ArchDesc::reg_mask(OperandForm  &opForm) {
  const char *regMask      = "RegMask::Empty";

  // Check constraints on result's register class
  const char *result_class = opForm.constrained_reg_class();
  if (result_class == NULL) {
    opForm.dump();
    syntax_err(opForm._linenum,
               "Use of an undefined result class for operand: %s",
               opForm._ident);
    abort();
  }

  regMask = reg_class_to_reg_mask( result_class );

  return regMask;
}
Ejemplo n.º 20
0
/**
 * ipset_parse_after - parse string as "after" reference setname
 * @session: session structure
 * @opt: option kind of the data
 * @str: string to parse
 *
 * Parse string as a "after" reference setname for list:set
 * type of sets. The value is stored in the data blob of the session.
 *
 * Returns 0 on success or a negative error code.
 */
int
ipset_parse_after(struct ipset_session *session,
		   enum ipset_opt opt, const char *str)
{
	struct ipset_data *data;

	assert(session);
	assert(opt == IPSET_OPT_NAMEREF);
	assert(str);

	data = ipset_session_data(session);
	if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_NAMEREF)))
		syntax_err("mixed syntax, before|after option already used");

	check_setname(str, NULL);

	return ipset_data_set(data, opt, str);
}
Ejemplo n.º 21
0
// Obtain the STACK_OR_reg_mask name for an OperandForm
char *ArchDesc::stack_or_reg_mask(OperandForm  &opForm) {
  // name of cisc_spillable version
  const char *reg_mask_name = reg_mask(opForm);

  if (reg_mask_name == NULL) {
     syntax_err(opForm._linenum,
                "Did not find reg_mask for opForm: %s",
                opForm._ident);
     abort();
  }

  const char *stack_or = "STACK_OR_";
  int   length         = (int)strlen(stack_or) + (int)strlen(reg_mask_name) + 1;
  char *result         = new char[length];
  sprintf(result,"%s%s", stack_or, reg_mask_name);

  return result;
}
Ejemplo n.º 22
0
static struct addrinfo *
call_getaddrinfo(struct ipset_session *session, const char *str,
		 uint8_t family)
{
	struct addrinfo hints;
        struct addrinfo *res;
	int err;

	memset(&hints, 0, sizeof(hints));
	hints.ai_flags = AI_CANONNAME;
        hints.ai_family = family;
        hints.ai_socktype = SOCK_RAW;
        hints.ai_protocol = 0;
        hints.ai_next = NULL;

        if ((err = getaddrinfo(str, NULL, &hints, &res)) != 0) {
        	syntax_err("cannot resolve '%s' to an %s address: %s",
        		   str, family == AF_INET6 ? "IPv6" : "IPv4",
        		   gai_strerror(err));
        	return NULL;
	} else
		return res;
}
Ejemplo n.º 23
0
/**
 * ipset_parse_proto_port - parse (optional) protocol and a single port
 * @session: session structure
 * @opt: option kind of the data
 * @str: string to parse
 *
 * Parse string as a protocol and port, separated by a colon.
 * The protocol part is optional.
 * The parsed protocol and port numbers are stored in the data
 * blob of the session.
 *
 * Returns 0 on success or a negative error code.
 */
int
ipset_parse_proto_port(struct ipset_session *session,
		       enum ipset_opt opt, const char *str)
{
	struct ipset_data *data;
	char *a, *saved, *tmp;
	const char *proto;
	uint8_t p = IPPROTO_TCP;
	int err = 0;

	assert(session);
	assert(opt == IPSET_OPT_PORT);
	assert(str);

	data = ipset_session_data(session);
	saved = tmp = strdup(str);
	if (tmp == NULL)
		return ipset_err(session,
				 "Cannot allocate memory to duplicate %s.",
				 str);

	a = proto_separator(tmp);
	if (a != NULL) {
		uint8_t family = ipset_data_family(data);

		/* proto:port */
		*a++ = '\0';
		err = ipset_parse_proto(session, IPSET_OPT_PROTO, tmp);
		if (err)
			goto error;
		
		p = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_PROTO);
		switch (p) {
		case IPPROTO_TCP:
			proto = tmp;
			tmp = a;
			goto parse_port;
		case IPPROTO_UDP:
			proto = tmp;
			tmp = a;
			goto parse_port;
		case IPPROTO_ICMP:
			if (family != AF_INET) {
				syntax_err("Protocol ICMP can be used with family INET only");
				goto error;
			}
			err = ipset_parse_icmp(session, opt, a);
			break;
		case IPPROTO_ICMPV6:
			if (family != AF_INET6) {
				syntax_err("Protocol ICMPv6 can be used with family INET6 only");
				goto error;
			}
			err = ipset_parse_icmpv6(session, opt, a);
			break;
		default:
			if (!STREQ(a, "0")) {
				syntax_err("Protocol %s can be used with pseudo port value 0 only.");
				goto error;
			}
			ipset_data_flags_set(data, IPSET_FLAG(opt));
		}
		goto error;
	} else {
		proto = "TCP";	
		err = ipset_data_set(data, IPSET_OPT_PROTO, &p);
		if (err)
			goto error;
	}
parse_port:
	err = ipset_parse_tcpudp_port(session, opt, tmp, proto);

error:
	free(saved);
	return err;
}