xref: /freebsd/sys/netinet/libalias/alias_mod.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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$");
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(foo);
56 #ifdef _KERNEL
57 struct rwlock   handler_rw;
58 #endif
59 SLIST_HEAD(dll_chain, dll) dll_chain = SLIST_HEAD_INITIALIZER(foo);
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
70 LIBALIAS_RLOCK(void)
71 {
72 	rw_rlock(&handler_rw);
73 }
74 
75 static __inline void
76 LIBALIAS_RUNLOCK(void)
77 {
78 	rw_runlock(&handler_rw);
79 }
80 
81 static __inline void
82 LIBALIAS_WLOCK(void)
83 {
84 	rw_wlock(&handler_rw);
85 }
86 
87 static __inline void
88 LIBALIAS_WUNLOCK(void)
89 {
90 	rw_wunlock(&handler_rw);
91 }
92 
93 static void
94 _handler_chain_init(void)
95 {
96 
97 	if (!rw_initialized(&handler_rw))
98 		LIBALIAS_RWLOCK_INIT();
99 }
100 
101 static 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
122 handler_chain_init(void)
123 {
124 	_handler_chain_init();
125 }
126 
127 void
128 handler_chain_destroy(void)
129 {
130 	_handler_chain_destroy();
131 }
132 
133 static int
134 _attach_handler(struct proto_handler *p)
135 {
136 	struct proto_handler *b = NULL;
137 
138 	LIBALIAS_WLOCK_ASSERT();
139 	LIST_FOREACH(b, &handler_chain, entries) {
140 		if ((b->pri == p->pri) &&
141 		    (b->dir == p->dir) &&
142 		    (b->proto == p->proto))
143 			return (EEXIST); /* Priority conflict. */
144 		if (b->pri > p->pri) {
145 			LIST_INSERT_BEFORE(b, p, entries);
146 			return (0);
147 		}
148 	}
149 	/* End of list or found right position, inserts here. */
150 	if (b)
151 		LIST_INSERT_AFTER(b, p, entries);
152 	else
153 		LIST_INSERT_HEAD(&handler_chain, p, entries);
154 	return (0);
155 }
156 
157 static int
158 _detach_handler(struct proto_handler *p)
159 {
160 	struct proto_handler *b, *b_tmp;;
161 
162 	LIBALIAS_WLOCK_ASSERT();
163 	LIST_FOREACH_SAFE(b, &handler_chain, entries, b_tmp) {
164 		if (b == p) {
165 			LIST_REMOVE(b, entries);
166 			return (0);
167 		}
168 	}
169 	return (ENOENT); /* Handler not found. */
170 }
171 
172 int
173 LibAliasAttachHandlers(struct proto_handler *_p)
174 {
175 	int i, error = -1;
176 
177 	LIBALIAS_WLOCK();
178 	for (i=0; 1; i++) {
179 		if (*((int *)&_p[i]) == EOH)
180 			break;
181 		error = _attach_handler(&_p[i]);
182 		if (error != 0)
183 			break;
184 	}
185 	LIBALIAS_WUNLOCK();
186 	return (error);
187 }
188 
189 int
190 LibAliasDetachHandlers(struct proto_handler *_p)
191 {
192 	int i, error = -1;
193 
194 	LIBALIAS_WLOCK();
195 	for (i=0; 1; i++) {
196 		if (*((int *)&_p[i]) == EOH)
197 			break;
198 		error = _detach_handler(&_p[i]);
199 		if (error != 0)
200 			break;
201 	}
202 	LIBALIAS_WUNLOCK();
203 	return (error);
204 }
205 
206 int
207 detach_handler(struct proto_handler *_p)
208 {
209 	int error = -1;
210 
211 	LIBALIAS_WLOCK();
212 	error = _detach_handler(_p);
213 	LIBALIAS_WUNLOCK();
214 	return (error);
215 }
216 
217 int
218 find_handler(int8_t dir, int8_t proto, struct libalias *la, struct ip *pip,
219 	     struct alias_data *ad)
220 {
221 	struct proto_handler *p;
222 	int error = ENOENT;
223 
224 	LIBALIAS_RLOCK();
225 
226 	LIST_FOREACH(p, &handler_chain, entries) {
227 		if ((p->dir & dir) && (p->proto & proto))
228 			if (p->fingerprint(la, pip, ad) == 0) {
229 				error = p->protohandler(la, pip, ad);
230 				break;
231 			}
232 	}
233 	LIBALIAS_RUNLOCK();
234 	return (error);
235 }
236 
237 struct proto_handler *
238 first_handler(void)
239 {
240 
241 	return (LIST_FIRST(&handler_chain));
242 }
243 
244 /* Dll manipulation code - this code is not thread safe... */
245 
246 int
247 attach_dll(struct dll *p)
248 {
249 	struct dll *b;
250 
251 	SLIST_FOREACH(b, &dll_chain, next) {
252 		if (!strncmp(b->name, p->name, DLL_LEN))
253 			return (EEXIST); /* Dll name conflict. */
254 	}
255 	SLIST_INSERT_HEAD(&dll_chain, p, next);
256 	return (0);
257 }
258 
259 void *
260 detach_dll(char *p)
261 {
262 	struct dll *b = NULL, *b_tmp;
263 	void *error = NULL;
264 
265 	SLIST_FOREACH_SAFE(b, &dll_chain, next, b_tmp)
266 		if (!strncmp(b->name, p, DLL_LEN)) {
267 			SLIST_REMOVE(&dll_chain, b, dll, next);
268 			error = b;
269 			break;
270 		}
271 	return (error);
272 }
273 
274 struct dll *
275 walk_dll_chain(void)
276 {
277 	struct dll *t;
278 
279 	t = SLIST_FIRST(&dll_chain);
280 	if (t == NULL)
281 		return (NULL);
282 	SLIST_REMOVE_HEAD(&dll_chain, next);
283 	return (t);
284 }
285