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