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