1 /* Copyright (C) 2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
8 /* Kernel module implementing an IP set type: the setlist type */
10 #include <linux/module.h>
12 #include <linux/skbuff.h>
13 #include <linux/errno.h>
15 #include <linux/netfilter_ipv4/ip_set.h>
16 #include <linux/netfilter_ipv4/ip_set_bitmaps.h>
17 #include <linux/netfilter_ipv4/ip_set_setlist.h>
20 * before ==> index, ref
21 * after ==> ref, index
25 next_index_eq(const struct ip_set_setlist
*map
, int i
, ip_set_id_t index
)
27 return i
< map
->size
&& map
->index
[i
] == index
;
31 setlist_utest(struct ip_set
*set
, const void *data
, u_int32_t size
)
33 const struct ip_set_setlist
*map
= set
->data
;
34 const struct ip_set_req_setlist
*req
= data
;
35 ip_set_id_t index
, ref
= IP_SET_INVALID_ID
;
39 if (req
->before
&& req
->ref
[0] == '\0')
42 index
= __ip_set_get_byname(req
->name
, &s
);
43 if (index
== IP_SET_INVALID_ID
)
45 if (req
->ref
[0] != '\0') {
46 ref
= __ip_set_get_byname(req
->ref
, &s
);
47 if (ref
== IP_SET_INVALID_ID
)
50 for (i
= 0; i
< map
->size
51 && map
->index
[i
] != IP_SET_INVALID_ID
; i
++) {
52 if (req
->before
&& map
->index
[i
] == index
) {
53 res
= next_index_eq(map
, i
+ 1, ref
);
55 } else if (!req
->before
) {
56 if ((ref
== IP_SET_INVALID_ID
57 && map
->index
[i
] == index
)
58 || (map
->index
[i
] == ref
59 && next_index_eq(map
, i
+ 1, index
))) {
65 if (ref
!= IP_SET_INVALID_ID
)
66 __ip_set_put_byindex(ref
);
68 __ip_set_put_byindex(index
);
73 setlist_ktest(struct ip_set
*set
,
74 const struct sk_buff
*skb
,
75 const u_int32_t
*flags
)
77 struct ip_set_setlist
*map
= set
->data
;
80 for (i
= 0; i
< map
->size
81 && map
->index
[i
] != IP_SET_INVALID_ID
83 res
= ip_set_testip_kernel(map
->index
[i
], skb
, flags
);
88 insert_setlist(struct ip_set_setlist
*map
, int i
, ip_set_id_t index
)
93 DP("i: %u, last %u\n", i
, map
->index
[map
->size
- 1]);
94 if (i
>= map
->size
|| map
->index
[map
->size
- 1] != IP_SET_INVALID_ID
)
97 for (j
= i
; j
< map
->size
98 && index
!= IP_SET_INVALID_ID
; j
++) {
100 map
->index
[j
] = index
;
107 setlist_uadd(struct ip_set
*set
, const void *data
, u_int32_t size
)
109 struct ip_set_setlist
*map
= set
->data
;
110 const struct ip_set_req_setlist
*req
= data
;
111 ip_set_id_t index
, ref
= IP_SET_INVALID_ID
;
112 int i
, res
= -ERANGE
;
115 if (req
->before
&& req
->ref
[0] == '\0')
118 index
= __ip_set_get_byname(req
->name
, &s
);
119 if (index
== IP_SET_INVALID_ID
)
121 /* "Loop detection" */
122 if (strcmp(s
->type
->typename
, "setlist") == 0)
125 if (req
->ref
[0] != '\0') {
126 ref
= __ip_set_get_byname(req
->ref
, &s
);
127 if (ref
== IP_SET_INVALID_ID
) {
132 for (i
= 0; i
< map
->size
; i
++) {
133 if (map
->index
[i
] != ref
)
136 res
= insert_setlist(map
, i
, index
);
138 res
= insert_setlist(map
,
139 ref
== IP_SET_INVALID_ID
? i
: i
+ 1,
143 if (ref
!= IP_SET_INVALID_ID
)
144 __ip_set_put_byindex(ref
);
145 /* In case of success, we keep the reference to the set */
148 __ip_set_put_byindex(index
);
153 setlist_kadd(struct ip_set
*set
,
154 const struct sk_buff
*skb
,
155 const u_int32_t
*flags
)
157 struct ip_set_setlist
*map
= set
->data
;
158 int i
, res
= -EINVAL
;
160 for (i
= 0; i
< map
->size
161 && map
->index
[i
] != IP_SET_INVALID_ID
163 res
= ip_set_addip_kernel(map
->index
[i
], skb
, flags
);
168 unshift_setlist(struct ip_set_setlist
*map
, int i
)
172 for (j
= i
; j
< map
->size
- 1; j
++)
173 map
->index
[j
] = map
->index
[j
+1];
174 map
->index
[map
->size
-1] = IP_SET_INVALID_ID
;
179 setlist_udel(struct ip_set
*set
, const void *data
, u_int32_t size
)
181 struct ip_set_setlist
*map
= set
->data
;
182 const struct ip_set_req_setlist
*req
= data
;
183 ip_set_id_t index
, ref
= IP_SET_INVALID_ID
;
184 int i
, res
= -EEXIST
;
187 if (req
->before
&& req
->ref
[0] == '\0')
190 index
= __ip_set_get_byname(req
->name
, &s
);
191 if (index
== IP_SET_INVALID_ID
)
193 if (req
->ref
[0] != '\0') {
194 ref
= __ip_set_get_byname(req
->ref
, &s
);
195 if (ref
== IP_SET_INVALID_ID
)
198 for (i
= 0; i
< map
->size
199 && map
->index
[i
] != IP_SET_INVALID_ID
; i
++) {
201 if (map
->index
[i
] == index
202 && next_index_eq(map
, i
+ 1, ref
)) {
203 res
= unshift_setlist(map
, i
);
206 } else if (ref
== IP_SET_INVALID_ID
) {
207 if (map
->index
[i
] == index
) {
208 res
= unshift_setlist(map
, i
);
211 } else if (map
->index
[i
] == ref
212 && next_index_eq(map
, i
+ 1, index
)) {
213 res
= unshift_setlist(map
, i
+ 1);
217 if (ref
!= IP_SET_INVALID_ID
)
218 __ip_set_put_byindex(ref
);
220 __ip_set_put_byindex(index
);
221 /* In case of success, release the reference to the set */
223 __ip_set_put_byindex(index
);
228 setlist_kdel(struct ip_set
*set
,
229 const struct sk_buff
*skb
,
230 const u_int32_t
*flags
)
232 struct ip_set_setlist
*map
= set
->data
;
233 int i
, res
= -EINVAL
;
235 for (i
= 0; i
< map
->size
236 && map
->index
[i
] != IP_SET_INVALID_ID
238 res
= ip_set_delip_kernel(map
->index
[i
], skb
, flags
);
243 setlist_create(struct ip_set
*set
, const void *data
, u_int32_t size
)
245 struct ip_set_setlist
*map
;
246 const struct ip_set_req_setlist_create
*req
= data
;
249 map
= kmalloc(sizeof(struct ip_set_setlist
) +
250 req
->size
* sizeof(ip_set_id_t
), GFP_KERNEL
);
253 map
->size
= req
->size
;
254 for (i
= 0; i
< map
->size
; i
++)
255 map
->index
[i
] = IP_SET_INVALID_ID
;
262 setlist_destroy(struct ip_set
*set
)
264 struct ip_set_setlist
*map
= set
->data
;
267 for (i
= 0; i
< map
->size
268 && map
->index
[i
] != IP_SET_INVALID_ID
; i
++)
269 __ip_set_put_byindex(map
->index
[i
]);
276 setlist_flush(struct ip_set
*set
)
278 struct ip_set_setlist
*map
= set
->data
;
281 for (i
= 0; i
< map
->size
282 && map
->index
[i
] != IP_SET_INVALID_ID
; i
++) {
283 __ip_set_put_byindex(map
->index
[i
]);
284 map
->index
[i
] = IP_SET_INVALID_ID
;
289 setlist_list_header(const struct ip_set
*set
, void *data
)
291 const struct ip_set_setlist
*map
= set
->data
;
292 struct ip_set_req_setlist_create
*header
= data
;
294 header
->size
= map
->size
;
298 setlist_list_members_size(const struct ip_set
*set
, char dont_align
)
300 const struct ip_set_setlist
*map
= set
->data
;
302 return map
->size
* IPSET_VALIGN(sizeof(ip_set_id_t
), dont_align
);
306 setlist_list_members(const struct ip_set
*set
, void *data
, char dont_align
)
308 struct ip_set_setlist
*map
= set
->data
;
312 for (i
= 0; i
< map
->size
; i
++) {
313 d
= data
+ i
* IPSET_VALIGN(sizeof(ip_set_id_t
), dont_align
);
314 *d
= ip_set_id(map
->index
[i
]);
318 IP_SET_TYPE(setlist
, IPSET_TYPE_SETNAME
| IPSET_DATA_SINGLE
)
320 MODULE_LICENSE("GPL");
321 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
322 MODULE_DESCRIPTION("setlist type of IP sets");
324 REGISTER_MODULE(setlist
)