1 1.5 pgoyette /* $NetBSD: ip_lookup.c,v 1.5 2016/06/09 04:43:46 pgoyette Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.3 darrenr * Copyright (C) 2012 by Darren Reed. 5 1.1 christos * 6 1.1 christos * See the IPFILTER.LICENCE file for details on licencing. 7 1.1 christos */ 8 1.1 christos #if defined(KERNEL) || defined(_KERNEL) 9 1.1 christos # undef KERNEL 10 1.1 christos # undef _KERNEL 11 1.1 christos # define KERNEL 1 12 1.1 christos # define _KERNEL 1 13 1.1 christos #endif 14 1.1 christos #if defined(__osf__) 15 1.1 christos # define _PROTO_NET_H_ 16 1.1 christos #endif 17 1.1 christos #include <sys/param.h> 18 1.2 christos #if defined(__NetBSD__) 19 1.2 christos # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL) 20 1.5 pgoyette # if (__NetBSD_Version__ >= 799003000) 21 1.5 pgoyette # if defined(_KERNEL_OPT) 22 1.5 pgoyette # include "opt_ipfilter.h" 23 1.5 pgoyette # endif 24 1.5 pgoyette # else 25 1.5 pgoyette # include "opt_ipfilter.h" 26 1.5 pgoyette # endif 27 1.2 christos # endif 28 1.2 christos #endif 29 1.1 christos #include <sys/errno.h> 30 1.1 christos #include <sys/types.h> 31 1.1 christos #include <sys/time.h> 32 1.1 christos #include <sys/file.h> 33 1.1 christos #if __FreeBSD_version >= 220000 && defined(_KERNEL) 34 1.1 christos # include <sys/fcntl.h> 35 1.1 christos # include <sys/filio.h> 36 1.1 christos #else 37 1.1 christos # include <sys/ioctl.h> 38 1.1 christos #endif 39 1.1 christos #if !defined(_KERNEL) 40 1.1 christos # include <stdio.h> 41 1.1 christos # include <string.h> 42 1.1 christos # include <stdlib.h> 43 1.1 christos # define _KERNEL 44 1.1 christos # ifdef __OpenBSD__ 45 1.1 christos struct file; 46 1.1 christos # endif 47 1.1 christos # include <sys/uio.h> 48 1.1 christos # undef _KERNEL 49 1.1 christos #endif 50 1.1 christos #include <sys/socket.h> 51 1.1 christos #include <net/if.h> 52 1.1 christos #if defined(__FreeBSD__) 53 1.1 christos # include <sys/cdefs.h> 54 1.1 christos # include <sys/proc.h> 55 1.1 christos #endif 56 1.1 christos #if defined(_KERNEL) 57 1.1 christos # include <sys/systm.h> 58 1.1 christos # if !defined(__SVR4) && !defined(__svr4__) 59 1.1 christos # include <sys/mbuf.h> 60 1.1 christos # endif 61 1.1 christos #else 62 1.1 christos # include "ipf.h" 63 1.1 christos #endif 64 1.1 christos #include <netinet/in.h> 65 1.1 christos 66 1.1 christos #include "netinet/ip_compat.h" 67 1.1 christos #include "netinet/ip_fil.h" 68 1.1 christos #include "netinet/ip_lookup.h" 69 1.1 christos #include "netinet/ip_pool.h" 70 1.1 christos #include "netinet/ip_htable.h" 71 1.1 christos #include "netinet/ip_dstlist.h" 72 1.1 christos /* END OF INCLUDES */ 73 1.1 christos 74 1.1 christos #if !defined(lint) 75 1.2 christos #if defined(__NetBSD__) 76 1.2 christos #include <sys/cdefs.h> 77 1.5 pgoyette __KERNEL_RCSID(0, "$NetBSD: ip_lookup.c,v 1.5 2016/06/09 04:43:46 pgoyette Exp $"); 78 1.2 christos #else 79 1.3 darrenr static const char rcsid[] = "@(#)Id: ip_lookup.c,v 1.1.1.2 2012/07/22 13:45:21 darrenr Exp"; 80 1.2 christos #endif 81 1.1 christos #endif 82 1.1 christos 83 1.1 christos /* 84 1.1 christos * In this file, ip_pool.c, ip_htable.c and ip_dstlist.c, you will find the 85 1.1 christos * range for unit is [-1,IPL_LOGMAX]. The -1 is considered to be a valid number 86 1.1 christos * and represents a "wildcard" or "all" units (IPL_LOGALL). The reason for not 87 1.1 christos * starting the numbering at 0 is because the numbers [0,IPL_LOGMAX] correspond 88 1.1 christos * to the minor device number for their respective device. Thus where there is 89 1.1 christos * array indexing on the unit, +1 is used to map [-1.IPL_LOGMAX] to 90 1.1 christos * [0.POOL_LOOKUP_MAX]. 91 1.1 christos */ 92 1.2 christos static int ipf_lookup_addnode(ipf_main_softc_t *, void *, int); 93 1.2 christos static int ipf_lookup_delnode(ipf_main_softc_t *, void *, int); 94 1.2 christos static int ipf_lookup_addtable(ipf_main_softc_t *, void *); 95 1.2 christos static int ipf_lookup_deltable(ipf_main_softc_t *, void *); 96 1.2 christos static int ipf_lookup_stats(ipf_main_softc_t *, void *); 97 1.2 christos static int ipf_lookup_flush(ipf_main_softc_t *, void *); 98 1.2 christos static int ipf_lookup_iterate(ipf_main_softc_t *, void *, int, void *); 99 1.2 christos static int ipf_lookup_deltok(ipf_main_softc_t *, void *, int, void *); 100 1.1 christos 101 1.1 christos #define MAX_BACKENDS 3 102 1.1 christos static ipf_lookup_t *backends[MAX_BACKENDS] = { 103 1.1 christos &ipf_pool_backend, 104 1.1 christos &ipf_htable_backend, 105 1.1 christos &ipf_dstlist_backend 106 1.1 christos }; 107 1.1 christos 108 1.1 christos 109 1.1 christos typedef struct ipf_lookup_softc_s { 110 1.1 christos void *ipf_back[MAX_BACKENDS]; 111 1.1 christos } ipf_lookup_softc_t; 112 1.1 christos 113 1.1 christos 114 1.1 christos /* ------------------------------------------------------------------------ */ 115 1.1 christos /* Function: ipf_lookup_init */ 116 1.1 christos /* Returns: int - 0 = success, else error */ 117 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 118 1.1 christos /* */ 119 1.1 christos /* Initialise all of the subcomponents of the lookup infrstructure. */ 120 1.1 christos /* ------------------------------------------------------------------------ */ 121 1.1 christos void * 122 1.2 christos ipf_lookup_soft_create(ipf_main_softc_t *softc) 123 1.1 christos { 124 1.1 christos ipf_lookup_softc_t *softl; 125 1.1 christos ipf_lookup_t **l; 126 1.1 christos int i; 127 1.1 christos 128 1.1 christos KMALLOC(softl, ipf_lookup_softc_t *); 129 1.1 christos if (softl == NULL) 130 1.1 christos return NULL; 131 1.1 christos 132 1.1 christos bzero((char *)softl, sizeof(*softl)); 133 1.1 christos 134 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 135 1.1 christos softl->ipf_back[i] = (*(*l)->ipfl_create)(softc); 136 1.1 christos if (softl->ipf_back[i] == NULL) { 137 1.1 christos ipf_lookup_soft_destroy(softc, softl); 138 1.1 christos return NULL; 139 1.1 christos } 140 1.1 christos } 141 1.1 christos 142 1.1 christos return softl; 143 1.1 christos } 144 1.1 christos 145 1.1 christos 146 1.1 christos /* ------------------------------------------------------------------------ */ 147 1.1 christos /* Function: ipf_lookup_soft_init */ 148 1.1 christos /* Returns: int - 0 = success, else error */ 149 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 150 1.1 christos /* arg(I) - pointer to local context to use */ 151 1.1 christos /* */ 152 1.1 christos /* Initialise all of the subcomponents of the lookup infrstructure. */ 153 1.1 christos /* ------------------------------------------------------------------------ */ 154 1.1 christos int 155 1.2 christos ipf_lookup_soft_init(ipf_main_softc_t *softc, void *arg) 156 1.1 christos { 157 1.1 christos ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; 158 1.1 christos int err = 0; 159 1.1 christos int i; 160 1.1 christos 161 1.1 christos for (i = 0; i < MAX_BACKENDS; i++) { 162 1.1 christos err = (*backends[i]->ipfl_init)(softc, softl->ipf_back[i]); 163 1.1 christos if (err != 0) 164 1.1 christos break; 165 1.1 christos } 166 1.1 christos 167 1.1 christos return err; 168 1.1 christos } 169 1.1 christos 170 1.1 christos 171 1.1 christos /* ------------------------------------------------------------------------ */ 172 1.1 christos /* Function: ipf_lookup_soft_fini */ 173 1.1 christos /* Returns: int - 0 = success, else error */ 174 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 175 1.1 christos /* arg(I) - pointer to local context to use */ 176 1.1 christos /* */ 177 1.1 christos /* Call the fini function in each backend to cleanup all allocated data. */ 178 1.1 christos /* ------------------------------------------------------------------------ */ 179 1.1 christos int 180 1.2 christos ipf_lookup_soft_fini(ipf_main_softc_t *softc, void *arg) 181 1.1 christos { 182 1.1 christos ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; 183 1.1 christos int i; 184 1.1 christos 185 1.1 christos for (i = 0; i < MAX_BACKENDS; i++) { 186 1.1 christos if (softl->ipf_back[i] != NULL) 187 1.1 christos (*backends[i]->ipfl_fini)(softc, 188 1.1 christos softl->ipf_back[i]); 189 1.1 christos } 190 1.1 christos 191 1.1 christos return 0; 192 1.1 christos } 193 1.1 christos 194 1.1 christos 195 1.1 christos /* ------------------------------------------------------------------------ */ 196 1.1 christos /* Function: ipf_lookup_expire */ 197 1.1 christos /* Returns: Nil */ 198 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 199 1.1 christos /* */ 200 1.1 christos /* Step through each of the backends and call their expire functions, */ 201 1.1 christos /* allowing them to delete any lifetime limited data. */ 202 1.1 christos /* ------------------------------------------------------------------------ */ 203 1.1 christos void 204 1.2 christos ipf_lookup_expire(ipf_main_softc_t *softc) 205 1.1 christos { 206 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 207 1.1 christos int i; 208 1.1 christos 209 1.1 christos WRITE_ENTER(&softc->ipf_poolrw); 210 1.1 christos for (i = 0; i < MAX_BACKENDS; i++) 211 1.1 christos (*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]); 212 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 213 1.1 christos } 214 1.1 christos 215 1.1 christos 216 1.1 christos /* ------------------------------------------------------------------------ */ 217 1.1 christos /* Function: ipf_lookup_softc_destroy */ 218 1.1 christos /* Returns: int - 0 = success, else error */ 219 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 220 1.1 christos /* arg(I) - pointer to local context to use */ 221 1.1 christos /* */ 222 1.1 christos /* Free up all pool related memory that has been allocated whilst IPFilter */ 223 1.1 christos /* has been running. Also, do any other deinitialisation required such */ 224 1.1 christos /* ipf_lookup_init() can be called again, safely. */ 225 1.1 christos /* ------------------------------------------------------------------------ */ 226 1.1 christos void 227 1.2 christos ipf_lookup_soft_destroy(ipf_main_softc_t *softc, void *arg) 228 1.1 christos { 229 1.1 christos ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; 230 1.1 christos int i; 231 1.1 christos 232 1.1 christos for (i = 0; i < MAX_BACKENDS; i++) { 233 1.1 christos if (softl->ipf_back[i] != NULL) 234 1.1 christos (*backends[i]->ipfl_destroy)(softc, 235 1.1 christos softl->ipf_back[i]); 236 1.1 christos } 237 1.1 christos 238 1.1 christos KFREE(softl); 239 1.1 christos } 240 1.1 christos 241 1.1 christos 242 1.1 christos /* ------------------------------------------------------------------------ */ 243 1.1 christos /* Function: ipf_lookup_ioctl */ 244 1.1 christos /* Returns: int - 0 = success, else error */ 245 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 246 1.1 christos /* arg(I) - pointer to local context to use */ 247 1.1 christos /* data(IO) - pointer to ioctl data to be copied to/from user */ 248 1.1 christos /* space. */ 249 1.1 christos /* cmd(I) - ioctl command number */ 250 1.1 christos /* mode(I) - file mode bits used with open */ 251 1.1 christos /* uid(I) - uid of process doing ioctl */ 252 1.1 christos /* ctx(I) - pointer that represents context for uid */ 253 1.1 christos /* */ 254 1.1 christos /* Handle ioctl commands sent to the ioctl device. For the most part, this */ 255 1.1 christos /* involves just calling another function to handle the specifics of each */ 256 1.1 christos /* command. */ 257 1.1 christos /* ------------------------------------------------------------------------ */ 258 1.1 christos int 259 1.2 christos ipf_lookup_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, 260 1.2 christos int mode, int uid, void *ctx) 261 1.1 christos { 262 1.1 christos int err; 263 1.1 christos SPL_INT(s); 264 1.1 christos 265 1.1 christos mode = mode; /* LINT */ 266 1.1 christos 267 1.1 christos SPL_NET(s); 268 1.1 christos 269 1.1 christos switch (cmd) 270 1.1 christos { 271 1.1 christos case SIOCLOOKUPADDNODE : 272 1.1 christos case SIOCLOOKUPADDNODEW : 273 1.1 christos WRITE_ENTER(&softc->ipf_poolrw); 274 1.1 christos err = ipf_lookup_addnode(softc, data, uid); 275 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 276 1.1 christos break; 277 1.1 christos 278 1.1 christos case SIOCLOOKUPDELNODE : 279 1.1 christos case SIOCLOOKUPDELNODEW : 280 1.1 christos WRITE_ENTER(&softc->ipf_poolrw); 281 1.1 christos err = ipf_lookup_delnode(softc, data, uid); 282 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 283 1.1 christos break; 284 1.1 christos 285 1.1 christos case SIOCLOOKUPADDTABLE : 286 1.1 christos WRITE_ENTER(&softc->ipf_poolrw); 287 1.1 christos err = ipf_lookup_addtable(softc, data); 288 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 289 1.1 christos break; 290 1.1 christos 291 1.1 christos case SIOCLOOKUPDELTABLE : 292 1.1 christos WRITE_ENTER(&softc->ipf_poolrw); 293 1.1 christos err = ipf_lookup_deltable(softc, data); 294 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 295 1.1 christos break; 296 1.1 christos 297 1.1 christos case SIOCLOOKUPSTAT : 298 1.1 christos case SIOCLOOKUPSTATW : 299 1.1 christos WRITE_ENTER(&softc->ipf_poolrw); 300 1.1 christos err = ipf_lookup_stats(softc, data); 301 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 302 1.1 christos break; 303 1.1 christos 304 1.1 christos case SIOCLOOKUPFLUSH : 305 1.1 christos WRITE_ENTER(&softc->ipf_poolrw); 306 1.1 christos err = ipf_lookup_flush(softc, data); 307 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 308 1.1 christos break; 309 1.1 christos 310 1.1 christos case SIOCLOOKUPITER : 311 1.1 christos err = ipf_lookup_iterate(softc, data, uid, ctx); 312 1.1 christos break; 313 1.1 christos 314 1.1 christos case SIOCIPFDELTOK : 315 1.1 christos err = ipf_lookup_deltok(softc, data, uid, ctx); 316 1.1 christos break; 317 1.1 christos 318 1.1 christos default : 319 1.1 christos IPFERROR(50001); 320 1.1 christos err = EINVAL; 321 1.1 christos break; 322 1.1 christos } 323 1.1 christos SPL_X(s); 324 1.1 christos return err; 325 1.1 christos } 326 1.1 christos 327 1.1 christos 328 1.1 christos /* ------------------------------------------------------------------------ */ 329 1.1 christos /* Function: ipf_lookup_addnode */ 330 1.1 christos /* Returns: int - 0 = success, else error */ 331 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 332 1.1 christos /* data(I) - pointer to data from ioctl call */ 333 1.1 christos /* */ 334 1.1 christos /* Add a new data node to a lookup structure. First, check to see if the */ 335 1.1 christos /* parent structure refered to by name exists and if it does, then go on to */ 336 1.1 christos /* add a node to it. */ 337 1.1 christos /* ------------------------------------------------------------------------ */ 338 1.1 christos static int 339 1.2 christos ipf_lookup_addnode(ipf_main_softc_t *softc, void *data, int uid) 340 1.1 christos { 341 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 342 1.1 christos iplookupop_t op; 343 1.1 christos ipf_lookup_t **l; 344 1.1 christos int err; 345 1.1 christos int i; 346 1.1 christos 347 1.1 christos err = BCOPYIN(data, &op, sizeof(op)); 348 1.1 christos if (err != 0) { 349 1.1 christos IPFERROR(50002); 350 1.1 christos return EFAULT; 351 1.1 christos } 352 1.1 christos 353 1.1 christos if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && 354 1.1 christos (op.iplo_unit != IPLT_ALL)) { 355 1.1 christos IPFERROR(50003); 356 1.1 christos return EINVAL; 357 1.1 christos } 358 1.1 christos 359 1.1 christos op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; 360 1.1 christos 361 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 362 1.1 christos if (op.iplo_type == (*l)->ipfl_type) { 363 1.1 christos err = (*(*l)->ipfl_node_add)(softc, 364 1.1 christos softl->ipf_back[i], 365 1.1 christos &op, uid); 366 1.1 christos break; 367 1.1 christos } 368 1.1 christos } 369 1.1 christos 370 1.1 christos if (i == MAX_BACKENDS) { 371 1.1 christos IPFERROR(50012); 372 1.1 christos err = EINVAL; 373 1.1 christos } 374 1.1 christos 375 1.1 christos return err; 376 1.1 christos } 377 1.1 christos 378 1.1 christos 379 1.1 christos /* ------------------------------------------------------------------------ */ 380 1.1 christos /* Function: ipf_lookup_delnode */ 381 1.1 christos /* Returns: int - 0 = success, else error */ 382 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 383 1.1 christos /* data(I) - pointer to data from ioctl call */ 384 1.1 christos /* */ 385 1.1 christos /* Delete a node from a lookup table by first looking for the table it is */ 386 1.1 christos /* in and then deleting the entry that gets found. */ 387 1.1 christos /* ------------------------------------------------------------------------ */ 388 1.1 christos static int 389 1.2 christos ipf_lookup_delnode(ipf_main_softc_t *softc, void *data, int uid) 390 1.1 christos { 391 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 392 1.1 christos iplookupop_t op; 393 1.1 christos ipf_lookup_t **l; 394 1.1 christos int err; 395 1.1 christos int i; 396 1.1 christos 397 1.1 christos err = BCOPYIN(data, &op, sizeof(op)); 398 1.1 christos if (err != 0) { 399 1.1 christos IPFERROR(50042); 400 1.1 christos return EFAULT; 401 1.1 christos } 402 1.1 christos 403 1.1 christos if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && 404 1.1 christos (op.iplo_unit != IPLT_ALL)) { 405 1.1 christos IPFERROR(50013); 406 1.1 christos return EINVAL; 407 1.1 christos } 408 1.1 christos 409 1.1 christos op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; 410 1.1 christos 411 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 412 1.1 christos if (op.iplo_type == (*l)->ipfl_type) { 413 1.1 christos err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i], 414 1.1 christos &op, uid); 415 1.1 christos break; 416 1.1 christos } 417 1.1 christos } 418 1.1 christos 419 1.1 christos if (i == MAX_BACKENDS) { 420 1.1 christos IPFERROR(50021); 421 1.1 christos err = EINVAL; 422 1.1 christos } 423 1.1 christos return err; 424 1.1 christos } 425 1.1 christos 426 1.1 christos 427 1.1 christos /* ------------------------------------------------------------------------ */ 428 1.1 christos /* Function: ipf_lookup_addtable */ 429 1.1 christos /* Returns: int - 0 = success, else error */ 430 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 431 1.1 christos /* data(I) - pointer to data from ioctl call */ 432 1.1 christos /* */ 433 1.1 christos /* Create a new lookup table, if one doesn't already exist using the name */ 434 1.1 christos /* for this one. */ 435 1.1 christos /* ------------------------------------------------------------------------ */ 436 1.1 christos static int 437 1.2 christos ipf_lookup_addtable(ipf_main_softc_t *softc, void *data) 438 1.1 christos { 439 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 440 1.1 christos iplookupop_t op; 441 1.1 christos ipf_lookup_t **l; 442 1.1 christos int err, i; 443 1.1 christos 444 1.1 christos err = BCOPYIN(data, &op, sizeof(op)); 445 1.1 christos if (err != 0) { 446 1.1 christos IPFERROR(50022); 447 1.1 christos return EFAULT; 448 1.1 christos } 449 1.1 christos 450 1.1 christos if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && 451 1.1 christos (op.iplo_unit != IPLT_ALL)) { 452 1.1 christos IPFERROR(50023); 453 1.1 christos return EINVAL; 454 1.1 christos } 455 1.1 christos 456 1.1 christos op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; 457 1.1 christos 458 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 459 1.1 christos if (op.iplo_type == (*l)->ipfl_type) { 460 1.1 christos err = (*(*l)->ipfl_table_add)(softc, 461 1.1 christos softl->ipf_back[i], 462 1.1 christos &op); 463 1.1 christos break; 464 1.1 christos } 465 1.1 christos } 466 1.1 christos 467 1.1 christos if (i == MAX_BACKENDS) { 468 1.1 christos IPFERROR(50026); 469 1.1 christos err = EINVAL; 470 1.1 christos } 471 1.1 christos 472 1.1 christos /* 473 1.1 christos * For anonymous pools, copy back the operation struct because in the 474 1.1 christos * case of success it will contain the new table's name. 475 1.1 christos */ 476 1.1 christos if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) { 477 1.1 christos err = BCOPYOUT(&op, data, sizeof(op)); 478 1.1 christos if (err != 0) { 479 1.1 christos IPFERROR(50027); 480 1.1 christos err = EFAULT; 481 1.1 christos } 482 1.1 christos } 483 1.1 christos 484 1.1 christos return err; 485 1.1 christos } 486 1.1 christos 487 1.1 christos 488 1.1 christos /* ------------------------------------------------------------------------ */ 489 1.1 christos /* Function: ipf_lookup_deltable */ 490 1.1 christos /* Returns: int - 0 = success, else error */ 491 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 492 1.1 christos /* data(I) - pointer to data from ioctl call */ 493 1.1 christos /* */ 494 1.1 christos /* Decodes ioctl request to remove a particular hash table or pool and */ 495 1.1 christos /* calls the relevant function to do the cleanup. */ 496 1.1 christos /* ------------------------------------------------------------------------ */ 497 1.1 christos static int 498 1.2 christos ipf_lookup_deltable(ipf_main_softc_t *softc, void *data) 499 1.1 christos { 500 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 501 1.1 christos iplookupop_t op; 502 1.1 christos ipf_lookup_t **l; 503 1.1 christos int err, i; 504 1.1 christos 505 1.1 christos err = BCOPYIN(data, &op, sizeof(op)); 506 1.1 christos if (err != 0) { 507 1.1 christos IPFERROR(50028); 508 1.1 christos return EFAULT; 509 1.1 christos } 510 1.1 christos 511 1.1 christos if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && 512 1.1 christos (op.iplo_unit != IPLT_ALL)) { 513 1.1 christos IPFERROR(50029); 514 1.1 christos return EINVAL; 515 1.1 christos } 516 1.1 christos 517 1.1 christos op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; 518 1.1 christos 519 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 520 1.1 christos if (op.iplo_type == (*l)->ipfl_type) { 521 1.1 christos err = (*(*l)->ipfl_table_del)(softc, 522 1.1 christos softl->ipf_back[i], 523 1.1 christos &op); 524 1.1 christos break; 525 1.1 christos } 526 1.1 christos } 527 1.1 christos 528 1.1 christos if (i == MAX_BACKENDS) { 529 1.1 christos IPFERROR(50030); 530 1.1 christos err = EINVAL; 531 1.1 christos } 532 1.1 christos return err; 533 1.1 christos } 534 1.1 christos 535 1.1 christos 536 1.1 christos /* ------------------------------------------------------------------------ */ 537 1.1 christos /* Function: ipf_lookup_stats */ 538 1.1 christos /* Returns: int - 0 = success, else error */ 539 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 540 1.1 christos /* data(I) - pointer to data from ioctl call */ 541 1.1 christos /* */ 542 1.1 christos /* Copy statistical information from inside the kernel back to user space. */ 543 1.1 christos /* ------------------------------------------------------------------------ */ 544 1.1 christos static int 545 1.2 christos ipf_lookup_stats(ipf_main_softc_t *softc, void *data) 546 1.1 christos { 547 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 548 1.1 christos iplookupop_t op; 549 1.1 christos ipf_lookup_t **l; 550 1.1 christos int err; 551 1.1 christos int i; 552 1.1 christos 553 1.1 christos err = BCOPYIN(data, &op, sizeof(op)); 554 1.1 christos if (err != 0) { 555 1.1 christos IPFERROR(50031); 556 1.1 christos return EFAULT; 557 1.1 christos } 558 1.1 christos 559 1.1 christos if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && 560 1.1 christos (op.iplo_unit != IPLT_ALL)) { 561 1.1 christos IPFERROR(50032); 562 1.1 christos return EINVAL; 563 1.1 christos } 564 1.1 christos 565 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 566 1.1 christos if (op.iplo_type == (*l)->ipfl_type) { 567 1.1 christos err = (*(*l)->ipfl_stats_get)(softc, 568 1.1 christos softl->ipf_back[i], 569 1.1 christos &op); 570 1.1 christos break; 571 1.1 christos } 572 1.1 christos } 573 1.1 christos 574 1.1 christos if (i == MAX_BACKENDS) { 575 1.1 christos IPFERROR(50033); 576 1.1 christos err = EINVAL; 577 1.1 christos } 578 1.1 christos 579 1.1 christos return err; 580 1.1 christos } 581 1.1 christos 582 1.1 christos 583 1.1 christos /* ------------------------------------------------------------------------ */ 584 1.1 christos /* Function: ipf_lookup_flush */ 585 1.1 christos /* Returns: int - 0 = success, else error */ 586 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 587 1.1 christos /* data(I) - pointer to data from ioctl call */ 588 1.1 christos /* */ 589 1.1 christos /* A flush is called when we want to flush all the nodes from a particular */ 590 1.1 christos /* entry in the hash table/pool or want to remove all groups from those. */ 591 1.1 christos /* ------------------------------------------------------------------------ */ 592 1.1 christos static int 593 1.2 christos ipf_lookup_flush(ipf_main_softc_t *softc, void *data) 594 1.1 christos { 595 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 596 1.1 christos int err, unit, num, type, i; 597 1.1 christos iplookupflush_t flush; 598 1.1 christos ipf_lookup_t **l; 599 1.1 christos 600 1.1 christos err = BCOPYIN(data, &flush, sizeof(flush)); 601 1.1 christos if (err != 0) { 602 1.1 christos IPFERROR(50034); 603 1.1 christos return EFAULT; 604 1.1 christos } 605 1.1 christos 606 1.1 christos unit = flush.iplf_unit; 607 1.1 christos if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) { 608 1.1 christos IPFERROR(50035); 609 1.1 christos return EINVAL; 610 1.1 christos } 611 1.1 christos 612 1.1 christos flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0'; 613 1.1 christos 614 1.1 christos type = flush.iplf_type; 615 1.1 christos IPFERROR(50036); 616 1.1 christos err = EINVAL; 617 1.1 christos num = 0; 618 1.1 christos 619 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 620 1.1 christos if (type == (*l)->ipfl_type || type == IPLT_ALL) { 621 1.1 christos err = 0; 622 1.1 christos num += (*(*l)->ipfl_flush)(softc, 623 1.1 christos softl->ipf_back[i], 624 1.1 christos &flush); 625 1.1 christos } 626 1.1 christos } 627 1.1 christos 628 1.1 christos if (err == 0) { 629 1.1 christos flush.iplf_count = num; 630 1.1 christos err = BCOPYOUT(&flush, data, sizeof(flush)); 631 1.1 christos if (err != 0) { 632 1.1 christos IPFERROR(50037); 633 1.1 christos err = EFAULT; 634 1.1 christos } 635 1.1 christos } 636 1.1 christos return err; 637 1.1 christos } 638 1.1 christos 639 1.1 christos 640 1.1 christos /* ------------------------------------------------------------------------ */ 641 1.1 christos /* Function: ipf_lookup_delref */ 642 1.1 christos /* Returns: void */ 643 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 644 1.1 christos /* type(I) - table type to operate on */ 645 1.1 christos /* ptr(I) - pointer to object to remove reference for */ 646 1.1 christos /* */ 647 1.1 christos /* This function organises calling the correct deref function for a given */ 648 1.1 christos /* type of object being passed into it. */ 649 1.1 christos /* ------------------------------------------------------------------------ */ 650 1.1 christos void 651 1.2 christos ipf_lookup_deref(ipf_main_softc_t *softc, int type, void *ptr) 652 1.1 christos { 653 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 654 1.1 christos int i; 655 1.1 christos 656 1.1 christos if (ptr == NULL) 657 1.1 christos return; 658 1.1 christos 659 1.1 christos for (i = 0; i < MAX_BACKENDS; i++) { 660 1.1 christos if (type == backends[i]->ipfl_type) { 661 1.1 christos WRITE_ENTER(&softc->ipf_poolrw); 662 1.1 christos (*backends[i]->ipfl_table_deref)(softc, 663 1.1 christos softl->ipf_back[i], 664 1.1 christos ptr); 665 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 666 1.1 christos break; 667 1.1 christos } 668 1.1 christos } 669 1.1 christos } 670 1.1 christos 671 1.1 christos 672 1.1 christos /* ------------------------------------------------------------------------ */ 673 1.1 christos /* Function: ipf_lookup_iterate */ 674 1.1 christos /* Returns: int - 0 = success, else error */ 675 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 676 1.1 christos /* data(I) - pointer to data from ioctl call */ 677 1.1 christos /* uid(I) - uid of caller */ 678 1.1 christos /* ctx(I) - pointer to give the uid context */ 679 1.1 christos /* */ 680 1.1 christos /* Decodes ioctl request to step through either hash tables or pools. */ 681 1.1 christos /* ------------------------------------------------------------------------ */ 682 1.1 christos static int 683 1.2 christos ipf_lookup_iterate(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 684 1.1 christos { 685 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 686 1.1 christos ipflookupiter_t iter; 687 1.1 christos ipftoken_t *token; 688 1.1 christos int err, i; 689 1.1 christos SPL_INT(s); 690 1.1 christos 691 1.1 christos err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER); 692 1.1 christos if (err != 0) 693 1.1 christos return err; 694 1.1 christos 695 1.1 christos if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) { 696 1.1 christos IPFERROR(50038); 697 1.1 christos return EINVAL; 698 1.1 christos } 699 1.1 christos 700 1.1 christos if (iter.ili_ival != IPFGENITER_LOOKUP) { 701 1.1 christos IPFERROR(50039); 702 1.1 christos return EINVAL; 703 1.1 christos } 704 1.1 christos 705 1.1 christos SPL_SCHED(s); 706 1.1 christos token = ipf_token_find(softc, iter.ili_key, uid, ctx); 707 1.1 christos if (token == NULL) { 708 1.1 christos SPL_X(s); 709 1.1 christos IPFERROR(50040); 710 1.1 christos return ESRCH; 711 1.1 christos } 712 1.1 christos 713 1.1 christos for (i = 0; i < MAX_BACKENDS; i++) { 714 1.1 christos if (iter.ili_type == backends[i]->ipfl_type) { 715 1.1 christos err = (*backends[i]->ipfl_iter_next)(softc, 716 1.1 christos softl->ipf_back[i], 717 1.1 christos token, &iter); 718 1.1 christos break; 719 1.1 christos } 720 1.1 christos } 721 1.1 christos SPL_X(s); 722 1.1 christos 723 1.1 christos if (i == MAX_BACKENDS) { 724 1.1 christos IPFERROR(50041); 725 1.1 christos err = EINVAL; 726 1.1 christos } 727 1.1 christos 728 1.1 christos WRITE_ENTER(&softc->ipf_tokens); 729 1.1 christos ipf_token_deref(softc, token); 730 1.1 christos RWLOCK_EXIT(&softc->ipf_tokens); 731 1.1 christos 732 1.1 christos return err; 733 1.1 christos } 734 1.1 christos 735 1.1 christos 736 1.1 christos /* ------------------------------------------------------------------------ */ 737 1.1 christos /* Function: ipf_lookup_iterderef */ 738 1.1 christos /* Returns: void */ 739 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 740 1.1 christos /* type(I) - backend type to iterate through */ 741 1.1 christos /* data(I) - pointer to data from ioctl call */ 742 1.1 christos /* */ 743 1.1 christos /* Decodes ioctl request to remove a particular hash table or pool and */ 744 1.1 christos /* calls the relevant function to do the cleanup. */ 745 1.1 christos /* Because each of the backend types has a different data structure, */ 746 1.1 christos /* iteration is limited to one type at a time (i.e. it is not permitted to */ 747 1.1 christos /* go on from pool types to hash types as part of the "get next".) */ 748 1.1 christos /* ------------------------------------------------------------------------ */ 749 1.1 christos void 750 1.2 christos ipf_lookup_iterderef(ipf_main_softc_t *softc, u_32_t type, void *data) 751 1.1 christos { 752 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 753 1.1 christos struct iplookupiterkey *lkey; 754 1.1 christos iplookupiterkey_t key; 755 1.1 christos int i; 756 1.1 christos 757 1.1 christos key.ilik_key = type; 758 1.1 christos lkey = &key.ilik_unstr; 759 1.1 christos 760 1.1 christos if (lkey->ilik_ival != IPFGENITER_LOOKUP) 761 1.1 christos return; 762 1.1 christos 763 1.1 christos WRITE_ENTER(&softc->ipf_poolrw); 764 1.1 christos 765 1.1 christos for (i = 0; i < MAX_BACKENDS; i++) { 766 1.3 darrenr if (lkey->ilik_type == backends[i]->ipfl_type) { 767 1.1 christos (*backends[i]->ipfl_iter_deref)(softc, 768 1.1 christos softl->ipf_back[i], 769 1.1 christos lkey->ilik_otype, 770 1.1 christos lkey->ilik_unit, 771 1.1 christos data); 772 1.1 christos break; 773 1.1 christos } 774 1.1 christos } 775 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 776 1.1 christos } 777 1.1 christos 778 1.1 christos 779 1.1 christos /* ------------------------------------------------------------------------ */ 780 1.1 christos /* Function: ipf_lookup_deltok */ 781 1.1 christos /* Returns: int - 0 = success, else error */ 782 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 783 1.1 christos /* data(I) - pointer to data from ioctl call */ 784 1.1 christos /* uid(I) - uid of caller */ 785 1.1 christos /* ctx(I) - pointer to give the uid context */ 786 1.1 christos /* */ 787 1.1 christos /* Deletes the token identified by the combination of (type,uid,ctx) */ 788 1.1 christos /* "key" is a combination of the table type, iterator type and the unit for */ 789 1.1 christos /* which the token was being used. */ 790 1.1 christos /* ------------------------------------------------------------------------ */ 791 1.1 christos int 792 1.2 christos ipf_lookup_deltok(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 793 1.1 christos { 794 1.1 christos int error, key; 795 1.1 christos SPL_INT(s); 796 1.1 christos 797 1.1 christos SPL_SCHED(s); 798 1.1 christos error = BCOPYIN(data, &key, sizeof(key)); 799 1.1 christos if (error == 0) 800 1.1 christos error = ipf_token_del(softc, key, uid, ctx); 801 1.1 christos SPL_X(s); 802 1.1 christos return error; 803 1.1 christos } 804 1.1 christos 805 1.1 christos 806 1.1 christos /* ------------------------------------------------------------------------ */ 807 1.1 christos /* Function: ipf_lookup_res_num */ 808 1.1 christos /* Returns: void * - NULL = failure, else success. */ 809 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 810 1.1 christos /* unit(I) - device for which this is for */ 811 1.1 christos /* type(I) - type of lookup these parameters are for. */ 812 1.1 christos /* number(I) - table number to use when searching */ 813 1.1 christos /* funcptr(IO) - pointer to pointer for storing IP address */ 814 1.1 christos /* searching function. */ 815 1.1 christos /* */ 816 1.1 christos /* Search for the "table" number passed in amongst those configured for */ 817 1.1 christos /* that particular type. If the type is recognised then the function to */ 818 1.1 christos /* call to do the IP address search will be change, regardless of whether */ 819 1.1 christos /* or not the "table" number exists. */ 820 1.1 christos /* ------------------------------------------------------------------------ */ 821 1.1 christos void * 822 1.2 christos ipf_lookup_res_num(ipf_main_softc_t *softc, int unit, u_int type, u_int number, 823 1.2 christos lookupfunc_t *funcptr) 824 1.1 christos { 825 1.1 christos char name[FR_GROUPLEN]; 826 1.1 christos 827 1.4 christos snprintf(name, sizeof(name), "%u", number); 828 1.1 christos 829 1.1 christos return ipf_lookup_res_name(softc, unit, type, name, funcptr); 830 1.1 christos } 831 1.1 christos 832 1.1 christos 833 1.1 christos /* ------------------------------------------------------------------------ */ 834 1.1 christos /* Function: ipf_lookup_res_name */ 835 1.1 christos /* Returns: void * - NULL = failure, else success. */ 836 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 837 1.1 christos /* unit(I) - device for which this is for */ 838 1.1 christos /* type(I) - type of lookup these parameters are for. */ 839 1.1 christos /* name(I) - table name to use when searching */ 840 1.1 christos /* funcptr(IO) - pointer to pointer for storing IP address */ 841 1.1 christos /* searching function. */ 842 1.1 christos /* */ 843 1.1 christos /* Search for the "table" number passed in amongst those configured for */ 844 1.1 christos /* that particular type. If the type is recognised then the function to */ 845 1.3 darrenr /* call to do the IP address search will be changed, regardless of whether */ 846 1.1 christos /* or not the "table" number exists. */ 847 1.1 christos /* ------------------------------------------------------------------------ */ 848 1.1 christos void * 849 1.2 christos ipf_lookup_res_name(ipf_main_softc_t *softc, int unit, u_int type, char *name, 850 1.2 christos lookupfunc_t *funcptr) 851 1.1 christos { 852 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 853 1.1 christos ipf_lookup_t **l; 854 1.1 christos void *ptr = NULL; 855 1.1 christos int i; 856 1.1 christos 857 1.1 christos READ_ENTER(&softc->ipf_poolrw); 858 1.1 christos 859 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 860 1.1 christos if (type == (*l)->ipfl_type) { 861 1.1 christos ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i], 862 1.1 christos unit, name); 863 1.1 christos if (ptr != NULL && funcptr != NULL) { 864 1.1 christos *funcptr = (*l)->ipfl_addr_find; 865 1.1 christos } 866 1.1 christos break; 867 1.1 christos } 868 1.1 christos } 869 1.1 christos 870 1.1 christos if (i == MAX_BACKENDS) { 871 1.1 christos ptr = NULL; 872 1.1 christos if (funcptr != NULL) 873 1.1 christos *funcptr = NULL; 874 1.1 christos } 875 1.1 christos 876 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 877 1.1 christos 878 1.1 christos return ptr; 879 1.1 christos } 880 1.1 christos 881 1.1 christos 882 1.1 christos /* ------------------------------------------------------------------------ */ 883 1.1 christos /* Function: ipf_lookup_find_htable */ 884 1.1 christos /* Returns: void * - NULL = failure, else success. */ 885 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 886 1.1 christos /* unit(I) - device for which this is for */ 887 1.1 christos /* name(I) - table name to use when searching */ 888 1.1 christos /* */ 889 1.1 christos /* To support the group-map feature, where a hash table maps address */ 890 1.1 christos /* networks to rule group numbers, we need to expose a function that uses */ 891 1.1 christos /* only the hash table backend. */ 892 1.1 christos /* ------------------------------------------------------------------------ */ 893 1.1 christos void * 894 1.2 christos ipf_lookup_find_htable(ipf_main_softc_t *softc, int unit, char *name) 895 1.1 christos { 896 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 897 1.1 christos ipf_lookup_t **l; 898 1.1 christos void *tab = NULL; 899 1.1 christos int i; 900 1.1 christos 901 1.1 christos READ_ENTER(&softc->ipf_poolrw); 902 1.1 christos 903 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) 904 1.1 christos if (IPLT_HASH == (*l)->ipfl_type) { 905 1.1 christos tab = ipf_htable_find(softl->ipf_back[i], unit, name); 906 1.1 christos break; 907 1.1 christos } 908 1.1 christos 909 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 910 1.1 christos 911 1.1 christos return tab; 912 1.1 christos } 913 1.1 christos 914 1.1 christos 915 1.1 christos /* ------------------------------------------------------------------------ */ 916 1.1 christos /* Function: ipf_lookup_sync */ 917 1.1 christos /* Returns: void */ 918 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 919 1.1 christos /* */ 920 1.1 christos /* This function is the interface that the machine dependent sync functions */ 921 1.1 christos /* call when a network interface name change occurs. It then calls the sync */ 922 1.1 christos /* functions of the lookup implementations - if they have one. */ 923 1.1 christos /* ------------------------------------------------------------------------ */ 924 1.1 christos /*ARGSUSED*/ 925 1.1 christos void 926 1.2 christos ipf_lookup_sync(ipf_main_softc_t *softc, void *ifp) 927 1.1 christos { 928 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 929 1.1 christos ipf_lookup_t **l; 930 1.1 christos int i; 931 1.1 christos 932 1.1 christos READ_ENTER(&softc->ipf_poolrw); 933 1.1 christos 934 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) 935 1.1 christos if ((*l)->ipfl_sync != NULL) 936 1.1 christos (*(*l)->ipfl_sync)(softc, softl->ipf_back[i]); 937 1.1 christos 938 1.1 christos RWLOCK_EXIT(&softc->ipf_poolrw); 939 1.1 christos } 940 1.1 christos 941 1.1 christos 942 1.1 christos #ifndef _KERNEL 943 1.1 christos void 944 1.1 christos ipf_lookup_dump(softc, arg) 945 1.1 christos ipf_main_softc_t *softc; 946 1.1 christos void *arg; 947 1.1 christos { 948 1.1 christos ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 949 1.1 christos ipf_lookup_t **l; 950 1.1 christos int i; 951 1.1 christos 952 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) 953 1.1 christos if (IPLT_POOL == (*l)->ipfl_type) { 954 1.1 christos ipf_pool_dump(softc, softl->ipf_back[i]); 955 1.1 christos break; 956 1.1 christos } 957 1.1 christos 958 1.1 christos for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) 959 1.1 christos if (IPLT_HASH == (*l)->ipfl_type) { 960 1.1 christos ipf_htable_dump(softc, softl->ipf_back[i]); 961 1.1 christos break; 962 1.1 christos } 963 1.1 christos } 964 1.1 christos #endif 965