aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlabel
diff options
context:
space:
mode:
Diffstat (limited to 'net/netlabel')
-rw-r--r--net/netlabel/Makefile3
-rw-r--r--net/netlabel/netlabel_addrlist.c258
-rw-r--r--net/netlabel/netlabel_addrlist.h174
-rw-r--r--net/netlabel/netlabel_unlabeled.c350
4 files changed, 569 insertions, 216 deletions
diff --git a/net/netlabel/Makefile b/net/netlabel/Makefile
index 8af18c0a47d9..ea750e9df65f 100644
--- a/net/netlabel/Makefile
+++ b/net/netlabel/Makefile
@@ -5,7 +5,8 @@
5# 5#
6 6
7# base objects 7# base objects
8obj-y := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o 8obj-y := netlabel_user.o netlabel_kapi.o
9obj-y += netlabel_domainhash.o netlabel_addrlist.o
9 10
10# management objects 11# management objects
11obj-y += netlabel_mgmt.o 12obj-y += netlabel_mgmt.o
diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c
new file mode 100644
index 000000000000..dd928aa52db1
--- /dev/null
+++ b/net/netlabel/netlabel_addrlist.c
@@ -0,0 +1,258 @@
1/*
2 * NetLabel Network Address Lists
3 *
4 * This file contains network address list functions used to manage ordered
5 * lists of network addresses for use by the NetLabel subsystem. The NetLabel
6 * system manages static and dynamic label mappings for network protocols such
7 * as CIPSO and RIPSO.
8 *
9 * Author: Paul Moore <paul.moore@hp.com>
10 *
11 */
12
13/*
14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
24 * the GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 */
31
32#include <linux/types.h>
33#include <linux/rcupdate.h>
34#include <linux/list.h>
35#include <linux/spinlock.h>
36#include <linux/in.h>
37#include <linux/in6.h>
38#include <linux/ip.h>
39#include <linux/ipv6.h>
40#include <net/ip.h>
41#include <net/ipv6.h>
42
43#include "netlabel_addrlist.h"
44
45/*
46 * Address List Functions
47 */
48
49/**
50 * netlbl_af4list_search - Search for a matching IPv4 address entry
51 * @addr: IPv4 address
52 * @head: the list head
53 *
54 * Description:
55 * Searches the IPv4 address list given by @head. If a matching address entry
56 * is found it is returned, otherwise NULL is returned. The caller is
57 * responsible for calling the rcu_read_[un]lock() functions.
58 *
59 */
60struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
61 struct list_head *head)
62{
63 struct netlbl_af4list *iter;
64
65 list_for_each_entry_rcu(iter, head, list)
66 if (iter->valid && (addr & iter->mask) == iter->addr)
67 return iter;
68
69 return NULL;
70}
71
72#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
73/**
74 * netlbl_af6list_search - Search for a matching IPv6 address entry
75 * @addr: IPv6 address
76 * @head: the list head
77 *
78 * Description:
79 * Searches the IPv6 address list given by @head. If a matching address entry
80 * is found it is returned, otherwise NULL is returned. The caller is
81 * responsible for calling the rcu_read_[un]lock() functions.
82 *
83 */
84struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
85 struct list_head *head)
86{
87 struct netlbl_af6list *iter;
88
89 list_for_each_entry_rcu(iter, head, list)
90 if (iter->valid &&
91 ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
92 return iter;
93
94 return NULL;
95}
96#endif /* IPv6 */
97
98/**
99 * netlbl_af4list_add - Add a new IPv4 address entry to a list
100 * @entry: address entry
101 * @head: the list head
102 *
103 * Description:
104 * Add a new address entry to the list pointed to by @head. On success zero is
105 * returned, otherwise a negative value is returned. The caller is responsible
106 * for calling the necessary locking functions.
107 *
108 */
109int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
110{
111 struct netlbl_af4list *iter;
112
113 iter = netlbl_af4list_search(entry->addr, head);
114 if (iter != NULL &&
115 iter->addr == entry->addr && iter->mask == entry->mask)
116 return -EEXIST;
117
118 /* in order to speed up address searches through the list (the common
119 * case) we need to keep the list in order based on the size of the
120 * address mask such that the entry with the widest mask (smallest
121 * numerical value) appears first in the list */
122 list_for_each_entry_rcu(iter, head, list)
123 if (iter->valid &&
124 ntohl(entry->mask) > ntohl(iter->mask)) {
125 __list_add_rcu(&entry->list,
126 iter->list.prev,
127 &iter->list);
128 return 0;
129 }
130 list_add_tail_rcu(&entry->list, head);
131 return 0;
132}
133
134#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
135/**
136 * netlbl_af6list_add - Add a new IPv6 address entry to a list
137 * @entry: address entry
138 * @head: the list head
139 *
140 * Description:
141 * Add a new address entry to the list pointed to by @head. On success zero is
142 * returned, otherwise a negative value is returned. The caller is responsible
143 * for calling the necessary locking functions.
144 *
145 */
146int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
147{
148 struct netlbl_af6list *iter;
149
150 iter = netlbl_af6list_search(&entry->addr, head);
151 if (iter != NULL &&
152 ipv6_addr_equal(&iter->addr, &entry->addr) &&
153 ipv6_addr_equal(&iter->mask, &entry->mask))
154 return -EEXIST;
155
156 /* in order to speed up address searches through the list (the common
157 * case) we need to keep the list in order based on the size of the
158 * address mask such that the entry with the widest mask (smallest
159 * numerical value) appears first in the list */
160 list_for_each_entry_rcu(iter, head, list)
161 if (iter->valid &&
162 ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
163 __list_add_rcu(&entry->list,
164 iter->list.prev,
165 &iter->list);
166 return 0;
167 }
168 list_add_tail_rcu(&entry->list, head);
169 return 0;
170}
171#endif /* IPv6 */
172
173/**
174 * netlbl_af4list_remove_entry - Remove an IPv4 address entry
175 * @entry: address entry
176 *
177 * Description:
178 * Remove the specified IP address entry. The caller is responsible for
179 * calling the necessary locking functions.
180 *
181 */
182void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
183{
184 entry->valid = 0;
185 list_del_rcu(&entry->list);
186}
187
188/**
189 * netlbl_af4list_remove - Remove an IPv4 address entry
190 * @addr: IP address
191 * @mask: IP address mask
192 * @head: the list head
193 *
194 * Description:
195 * Remove an IP address entry from the list pointed to by @head. Returns the
196 * entry on success, NULL on failure. The caller is responsible for calling
197 * the necessary locking functions.
198 *
199 */
200struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
201 struct list_head *head)
202{
203 struct netlbl_af4list *entry;
204
205 entry = netlbl_af4list_search(addr, head);
206 if (entry != NULL && entry->addr == addr && entry->mask == mask) {
207 netlbl_af4list_remove_entry(entry);
208 return entry;
209 }
210
211 return NULL;
212}
213
214#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
215/**
216 * netlbl_af6list_remove_entry - Remove an IPv6 address entry
217 * @entry: address entry
218 *
219 * Description:
220 * Remove the specified IP address entry. The caller is responsible for
221 * calling the necessary locking functions.
222 *
223 */
224void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
225{
226 entry->valid = 0;
227 list_del_rcu(&entry->list);
228}
229
230/**
231 * netlbl_af6list_remove - Remove an IPv6 address entry
232 * @addr: IP address
233 * @mask: IP address mask
234 * @head: the list head
235 *
236 * Description:
237 * Remove an IP address entry from the list pointed to by @head. Returns the
238 * entry on success, NULL on failure. The caller is responsible for calling
239 * the necessary locking functions.
240 *
241 */
242struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
243 const struct in6_addr *mask,
244 struct list_head *head)
245{
246 struct netlbl_af6list *entry;
247
248 entry = netlbl_af6list_search(addr, head);
249 if (entry != NULL &&
250 ipv6_addr_equal(&entry->addr, addr) &&
251 ipv6_addr_equal(&entry->mask, mask)) {
252 netlbl_af6list_remove_entry(entry);
253 return entry;
254 }
255
256 return NULL;
257}
258#endif /* IPv6 */
diff --git a/net/netlabel/netlabel_addrlist.h b/net/netlabel/netlabel_addrlist.h
new file mode 100644
index 000000000000..0c41df057fa8
--- /dev/null
+++ b/net/netlabel/netlabel_addrlist.h
@@ -0,0 +1,174 @@
1/*
2 * NetLabel Network Address Lists
3 *
4 * This file contains network address list functions used to manage ordered
5 * lists of network addresses for use by the NetLabel subsystem. The NetLabel
6 * system manages static and dynamic label mappings for network protocols such
7 * as CIPSO and RIPSO.
8 *
9 * Author: Paul Moore <paul.moore@hp.com>
10 *
11 */
12
13/*
14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
24 * the GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 */
31
32#ifndef _NETLABEL_ADDRLIST_H
33#define _NETLABEL_ADDRLIST_H
34
35#include <linux/types.h>
36#include <linux/rcupdate.h>
37#include <linux/list.h>
38#include <linux/in6.h>
39
40/**
41 * struct netlbl_af4list - NetLabel IPv4 address list
42 * @addr: IPv4 address
43 * @mask: IPv4 address mask
44 * @valid: valid flag
45 * @list: list structure, used internally
46 */
47struct netlbl_af4list {
48 __be32 addr;
49 __be32 mask;
50
51 u32 valid;
52 struct list_head list;
53};
54
55/**
56 * struct netlbl_af6list - NetLabel IPv6 address list
57 * @addr: IPv6 address
58 * @mask: IPv6 address mask
59 * @valid: valid flag
60 * @list: list structure, used internally
61 */
62struct netlbl_af6list {
63 struct in6_addr addr;
64 struct in6_addr mask;
65
66 u32 valid;
67 struct list_head list;
68};
69
70#define __af4list_entry(ptr) container_of(ptr, struct netlbl_af4list, list)
71
72static inline struct netlbl_af4list *__af4list_valid(struct list_head *s,
73 struct list_head *h)
74{
75 struct list_head *i = s;
76 struct netlbl_af4list *n = __af4list_entry(s);
77 while (i != h && !n->valid) {
78 i = i->next;
79 n = __af4list_entry(i);
80 }
81 return n;
82}
83
84static inline struct netlbl_af4list *__af4list_valid_rcu(struct list_head *s,
85 struct list_head *h)
86{
87 struct list_head *i = s;
88 struct netlbl_af4list *n = __af4list_entry(s);
89 while (i != h && !n->valid) {
90 i = rcu_dereference(i->next);
91 n = __af4list_entry(i);
92 }
93 return n;
94}
95
96#define netlbl_af4list_foreach(iter, head) \
97 for (iter = __af4list_valid((head)->next, head); \
98 prefetch(iter->list.next), &iter->list != (head); \
99 iter = __af4list_valid(iter->list.next, head))
100
101#define netlbl_af4list_foreach_rcu(iter, head) \
102 for (iter = __af4list_valid_rcu((head)->next, head); \
103 prefetch(iter->list.next), &iter->list != (head); \
104 iter = __af4list_valid_rcu(iter->list.next, head))
105
106#define netlbl_af4list_foreach_safe(iter, tmp, head) \
107 for (iter = __af4list_valid((head)->next, head), \
108 tmp = __af4list_valid(iter->list.next, head); \
109 &iter->list != (head); \
110 iter = tmp, tmp = __af4list_valid(iter->list.next, head))
111
112int netlbl_af4list_add(struct netlbl_af4list *entry,
113 struct list_head *head);
114struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
115 struct list_head *head);
116void netlbl_af4list_remove_entry(struct netlbl_af4list *entry);
117struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
118 struct list_head *head);
119
120#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
121
122#define __af6list_entry(ptr) container_of(ptr, struct netlbl_af6list, list)
123
124static inline struct netlbl_af6list *__af6list_valid(struct list_head *s,
125 struct list_head *h)
126{
127 struct list_head *i = s;
128 struct netlbl_af6list *n = __af6list_entry(s);
129 while (i != h && !n->valid) {
130 i = i->next;
131 n = __af6list_entry(i);
132 }
133 return n;
134}
135
136static inline struct netlbl_af6list *__af6list_valid_rcu(struct list_head *s,
137 struct list_head *h)
138{
139 struct list_head *i = s;
140 struct netlbl_af6list *n = __af6list_entry(s);
141 while (i != h && !n->valid) {
142 i = rcu_dereference(i->next);
143 n = __af6list_entry(i);
144 }
145 return n;
146}
147
148#define netlbl_af6list_foreach(iter, head) \
149 for (iter = __af6list_valid((head)->next, head); \
150 prefetch(iter->list.next), &iter->list != (head); \
151 iter = __af6list_valid(iter->list.next, head))
152
153#define netlbl_af6list_foreach_rcu(iter, head) \
154 for (iter = __af6list_valid_rcu((head)->next, head); \
155 prefetch(iter->list.next), &iter->list != (head); \
156 iter = __af6list_valid_rcu(iter->list.next, head))
157
158#define netlbl_af6list_foreach_safe(iter, tmp, head) \
159 for (iter = __af6list_valid((head)->next, head), \
160 tmp = __af6list_valid(iter->list.next, head); \
161 &iter->list != (head); \
162 iter = tmp, tmp = __af6list_valid(iter->list.next, head))
163
164int netlbl_af6list_add(struct netlbl_af6list *entry,
165 struct list_head *head);
166struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
167 const struct in6_addr *mask,
168 struct list_head *head);
169void netlbl_af6list_remove_entry(struct netlbl_af6list *entry);
170struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
171 struct list_head *head);
172#endif /* IPV6 */
173
174#endif
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index cc105a10e3f8..ab8131a8e489 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12/* 12/*
13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2007 13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2008
14 * 14 *
15 * This program is free software; you can redistribute it and/or modify 15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@
54#include <asm/atomic.h> 54#include <asm/atomic.h>
55 55
56#include "netlabel_user.h" 56#include "netlabel_user.h"
57#include "netlabel_addrlist.h"
57#include "netlabel_domainhash.h" 58#include "netlabel_domainhash.h"
58#include "netlabel_unlabeled.h" 59#include "netlabel_unlabeled.h"
59#include "netlabel_mgmt.h" 60#include "netlabel_mgmt.h"
@@ -76,22 +77,20 @@ struct netlbl_unlhsh_tbl {
76 struct list_head *tbl; 77 struct list_head *tbl;
77 u32 size; 78 u32 size;
78}; 79};
80#define netlbl_unlhsh_addr4_entry(iter) \
81 container_of(iter, struct netlbl_unlhsh_addr4, list)
79struct netlbl_unlhsh_addr4 { 82struct netlbl_unlhsh_addr4 {
80 __be32 addr;
81 __be32 mask;
82 u32 secid; 83 u32 secid;
83 84
84 u32 valid; 85 struct netlbl_af4list list;
85 struct list_head list;
86 struct rcu_head rcu; 86 struct rcu_head rcu;
87}; 87};
88#define netlbl_unlhsh_addr6_entry(iter) \
89 container_of(iter, struct netlbl_unlhsh_addr6, list)
88struct netlbl_unlhsh_addr6 { 90struct netlbl_unlhsh_addr6 {
89 struct in6_addr addr;
90 struct in6_addr mask;
91 u32 secid; 91 u32 secid;
92 92
93 u32 valid; 93 struct netlbl_af6list list;
94 struct list_head list;
95 struct rcu_head rcu; 94 struct rcu_head rcu;
96}; 95};
97struct netlbl_unlhsh_iface { 96struct netlbl_unlhsh_iface {
@@ -274,26 +273,28 @@ static void netlbl_unlhsh_free_addr6(struct rcu_head *entry)
274static void netlbl_unlhsh_free_iface(struct rcu_head *entry) 273static void netlbl_unlhsh_free_iface(struct rcu_head *entry)
275{ 274{
276 struct netlbl_unlhsh_iface *iface; 275 struct netlbl_unlhsh_iface *iface;
277 struct netlbl_unlhsh_addr4 *iter4; 276 struct netlbl_af4list *iter4;
278 struct netlbl_unlhsh_addr4 *tmp4; 277 struct netlbl_af4list *tmp4;
279 struct netlbl_unlhsh_addr6 *iter6; 278#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
280 struct netlbl_unlhsh_addr6 *tmp6; 279 struct netlbl_af6list *iter6;
280 struct netlbl_af6list *tmp6;
281#endif /* IPv6 */
281 282
282 iface = container_of(entry, struct netlbl_unlhsh_iface, rcu); 283 iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);
283 284
284 /* no need for locks here since we are the only one with access to this 285 /* no need for locks here since we are the only one with access to this
285 * structure */ 286 * structure */
286 287
287 list_for_each_entry_safe(iter4, tmp4, &iface->addr4_list, list) 288 netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) {
288 if (iter4->valid) { 289 netlbl_af4list_remove_entry(iter4);
289 list_del_rcu(&iter4->list); 290 kfree(netlbl_unlhsh_addr4_entry(iter4));
290 kfree(iter4); 291 }
291 } 292#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
292 list_for_each_entry_safe(iter6, tmp6, &iface->addr6_list, list) 293 netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) {
293 if (iter6->valid) { 294 netlbl_af6list_remove_entry(iter6);
294 list_del_rcu(&iter6->list); 295 kfree(netlbl_unlhsh_addr6_entry(iter6));
295 kfree(iter6); 296 }
296 } 297#endif /* IPv6 */
297 kfree(iface); 298 kfree(iface);
298} 299}
299 300
@@ -316,59 +317,6 @@ static u32 netlbl_unlhsh_hash(int ifindex)
316} 317}
317 318
318/** 319/**
319 * netlbl_unlhsh_search_addr4 - Search for a matching IPv4 address entry
320 * @addr: IPv4 address
321 * @iface: the network interface entry
322 *
323 * Description:
324 * Searches the IPv4 address list of the network interface specified by @iface.
325 * If a matching address entry is found it is returned, otherwise NULL is
326 * returned. The caller is responsible for calling the rcu_read_[un]lock()
327 * functions.
328 *
329 */
330static struct netlbl_unlhsh_addr4 *netlbl_unlhsh_search_addr4(
331 __be32 addr,
332 const struct netlbl_unlhsh_iface *iface)
333{
334 struct netlbl_unlhsh_addr4 *iter;
335
336 list_for_each_entry_rcu(iter, &iface->addr4_list, list)
337 if (iter->valid && (addr & iter->mask) == iter->addr)
338 return iter;
339
340 return NULL;
341}
342
343#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
344/**
345 * netlbl_unlhsh_search_addr6 - Search for a matching IPv6 address entry
346 * @addr: IPv6 address
347 * @iface: the network interface entry
348 *
349 * Description:
350 * Searches the IPv6 address list of the network interface specified by @iface.
351 * If a matching address entry is found it is returned, otherwise NULL is
352 * returned. The caller is responsible for calling the rcu_read_[un]lock()
353 * functions.
354 *
355 */
356static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
357 const struct in6_addr *addr,
358 const struct netlbl_unlhsh_iface *iface)
359{
360 struct netlbl_unlhsh_addr6 *iter;
361
362 list_for_each_entry_rcu(iter, &iface->addr6_list, list)
363 if (iter->valid &&
364 ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
365 return iter;
366
367 return NULL;
368}
369#endif /* IPv6 */
370
371/**
372 * netlbl_unlhsh_search_iface - Search for a matching interface entry 320 * netlbl_unlhsh_search_iface - Search for a matching interface entry
373 * @ifindex: the network interface 321 * @ifindex: the network interface
374 * 322 *
@@ -439,43 +387,26 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
439 const struct in_addr *mask, 387 const struct in_addr *mask,
440 u32 secid) 388 u32 secid)
441{ 389{
390 int ret_val;
442 struct netlbl_unlhsh_addr4 *entry; 391 struct netlbl_unlhsh_addr4 *entry;
443 struct netlbl_unlhsh_addr4 *iter;
444 392
445 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 393 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
446 if (entry == NULL) 394 if (entry == NULL)
447 return -ENOMEM; 395 return -ENOMEM;
448 396
449 entry->addr = addr->s_addr & mask->s_addr; 397 entry->list.addr = addr->s_addr & mask->s_addr;
450 entry->mask = mask->s_addr; 398 entry->list.mask = mask->s_addr;
451 entry->secid = secid; 399 entry->list.valid = 1;
452 entry->valid = 1;
453 INIT_RCU_HEAD(&entry->rcu); 400 INIT_RCU_HEAD(&entry->rcu);
401 entry->secid = secid;
454 402
455 spin_lock(&netlbl_unlhsh_lock); 403 spin_lock(&netlbl_unlhsh_lock);
456 iter = netlbl_unlhsh_search_addr4(entry->addr, iface); 404 ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list);
457 if (iter != NULL &&
458 iter->addr == addr->s_addr && iter->mask == mask->s_addr) {
459 spin_unlock(&netlbl_unlhsh_lock);
460 kfree(entry);
461 return -EEXIST;
462 }
463 /* in order to speed up address searches through the list (the common
464 * case) we need to keep the list in order based on the size of the
465 * address mask such that the entry with the widest mask (smallest
466 * numerical value) appears first in the list */
467 list_for_each_entry_rcu(iter, &iface->addr4_list, list)
468 if (iter->valid &&
469 ntohl(entry->mask) > ntohl(iter->mask)) {
470 __list_add_rcu(&entry->list,
471 iter->list.prev,
472 &iter->list);
473 spin_unlock(&netlbl_unlhsh_lock);
474 return 0;
475 }
476 list_add_tail_rcu(&entry->list, &iface->addr4_list);
477 spin_unlock(&netlbl_unlhsh_lock); 405 spin_unlock(&netlbl_unlhsh_lock);
478 return 0; 406
407 if (ret_val != 0)
408 kfree(entry);
409 return ret_val;
479} 410}
480 411
481#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 412#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -498,47 +429,29 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
498 const struct in6_addr *mask, 429 const struct in6_addr *mask,
499 u32 secid) 430 u32 secid)
500{ 431{
432 int ret_val;
501 struct netlbl_unlhsh_addr6 *entry; 433 struct netlbl_unlhsh_addr6 *entry;
502 struct netlbl_unlhsh_addr6 *iter;
503 434
504 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 435 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
505 if (entry == NULL) 436 if (entry == NULL)
506 return -ENOMEM; 437 return -ENOMEM;
507 438
508 ipv6_addr_copy(&entry->addr, addr); 439 ipv6_addr_copy(&entry->list.addr, addr);
509 entry->addr.s6_addr32[0] &= mask->s6_addr32[0]; 440 entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
510 entry->addr.s6_addr32[1] &= mask->s6_addr32[1]; 441 entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
511 entry->addr.s6_addr32[2] &= mask->s6_addr32[2]; 442 entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
512 entry->addr.s6_addr32[3] &= mask->s6_addr32[3]; 443 entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
513 ipv6_addr_copy(&entry->mask, mask); 444 ipv6_addr_copy(&entry->list.mask, mask);
514 entry->secid = secid; 445 entry->list.valid = 1;
515 entry->valid = 1;
516 INIT_RCU_HEAD(&entry->rcu); 446 INIT_RCU_HEAD(&entry->rcu);
447 entry->secid = secid;
517 448
518 spin_lock(&netlbl_unlhsh_lock); 449 spin_lock(&netlbl_unlhsh_lock);
519 iter = netlbl_unlhsh_search_addr6(&entry->addr, iface); 450 ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list);
520 if (iter != NULL &&
521 (ipv6_addr_equal(&iter->addr, addr) &&
522 ipv6_addr_equal(&iter->mask, mask))) {
523 spin_unlock(&netlbl_unlhsh_lock);
524 kfree(entry);
525 return -EEXIST;
526 }
527 /* in order to speed up address searches through the list (the common
528 * case) we need to keep the list in order based on the size of the
529 * address mask such that the entry with the widest mask (smallest
530 * numerical value) appears first in the list */
531 list_for_each_entry_rcu(iter, &iface->addr6_list, list)
532 if (iter->valid &&
533 ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
534 __list_add_rcu(&entry->list,
535 iter->list.prev,
536 &iter->list);
537 spin_unlock(&netlbl_unlhsh_lock);
538 return 0;
539 }
540 list_add_tail_rcu(&entry->list, &iface->addr6_list);
541 spin_unlock(&netlbl_unlhsh_lock); 451 spin_unlock(&netlbl_unlhsh_lock);
452
453 if (ret_val != 0)
454 kfree(entry);
542 return 0; 455 return 0;
543} 456}
544#endif /* IPv6 */ 457#endif /* IPv6 */
@@ -719,22 +632,21 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
719 const struct in_addr *mask, 632 const struct in_addr *mask,
720 struct netlbl_audit *audit_info) 633 struct netlbl_audit *audit_info)
721{ 634{
722 int ret_val = -ENOENT; 635 int ret_val = 0;
636 struct netlbl_af4list *list_entry;
723 struct netlbl_unlhsh_addr4 *entry; 637 struct netlbl_unlhsh_addr4 *entry;
724 struct audit_buffer *audit_buf = NULL; 638 struct audit_buffer *audit_buf;
725 struct net_device *dev; 639 struct net_device *dev;
726 char *secctx = NULL; 640 char *secctx;
727 u32 secctx_len; 641 u32 secctx_len;
728 642
729 spin_lock(&netlbl_unlhsh_lock); 643 spin_lock(&netlbl_unlhsh_lock);
730 entry = netlbl_unlhsh_search_addr4(addr->s_addr, iface); 644 list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
731 if (entry != NULL && 645 &iface->addr4_list);
732 entry->addr == addr->s_addr && entry->mask == mask->s_addr) {
733 entry->valid = 0;
734 list_del_rcu(&entry->list);
735 ret_val = 0;
736 }
737 spin_unlock(&netlbl_unlhsh_lock); 646 spin_unlock(&netlbl_unlhsh_lock);
647 if (list_entry == NULL)
648 ret_val = -ENOENT;
649 entry = netlbl_unlhsh_addr4_entry(list_entry);
738 650
739 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, 651 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
740 audit_info); 652 audit_info);
@@ -742,12 +654,12 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
742 dev = dev_get_by_index(net, iface->ifindex); 654 dev = dev_get_by_index(net, iface->ifindex);
743 netlbl_unlabel_audit_addr4(audit_buf, 655 netlbl_unlabel_audit_addr4(audit_buf,
744 (dev != NULL ? dev->name : NULL), 656 (dev != NULL ? dev->name : NULL),
745 entry->addr, entry->mask); 657 addr->s_addr, mask->s_addr);
746 if (dev != NULL) 658 if (dev != NULL)
747 dev_put(dev); 659 dev_put(dev);
748 if (security_secid_to_secctx(entry->secid, 660 if (entry && security_secid_to_secctx(entry->secid,
749 &secctx, 661 &secctx,
750 &secctx_len) == 0) { 662 &secctx_len) == 0) {
751 audit_log_format(audit_buf, " sec_obj=%s", secctx); 663 audit_log_format(audit_buf, " sec_obj=%s", secctx);
752 security_release_secctx(secctx, secctx_len); 664 security_release_secctx(secctx, secctx_len);
753 } 665 }
@@ -781,23 +693,20 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
781 const struct in6_addr *mask, 693 const struct in6_addr *mask,
782 struct netlbl_audit *audit_info) 694 struct netlbl_audit *audit_info)
783{ 695{
784 int ret_val = -ENOENT; 696 int ret_val = 0;
697 struct netlbl_af6list *list_entry;
785 struct netlbl_unlhsh_addr6 *entry; 698 struct netlbl_unlhsh_addr6 *entry;
786 struct audit_buffer *audit_buf = NULL; 699 struct audit_buffer *audit_buf;
787 struct net_device *dev; 700 struct net_device *dev;
788 char *secctx = NULL; 701 char *secctx;
789 u32 secctx_len; 702 u32 secctx_len;
790 703
791 spin_lock(&netlbl_unlhsh_lock); 704 spin_lock(&netlbl_unlhsh_lock);
792 entry = netlbl_unlhsh_search_addr6(addr, iface); 705 list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
793 if (entry != NULL &&
794 (ipv6_addr_equal(&entry->addr, addr) &&
795 ipv6_addr_equal(&entry->mask, mask))) {
796 entry->valid = 0;
797 list_del_rcu(&entry->list);
798 ret_val = 0;
799 }
800 spin_unlock(&netlbl_unlhsh_lock); 706 spin_unlock(&netlbl_unlhsh_lock);
707 if (list_entry == NULL)
708 ret_val = -ENOENT;
709 entry = netlbl_unlhsh_addr6_entry(list_entry);
801 710
802 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, 711 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
803 audit_info); 712 audit_info);
@@ -808,9 +717,9 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
808 addr, mask); 717 addr, mask);
809 if (dev != NULL) 718 if (dev != NULL)
810 dev_put(dev); 719 dev_put(dev);
811 if (security_secid_to_secctx(entry->secid, 720 if (entry && security_secid_to_secctx(entry->secid,
812 &secctx, 721 &secctx,
813 &secctx_len) == 0) { 722 &secctx_len) == 0) {
814 audit_log_format(audit_buf, " sec_obj=%s", secctx); 723 audit_log_format(audit_buf, " sec_obj=%s", secctx);
815 security_release_secctx(secctx, secctx_len); 724 security_release_secctx(secctx, secctx_len);
816 } 725 }
@@ -836,16 +745,18 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
836 */ 745 */
837static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface) 746static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
838{ 747{
839 struct netlbl_unlhsh_addr4 *iter4; 748 struct netlbl_af4list *iter4;
840 struct netlbl_unlhsh_addr6 *iter6; 749#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
750 struct netlbl_af6list *iter6;
751#endif /* IPv6 */
841 752
842 spin_lock(&netlbl_unlhsh_lock); 753 spin_lock(&netlbl_unlhsh_lock);
843 list_for_each_entry_rcu(iter4, &iface->addr4_list, list) 754 netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list)
844 if (iter4->valid) 755 goto unlhsh_condremove_failure;
845 goto unlhsh_condremove_failure; 756#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
846 list_for_each_entry_rcu(iter6, &iface->addr6_list, list) 757 netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list)
847 if (iter6->valid) 758 goto unlhsh_condremove_failure;
848 goto unlhsh_condremove_failure; 759#endif /* IPv6 */
849 iface->valid = 0; 760 iface->valid = 0;
850 if (iface->ifindex > 0) 761 if (iface->ifindex > 0)
851 list_del_rcu(&iface->list); 762 list_del_rcu(&iface->list);
@@ -1349,7 +1260,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
1349 if (addr4) { 1260 if (addr4) {
1350 struct in_addr addr_struct; 1261 struct in_addr addr_struct;
1351 1262
1352 addr_struct.s_addr = addr4->addr; 1263 addr_struct.s_addr = addr4->list.addr;
1353 ret_val = nla_put(cb_arg->skb, 1264 ret_val = nla_put(cb_arg->skb,
1354 NLBL_UNLABEL_A_IPV4ADDR, 1265 NLBL_UNLABEL_A_IPV4ADDR,
1355 sizeof(struct in_addr), 1266 sizeof(struct in_addr),
@@ -1357,7 +1268,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
1357 if (ret_val != 0) 1268 if (ret_val != 0)
1358 goto list_cb_failure; 1269 goto list_cb_failure;
1359 1270
1360 addr_struct.s_addr = addr4->mask; 1271 addr_struct.s_addr = addr4->list.mask;
1361 ret_val = nla_put(cb_arg->skb, 1272 ret_val = nla_put(cb_arg->skb,
1362 NLBL_UNLABEL_A_IPV4MASK, 1273 NLBL_UNLABEL_A_IPV4MASK,
1363 sizeof(struct in_addr), 1274 sizeof(struct in_addr),
@@ -1370,14 +1281,14 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
1370 ret_val = nla_put(cb_arg->skb, 1281 ret_val = nla_put(cb_arg->skb,
1371 NLBL_UNLABEL_A_IPV6ADDR, 1282 NLBL_UNLABEL_A_IPV6ADDR,
1372 sizeof(struct in6_addr), 1283 sizeof(struct in6_addr),
1373 &addr6->addr); 1284 &addr6->list.addr);
1374 if (ret_val != 0) 1285 if (ret_val != 0)
1375 goto list_cb_failure; 1286 goto list_cb_failure;
1376 1287
1377 ret_val = nla_put(cb_arg->skb, 1288 ret_val = nla_put(cb_arg->skb,
1378 NLBL_UNLABEL_A_IPV6MASK, 1289 NLBL_UNLABEL_A_IPV6MASK,
1379 sizeof(struct in6_addr), 1290 sizeof(struct in6_addr),
1380 &addr6->mask); 1291 &addr6->list.mask);
1381 if (ret_val != 0) 1292 if (ret_val != 0)
1382 goto list_cb_failure; 1293 goto list_cb_failure;
1383 1294
@@ -1425,9 +1336,11 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
1425 u32 iter_bkt; 1336 u32 iter_bkt;
1426 u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0; 1337 u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
1427 struct netlbl_unlhsh_iface *iface; 1338 struct netlbl_unlhsh_iface *iface;
1428 struct netlbl_unlhsh_addr4 *addr4;
1429 struct netlbl_unlhsh_addr6 *addr6;
1430 struct list_head *iter_list; 1339 struct list_head *iter_list;
1340 struct netlbl_af4list *addr4;
1341#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1342 struct netlbl_af6list *addr6;
1343#endif
1431 1344
1432 cb_arg.nl_cb = cb; 1345 cb_arg.nl_cb = cb;
1433 cb_arg.skb = skb; 1346 cb_arg.skb = skb;
@@ -1442,38 +1355,38 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
1442 if (!iface->valid || 1355 if (!iface->valid ||
1443 iter_chain++ < skip_chain) 1356 iter_chain++ < skip_chain)
1444 continue; 1357 continue;
1445 list_for_each_entry_rcu(addr4, 1358 netlbl_af4list_foreach_rcu(addr4,
1446 &iface->addr4_list, 1359 &iface->addr4_list) {
1447 list) { 1360 if (iter_addr4++ < skip_addr4)
1448 if (!addr4->valid || iter_addr4++ < skip_addr4)
1449 continue; 1361 continue;
1450 if (netlbl_unlabel_staticlist_gen( 1362 if (netlbl_unlabel_staticlist_gen(
1451 NLBL_UNLABEL_C_STATICLIST, 1363 NLBL_UNLABEL_C_STATICLIST,
1452 iface, 1364 iface,
1453 addr4, 1365 netlbl_unlhsh_addr4_entry(addr4),
1454 NULL, 1366 NULL,
1455 &cb_arg) < 0) { 1367 &cb_arg) < 0) {
1456 iter_addr4--; 1368 iter_addr4--;
1457 iter_chain--; 1369 iter_chain--;
1458 goto unlabel_staticlist_return; 1370 goto unlabel_staticlist_return;
1459 } 1371 }
1460 } 1372 }
1461 list_for_each_entry_rcu(addr6, 1373#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1462 &iface->addr6_list, 1374 netlbl_af6list_foreach_rcu(addr6,
1463 list) { 1375 &iface->addr6_list) {
1464 if (!addr6->valid || iter_addr6++ < skip_addr6) 1376 if (iter_addr6++ < skip_addr6)
1465 continue; 1377 continue;
1466 if (netlbl_unlabel_staticlist_gen( 1378 if (netlbl_unlabel_staticlist_gen(
1467 NLBL_UNLABEL_C_STATICLIST, 1379 NLBL_UNLABEL_C_STATICLIST,
1468 iface, 1380 iface,
1469 NULL, 1381 NULL,
1470 addr6, 1382 netlbl_unlhsh_addr6_entry(addr6),
1471 &cb_arg) < 0) { 1383 &cb_arg) < 0) {
1472 iter_addr6--; 1384 iter_addr6--;
1473 iter_chain--; 1385 iter_chain--;
1474 goto unlabel_staticlist_return; 1386 goto unlabel_staticlist_return;
1475 } 1387 }
1476 } 1388 }
1389#endif /* IPv6 */
1477 } 1390 }
1478 } 1391 }
1479 1392
@@ -1504,9 +1417,12 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
1504 struct netlbl_unlhsh_iface *iface; 1417 struct netlbl_unlhsh_iface *iface;
1505 u32 skip_addr4 = cb->args[0]; 1418 u32 skip_addr4 = cb->args[0];
1506 u32 skip_addr6 = cb->args[1]; 1419 u32 skip_addr6 = cb->args[1];
1507 u32 iter_addr4 = 0, iter_addr6 = 0; 1420 u32 iter_addr4 = 0;
1508 struct netlbl_unlhsh_addr4 *addr4; 1421 struct netlbl_af4list *addr4;
1509 struct netlbl_unlhsh_addr6 *addr6; 1422#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1423 u32 iter_addr6 = 0;
1424 struct netlbl_af6list *addr6;
1425#endif
1510 1426
1511 cb_arg.nl_cb = cb; 1427 cb_arg.nl_cb = cb;
1512 cb_arg.skb = skb; 1428 cb_arg.skb = skb;
@@ -1517,30 +1433,32 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
1517 if (iface == NULL || !iface->valid) 1433 if (iface == NULL || !iface->valid)
1518 goto unlabel_staticlistdef_return; 1434 goto unlabel_staticlistdef_return;
1519 1435
1520 list_for_each_entry_rcu(addr4, &iface->addr4_list, list) { 1436 netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) {
1521 if (!addr4->valid || iter_addr4++ < skip_addr4) 1437 if (iter_addr4++ < skip_addr4)
1522 continue; 1438 continue;
1523 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, 1439 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1524 iface, 1440 iface,
1525 addr4, 1441 netlbl_unlhsh_addr4_entry(addr4),
1526 NULL, 1442 NULL,
1527 &cb_arg) < 0) { 1443 &cb_arg) < 0) {
1528 iter_addr4--; 1444 iter_addr4--;
1529 goto unlabel_staticlistdef_return; 1445 goto unlabel_staticlistdef_return;
1530 } 1446 }
1531 } 1447 }
1532 list_for_each_entry_rcu(addr6, &iface->addr6_list, list) { 1448#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1533 if (!addr6->valid || iter_addr6++ < skip_addr6) 1449 netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) {
1450 if (iter_addr6++ < skip_addr6)
1534 continue; 1451 continue;
1535 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, 1452 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1536 iface, 1453 iface,
1537 NULL, 1454 NULL,
1538 addr6, 1455 netlbl_unlhsh_addr6_entry(addr6),
1539 &cb_arg) < 0) { 1456 &cb_arg) < 0) {
1540 iter_addr6--; 1457 iter_addr6--;
1541 goto unlabel_staticlistdef_return; 1458 goto unlabel_staticlistdef_return;
1542 } 1459 }
1543 } 1460 }
1461#endif /* IPv6 */
1544 1462
1545unlabel_staticlistdef_return: 1463unlabel_staticlistdef_return:
1546 rcu_read_unlock(); 1464 rcu_read_unlock();
@@ -1718,25 +1636,27 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb,
1718 switch (family) { 1636 switch (family) {
1719 case PF_INET: { 1637 case PF_INET: {
1720 struct iphdr *hdr4; 1638 struct iphdr *hdr4;
1721 struct netlbl_unlhsh_addr4 *addr4; 1639 struct netlbl_af4list *addr4;
1722 1640
1723 hdr4 = ip_hdr(skb); 1641 hdr4 = ip_hdr(skb);
1724 addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface); 1642 addr4 = netlbl_af4list_search(hdr4->saddr,
1643 &iface->addr4_list);
1725 if (addr4 == NULL) 1644 if (addr4 == NULL)
1726 goto unlabel_getattr_nolabel; 1645 goto unlabel_getattr_nolabel;
1727 secattr->attr.secid = addr4->secid; 1646 secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;
1728 break; 1647 break;
1729 } 1648 }
1730#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 1649#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1731 case PF_INET6: { 1650 case PF_INET6: {
1732 struct ipv6hdr *hdr6; 1651 struct ipv6hdr *hdr6;
1733 struct netlbl_unlhsh_addr6 *addr6; 1652 struct netlbl_af6list *addr6;
1734 1653
1735 hdr6 = ipv6_hdr(skb); 1654 hdr6 = ipv6_hdr(skb);
1736 addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface); 1655 addr6 = netlbl_af6list_search(&hdr6->saddr,
1656 &iface->addr6_list);
1737 if (addr6 == NULL) 1657 if (addr6 == NULL)
1738 goto unlabel_getattr_nolabel; 1658 goto unlabel_getattr_nolabel;
1739 secattr->attr.secid = addr6->secid; 1659 secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;
1740 break; 1660 break;
1741 } 1661 }
1742#endif /* IPv6 */ 1662#endif /* IPv6 */