141d22f7bSJozsef Kadlecsik /* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
241d22f7bSJozsef Kadlecsik  *
341d22f7bSJozsef Kadlecsik  * This program is free software; you can redistribute it and/or modify
441d22f7bSJozsef Kadlecsik  * it under the terms of the GNU General Public License version 2 as
541d22f7bSJozsef Kadlecsik  * published by the Free Software Foundation.
641d22f7bSJozsef Kadlecsik  */
741d22f7bSJozsef Kadlecsik 
841d22f7bSJozsef Kadlecsik /* Kernel module implementing an IP set type: the hash:ip,port,net type */
941d22f7bSJozsef Kadlecsik 
1041d22f7bSJozsef Kadlecsik #include <linux/jhash.h>
1141d22f7bSJozsef Kadlecsik #include <linux/module.h>
1241d22f7bSJozsef Kadlecsik #include <linux/ip.h>
1341d22f7bSJozsef Kadlecsik #include <linux/skbuff.h>
1441d22f7bSJozsef Kadlecsik #include <linux/errno.h>
1541d22f7bSJozsef Kadlecsik #include <linux/random.h>
1641d22f7bSJozsef Kadlecsik #include <net/ip.h>
1741d22f7bSJozsef Kadlecsik #include <net/ipv6.h>
1841d22f7bSJozsef Kadlecsik #include <net/netlink.h>
1941d22f7bSJozsef Kadlecsik #include <net/tcp.h>
2041d22f7bSJozsef Kadlecsik 
2141d22f7bSJozsef Kadlecsik #include <linux/netfilter.h>
2241d22f7bSJozsef Kadlecsik #include <linux/netfilter/ipset/pfxlen.h>
2341d22f7bSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set.h>
2441d22f7bSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_timeout.h>
2541d22f7bSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_getport.h>
2641d22f7bSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_hash.h>
2741d22f7bSJozsef Kadlecsik 
2841d22f7bSJozsef Kadlecsik MODULE_LICENSE("GPL");
2941d22f7bSJozsef Kadlecsik MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
3041d22f7bSJozsef Kadlecsik MODULE_DESCRIPTION("hash:ip,port,net type of IP sets");
3141d22f7bSJozsef Kadlecsik MODULE_ALIAS("ip_set_hash:ip,port,net");
3241d22f7bSJozsef Kadlecsik 
3341d22f7bSJozsef Kadlecsik /* Type specific function prefix */
3441d22f7bSJozsef Kadlecsik #define TYPE		hash_ipportnet
3541d22f7bSJozsef Kadlecsik 
3641d22f7bSJozsef Kadlecsik static bool
3741d22f7bSJozsef Kadlecsik hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b);
3841d22f7bSJozsef Kadlecsik 
3941d22f7bSJozsef Kadlecsik #define hash_ipportnet4_same_set	hash_ipportnet_same_set
4041d22f7bSJozsef Kadlecsik #define hash_ipportnet6_same_set	hash_ipportnet_same_set
4141d22f7bSJozsef Kadlecsik 
4241d22f7bSJozsef Kadlecsik /* The type variant functions: IPv4 */
4341d22f7bSJozsef Kadlecsik 
4441d22f7bSJozsef Kadlecsik /* Member elements without timeout */
4541d22f7bSJozsef Kadlecsik struct hash_ipportnet4_elem {
4641d22f7bSJozsef Kadlecsik 	__be32 ip;
4741d22f7bSJozsef Kadlecsik 	__be32 ip2;
4841d22f7bSJozsef Kadlecsik 	__be16 port;
4941d22f7bSJozsef Kadlecsik 	u8 cidr;
5041d22f7bSJozsef Kadlecsik 	u8 proto;
5141d22f7bSJozsef Kadlecsik };
5241d22f7bSJozsef Kadlecsik 
5341d22f7bSJozsef Kadlecsik /* Member elements with timeout support */
5441d22f7bSJozsef Kadlecsik struct hash_ipportnet4_telem {
5541d22f7bSJozsef Kadlecsik 	__be32 ip;
5641d22f7bSJozsef Kadlecsik 	__be32 ip2;
5741d22f7bSJozsef Kadlecsik 	__be16 port;
5841d22f7bSJozsef Kadlecsik 	u8 cidr;
5941d22f7bSJozsef Kadlecsik 	u8 proto;
6041d22f7bSJozsef Kadlecsik 	unsigned long timeout;
6141d22f7bSJozsef Kadlecsik };
6241d22f7bSJozsef Kadlecsik 
6341d22f7bSJozsef Kadlecsik static inline bool
6441d22f7bSJozsef Kadlecsik hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
6541d22f7bSJozsef Kadlecsik 			   const struct hash_ipportnet4_elem *ip2)
6641d22f7bSJozsef Kadlecsik {
6741d22f7bSJozsef Kadlecsik 	return ip1->ip == ip2->ip &&
6841d22f7bSJozsef Kadlecsik 	       ip1->ip2 == ip2->ip2 &&
6941d22f7bSJozsef Kadlecsik 	       ip1->cidr == ip2->cidr &&
7041d22f7bSJozsef Kadlecsik 	       ip1->port == ip2->port &&
7141d22f7bSJozsef Kadlecsik 	       ip1->proto == ip2->proto;
7241d22f7bSJozsef Kadlecsik }
7341d22f7bSJozsef Kadlecsik 
7441d22f7bSJozsef Kadlecsik static inline bool
7541d22f7bSJozsef Kadlecsik hash_ipportnet4_data_isnull(const struct hash_ipportnet4_elem *elem)
7641d22f7bSJozsef Kadlecsik {
7741d22f7bSJozsef Kadlecsik 	return elem->proto == 0;
7841d22f7bSJozsef Kadlecsik }
7941d22f7bSJozsef Kadlecsik 
8041d22f7bSJozsef Kadlecsik static inline void
8141d22f7bSJozsef Kadlecsik hash_ipportnet4_data_copy(struct hash_ipportnet4_elem *dst,
8241d22f7bSJozsef Kadlecsik 			  const struct hash_ipportnet4_elem *src)
8341d22f7bSJozsef Kadlecsik {
8441d22f7bSJozsef Kadlecsik 	memcpy(dst, src, sizeof(*dst));
8541d22f7bSJozsef Kadlecsik }
8641d22f7bSJozsef Kadlecsik 
8741d22f7bSJozsef Kadlecsik static inline void
8841d22f7bSJozsef Kadlecsik hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
8941d22f7bSJozsef Kadlecsik {
9041d22f7bSJozsef Kadlecsik 	elem->ip2 &= ip_set_netmask(cidr);
9141d22f7bSJozsef Kadlecsik 	elem->cidr = cidr;
9241d22f7bSJozsef Kadlecsik }
9341d22f7bSJozsef Kadlecsik 
9441d22f7bSJozsef Kadlecsik static inline void
9541d22f7bSJozsef Kadlecsik hash_ipportnet4_data_zero_out(struct hash_ipportnet4_elem *elem)
9641d22f7bSJozsef Kadlecsik {
9741d22f7bSJozsef Kadlecsik 	elem->proto = 0;
9841d22f7bSJozsef Kadlecsik }
9941d22f7bSJozsef Kadlecsik 
10041d22f7bSJozsef Kadlecsik static bool
10141d22f7bSJozsef Kadlecsik hash_ipportnet4_data_list(struct sk_buff *skb,
10241d22f7bSJozsef Kadlecsik 			  const struct hash_ipportnet4_elem *data)
10341d22f7bSJozsef Kadlecsik {
10441d22f7bSJozsef Kadlecsik 	NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
10541d22f7bSJozsef Kadlecsik 	NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2);
10641d22f7bSJozsef Kadlecsik 	NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
10741d22f7bSJozsef Kadlecsik 	NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
10841d22f7bSJozsef Kadlecsik 	NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
10941d22f7bSJozsef Kadlecsik 	return 0;
11041d22f7bSJozsef Kadlecsik 
11141d22f7bSJozsef Kadlecsik nla_put_failure:
11241d22f7bSJozsef Kadlecsik 	return 1;
11341d22f7bSJozsef Kadlecsik }
11441d22f7bSJozsef Kadlecsik 
11541d22f7bSJozsef Kadlecsik static bool
11641d22f7bSJozsef Kadlecsik hash_ipportnet4_data_tlist(struct sk_buff *skb,
11741d22f7bSJozsef Kadlecsik 			   const struct hash_ipportnet4_elem *data)
11841d22f7bSJozsef Kadlecsik {
11941d22f7bSJozsef Kadlecsik 	const struct hash_ipportnet4_telem *tdata =
12041d22f7bSJozsef Kadlecsik 		(const struct hash_ipportnet4_telem *)data;
12141d22f7bSJozsef Kadlecsik 
12241d22f7bSJozsef Kadlecsik 	NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
12341d22f7bSJozsef Kadlecsik 	NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2);
12441d22f7bSJozsef Kadlecsik 	NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
12541d22f7bSJozsef Kadlecsik 	NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
12641d22f7bSJozsef Kadlecsik 	NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
12741d22f7bSJozsef Kadlecsik 	NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
12841d22f7bSJozsef Kadlecsik 		      htonl(ip_set_timeout_get(tdata->timeout)));
12941d22f7bSJozsef Kadlecsik 
13041d22f7bSJozsef Kadlecsik 	return 0;
13141d22f7bSJozsef Kadlecsik 
13241d22f7bSJozsef Kadlecsik nla_put_failure:
13341d22f7bSJozsef Kadlecsik 	return 1;
13441d22f7bSJozsef Kadlecsik }
13541d22f7bSJozsef Kadlecsik 
13641d22f7bSJozsef Kadlecsik #define IP_SET_HASH_WITH_PROTO
13741d22f7bSJozsef Kadlecsik #define IP_SET_HASH_WITH_NETS
13841d22f7bSJozsef Kadlecsik 
13941d22f7bSJozsef Kadlecsik #define PF		4
14041d22f7bSJozsef Kadlecsik #define HOST_MASK	32
14141d22f7bSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_ahash.h>
14241d22f7bSJozsef Kadlecsik 
14341d22f7bSJozsef Kadlecsik static int
14441d22f7bSJozsef Kadlecsik hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
145ac8cc925SJozsef Kadlecsik 		     enum ipset_adt adt, const struct ip_set_adt_opt *opt)
14641d22f7bSJozsef Kadlecsik {
14741d22f7bSJozsef Kadlecsik 	const struct ip_set_hash *h = set->data;
14841d22f7bSJozsef Kadlecsik 	ipset_adtfn adtfn = set->variant->adt[adt];
14941d22f7bSJozsef Kadlecsik 	struct hash_ipportnet4_elem data =
15041d22f7bSJozsef Kadlecsik 		{ .cidr = h->nets[0].cidr || HOST_MASK };
15141d22f7bSJozsef Kadlecsik 
15241d22f7bSJozsef Kadlecsik 	if (data.cidr == 0)
15341d22f7bSJozsef Kadlecsik 		return -EINVAL;
15441d22f7bSJozsef Kadlecsik 	if (adt == IPSET_TEST)
15541d22f7bSJozsef Kadlecsik 		data.cidr = HOST_MASK;
15641d22f7bSJozsef Kadlecsik 
157ac8cc925SJozsef Kadlecsik 	if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
15841d22f7bSJozsef Kadlecsik 				 &data.port, &data.proto))
15941d22f7bSJozsef Kadlecsik 		return -EINVAL;
16041d22f7bSJozsef Kadlecsik 
161ac8cc925SJozsef Kadlecsik 	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
162ac8cc925SJozsef Kadlecsik 	ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
16341d22f7bSJozsef Kadlecsik 	data.ip2 &= ip_set_netmask(data.cidr);
16441d22f7bSJozsef Kadlecsik 
165ac8cc925SJozsef Kadlecsik 	return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
16641d22f7bSJozsef Kadlecsik }
16741d22f7bSJozsef Kadlecsik 
16841d22f7bSJozsef Kadlecsik static int
16941d22f7bSJozsef Kadlecsik hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
17041d22f7bSJozsef Kadlecsik 		     enum ipset_adt adt, u32 *lineno, u32 flags)
17141d22f7bSJozsef Kadlecsik {
17241d22f7bSJozsef Kadlecsik 	const struct ip_set_hash *h = set->data;
17341d22f7bSJozsef Kadlecsik 	ipset_adtfn adtfn = set->variant->adt[adt];
17441d22f7bSJozsef Kadlecsik 	struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
17541d22f7bSJozsef Kadlecsik 	u32 ip, ip_to, p, port, port_to;
17641d22f7bSJozsef Kadlecsik 	u32 timeout = h->timeout;
1775e0c1eb7SJozsef Kadlecsik 	bool with_ports = false;
17841d22f7bSJozsef Kadlecsik 	int ret;
17941d22f7bSJozsef Kadlecsik 
18041d22f7bSJozsef Kadlecsik 	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
18141d22f7bSJozsef Kadlecsik 		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
18241d22f7bSJozsef Kadlecsik 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
18341d22f7bSJozsef Kadlecsik 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
18441d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_PROTOCOL;
18541d22f7bSJozsef Kadlecsik 
18641d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_LINENO])
18741d22f7bSJozsef Kadlecsik 		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
18841d22f7bSJozsef Kadlecsik 
18941d22f7bSJozsef Kadlecsik 	ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
19041d22f7bSJozsef Kadlecsik 	if (ret)
19141d22f7bSJozsef Kadlecsik 		return ret;
19241d22f7bSJozsef Kadlecsik 
19341d22f7bSJozsef Kadlecsik 	ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
19441d22f7bSJozsef Kadlecsik 	if (ret)
19541d22f7bSJozsef Kadlecsik 		return ret;
19641d22f7bSJozsef Kadlecsik 
19741d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_CIDR2])
19841d22f7bSJozsef Kadlecsik 		data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
19941d22f7bSJozsef Kadlecsik 
20041d22f7bSJozsef Kadlecsik 	if (!data.cidr)
20141d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_INVALID_CIDR;
20241d22f7bSJozsef Kadlecsik 
20341d22f7bSJozsef Kadlecsik 	data.ip2 &= ip_set_netmask(data.cidr);
20441d22f7bSJozsef Kadlecsik 
20541d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_PORT])
20641d22f7bSJozsef Kadlecsik 		data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
20741d22f7bSJozsef Kadlecsik 	else
20841d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_PROTOCOL;
20941d22f7bSJozsef Kadlecsik 
21041d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_PROTO]) {
21141d22f7bSJozsef Kadlecsik 		data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
2125e0c1eb7SJozsef Kadlecsik 		with_ports = ip_set_proto_with_ports(data.proto);
21341d22f7bSJozsef Kadlecsik 
21441d22f7bSJozsef Kadlecsik 		if (data.proto == 0)
21541d22f7bSJozsef Kadlecsik 			return -IPSET_ERR_INVALID_PROTO;
21641d22f7bSJozsef Kadlecsik 	} else
21741d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_MISSING_PROTO;
21841d22f7bSJozsef Kadlecsik 
2195e0c1eb7SJozsef Kadlecsik 	if (!(with_ports || data.proto == IPPROTO_ICMP))
22041d22f7bSJozsef Kadlecsik 		data.port = 0;
22141d22f7bSJozsef Kadlecsik 
22241d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_TIMEOUT]) {
22341d22f7bSJozsef Kadlecsik 		if (!with_timeout(h->timeout))
22441d22f7bSJozsef Kadlecsik 			return -IPSET_ERR_TIMEOUT;
22541d22f7bSJozsef Kadlecsik 		timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
22641d22f7bSJozsef Kadlecsik 	}
22741d22f7bSJozsef Kadlecsik 
22841d22f7bSJozsef Kadlecsik 	if (adt == IPSET_TEST ||
22941d22f7bSJozsef Kadlecsik 	    !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
23041d22f7bSJozsef Kadlecsik 	      tb[IPSET_ATTR_PORT_TO])) {
2315416219eSJozsef Kadlecsik 		ret = adtfn(set, &data, timeout, flags);
23241d22f7bSJozsef Kadlecsik 		return ip_set_eexist(ret, flags) ? 0 : ret;
23341d22f7bSJozsef Kadlecsik 	}
23441d22f7bSJozsef Kadlecsik 
23541d22f7bSJozsef Kadlecsik 	ip = ntohl(data.ip);
23641d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_IP_TO]) {
23741d22f7bSJozsef Kadlecsik 		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
23841d22f7bSJozsef Kadlecsik 		if (ret)
23941d22f7bSJozsef Kadlecsik 			return ret;
24041d22f7bSJozsef Kadlecsik 		if (ip > ip_to)
24141d22f7bSJozsef Kadlecsik 			swap(ip, ip_to);
24241d22f7bSJozsef Kadlecsik 	} else if (tb[IPSET_ATTR_CIDR]) {
24341d22f7bSJozsef Kadlecsik 		u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
24441d22f7bSJozsef Kadlecsik 
24541d22f7bSJozsef Kadlecsik 		if (cidr > 32)
24641d22f7bSJozsef Kadlecsik 			return -IPSET_ERR_INVALID_CIDR;
24741d22f7bSJozsef Kadlecsik 		ip &= ip_set_hostmask(cidr);
24841d22f7bSJozsef Kadlecsik 		ip_to = ip | ~ip_set_hostmask(cidr);
24941d22f7bSJozsef Kadlecsik 	} else
25041d22f7bSJozsef Kadlecsik 		ip_to = ip;
25141d22f7bSJozsef Kadlecsik 
2525e0c1eb7SJozsef Kadlecsik 	port_to = port = ntohs(data.port);
2535e0c1eb7SJozsef Kadlecsik 	if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
25441d22f7bSJozsef Kadlecsik 		port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
25541d22f7bSJozsef Kadlecsik 		if (port > port_to)
25641d22f7bSJozsef Kadlecsik 			swap(port, port_to);
2575e0c1eb7SJozsef Kadlecsik 	}
25841d22f7bSJozsef Kadlecsik 
25941d22f7bSJozsef Kadlecsik 	for (; !before(ip_to, ip); ip++)
26041d22f7bSJozsef Kadlecsik 		for (p = port; p <= port_to; p++) {
26141d22f7bSJozsef Kadlecsik 			data.ip = htonl(ip);
26241d22f7bSJozsef Kadlecsik 			data.port = htons(p);
2635416219eSJozsef Kadlecsik 			ret = adtfn(set, &data, timeout, flags);
26441d22f7bSJozsef Kadlecsik 
26541d22f7bSJozsef Kadlecsik 			if (ret && !ip_set_eexist(ret, flags))
26641d22f7bSJozsef Kadlecsik 				return ret;
26741d22f7bSJozsef Kadlecsik 			else
26841d22f7bSJozsef Kadlecsik 				ret = 0;
26941d22f7bSJozsef Kadlecsik 		}
27041d22f7bSJozsef Kadlecsik 	return ret;
27141d22f7bSJozsef Kadlecsik }
27241d22f7bSJozsef Kadlecsik 
27341d22f7bSJozsef Kadlecsik static bool
27441d22f7bSJozsef Kadlecsik hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b)
27541d22f7bSJozsef Kadlecsik {
27641d22f7bSJozsef Kadlecsik 	const struct ip_set_hash *x = a->data;
27741d22f7bSJozsef Kadlecsik 	const struct ip_set_hash *y = b->data;
27841d22f7bSJozsef Kadlecsik 
27941d22f7bSJozsef Kadlecsik 	/* Resizing changes htable_bits, so we ignore it */
28041d22f7bSJozsef Kadlecsik 	return x->maxelem == y->maxelem &&
28141d22f7bSJozsef Kadlecsik 	       x->timeout == y->timeout;
28241d22f7bSJozsef Kadlecsik }
28341d22f7bSJozsef Kadlecsik 
28441d22f7bSJozsef Kadlecsik /* The type variant functions: IPv6 */
28541d22f7bSJozsef Kadlecsik 
28641d22f7bSJozsef Kadlecsik struct hash_ipportnet6_elem {
28741d22f7bSJozsef Kadlecsik 	union nf_inet_addr ip;
28841d22f7bSJozsef Kadlecsik 	union nf_inet_addr ip2;
28941d22f7bSJozsef Kadlecsik 	__be16 port;
29041d22f7bSJozsef Kadlecsik 	u8 cidr;
29141d22f7bSJozsef Kadlecsik 	u8 proto;
29241d22f7bSJozsef Kadlecsik };
29341d22f7bSJozsef Kadlecsik 
29441d22f7bSJozsef Kadlecsik struct hash_ipportnet6_telem {
29541d22f7bSJozsef Kadlecsik 	union nf_inet_addr ip;
29641d22f7bSJozsef Kadlecsik 	union nf_inet_addr ip2;
29741d22f7bSJozsef Kadlecsik 	__be16 port;
29841d22f7bSJozsef Kadlecsik 	u8 cidr;
29941d22f7bSJozsef Kadlecsik 	u8 proto;
30041d22f7bSJozsef Kadlecsik 	unsigned long timeout;
30141d22f7bSJozsef Kadlecsik };
30241d22f7bSJozsef Kadlecsik 
30341d22f7bSJozsef Kadlecsik static inline bool
30441d22f7bSJozsef Kadlecsik hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
30541d22f7bSJozsef Kadlecsik 			   const struct hash_ipportnet6_elem *ip2)
30641d22f7bSJozsef Kadlecsik {
30741d22f7bSJozsef Kadlecsik 	return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
30841d22f7bSJozsef Kadlecsik 	       ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
30941d22f7bSJozsef Kadlecsik 	       ip1->cidr == ip2->cidr &&
31041d22f7bSJozsef Kadlecsik 	       ip1->port == ip2->port &&
31141d22f7bSJozsef Kadlecsik 	       ip1->proto == ip2->proto;
31241d22f7bSJozsef Kadlecsik }
31341d22f7bSJozsef Kadlecsik 
31441d22f7bSJozsef Kadlecsik static inline bool
31541d22f7bSJozsef Kadlecsik hash_ipportnet6_data_isnull(const struct hash_ipportnet6_elem *elem)
31641d22f7bSJozsef Kadlecsik {
31741d22f7bSJozsef Kadlecsik 	return elem->proto == 0;
31841d22f7bSJozsef Kadlecsik }
31941d22f7bSJozsef Kadlecsik 
32041d22f7bSJozsef Kadlecsik static inline void
32141d22f7bSJozsef Kadlecsik hash_ipportnet6_data_copy(struct hash_ipportnet6_elem *dst,
32241d22f7bSJozsef Kadlecsik 			  const struct hash_ipportnet6_elem *src)
32341d22f7bSJozsef Kadlecsik {
32441d22f7bSJozsef Kadlecsik 	memcpy(dst, src, sizeof(*dst));
32541d22f7bSJozsef Kadlecsik }
32641d22f7bSJozsef Kadlecsik 
32741d22f7bSJozsef Kadlecsik static inline void
32841d22f7bSJozsef Kadlecsik hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem)
32941d22f7bSJozsef Kadlecsik {
33041d22f7bSJozsef Kadlecsik 	elem->proto = 0;
33141d22f7bSJozsef Kadlecsik }
33241d22f7bSJozsef Kadlecsik 
33341d22f7bSJozsef Kadlecsik static inline void
33441d22f7bSJozsef Kadlecsik ip6_netmask(union nf_inet_addr *ip, u8 prefix)
33541d22f7bSJozsef Kadlecsik {
33641d22f7bSJozsef Kadlecsik 	ip->ip6[0] &= ip_set_netmask6(prefix)[0];
33741d22f7bSJozsef Kadlecsik 	ip->ip6[1] &= ip_set_netmask6(prefix)[1];
33841d22f7bSJozsef Kadlecsik 	ip->ip6[2] &= ip_set_netmask6(prefix)[2];
33941d22f7bSJozsef Kadlecsik 	ip->ip6[3] &= ip_set_netmask6(prefix)[3];
34041d22f7bSJozsef Kadlecsik }
34141d22f7bSJozsef Kadlecsik 
34241d22f7bSJozsef Kadlecsik static inline void
34341d22f7bSJozsef Kadlecsik hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr)
34441d22f7bSJozsef Kadlecsik {
34541d22f7bSJozsef Kadlecsik 	ip6_netmask(&elem->ip2, cidr);
34641d22f7bSJozsef Kadlecsik 	elem->cidr = cidr;
34741d22f7bSJozsef Kadlecsik }
34841d22f7bSJozsef Kadlecsik 
34941d22f7bSJozsef Kadlecsik static bool
35041d22f7bSJozsef Kadlecsik hash_ipportnet6_data_list(struct sk_buff *skb,
35141d22f7bSJozsef Kadlecsik 			  const struct hash_ipportnet6_elem *data)
35241d22f7bSJozsef Kadlecsik {
35341d22f7bSJozsef Kadlecsik 	NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
35441d22f7bSJozsef Kadlecsik 	NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
35541d22f7bSJozsef Kadlecsik 	NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
35641d22f7bSJozsef Kadlecsik 	NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
35741d22f7bSJozsef Kadlecsik 	NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
35841d22f7bSJozsef Kadlecsik 	return 0;
35941d22f7bSJozsef Kadlecsik 
36041d22f7bSJozsef Kadlecsik nla_put_failure:
36141d22f7bSJozsef Kadlecsik 	return 1;
36241d22f7bSJozsef Kadlecsik }
36341d22f7bSJozsef Kadlecsik 
36441d22f7bSJozsef Kadlecsik static bool
36541d22f7bSJozsef Kadlecsik hash_ipportnet6_data_tlist(struct sk_buff *skb,
36641d22f7bSJozsef Kadlecsik 			   const struct hash_ipportnet6_elem *data)
36741d22f7bSJozsef Kadlecsik {
36841d22f7bSJozsef Kadlecsik 	const struct hash_ipportnet6_telem *e =
36941d22f7bSJozsef Kadlecsik 		(const struct hash_ipportnet6_telem *)data;
37041d22f7bSJozsef Kadlecsik 
37141d22f7bSJozsef Kadlecsik 	NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
37241d22f7bSJozsef Kadlecsik 	NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
37341d22f7bSJozsef Kadlecsik 	NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
37441d22f7bSJozsef Kadlecsik 	NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
37541d22f7bSJozsef Kadlecsik 	NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
37641d22f7bSJozsef Kadlecsik 	NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
37741d22f7bSJozsef Kadlecsik 		      htonl(ip_set_timeout_get(e->timeout)));
37841d22f7bSJozsef Kadlecsik 	return 0;
37941d22f7bSJozsef Kadlecsik 
38041d22f7bSJozsef Kadlecsik nla_put_failure:
38141d22f7bSJozsef Kadlecsik 	return 1;
38241d22f7bSJozsef Kadlecsik }
38341d22f7bSJozsef Kadlecsik 
38441d22f7bSJozsef Kadlecsik #undef PF
38541d22f7bSJozsef Kadlecsik #undef HOST_MASK
38641d22f7bSJozsef Kadlecsik 
38741d22f7bSJozsef Kadlecsik #define PF		6
38841d22f7bSJozsef Kadlecsik #define HOST_MASK	128
38941d22f7bSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_ahash.h>
39041d22f7bSJozsef Kadlecsik 
39141d22f7bSJozsef Kadlecsik static int
39241d22f7bSJozsef Kadlecsik hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
393ac8cc925SJozsef Kadlecsik 		     enum ipset_adt adt, const struct ip_set_adt_opt *opt)
39441d22f7bSJozsef Kadlecsik {
39541d22f7bSJozsef Kadlecsik 	const struct ip_set_hash *h = set->data;
39641d22f7bSJozsef Kadlecsik 	ipset_adtfn adtfn = set->variant->adt[adt];
39741d22f7bSJozsef Kadlecsik 	struct hash_ipportnet6_elem data =
39841d22f7bSJozsef Kadlecsik 		{ .cidr = h->nets[0].cidr || HOST_MASK };
39941d22f7bSJozsef Kadlecsik 
40041d22f7bSJozsef Kadlecsik 	if (data.cidr == 0)
40141d22f7bSJozsef Kadlecsik 		return -EINVAL;
40241d22f7bSJozsef Kadlecsik 	if (adt == IPSET_TEST)
40341d22f7bSJozsef Kadlecsik 		data.cidr = HOST_MASK;
40441d22f7bSJozsef Kadlecsik 
405ac8cc925SJozsef Kadlecsik 	if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
40641d22f7bSJozsef Kadlecsik 				 &data.port, &data.proto))
40741d22f7bSJozsef Kadlecsik 		return -EINVAL;
40841d22f7bSJozsef Kadlecsik 
409ac8cc925SJozsef Kadlecsik 	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
410ac8cc925SJozsef Kadlecsik 	ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
41141d22f7bSJozsef Kadlecsik 	ip6_netmask(&data.ip2, data.cidr);
41241d22f7bSJozsef Kadlecsik 
413ac8cc925SJozsef Kadlecsik 	return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
41441d22f7bSJozsef Kadlecsik }
41541d22f7bSJozsef Kadlecsik 
41641d22f7bSJozsef Kadlecsik static int
41741d22f7bSJozsef Kadlecsik hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
41841d22f7bSJozsef Kadlecsik 		     enum ipset_adt adt, u32 *lineno, u32 flags)
41941d22f7bSJozsef Kadlecsik {
42041d22f7bSJozsef Kadlecsik 	const struct ip_set_hash *h = set->data;
42141d22f7bSJozsef Kadlecsik 	ipset_adtfn adtfn = set->variant->adt[adt];
42241d22f7bSJozsef Kadlecsik 	struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
42341d22f7bSJozsef Kadlecsik 	u32 port, port_to;
42441d22f7bSJozsef Kadlecsik 	u32 timeout = h->timeout;
4255e0c1eb7SJozsef Kadlecsik 	bool with_ports = false;
42641d22f7bSJozsef Kadlecsik 	int ret;
42741d22f7bSJozsef Kadlecsik 
42841d22f7bSJozsef Kadlecsik 	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
42941d22f7bSJozsef Kadlecsik 		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
43041d22f7bSJozsef Kadlecsik 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
43141d22f7bSJozsef Kadlecsik 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
43241d22f7bSJozsef Kadlecsik 		     tb[IPSET_ATTR_IP_TO] ||
43341d22f7bSJozsef Kadlecsik 		     tb[IPSET_ATTR_CIDR]))
43441d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_PROTOCOL;
43541d22f7bSJozsef Kadlecsik 
43641d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_LINENO])
43741d22f7bSJozsef Kadlecsik 		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
43841d22f7bSJozsef Kadlecsik 
43941d22f7bSJozsef Kadlecsik 	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
44041d22f7bSJozsef Kadlecsik 	if (ret)
44141d22f7bSJozsef Kadlecsik 		return ret;
44241d22f7bSJozsef Kadlecsik 
44341d22f7bSJozsef Kadlecsik 	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &data.ip2);
44441d22f7bSJozsef Kadlecsik 	if (ret)
44541d22f7bSJozsef Kadlecsik 		return ret;
44641d22f7bSJozsef Kadlecsik 
44741d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_CIDR2])
44841d22f7bSJozsef Kadlecsik 		data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
44941d22f7bSJozsef Kadlecsik 
45041d22f7bSJozsef Kadlecsik 	if (!data.cidr)
45141d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_INVALID_CIDR;
45241d22f7bSJozsef Kadlecsik 
45341d22f7bSJozsef Kadlecsik 	ip6_netmask(&data.ip2, data.cidr);
45441d22f7bSJozsef Kadlecsik 
45541d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_PORT])
45641d22f7bSJozsef Kadlecsik 		data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
45741d22f7bSJozsef Kadlecsik 	else
45841d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_PROTOCOL;
45941d22f7bSJozsef Kadlecsik 
46041d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_PROTO]) {
46141d22f7bSJozsef Kadlecsik 		data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
4625e0c1eb7SJozsef Kadlecsik 		with_ports = ip_set_proto_with_ports(data.proto);
46341d22f7bSJozsef Kadlecsik 
46441d22f7bSJozsef Kadlecsik 		if (data.proto == 0)
46541d22f7bSJozsef Kadlecsik 			return -IPSET_ERR_INVALID_PROTO;
46641d22f7bSJozsef Kadlecsik 	} else
46741d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_MISSING_PROTO;
46841d22f7bSJozsef Kadlecsik 
4695e0c1eb7SJozsef Kadlecsik 	if (!(with_ports || data.proto == IPPROTO_ICMPV6))
47041d22f7bSJozsef Kadlecsik 		data.port = 0;
47141d22f7bSJozsef Kadlecsik 
47241d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_TIMEOUT]) {
47341d22f7bSJozsef Kadlecsik 		if (!with_timeout(h->timeout))
47441d22f7bSJozsef Kadlecsik 			return -IPSET_ERR_TIMEOUT;
47541d22f7bSJozsef Kadlecsik 		timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
47641d22f7bSJozsef Kadlecsik 	}
47741d22f7bSJozsef Kadlecsik 
4785e0c1eb7SJozsef Kadlecsik 	if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
4795416219eSJozsef Kadlecsik 		ret = adtfn(set, &data, timeout, flags);
48041d22f7bSJozsef Kadlecsik 		return ip_set_eexist(ret, flags) ? 0 : ret;
48141d22f7bSJozsef Kadlecsik 	}
48241d22f7bSJozsef Kadlecsik 
48341d22f7bSJozsef Kadlecsik 	port = ntohs(data.port);
48441d22f7bSJozsef Kadlecsik 	port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
48541d22f7bSJozsef Kadlecsik 	if (port > port_to)
48641d22f7bSJozsef Kadlecsik 		swap(port, port_to);
48741d22f7bSJozsef Kadlecsik 
48841d22f7bSJozsef Kadlecsik 	for (; port <= port_to; port++) {
48941d22f7bSJozsef Kadlecsik 		data.port = htons(port);
4905416219eSJozsef Kadlecsik 		ret = adtfn(set, &data, timeout, flags);
49141d22f7bSJozsef Kadlecsik 
49241d22f7bSJozsef Kadlecsik 		if (ret && !ip_set_eexist(ret, flags))
49341d22f7bSJozsef Kadlecsik 			return ret;
49441d22f7bSJozsef Kadlecsik 		else
49541d22f7bSJozsef Kadlecsik 			ret = 0;
49641d22f7bSJozsef Kadlecsik 	}
49741d22f7bSJozsef Kadlecsik 	return ret;
49841d22f7bSJozsef Kadlecsik }
49941d22f7bSJozsef Kadlecsik 
50041d22f7bSJozsef Kadlecsik /* Create hash:ip type of sets */
50141d22f7bSJozsef Kadlecsik 
50241d22f7bSJozsef Kadlecsik static int
50341d22f7bSJozsef Kadlecsik hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
50441d22f7bSJozsef Kadlecsik {
50541d22f7bSJozsef Kadlecsik 	struct ip_set_hash *h;
50641d22f7bSJozsef Kadlecsik 	u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
50741d22f7bSJozsef Kadlecsik 	u8 hbits;
50841d22f7bSJozsef Kadlecsik 
50941d22f7bSJozsef Kadlecsik 	if (!(set->family == AF_INET || set->family == AF_INET6))
51041d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_INVALID_FAMILY;
51141d22f7bSJozsef Kadlecsik 
51241d22f7bSJozsef Kadlecsik 	if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
51341d22f7bSJozsef Kadlecsik 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
51441d22f7bSJozsef Kadlecsik 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
51541d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_PROTOCOL;
51641d22f7bSJozsef Kadlecsik 
51741d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_HASHSIZE]) {
51841d22f7bSJozsef Kadlecsik 		hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
51941d22f7bSJozsef Kadlecsik 		if (hashsize < IPSET_MIMINAL_HASHSIZE)
52041d22f7bSJozsef Kadlecsik 			hashsize = IPSET_MIMINAL_HASHSIZE;
52141d22f7bSJozsef Kadlecsik 	}
52241d22f7bSJozsef Kadlecsik 
52341d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_MAXELEM])
52441d22f7bSJozsef Kadlecsik 		maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
52541d22f7bSJozsef Kadlecsik 
52641d22f7bSJozsef Kadlecsik 	h = kzalloc(sizeof(*h)
52741d22f7bSJozsef Kadlecsik 		    + sizeof(struct ip_set_hash_nets)
52841d22f7bSJozsef Kadlecsik 		      * (set->family == AF_INET ? 32 : 128), GFP_KERNEL);
52941d22f7bSJozsef Kadlecsik 	if (!h)
53041d22f7bSJozsef Kadlecsik 		return -ENOMEM;
53141d22f7bSJozsef Kadlecsik 
53241d22f7bSJozsef Kadlecsik 	h->maxelem = maxelem;
53341d22f7bSJozsef Kadlecsik 	get_random_bytes(&h->initval, sizeof(h->initval));
53441d22f7bSJozsef Kadlecsik 	h->timeout = IPSET_NO_TIMEOUT;
53541d22f7bSJozsef Kadlecsik 
53641d22f7bSJozsef Kadlecsik 	hbits = htable_bits(hashsize);
53741d22f7bSJozsef Kadlecsik 	h->table = ip_set_alloc(
53841d22f7bSJozsef Kadlecsik 			sizeof(struct htable)
53941d22f7bSJozsef Kadlecsik 			+ jhash_size(hbits) * sizeof(struct hbucket));
54041d22f7bSJozsef Kadlecsik 	if (!h->table) {
54141d22f7bSJozsef Kadlecsik 		kfree(h);
54241d22f7bSJozsef Kadlecsik 		return -ENOMEM;
54341d22f7bSJozsef Kadlecsik 	}
54441d22f7bSJozsef Kadlecsik 	h->table->htable_bits = hbits;
54541d22f7bSJozsef Kadlecsik 
54641d22f7bSJozsef Kadlecsik 	set->data = h;
54741d22f7bSJozsef Kadlecsik 
54841d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_TIMEOUT]) {
54941d22f7bSJozsef Kadlecsik 		h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
55041d22f7bSJozsef Kadlecsik 
55141d22f7bSJozsef Kadlecsik 		set->variant = set->family == AF_INET
55241d22f7bSJozsef Kadlecsik 			? &hash_ipportnet4_tvariant
55341d22f7bSJozsef Kadlecsik 			: &hash_ipportnet6_tvariant;
55441d22f7bSJozsef Kadlecsik 
55541d22f7bSJozsef Kadlecsik 		if (set->family == AF_INET)
55641d22f7bSJozsef Kadlecsik 			hash_ipportnet4_gc_init(set);
55741d22f7bSJozsef Kadlecsik 		else
55841d22f7bSJozsef Kadlecsik 			hash_ipportnet6_gc_init(set);
55941d22f7bSJozsef Kadlecsik 	} else {
56041d22f7bSJozsef Kadlecsik 		set->variant = set->family == AF_INET
56141d22f7bSJozsef Kadlecsik 			? &hash_ipportnet4_variant : &hash_ipportnet6_variant;
56241d22f7bSJozsef Kadlecsik 	}
56341d22f7bSJozsef Kadlecsik 
56441d22f7bSJozsef Kadlecsik 	pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
56541d22f7bSJozsef Kadlecsik 		 set->name, jhash_size(h->table->htable_bits),
56641d22f7bSJozsef Kadlecsik 		 h->table->htable_bits, h->maxelem, set->data, h->table);
56741d22f7bSJozsef Kadlecsik 
56841d22f7bSJozsef Kadlecsik 	return 0;
56941d22f7bSJozsef Kadlecsik }
57041d22f7bSJozsef Kadlecsik 
57141d22f7bSJozsef Kadlecsik static struct ip_set_type hash_ipportnet_type __read_mostly = {
57241d22f7bSJozsef Kadlecsik 	.name		= "hash:ip,port,net",
57341d22f7bSJozsef Kadlecsik 	.protocol	= IPSET_PROTOCOL,
57441d22f7bSJozsef Kadlecsik 	.features	= IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
57541d22f7bSJozsef Kadlecsik 	.dimension	= IPSET_DIM_THREE,
57641d22f7bSJozsef Kadlecsik 	.family		= AF_UNSPEC,
57791eb7c08SJozsef Kadlecsik 	.revision	= 1,
57841d22f7bSJozsef Kadlecsik 	.create		= hash_ipportnet_create,
57941d22f7bSJozsef Kadlecsik 	.create_policy	= {
58041d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 },
58141d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_MAXELEM]	= { .type = NLA_U32 },
58241d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_PROBES]	= { .type = NLA_U8 },
58341d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_RESIZE]	= { .type = NLA_U8  },
58441d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
58541d22f7bSJozsef Kadlecsik 	},
58641d22f7bSJozsef Kadlecsik 	.adt_policy	= {
58741d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_IP]		= { .type = NLA_NESTED },
58841d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_IP_TO]	= { .type = NLA_NESTED },
58941d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_IP2]	= { .type = NLA_NESTED },
59041d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_PORT]	= { .type = NLA_U16 },
59141d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_PORT_TO]	= { .type = NLA_U16 },
59241d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_CIDR]	= { .type = NLA_U8 },
59341d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_CIDR2]	= { .type = NLA_U8 },
59441d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_PROTO]	= { .type = NLA_U8 },
59541d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
59641d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },
59741d22f7bSJozsef Kadlecsik 	},
59841d22f7bSJozsef Kadlecsik 	.me		= THIS_MODULE,
59941d22f7bSJozsef Kadlecsik };
60041d22f7bSJozsef Kadlecsik 
60141d22f7bSJozsef Kadlecsik static int __init
60241d22f7bSJozsef Kadlecsik hash_ipportnet_init(void)
60341d22f7bSJozsef Kadlecsik {
60441d22f7bSJozsef Kadlecsik 	return ip_set_type_register(&hash_ipportnet_type);
60541d22f7bSJozsef Kadlecsik }
60641d22f7bSJozsef Kadlecsik 
60741d22f7bSJozsef Kadlecsik static void __exit
60841d22f7bSJozsef Kadlecsik hash_ipportnet_fini(void)
60941d22f7bSJozsef Kadlecsik {
61041d22f7bSJozsef Kadlecsik 	ip_set_type_unregister(&hash_ipportnet_type);
61141d22f7bSJozsef Kadlecsik }
61241d22f7bSJozsef Kadlecsik 
61341d22f7bSJozsef Kadlecsik module_init(hash_ipportnet_init);
61441d22f7bSJozsef Kadlecsik module_exit(hash_ipportnet_fini);
615