blob: dd928aa52db1553016aa95eb02d9847d190f3e8b [file] [log] [blame]
Paul Moore61e10682008-10-10 10:16:32 -04001/*
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 */