1 /*-
2 * Copyright (c) 2005 Paolo Pisati <piso@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: stable/10/sys/netinet/libalias/alias_mod.c 201758 2010-01-07 21:01:37Z mbr $");
29
30 #ifdef _KERNEL
31 #include <sys/libkern.h>
32 #include <sys/param.h>
33 #include <sys/lock.h>
34 #include <sys/rwlock.h>
35 #else
36 #include <stdio.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <errno.h>
40 #endif
41
42 #include <netinet/in_systm.h>
43 #include <netinet/in.h>
44 #include <netinet/ip.h>
45
46 #ifdef _KERNEL
47 #include <netinet/libalias/alias_local.h>
48 #include <netinet/libalias/alias_mod.h>
49 #else
50 #include "alias_local.h"
51 #include "alias_mod.h"
52 #endif
53
54 /* Protocol and userland module handlers chains. */
55 LIST_HEAD(handler_chain, proto_handler) handler_chain = LIST_HEAD_INITIALIZER(handler_chain);
56 #ifdef _KERNEL
57 struct rwlock handler_rw;
58 #endif
59 SLIST_HEAD(dll_chain, dll) dll_chain = SLIST_HEAD_INITIALIZER(dll_chain);
60
61 #ifdef _KERNEL
62
63 #define LIBALIAS_RWLOCK_INIT() \
64 rw_init(&handler_rw, "Libalias_modules_rwlock")
65 #define LIBALIAS_RWLOCK_DESTROY() rw_destroy(&handler_rw)
66 #define LIBALIAS_WLOCK_ASSERT() \
67 rw_assert(&handler_rw, RA_WLOCKED)
68
69 static __inline void
LIBALIAS_RLOCK(void)70 LIBALIAS_RLOCK(void)
71 {
72 rw_rlock(&handler_rw);
73 }
74
75 static __inline void
LIBALIAS_RUNLOCK(void)76 LIBALIAS_RUNLOCK(void)
77 {
78 rw_runlock(&handler_rw);
79 }
80
81 static __inline void
LIBALIAS_WLOCK(void)82 LIBALIAS_WLOCK(void)
83 {
84 rw_wlock(&handler_rw);
85 }
86
87 static __inline void
LIBALIAS_WUNLOCK(void)88 LIBALIAS_WUNLOCK(void)
89 {
90 rw_wunlock(&handler_rw);
91 }
92
93 static void
_handler_chain_init(void)94 _handler_chain_init(void)
95 {
96
97 if (!rw_initialized(&handler_rw))
98 LIBALIAS_RWLOCK_INIT();
99 }
100
101 static void
_handler_chain_destroy(void)102 _handler_chain_destroy(void)
103 {
104
105 if (rw_initialized(&handler_rw))
106 LIBALIAS_RWLOCK_DESTROY();
107 }
108
109 #else
110 #define LIBALIAS_RWLOCK_INIT() ;
111 #define LIBALIAS_RWLOCK_DESTROY() ;
112 #define LIBALIAS_WLOCK_ASSERT() ;
113 #define LIBALIAS_RLOCK() ;
114 #define LIBALIAS_RUNLOCK() ;
115 #define LIBALIAS_WLOCK() ;
116 #define LIBALIAS_WUNLOCK() ;
117 #define _handler_chain_init() ;
118 #define _handler_chain_destroy() ;
119 #endif
120
121 void
handler_chain_init(void)122 handler_chain_init(void)
123 {
124 _handler_chain_init();
125 }
126
127 void
handler_chain_destroy(void)128 handler_chain_destroy(void)
129 {
130 _handler_chain_destroy();
131 }
132
133 static int
_attach_handler(struct proto_handler * p)134 _attach_handler(struct proto_handler *p)
135 {
136 struct proto_handler *b;
137
138 LIBALIAS_WLOCK_ASSERT();
139 b = NULL;
140 LIST_FOREACH(b, &handler_chain, entries) {
141 if ((b->pri == p->pri) &&
142 (b->dir == p->dir) &&
143 (b->proto == p->proto))
144 return (EEXIST); /* Priority conflict. */
145 if (b->pri > p->pri) {
146 LIST_INSERT_BEFORE(b, p, entries);
147 return (0);
148 }
149 }
150 /* End of list or found right position, inserts here. */
151 if (b)
152 LIST_INSERT_AFTER(b, p, entries);
153 else
154 LIST_INSERT_HEAD(&handler_chain, p, entries);
155 return (0);
156 }
157
158 static int
_detach_handler(struct proto_handler * p)159 _detach_handler(struct proto_handler *p)
160 {
161 struct proto_handler *b, *b_tmp;
162
163 LIBALIAS_WLOCK_ASSERT();
164 LIST_FOREACH_SAFE(b, &handler_chain, entries, b_tmp) {
165 if (b == p) {
166 LIST_REMOVE(b, entries);
167 return (0);
168 }
169 }
170 return (ENOENT); /* Handler not found. */
171 }
172
173 int
LibAliasAttachHandlers(struct proto_handler * _p)174 LibAliasAttachHandlers(struct proto_handler *_p)
175 {
176 int i, error;
177
178 LIBALIAS_WLOCK();
179 error = -1;
180 for (i = 0; 1; i++) {
181 if (*((int *)&_p[i]) == EOH)
182 break;
183 error = _attach_handler(&_p[i]);
184 if (error != 0)
185 break;
186 }
187 LIBALIAS_WUNLOCK();
188 return (error);
189 }
190
191 int
LibAliasDetachHandlers(struct proto_handler * _p)192 LibAliasDetachHandlers(struct proto_handler *_p)
193 {
194 int i, error;
195
196 LIBALIAS_WLOCK();
197 error = -1;
198 for (i = 0; 1; i++) {
199 if (*((int *)&_p[i]) == EOH)
200 break;
201 error = _detach_handler(&_p[i]);
202 if (error != 0)
203 break;
204 }
205 LIBALIAS_WUNLOCK();
206 return (error);
207 }
208
209 int
detach_handler(struct proto_handler * _p)210 detach_handler(struct proto_handler *_p)
211 {
212 int error;
213
214 LIBALIAS_WLOCK();
215 error = -1;
216 error = _detach_handler(_p);
217 LIBALIAS_WUNLOCK();
218 return (error);
219 }
220
221 int
find_handler(int8_t dir,int8_t proto,struct libalias * la,__unused struct ip * pip,struct alias_data * ad)222 find_handler(int8_t dir, int8_t proto, struct libalias *la, __unused struct ip *pip,
223 struct alias_data *ad)
224 {
225 struct proto_handler *p;
226 int error;
227
228 LIBALIAS_RLOCK();
229 error = ENOENT;
230 LIST_FOREACH(p, &handler_chain, entries) {
231 if ((p->dir & dir) && (p->proto & proto))
232 if (p->fingerprint(la, ad) == 0) {
233 error = p->protohandler(la, pip, ad);
234 break;
235 }
236 }
237 LIBALIAS_RUNLOCK();
238 return (error);
239 }
240
241 struct proto_handler *
first_handler(void)242 first_handler(void)
243 {
244
245 return (LIST_FIRST(&handler_chain));
246 }
247
248 /* Dll manipulation code - this code is not thread safe... */
249
250 int
attach_dll(struct dll * p)251 attach_dll(struct dll *p)
252 {
253 struct dll *b;
254
255 SLIST_FOREACH(b, &dll_chain, next) {
256 if (!strncmp(b->name, p->name, DLL_LEN))
257 return (EEXIST); /* Dll name conflict. */
258 }
259 SLIST_INSERT_HEAD(&dll_chain, p, next);
260 return (0);
261 }
262
263 void *
detach_dll(char * p)264 detach_dll(char *p)
265 {
266 struct dll *b, *b_tmp;
267 void *error;
268
269 b = NULL;
270 error = NULL;
271 SLIST_FOREACH_SAFE(b, &dll_chain, next, b_tmp)
272 if (!strncmp(b->name, p, DLL_LEN)) {
273 SLIST_REMOVE(&dll_chain, b, dll, next);
274 error = b;
275 break;
276 }
277 return (error);
278 }
279
280 struct dll *
walk_dll_chain(void)281 walk_dll_chain(void)
282 {
283 struct dll *t;
284
285 t = SLIST_FIRST(&dll_chain);
286 if (t == NULL)
287 return (NULL);
288 SLIST_REMOVE_HEAD(&dll_chain, next);
289 return (t);
290 }
291