1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21c5ba67dSPablo Neira Ayuso /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
341d22f7bSJozsef Kadlecsik 
441d22f7bSJozsef Kadlecsik /* Kernel module implementing an IP set type: the hash:ip,port,net type */
541d22f7bSJozsef Kadlecsik 
641d22f7bSJozsef Kadlecsik #include <linux/jhash.h>
741d22f7bSJozsef Kadlecsik #include <linux/module.h>
841d22f7bSJozsef Kadlecsik #include <linux/ip.h>
941d22f7bSJozsef Kadlecsik #include <linux/skbuff.h>
1041d22f7bSJozsef Kadlecsik #include <linux/errno.h>
1141d22f7bSJozsef Kadlecsik #include <linux/random.h>
1241d22f7bSJozsef Kadlecsik #include <net/ip.h>
1341d22f7bSJozsef Kadlecsik #include <net/ipv6.h>
1441d22f7bSJozsef Kadlecsik #include <net/netlink.h>
1541d22f7bSJozsef Kadlecsik #include <net/tcp.h>
1641d22f7bSJozsef Kadlecsik 
1741d22f7bSJozsef Kadlecsik #include <linux/netfilter.h>
1841d22f7bSJozsef Kadlecsik #include <linux/netfilter/ipset/pfxlen.h>
1941d22f7bSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set.h>
2041d22f7bSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_getport.h>
2141d22f7bSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_hash.h>
2241d22f7bSJozsef Kadlecsik 
2335b8dcf8SJozsef Kadlecsik #define IPSET_TYPE_REV_MIN	0
2410111a6eSJozsef Kadlecsik /*				1    SCTP and UDPLITE support added */
2510111a6eSJozsef Kadlecsik /*				2    Range as input support for IPv4 added */
2600d71b27SJozsef Kadlecsik /*				3    nomatch flag support added */
27fda75c6dSOliver Smith /*				4    Counters support added */
2807cf8f5aSJosh Hunt /*				5    Comments support added */
29af331419SAnton Danilov /*				6    Forceadd support added */
30ccf0a4b7SJozsef Kadlecsik /*				7    skbinfo support added */
313976ca10SJozsef Kadlecsik #define IPSET_TYPE_REV_MAX	8 /* bucketsize, initval support added */
3210111a6eSJozsef Kadlecsik 
3341d22f7bSJozsef Kadlecsik MODULE_LICENSE("GPL");
34fe03d474SJozsef Kadlecsik MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
3535b8dcf8SJozsef Kadlecsik IP_SET_MODULE_DESC("hash:ip,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
3641d22f7bSJozsef Kadlecsik MODULE_ALIAS("ip_set_hash:ip,port,net");
3741d22f7bSJozsef Kadlecsik 
3841d22f7bSJozsef Kadlecsik /* Type specific function prefix */
395d50e1d8SJozsef Kadlecsik #define HTYPE		hash_ipportnet
4041d22f7bSJozsef Kadlecsik 
412a7cef2aSJozsef Kadlecsik /* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0
422a7cef2aSJozsef Kadlecsik  * However this way we have to store internally cidr - 1,
432a7cef2aSJozsef Kadlecsik  * dancing back and forth.
442a7cef2aSJozsef Kadlecsik  */
452a7cef2aSJozsef Kadlecsik #define IP_SET_HASH_WITH_NETS_PACKED
465d50e1d8SJozsef Kadlecsik #define IP_SET_HASH_WITH_PROTO
475d50e1d8SJozsef Kadlecsik #define IP_SET_HASH_WITH_NETS
482a7cef2aSJozsef Kadlecsik 
4903c8b234SJozsef Kadlecsik /* IPv4 variant */
505d50e1d8SJozsef Kadlecsik 
515d50e1d8SJozsef Kadlecsik /* Member elements */
5241d22f7bSJozsef Kadlecsik struct hash_ipportnet4_elem {
5341d22f7bSJozsef Kadlecsik 	__be32 ip;
5441d22f7bSJozsef Kadlecsik 	__be32 ip2;
5541d22f7bSJozsef Kadlecsik 	__be16 port;
562a7cef2aSJozsef Kadlecsik 	u8 cidr:7;
572a7cef2aSJozsef Kadlecsik 	u8 nomatch:1;
5841d22f7bSJozsef Kadlecsik 	u8 proto;
5941d22f7bSJozsef Kadlecsik };
6041d22f7bSJozsef Kadlecsik 
615d50e1d8SJozsef Kadlecsik /* Common functions */
625d50e1d8SJozsef Kadlecsik 
638dea982aSJeremy Sowden static bool
hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem * ip1,const struct hash_ipportnet4_elem * ip2,u32 * multi)6441d22f7bSJozsef Kadlecsik hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
6589dc79b7SJozsef Kadlecsik 			   const struct hash_ipportnet4_elem *ip2,
6689dc79b7SJozsef Kadlecsik 			   u32 *multi)
6741d22f7bSJozsef Kadlecsik {
6841d22f7bSJozsef Kadlecsik 	return ip1->ip == ip2->ip &&
6941d22f7bSJozsef Kadlecsik 	       ip1->ip2 == ip2->ip2 &&
7041d22f7bSJozsef Kadlecsik 	       ip1->cidr == ip2->cidr &&
7141d22f7bSJozsef Kadlecsik 	       ip1->port == ip2->port &&
7241d22f7bSJozsef Kadlecsik 	       ip1->proto == ip2->proto;
7341d22f7bSJozsef Kadlecsik }
7441d22f7bSJozsef Kadlecsik 
758dea982aSJeremy Sowden static int
hash_ipportnet4_do_data_match(const struct hash_ipportnet4_elem * elem)765d50e1d8SJozsef Kadlecsik hash_ipportnet4_do_data_match(const struct hash_ipportnet4_elem *elem)
772a7cef2aSJozsef Kadlecsik {
783e0304a5SJozsef Kadlecsik 	return elem->nomatch ? -ENOTEMPTY : 1;
792a7cef2aSJozsef Kadlecsik }
802a7cef2aSJozsef Kadlecsik 
818dea982aSJeremy Sowden static void
hash_ipportnet4_data_set_flags(struct hash_ipportnet4_elem * elem,u32 flags)825d50e1d8SJozsef Kadlecsik hash_ipportnet4_data_set_flags(struct hash_ipportnet4_elem *elem, u32 flags)
835d50e1d8SJozsef Kadlecsik {
845d50e1d8SJozsef Kadlecsik 	elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
855d50e1d8SJozsef Kadlecsik }
865d50e1d8SJozsef Kadlecsik 
878dea982aSJeremy Sowden static void
hash_ipportnet4_data_reset_flags(struct hash_ipportnet4_elem * elem,u8 * flags)885d50e1d8SJozsef Kadlecsik hash_ipportnet4_data_reset_flags(struct hash_ipportnet4_elem *elem, u8 *flags)
895d50e1d8SJozsef Kadlecsik {
905d50e1d8SJozsef Kadlecsik 	swap(*flags, elem->nomatch);
915d50e1d8SJozsef Kadlecsik }
925d50e1d8SJozsef Kadlecsik 
938dea982aSJeremy Sowden static void
hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem * elem,u8 cidr)9441d22f7bSJozsef Kadlecsik hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
9541d22f7bSJozsef Kadlecsik {
9641d22f7bSJozsef Kadlecsik 	elem->ip2 &= ip_set_netmask(cidr);
972a7cef2aSJozsef Kadlecsik 	elem->cidr = cidr - 1;
9841d22f7bSJozsef Kadlecsik }
9941d22f7bSJozsef Kadlecsik 
10041d22f7bSJozsef Kadlecsik static bool
hash_ipportnet4_data_list(struct sk_buff * skb,const struct hash_ipportnet4_elem * data)10141d22f7bSJozsef Kadlecsik hash_ipportnet4_data_list(struct sk_buff *skb,
10241d22f7bSJozsef Kadlecsik 			  const struct hash_ipportnet4_elem *data)
10341d22f7bSJozsef Kadlecsik {
1042a7cef2aSJozsef Kadlecsik 	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
1052a7cef2aSJozsef Kadlecsik 
1067cf7899dSDavid S. Miller 	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
1077cf7899dSDavid S. Miller 	    nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip2) ||
1087cf7899dSDavid S. Miller 	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
1097cf7899dSDavid S. Miller 	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
1107cf7899dSDavid S. Miller 	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
1117cf7899dSDavid S. Miller 	    (flags &&
1127cf7899dSDavid S. Miller 	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
1137cf7899dSDavid S. Miller 		goto nla_put_failure;
114728a7e69SSergey Popovich 	return false;
11541d22f7bSJozsef Kadlecsik 
11641d22f7bSJozsef Kadlecsik nla_put_failure:
117728a7e69SSergey Popovich 	return true;
11841d22f7bSJozsef Kadlecsik }
11941d22f7bSJozsef Kadlecsik 
1208dea982aSJeremy Sowden static void
hash_ipportnet4_data_next(struct hash_ipportnet4_elem * next,const struct hash_ipportnet4_elem * d)1215d50e1d8SJozsef Kadlecsik hash_ipportnet4_data_next(struct hash_ipportnet4_elem *next,
1223d14b171SJozsef Kadlecsik 			  const struct hash_ipportnet4_elem *d)
1233d14b171SJozsef Kadlecsik {
1245d50e1d8SJozsef Kadlecsik 	next->ip = d->ip;
1255d50e1d8SJozsef Kadlecsik 	next->port = d->port;
1265d50e1d8SJozsef Kadlecsik 	next->ip2 = d->ip2;
1273d14b171SJozsef Kadlecsik }
1283d14b171SJozsef Kadlecsik 
1295d50e1d8SJozsef Kadlecsik #define MTYPE		hash_ipportnet4
1305d50e1d8SJozsef Kadlecsik #define HOST_MASK	32
1315d50e1d8SJozsef Kadlecsik #include "ip_set_hash_gen.h"
1325d50e1d8SJozsef Kadlecsik 
13341d22f7bSJozsef Kadlecsik static int
hash_ipportnet4_kadt(struct ip_set * set,const struct sk_buff * skb,const struct xt_action_param * par,enum ipset_adt adt,struct ip_set_adt_opt * opt)13441d22f7bSJozsef Kadlecsik hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
135b66554cfSJozsef Kadlecsik 		     const struct xt_action_param *par,
1365d50e1d8SJozsef Kadlecsik 		     enum ipset_adt adt, struct ip_set_adt_opt *opt)
13741d22f7bSJozsef Kadlecsik {
13821956ab2SJozsef Kadlecsik 	const struct hash_ipportnet4 *h = set->data;
13941d22f7bSJozsef Kadlecsik 	ipset_adtfn adtfn = set->variant->adt[adt];
1405d50e1d8SJozsef Kadlecsik 	struct hash_ipportnet4_elem e = {
141f690cbaeSJozsef Kadlecsik 		.cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
1429b03a5efSJozsef Kadlecsik 	};
143ca134ce8SJozsef Kadlecsik 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
14441d22f7bSJozsef Kadlecsik 
14541d22f7bSJozsef Kadlecsik 	if (adt == IPSET_TEST)
1465d50e1d8SJozsef Kadlecsik 		e.cidr = HOST_MASK - 1;
14741d22f7bSJozsef Kadlecsik 
148ac8cc925SJozsef Kadlecsik 	if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
1495d50e1d8SJozsef Kadlecsik 				 &e.port, &e.proto))
15041d22f7bSJozsef Kadlecsik 		return -EINVAL;
15141d22f7bSJozsef Kadlecsik 
1525d50e1d8SJozsef Kadlecsik 	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
1535d50e1d8SJozsef Kadlecsik 	ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2);
1545d50e1d8SJozsef Kadlecsik 	e.ip2 &= ip_set_netmask(e.cidr + 1);
15541d22f7bSJozsef Kadlecsik 
1565d50e1d8SJozsef Kadlecsik 	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
15741d22f7bSJozsef Kadlecsik }
15841d22f7bSJozsef Kadlecsik 
15941d22f7bSJozsef Kadlecsik static int
hash_ipportnet4_uadt(struct ip_set * set,struct nlattr * tb[],enum ipset_adt adt,u32 * lineno,u32 flags,bool retried)16041d22f7bSJozsef Kadlecsik hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
1613d14b171SJozsef Kadlecsik 		     enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
16241d22f7bSJozsef Kadlecsik {
163*5e29dc36SJozsef Kadlecsik 	struct hash_ipportnet4 *h = set->data;
16441d22f7bSJozsef Kadlecsik 	ipset_adtfn adtfn = set->variant->adt[adt];
1655d50e1d8SJozsef Kadlecsik 	struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
166ca134ce8SJozsef Kadlecsik 	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
16720b2fab4SJozsef Kadlecsik 	u32 ip = 0, ip_to = 0, p = 0, port, port_to;
168*5e29dc36SJozsef Kadlecsik 	u32 ip2_from = 0, ip2_to = 0, ip2, i = 0;
1695e0c1eb7SJozsef Kadlecsik 	bool with_ports = false;
1702a7cef2aSJozsef Kadlecsik 	u8 cidr;
17141d22f7bSJozsef Kadlecsik 	int ret;
17241d22f7bSJozsef Kadlecsik 
173a212e08eSSergey Popovich 	if (tb[IPSET_ATTR_LINENO])
174a212e08eSSergey Popovich 		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
175a212e08eSSergey Popovich 
17641d22f7bSJozsef Kadlecsik 	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
17741d22f7bSJozsef Kadlecsik 		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
17841d22f7bSJozsef Kadlecsik 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
1797dd37bc8SSergey Popovich 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
18041d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_PROTOCOL;
18141d22f7bSJozsef Kadlecsik 
1828e55d2e5SSergey Popovich 	ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
1838e55d2e5SSergey Popovich 	if (ret)
1848e55d2e5SSergey Popovich 		return ret;
1858e55d2e5SSergey Popovich 
1868e55d2e5SSergey Popovich 	ret = ip_set_get_extensions(set, tb, &ext);
18741d22f7bSJozsef Kadlecsik 	if (ret)
18841d22f7bSJozsef Kadlecsik 		return ret;
18941d22f7bSJozsef Kadlecsik 
190d0d9e0a5SJozsef Kadlecsik 	ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from);
19141d22f7bSJozsef Kadlecsik 	if (ret)
19241d22f7bSJozsef Kadlecsik 		return ret;
19341d22f7bSJozsef Kadlecsik 
194d0d9e0a5SJozsef Kadlecsik 	if (tb[IPSET_ATTR_CIDR2]) {
1952a7cef2aSJozsef Kadlecsik 		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
1962a7cef2aSJozsef Kadlecsik 		if (!cidr || cidr > HOST_MASK)
19741d22f7bSJozsef Kadlecsik 			return -IPSET_ERR_INVALID_CIDR;
1985d50e1d8SJozsef Kadlecsik 		e.cidr = cidr - 1;
199d0d9e0a5SJozsef Kadlecsik 	}
20041d22f7bSJozsef Kadlecsik 
2015d50e1d8SJozsef Kadlecsik 	e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
20241d22f7bSJozsef Kadlecsik 
20341d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_PROTO]) {
2045d50e1d8SJozsef Kadlecsik 		e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
2055d50e1d8SJozsef Kadlecsik 		with_ports = ip_set_proto_with_ports(e.proto);
20641d22f7bSJozsef Kadlecsik 
2075d50e1d8SJozsef Kadlecsik 		if (e.proto == 0)
20841d22f7bSJozsef Kadlecsik 			return -IPSET_ERR_INVALID_PROTO;
209ca0f6a5cSJozsef Kadlecsik 	} else {
21041d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_MISSING_PROTO;
211ca0f6a5cSJozsef Kadlecsik 	}
21241d22f7bSJozsef Kadlecsik 
2135d50e1d8SJozsef Kadlecsik 	if (!(with_ports || e.proto == IPPROTO_ICMP))
2145d50e1d8SJozsef Kadlecsik 		e.port = 0;
21541d22f7bSJozsef Kadlecsik 
21643c56e59SJozsef Kadlecsik 	if (tb[IPSET_ATTR_CADT_FLAGS]) {
2172a7cef2aSJozsef Kadlecsik 		u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
218ca0f6a5cSJozsef Kadlecsik 
2192a7cef2aSJozsef Kadlecsik 		if (cadt_flags & IPSET_FLAG_NOMATCH)
22043c56e59SJozsef Kadlecsik 			flags |= (IPSET_FLAG_NOMATCH << 16);
2212a7cef2aSJozsef Kadlecsik 	}
2222a7cef2aSJozsef Kadlecsik 
223d0d9e0a5SJozsef Kadlecsik 	with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
22441d22f7bSJozsef Kadlecsik 	if (adt == IPSET_TEST ||
225d0d9e0a5SJozsef Kadlecsik 	    !(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports ||
226d0d9e0a5SJozsef Kadlecsik 	      tb[IPSET_ATTR_IP2_TO])) {
2275d50e1d8SJozsef Kadlecsik 		e.ip = htonl(ip);
2285d50e1d8SJozsef Kadlecsik 		e.ip2 = htonl(ip2_from & ip_set_hostmask(e.cidr + 1));
2295d50e1d8SJozsef Kadlecsik 		ret = adtfn(set, &e, &ext, &ext, flags);
2300f1799baSJozsef Kadlecsik 		return ip_set_enomatch(ret, flags, adt, set) ? -ret :
23143c56e59SJozsef Kadlecsik 		       ip_set_eexist(ret, flags) ? 0 : ret;
23241d22f7bSJozsef Kadlecsik 	}
23341d22f7bSJozsef Kadlecsik 
2344fe198e6SJozsef Kadlecsik 	ip_to = ip;
23541d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_IP_TO]) {
23641d22f7bSJozsef Kadlecsik 		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
23741d22f7bSJozsef Kadlecsik 		if (ret)
23841d22f7bSJozsef Kadlecsik 			return ret;
23941d22f7bSJozsef Kadlecsik 		if (ip > ip_to)
24041d22f7bSJozsef Kadlecsik 			swap(ip, ip_to);
24141d22f7bSJozsef Kadlecsik 	} else if (tb[IPSET_ATTR_CIDR]) {
242b3aabd14SJozsef Kadlecsik 		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
24341d22f7bSJozsef Kadlecsik 
244cabfd139SSergey Popovich 		if (!cidr || cidr > HOST_MASK)
24541d22f7bSJozsef Kadlecsik 			return -IPSET_ERR_INVALID_CIDR;
246e6146e86SJozsef Kadlecsik 		ip_set_mask_from_to(ip, ip_to, cidr);
247d0d9e0a5SJozsef Kadlecsik 	}
24841d22f7bSJozsef Kadlecsik 
2495d50e1d8SJozsef Kadlecsik 	port_to = port = ntohs(e.port);
250d0d9e0a5SJozsef Kadlecsik 	if (tb[IPSET_ATTR_PORT_TO]) {
25141d22f7bSJozsef Kadlecsik 		port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
25241d22f7bSJozsef Kadlecsik 		if (port > port_to)
25341d22f7bSJozsef Kadlecsik 			swap(port, port_to);
2545e0c1eb7SJozsef Kadlecsik 	}
2554fe198e6SJozsef Kadlecsik 
2564fe198e6SJozsef Kadlecsik 	ip2_to = ip2_from;
257d0d9e0a5SJozsef Kadlecsik 	if (tb[IPSET_ATTR_IP2_TO]) {
258d0d9e0a5SJozsef Kadlecsik 		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
259d0d9e0a5SJozsef Kadlecsik 		if (ret)
260d0d9e0a5SJozsef Kadlecsik 			return ret;
261d0d9e0a5SJozsef Kadlecsik 		if (ip2_from > ip2_to)
262d0d9e0a5SJozsef Kadlecsik 			swap(ip2_from, ip2_to);
263d0d9e0a5SJozsef Kadlecsik 		if (ip2_from + UINT_MAX == ip2_to)
264d0d9e0a5SJozsef Kadlecsik 			return -IPSET_ERR_HASH_RANGE;
265ca0f6a5cSJozsef Kadlecsik 	} else {
2665d50e1d8SJozsef Kadlecsik 		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr + 1);
267ca0f6a5cSJozsef Kadlecsik 	}
26841d22f7bSJozsef Kadlecsik 
2690b8d9073SJozsef Kadlecsik 	if (retried) {
2706e27c9b4SJozsef Kadlecsik 		ip = ntohl(h->next.ip);
2710b8d9073SJozsef Kadlecsik 		p = ntohs(h->next.port);
2720b8d9073SJozsef Kadlecsik 		ip2 = ntohl(h->next.ip2);
2730b8d9073SJozsef Kadlecsik 	} else {
2740b8d9073SJozsef Kadlecsik 		p = port;
2750b8d9073SJozsef Kadlecsik 		ip2 = ip2_from;
2760b8d9073SJozsef Kadlecsik 	}
27748596a8dSJozsef Kadlecsik 	for (; ip <= ip_to; ip++) {
2785d50e1d8SJozsef Kadlecsik 		e.ip = htonl(ip);
2793d14b171SJozsef Kadlecsik 		for (; p <= port_to; p++) {
2805d50e1d8SJozsef Kadlecsik 			e.port = htons(p);
2810b8d9073SJozsef Kadlecsik 			do {
282*5e29dc36SJozsef Kadlecsik 				i++;
2835d50e1d8SJozsef Kadlecsik 				e.ip2 = htonl(ip2);
2840b8d9073SJozsef Kadlecsik 				ip2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr);
2855d50e1d8SJozsef Kadlecsik 				e.cidr = cidr - 1;
286*5e29dc36SJozsef Kadlecsik 				if (i > IPSET_MAX_RANGE) {
287*5e29dc36SJozsef Kadlecsik 					hash_ipportnet4_data_next(&h->next,
288*5e29dc36SJozsef Kadlecsik 								  &e);
289*5e29dc36SJozsef Kadlecsik 					return -ERANGE;
290*5e29dc36SJozsef Kadlecsik 				}
2915d50e1d8SJozsef Kadlecsik 				ret = adtfn(set, &e, &ext, &ext, flags);
29241d22f7bSJozsef Kadlecsik 
29341d22f7bSJozsef Kadlecsik 				if (ret && !ip_set_eexist(ret, flags))
29441d22f7bSJozsef Kadlecsik 					return ret;
295ca0f6a5cSJozsef Kadlecsik 
29641d22f7bSJozsef Kadlecsik 				ret = 0;
2970b8d9073SJozsef Kadlecsik 			} while (ip2++ < ip2_to);
2980b8d9073SJozsef Kadlecsik 			ip2 = ip2_from;
299d0d9e0a5SJozsef Kadlecsik 		}
3000b8d9073SJozsef Kadlecsik 		p = port;
3013d14b171SJozsef Kadlecsik 	}
30241d22f7bSJozsef Kadlecsik 	return ret;
30341d22f7bSJozsef Kadlecsik }
30441d22f7bSJozsef Kadlecsik 
30503c8b234SJozsef Kadlecsik /* IPv6 variant */
30641d22f7bSJozsef Kadlecsik 
30741d22f7bSJozsef Kadlecsik struct hash_ipportnet6_elem {
30841d22f7bSJozsef Kadlecsik 	union nf_inet_addr ip;
30941d22f7bSJozsef Kadlecsik 	union nf_inet_addr ip2;
31041d22f7bSJozsef Kadlecsik 	__be16 port;
3112a7cef2aSJozsef Kadlecsik 	u8 cidr:7;
3122a7cef2aSJozsef Kadlecsik 	u8 nomatch:1;
31341d22f7bSJozsef Kadlecsik 	u8 proto;
31441d22f7bSJozsef Kadlecsik };
31541d22f7bSJozsef Kadlecsik 
3165d50e1d8SJozsef Kadlecsik /* Common functions */
3175d50e1d8SJozsef Kadlecsik 
3188dea982aSJeremy Sowden static bool
hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem * ip1,const struct hash_ipportnet6_elem * ip2,u32 * multi)31941d22f7bSJozsef Kadlecsik hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
32089dc79b7SJozsef Kadlecsik 			   const struct hash_ipportnet6_elem *ip2,
32189dc79b7SJozsef Kadlecsik 			   u32 *multi)
32241d22f7bSJozsef Kadlecsik {
32329e3b160SYOSHIFUJI Hideaki / 吉藤英明 	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
32429e3b160SYOSHIFUJI Hideaki / 吉藤英明 	       ipv6_addr_equal(&ip1->ip2.in6, &ip2->ip2.in6) &&
32541d22f7bSJozsef Kadlecsik 	       ip1->cidr == ip2->cidr &&
32641d22f7bSJozsef Kadlecsik 	       ip1->port == ip2->port &&
32741d22f7bSJozsef Kadlecsik 	       ip1->proto == ip2->proto;
32841d22f7bSJozsef Kadlecsik }
32941d22f7bSJozsef Kadlecsik 
3308dea982aSJeremy Sowden static int
hash_ipportnet6_do_data_match(const struct hash_ipportnet6_elem * elem)3315d50e1d8SJozsef Kadlecsik hash_ipportnet6_do_data_match(const struct hash_ipportnet6_elem *elem)
3322a7cef2aSJozsef Kadlecsik {
3333e0304a5SJozsef Kadlecsik 	return elem->nomatch ? -ENOTEMPTY : 1;
3342a7cef2aSJozsef Kadlecsik }
3352a7cef2aSJozsef Kadlecsik 
3368dea982aSJeremy Sowden static void
hash_ipportnet6_data_set_flags(struct hash_ipportnet6_elem * elem,u32 flags)3375d50e1d8SJozsef Kadlecsik hash_ipportnet6_data_set_flags(struct hash_ipportnet6_elem *elem, u32 flags)
33841d22f7bSJozsef Kadlecsik {
3395d50e1d8SJozsef Kadlecsik 	elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
3405d50e1d8SJozsef Kadlecsik }
3415d50e1d8SJozsef Kadlecsik 
3428dea982aSJeremy Sowden static void
hash_ipportnet6_data_reset_flags(struct hash_ipportnet6_elem * elem,u8 * flags)3435d50e1d8SJozsef Kadlecsik hash_ipportnet6_data_reset_flags(struct hash_ipportnet6_elem *elem, u8 *flags)
3445d50e1d8SJozsef Kadlecsik {
3455d50e1d8SJozsef Kadlecsik 	swap(*flags, elem->nomatch);
34641d22f7bSJozsef Kadlecsik }
34741d22f7bSJozsef Kadlecsik 
3488dea982aSJeremy Sowden static void
hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem * elem,u8 cidr)34941d22f7bSJozsef Kadlecsik hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr)
35041d22f7bSJozsef Kadlecsik {
35141d22f7bSJozsef Kadlecsik 	ip6_netmask(&elem->ip2, cidr);
3522a7cef2aSJozsef Kadlecsik 	elem->cidr = cidr - 1;
35341d22f7bSJozsef Kadlecsik }
35441d22f7bSJozsef Kadlecsik 
35541d22f7bSJozsef Kadlecsik static bool
hash_ipportnet6_data_list(struct sk_buff * skb,const struct hash_ipportnet6_elem * data)35641d22f7bSJozsef Kadlecsik hash_ipportnet6_data_list(struct sk_buff *skb,
35741d22f7bSJozsef Kadlecsik 			  const struct hash_ipportnet6_elem *data)
35841d22f7bSJozsef Kadlecsik {
3592a7cef2aSJozsef Kadlecsik 	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
3602a7cef2aSJozsef Kadlecsik 
3617cf7899dSDavid S. Miller 	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
3627cf7899dSDavid S. Miller 	    nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
3637cf7899dSDavid S. Miller 	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
3647cf7899dSDavid S. Miller 	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
3657cf7899dSDavid S. Miller 	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
3667cf7899dSDavid S. Miller 	    (flags &&
3677cf7899dSDavid S. Miller 	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
3687cf7899dSDavid S. Miller 		goto nla_put_failure;
369728a7e69SSergey Popovich 	return false;
37041d22f7bSJozsef Kadlecsik 
37141d22f7bSJozsef Kadlecsik nla_put_failure:
372728a7e69SSergey Popovich 	return true;
37341d22f7bSJozsef Kadlecsik }
37441d22f7bSJozsef Kadlecsik 
3758dea982aSJeremy Sowden static void
hash_ipportnet6_data_next(struct hash_ipportnet6_elem * next,const struct hash_ipportnet6_elem * d)37621956ab2SJozsef Kadlecsik hash_ipportnet6_data_next(struct hash_ipportnet6_elem *next,
3775d50e1d8SJozsef Kadlecsik 			  const struct hash_ipportnet6_elem *d)
37841d22f7bSJozsef Kadlecsik {
3795d50e1d8SJozsef Kadlecsik 	next->port = d->port;
38041d22f7bSJozsef Kadlecsik }
38141d22f7bSJozsef Kadlecsik 
3825d50e1d8SJozsef Kadlecsik #undef MTYPE
38341d22f7bSJozsef Kadlecsik #undef HOST_MASK
38441d22f7bSJozsef Kadlecsik 
3855d50e1d8SJozsef Kadlecsik #define MTYPE		hash_ipportnet6
38641d22f7bSJozsef Kadlecsik #define HOST_MASK	128
3875d50e1d8SJozsef Kadlecsik #define IP_SET_EMIT_CREATE
3885d50e1d8SJozsef Kadlecsik #include "ip_set_hash_gen.h"
3893d14b171SJozsef Kadlecsik 
39041d22f7bSJozsef Kadlecsik static int
hash_ipportnet6_kadt(struct ip_set * set,const struct sk_buff * skb,const struct xt_action_param * par,enum ipset_adt adt,struct ip_set_adt_opt * opt)39141d22f7bSJozsef Kadlecsik hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
392b66554cfSJozsef Kadlecsik 		     const struct xt_action_param *par,
3935d50e1d8SJozsef Kadlecsik 		     enum ipset_adt adt, struct ip_set_adt_opt *opt)
39441d22f7bSJozsef Kadlecsik {
39521956ab2SJozsef Kadlecsik 	const struct hash_ipportnet6 *h = set->data;
39641d22f7bSJozsef Kadlecsik 	ipset_adtfn adtfn = set->variant->adt[adt];
3975d50e1d8SJozsef Kadlecsik 	struct hash_ipportnet6_elem e = {
398f690cbaeSJozsef Kadlecsik 		.cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
3999b03a5efSJozsef Kadlecsik 	};
400ca134ce8SJozsef Kadlecsik 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
40141d22f7bSJozsef Kadlecsik 
40241d22f7bSJozsef Kadlecsik 	if (adt == IPSET_TEST)
4035d50e1d8SJozsef Kadlecsik 		e.cidr = HOST_MASK - 1;
40441d22f7bSJozsef Kadlecsik 
405ac8cc925SJozsef Kadlecsik 	if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
4065d50e1d8SJozsef Kadlecsik 				 &e.port, &e.proto))
40741d22f7bSJozsef Kadlecsik 		return -EINVAL;
40841d22f7bSJozsef Kadlecsik 
4095d50e1d8SJozsef Kadlecsik 	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
4105d50e1d8SJozsef Kadlecsik 	ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2.in6);
4115d50e1d8SJozsef Kadlecsik 	ip6_netmask(&e.ip2, e.cidr + 1);
41241d22f7bSJozsef Kadlecsik 
4135d50e1d8SJozsef Kadlecsik 	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
41441d22f7bSJozsef Kadlecsik }
41541d22f7bSJozsef Kadlecsik 
41641d22f7bSJozsef Kadlecsik static int
hash_ipportnet6_uadt(struct ip_set * set,struct nlattr * tb[],enum ipset_adt adt,u32 * lineno,u32 flags,bool retried)41741d22f7bSJozsef Kadlecsik hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
4183d14b171SJozsef Kadlecsik 		     enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
41941d22f7bSJozsef Kadlecsik {
42021956ab2SJozsef Kadlecsik 	const struct hash_ipportnet6 *h = set->data;
42141d22f7bSJozsef Kadlecsik 	ipset_adtfn adtfn = set->variant->adt[adt];
4225d50e1d8SJozsef Kadlecsik 	struct hash_ipportnet6_elem e = { .cidr = HOST_MASK - 1 };
423ca134ce8SJozsef Kadlecsik 	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
42441d22f7bSJozsef Kadlecsik 	u32 port, port_to;
4255e0c1eb7SJozsef Kadlecsik 	bool with_ports = false;
4262a7cef2aSJozsef Kadlecsik 	u8 cidr;
42741d22f7bSJozsef Kadlecsik 	int ret;
42841d22f7bSJozsef Kadlecsik 
429a212e08eSSergey Popovich 	if (tb[IPSET_ATTR_LINENO])
430a212e08eSSergey Popovich 		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
431a212e08eSSergey Popovich 
43241d22f7bSJozsef Kadlecsik 	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
43341d22f7bSJozsef Kadlecsik 		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
43441d22f7bSJozsef Kadlecsik 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
4352c227f27SSergey Popovich 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
43641d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_PROTOCOL;
437d0d9e0a5SJozsef Kadlecsik 	if (unlikely(tb[IPSET_ATTR_IP_TO]))
438d0d9e0a5SJozsef Kadlecsik 		return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
4392c227f27SSergey Popovich 	if (unlikely(tb[IPSET_ATTR_CIDR])) {
4408851e799SJozsef Kadlecsik 		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
4412c227f27SSergey Popovich 
4422c227f27SSergey Popovich 		if (cidr != HOST_MASK)
4432c227f27SSergey Popovich 			return -IPSET_ERR_INVALID_CIDR;
4442c227f27SSergey Popovich 	}
44541d22f7bSJozsef Kadlecsik 
4468e55d2e5SSergey Popovich 	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
4478e55d2e5SSergey Popovich 	if (ret)
4488e55d2e5SSergey Popovich 		return ret;
4498e55d2e5SSergey Popovich 
4508e55d2e5SSergey Popovich 	ret = ip_set_get_extensions(set, tb, &ext);
45141d22f7bSJozsef Kadlecsik 	if (ret)
45241d22f7bSJozsef Kadlecsik 		return ret;
45341d22f7bSJozsef Kadlecsik 
4545d50e1d8SJozsef Kadlecsik 	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip2);
45541d22f7bSJozsef Kadlecsik 	if (ret)
45641d22f7bSJozsef Kadlecsik 		return ret;
45741d22f7bSJozsef Kadlecsik 
4582a7cef2aSJozsef Kadlecsik 	if (tb[IPSET_ATTR_CIDR2]) {
4592a7cef2aSJozsef Kadlecsik 		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
4602a7cef2aSJozsef Kadlecsik 		if (!cidr || cidr > HOST_MASK)
46141d22f7bSJozsef Kadlecsik 			return -IPSET_ERR_INVALID_CIDR;
4625d50e1d8SJozsef Kadlecsik 		e.cidr = cidr - 1;
4632a7cef2aSJozsef Kadlecsik 	}
46441d22f7bSJozsef Kadlecsik 
4655d50e1d8SJozsef Kadlecsik 	ip6_netmask(&e.ip2, e.cidr + 1);
46641d22f7bSJozsef Kadlecsik 
4675d50e1d8SJozsef Kadlecsik 	e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
46841d22f7bSJozsef Kadlecsik 
46941d22f7bSJozsef Kadlecsik 	if (tb[IPSET_ATTR_PROTO]) {
4705d50e1d8SJozsef Kadlecsik 		e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
4715d50e1d8SJozsef Kadlecsik 		with_ports = ip_set_proto_with_ports(e.proto);
47241d22f7bSJozsef Kadlecsik 
4735d50e1d8SJozsef Kadlecsik 		if (e.proto == 0)
47441d22f7bSJozsef Kadlecsik 			return -IPSET_ERR_INVALID_PROTO;
475ca0f6a5cSJozsef Kadlecsik 	} else {
47641d22f7bSJozsef Kadlecsik 		return -IPSET_ERR_MISSING_PROTO;
477ca0f6a5cSJozsef Kadlecsik 	}
47841d22f7bSJozsef Kadlecsik 
4795d50e1d8SJozsef Kadlecsik 	if (!(with_ports || e.proto == IPPROTO_ICMPV6))
4805d50e1d8SJozsef Kadlecsik 		e.port = 0;
48141d22f7bSJozsef Kadlecsik 
48243c56e59SJozsef Kadlecsik 	if (tb[IPSET_ATTR_CADT_FLAGS]) {
4832a7cef2aSJozsef Kadlecsik 		u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
484ca0f6a5cSJozsef Kadlecsik 
4852a7cef2aSJozsef Kadlecsik 		if (cadt_flags & IPSET_FLAG_NOMATCH)
48643c56e59SJozsef Kadlecsik 			flags |= (IPSET_FLAG_NOMATCH << 16);
4872a7cef2aSJozsef Kadlecsik 	}
4882a7cef2aSJozsef Kadlecsik 
4895e0c1eb7SJozsef Kadlecsik 	if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
4905d50e1d8SJozsef Kadlecsik 		ret = adtfn(set, &e, &ext, &ext, flags);
4910f1799baSJozsef Kadlecsik 		return ip_set_enomatch(ret, flags, adt, set) ? -ret :
49243c56e59SJozsef Kadlecsik 		       ip_set_eexist(ret, flags) ? 0 : ret;
49341d22f7bSJozsef Kadlecsik 	}
49441d22f7bSJozsef Kadlecsik 
4955d50e1d8SJozsef Kadlecsik 	port = ntohs(e.port);
49641d22f7bSJozsef Kadlecsik 	port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
49741d22f7bSJozsef Kadlecsik 	if (port > port_to)
49841d22f7bSJozsef Kadlecsik 		swap(port, port_to);
49941d22f7bSJozsef Kadlecsik 
5003d14b171SJozsef Kadlecsik 	if (retried)
5016e27c9b4SJozsef Kadlecsik 		port = ntohs(h->next.port);
50241d22f7bSJozsef Kadlecsik 	for (; port <= port_to; port++) {
5035d50e1d8SJozsef Kadlecsik 		e.port = htons(port);
5045d50e1d8SJozsef Kadlecsik 		ret = adtfn(set, &e, &ext, &ext, flags);
50541d22f7bSJozsef Kadlecsik 
50641d22f7bSJozsef Kadlecsik 		if (ret && !ip_set_eexist(ret, flags))
50741d22f7bSJozsef Kadlecsik 			return ret;
508ca0f6a5cSJozsef Kadlecsik 
50941d22f7bSJozsef Kadlecsik 		ret = 0;
51041d22f7bSJozsef Kadlecsik 	}
51141d22f7bSJozsef Kadlecsik 	return ret;
51241d22f7bSJozsef Kadlecsik }
51341d22f7bSJozsef Kadlecsik 
51441d22f7bSJozsef Kadlecsik static struct ip_set_type hash_ipportnet_type __read_mostly = {
51541d22f7bSJozsef Kadlecsik 	.name		= "hash:ip,port,net",
51641d22f7bSJozsef Kadlecsik 	.protocol	= IPSET_PROTOCOL,
5173e0304a5SJozsef Kadlecsik 	.features	= IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2 |
5183e0304a5SJozsef Kadlecsik 			  IPSET_TYPE_NOMATCH,
51941d22f7bSJozsef Kadlecsik 	.dimension	= IPSET_DIM_THREE,
520c15f1c83SJan Engelhardt 	.family		= NFPROTO_UNSPEC,
52135b8dcf8SJozsef Kadlecsik 	.revision_min	= IPSET_TYPE_REV_MIN,
52235b8dcf8SJozsef Kadlecsik 	.revision_max	= IPSET_TYPE_REV_MAX,
523ccf0a4b7SJozsef Kadlecsik 	.create_flags[IPSET_TYPE_REV_MAX] = IPSET_CREATE_FLAG_BUCKETSIZE,
52441d22f7bSJozsef Kadlecsik 	.create		= hash_ipportnet_create,
52541d22f7bSJozsef Kadlecsik 	.create_policy	= {
52641d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 },
52741d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_MAXELEM]	= { .type = NLA_U32 },
5283976ca10SJozsef Kadlecsik 		[IPSET_ATTR_INITVAL]	= { .type = NLA_U32 },
529ccf0a4b7SJozsef Kadlecsik 		[IPSET_ATTR_BUCKETSIZE]	= { .type = NLA_U8 },
53041d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_RESIZE]	= { .type = NLA_U8  },
53141d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
5325d50e1d8SJozsef Kadlecsik 		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
53341d22f7bSJozsef Kadlecsik 	},
53441d22f7bSJozsef Kadlecsik 	.adt_policy	= {
53541d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_IP]		= { .type = NLA_NESTED },
53641d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_IP_TO]	= { .type = NLA_NESTED },
53741d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_IP2]	= { .type = NLA_NESTED },
538d0d9e0a5SJozsef Kadlecsik 		[IPSET_ATTR_IP2_TO]	= { .type = NLA_NESTED },
53941d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_PORT]	= { .type = NLA_U16 },
54041d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_PORT_TO]	= { .type = NLA_U16 },
54141d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_CIDR]	= { .type = NLA_U8 },
54241d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_CIDR2]	= { .type = NLA_U8 },
54341d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_PROTO]	= { .type = NLA_U8 },
5442a7cef2aSJozsef Kadlecsik 		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
54541d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
54641d22f7bSJozsef Kadlecsik 		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },
54700d71b27SJozsef Kadlecsik 		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },
54800d71b27SJozsef Kadlecsik 		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 },
54903726186SSergey Popovich 		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING,
55003726186SSergey Popovich 					    .len  = IPSET_MAX_COMMENT_SIZE },
551af331419SAnton Danilov 		[IPSET_ATTR_SKBMARK]	= { .type = NLA_U64 },
552af331419SAnton Danilov 		[IPSET_ATTR_SKBPRIO]	= { .type = NLA_U32 },
553af331419SAnton Danilov 		[IPSET_ATTR_SKBQUEUE]	= { .type = NLA_U16 },
55441d22f7bSJozsef Kadlecsik 	},
55541d22f7bSJozsef Kadlecsik 	.me		= THIS_MODULE,
55641d22f7bSJozsef Kadlecsik };
55741d22f7bSJozsef Kadlecsik 
55841d22f7bSJozsef Kadlecsik static int __init
hash_ipportnet_init(void)55941d22f7bSJozsef Kadlecsik hash_ipportnet_init(void)
56041d22f7bSJozsef Kadlecsik {
56141d22f7bSJozsef Kadlecsik 	return ip_set_type_register(&hash_ipportnet_type);
56241d22f7bSJozsef Kadlecsik }
56341d22f7bSJozsef Kadlecsik 
56441d22f7bSJozsef Kadlecsik static void __exit
hash_ipportnet_fini(void)56541d22f7bSJozsef Kadlecsik hash_ipportnet_fini(void)
56641d22f7bSJozsef Kadlecsik {
56718f84d41SJozsef Kadlecsik 	rcu_barrier();
56841d22f7bSJozsef Kadlecsik 	ip_set_type_unregister(&hash_ipportnet_type);
56941d22f7bSJozsef Kadlecsik }
57041d22f7bSJozsef Kadlecsik 
57141d22f7bSJozsef Kadlecsik module_init(hash_ipportnet_init);
57241d22f7bSJozsef Kadlecsik module_exit(hash_ipportnet_fini);
573