Commit | Line | Data |
---|---|---|
61e10682 PM |
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 | */ | |
60 | struct 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 | */ | |
84 | struct 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 | */ | |
109 | int 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 | */ | |
146 | int 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 | */ | |
182 | void 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 | */ | |
200 | struct 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 | */ | |
224 | void 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 | */ | |
242 | struct 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 */ |