aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlabel/netlabel_addrlist.c
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 /net/netlabel/netlabel_addrlist.c
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>
Diffstat (limited to 'net/netlabel/netlabel_addrlist.c')
-rw-r--r--net/netlabel/netlabel_addrlist.c258
1 files changed, 258 insertions, 0 deletions
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 */