aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2008-10-10 10:16:32 -0400
committerPaul Moore <paul.moore@hp.com>2008-10-10 10:16:32 -0400
commit61e1068219950c672ce979719ad2be3aadb00d7d (patch)
treeda987ee4b5be90f95ca8e0b20bd872ff75d82934
parentb1edeb102397546438ab4624489c6ccd7b410d97 (diff)
netlabel: Add a generic way to create ordered linked lists of network addrs
Create an ordered IP address linked list mechanism similar to the core kernel's linked list construct. The idea behind this list functionality is to create an extensibile linked list ordered by IP address mask to ease the matching of network addresses. The linked list is ordered with larger address masks at the front of the list and shorter address masks at the end to facilitate overriding network entries with individual host or subnet entries. Signed-off-by: Paul Moore <paul.moore@hp.com> Reviewed-by: James Morris <jmorris@namei.org>
-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 8af18c0a47d..ea750e9df65 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 00000000000..dd928aa52db
--- /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 00000000000..0c41df057fa
--- /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 cc105a10e3f..ab8131a8e48 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 */