1255332Scy/* $FreeBSD$ */ 2145516Sdarrenr/* 3255332Scy * Copyright (C) 2012 by Darren Reed. 4145516Sdarrenr * 5145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 6145516Sdarrenr */ 7145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL) 8145516Sdarrenr# undef KERNEL 9145516Sdarrenr# undef _KERNEL 10145516Sdarrenr# define KERNEL 1 11145516Sdarrenr# define _KERNEL 1 12145516Sdarrenr#endif 13145516Sdarrenr#if defined(__osf__) 14145516Sdarrenr# define _PROTO_NET_H_ 15145516Sdarrenr#endif 16145516Sdarrenr#include <sys/param.h> 17145516Sdarrenr#include <sys/errno.h> 18145516Sdarrenr#include <sys/types.h> 19145516Sdarrenr#include <sys/time.h> 20145516Sdarrenr#include <sys/file.h> 21145516Sdarrenr#if __FreeBSD_version >= 220000 && defined(_KERNEL) 22145516Sdarrenr# include <sys/fcntl.h> 23145516Sdarrenr# include <sys/filio.h> 24145516Sdarrenr#else 25145516Sdarrenr# include <sys/ioctl.h> 26145516Sdarrenr#endif 27145516Sdarrenr#if !defined(_KERNEL) 28255332Scy# include <stdio.h> 29145516Sdarrenr# include <string.h> 30255332Scy# include <stdlib.h> 31145516Sdarrenr# define _KERNEL 32145516Sdarrenr# ifdef __OpenBSD__ 33145516Sdarrenrstruct file; 34145516Sdarrenr# endif 35145516Sdarrenr# include <sys/uio.h> 36145516Sdarrenr# undef _KERNEL 37145516Sdarrenr#endif 38145516Sdarrenr#include <sys/socket.h> 39145516Sdarrenr#include <net/if.h> 40145516Sdarrenr#if defined(__FreeBSD__) 41255332Scy# include <sys/cdefs.h> 42255332Scy# include <sys/proc.h> 43145516Sdarrenr#endif 44145516Sdarrenr#if defined(_KERNEL) 45145516Sdarrenr# include <sys/systm.h> 46145516Sdarrenr# if !defined(__SVR4) && !defined(__svr4__) 47145516Sdarrenr# include <sys/mbuf.h> 48145516Sdarrenr# endif 49255332Scy#else 50255332Scy# include "ipf.h" 51145516Sdarrenr#endif 52145516Sdarrenr#include <netinet/in.h> 53145516Sdarrenr 54145516Sdarrenr#include "netinet/ip_compat.h" 55145516Sdarrenr#include "netinet/ip_fil.h" 56255332Scy#include "netinet/ip_lookup.h" 57145516Sdarrenr#include "netinet/ip_pool.h" 58145516Sdarrenr#include "netinet/ip_htable.h" 59255332Scy#include "netinet/ip_dstlist.h" 60145516Sdarrenr/* END OF INCLUDES */ 61145516Sdarrenr 62145516Sdarrenr#if !defined(lint) 63255332Scystatic const char rcsid[] = "@(#)$Id$"; 64145516Sdarrenr#endif 65145516Sdarrenr 66255332Scy/* 67255332Scy * In this file, ip_pool.c, ip_htable.c and ip_dstlist.c, you will find the 68255332Scy * range for unit is [-1,IPL_LOGMAX]. The -1 is considered to be a valid number 69255332Scy * and represents a "wildcard" or "all" units (IPL_LOGALL). The reason for not 70255332Scy * starting the numbering at 0 is because the numbers [0,IPL_LOGMAX] correspond 71255332Scy * to the minor device number for their respective device. Thus where there is 72255332Scy * array indexing on the unit, +1 is used to map [-1.IPL_LOGMAX] to 73255332Scy * [0.POOL_LOOKUP_MAX]. 74255332Scy */ 75255332Scystatic int ipf_lookup_addnode __P((ipf_main_softc_t *, caddr_t, int)); 76255332Scystatic int ipf_lookup_delnode __P((ipf_main_softc_t *, caddr_t, int)); 77255332Scystatic int ipf_lookup_addtable __P((ipf_main_softc_t *, caddr_t)); 78255332Scystatic int ipf_lookup_deltable __P((ipf_main_softc_t *, caddr_t)); 79255332Scystatic int ipf_lookup_stats __P((ipf_main_softc_t *, caddr_t)); 80255332Scystatic int ipf_lookup_flush __P((ipf_main_softc_t *, caddr_t)); 81255332Scystatic int ipf_lookup_iterate __P((ipf_main_softc_t *, void *, int, void *)); 82255332Scystatic int ipf_lookup_deltok __P((ipf_main_softc_t *, void *, int, void *)); 83145516Sdarrenr 84255332Scy#define MAX_BACKENDS 3 85255332Scystatic ipf_lookup_t *backends[MAX_BACKENDS] = { 86255332Scy &ipf_pool_backend, 87255332Scy &ipf_htable_backend, 88255332Scy &ipf_dstlist_backend 89255332Scy}; 90145516Sdarrenr 91145516Sdarrenr 92255332Scytypedef struct ipf_lookup_softc_s { 93255332Scy void *ipf_back[MAX_BACKENDS]; 94255332Scy} ipf_lookup_softc_t; 95255332Scy 96255332Scy 97145516Sdarrenr/* ------------------------------------------------------------------------ */ 98255332Scy/* Function: ipf_lookup_init */ 99255332Scy/* Returns: int - 0 = success, else error */ 100255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 101145516Sdarrenr/* */ 102145516Sdarrenr/* Initialise all of the subcomponents of the lookup infrstructure. */ 103145516Sdarrenr/* ------------------------------------------------------------------------ */ 104255332Scyvoid * 105255332Scyipf_lookup_soft_create(softc) 106255332Scy ipf_main_softc_t *softc; 107145516Sdarrenr{ 108255332Scy ipf_lookup_softc_t *softl; 109255332Scy ipf_lookup_t **l; 110255332Scy int i; 111145516Sdarrenr 112255332Scy KMALLOC(softl, ipf_lookup_softc_t *); 113255332Scy if (softl == NULL) 114255332Scy return NULL; 115145516Sdarrenr 116255332Scy bzero((char *)softl, sizeof(*softl)); 117145516Sdarrenr 118255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 119255332Scy softl->ipf_back[i] = (*(*l)->ipfl_create)(softc); 120255332Scy if (softl->ipf_back[i] == NULL) { 121255332Scy ipf_lookup_soft_destroy(softc, softl); 122255332Scy return NULL; 123255332Scy } 124255332Scy } 125145516Sdarrenr 126255332Scy return softl; 127255332Scy} 128255332Scy 129255332Scy 130255332Scy/* ------------------------------------------------------------------------ */ 131255332Scy/* Function: ipf_lookup_soft_init */ 132255332Scy/* Returns: int - 0 = success, else error */ 133255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 134255332Scy/* arg(I) - pointer to local context to use */ 135255332Scy/* */ 136255332Scy/* Initialise all of the subcomponents of the lookup infrstructure. */ 137255332Scy/* ------------------------------------------------------------------------ */ 138255332Scyint 139255332Scyipf_lookup_soft_init(softc, arg) 140255332Scy ipf_main_softc_t *softc; 141255332Scy void *arg; 142255332Scy{ 143255332Scy ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; 144255332Scy int err = 0; 145255332Scy int i; 146255332Scy 147255332Scy for (i = 0; i < MAX_BACKENDS; i++) { 148255332Scy err = (*backends[i]->ipfl_init)(softc, softl->ipf_back[i]); 149255332Scy if (err != 0) 150255332Scy break; 151255332Scy } 152255332Scy 153255332Scy return err; 154255332Scy} 155255332Scy 156255332Scy 157255332Scy/* ------------------------------------------------------------------------ */ 158255332Scy/* Function: ipf_lookup_soft_fini */ 159255332Scy/* Returns: int - 0 = success, else error */ 160255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 161255332Scy/* arg(I) - pointer to local context to use */ 162255332Scy/* */ 163255332Scy/* Call the fini function in each backend to cleanup all allocated data. */ 164255332Scy/* ------------------------------------------------------------------------ */ 165255332Scyint 166255332Scyipf_lookup_soft_fini(softc, arg) 167255332Scy ipf_main_softc_t *softc; 168255332Scy void *arg; 169255332Scy{ 170255332Scy ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; 171255332Scy int i; 172255332Scy 173255332Scy for (i = 0; i < MAX_BACKENDS; i++) { 174255332Scy if (softl->ipf_back[i] != NULL) 175255332Scy (*backends[i]->ipfl_fini)(softc, 176255332Scy softl->ipf_back[i]); 177255332Scy } 178255332Scy 179145516Sdarrenr return 0; 180145516Sdarrenr} 181145516Sdarrenr 182145516Sdarrenr 183145516Sdarrenr/* ------------------------------------------------------------------------ */ 184255332Scy/* Function: ipf_lookup_expire */ 185255332Scy/* Returns: Nil */ 186255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 187255332Scy/* */ 188255332Scy/* Step through each of the backends and call their expire functions, */ 189255332Scy/* allowing them to delete any lifetime limited data. */ 190255332Scy/* ------------------------------------------------------------------------ */ 191255332Scyvoid 192255332Scyipf_lookup_expire(softc) 193255332Scy ipf_main_softc_t *softc; 194255332Scy{ 195255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 196255332Scy int i; 197255332Scy 198255332Scy WRITE_ENTER(&softc->ipf_poolrw); 199255332Scy for (i = 0; i < MAX_BACKENDS; i++) 200255332Scy (*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]); 201255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 202255332Scy} 203255332Scy 204255332Scy 205255332Scy/* ------------------------------------------------------------------------ */ 206255332Scy/* Function: ipf_lookup_softc_destroy */ 207145516Sdarrenr/* Returns: int - 0 = success, else error */ 208255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 209255332Scy/* arg(I) - pointer to local context to use */ 210145516Sdarrenr/* */ 211145516Sdarrenr/* Free up all pool related memory that has been allocated whilst IPFilter */ 212145516Sdarrenr/* has been running. Also, do any other deinitialisation required such */ 213255332Scy/* ipf_lookup_init() can be called again, safely. */ 214145516Sdarrenr/* ------------------------------------------------------------------------ */ 215255332Scyvoid 216255332Scyipf_lookup_soft_destroy(softc, arg) 217255332Scy ipf_main_softc_t *softc; 218255332Scy void *arg; 219145516Sdarrenr{ 220255332Scy ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; 221255332Scy int i; 222145516Sdarrenr 223255332Scy for (i = 0; i < MAX_BACKENDS; i++) { 224255332Scy if (softl->ipf_back[i] != NULL) 225255332Scy (*backends[i]->ipfl_destroy)(softc, 226255332Scy softl->ipf_back[i]); 227145516Sdarrenr } 228255332Scy 229255332Scy KFREE(softl); 230145516Sdarrenr} 231145516Sdarrenr 232145516Sdarrenr 233145516Sdarrenr/* ------------------------------------------------------------------------ */ 234255332Scy/* Function: ipf_lookup_ioctl */ 235145516Sdarrenr/* Returns: int - 0 = success, else error */ 236255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 237255332Scy/* arg(I) - pointer to local context to use */ 238255332Scy/* data(IO) - pointer to ioctl data to be copied to/from user */ 239145516Sdarrenr/* space. */ 240145516Sdarrenr/* cmd(I) - ioctl command number */ 241145516Sdarrenr/* mode(I) - file mode bits used with open */ 242255332Scy/* uid(I) - uid of process doing ioctl */ 243255332Scy/* ctx(I) - pointer that represents context for uid */ 244145516Sdarrenr/* */ 245145516Sdarrenr/* Handle ioctl commands sent to the ioctl device. For the most part, this */ 246145516Sdarrenr/* involves just calling another function to handle the specifics of each */ 247145516Sdarrenr/* command. */ 248145516Sdarrenr/* ------------------------------------------------------------------------ */ 249255332Scyint 250255332Scyipf_lookup_ioctl(softc, data, cmd, mode, uid, ctx) 251255332Scy ipf_main_softc_t *softc; 252255332Scy caddr_t data; 253255332Scy ioctlcmd_t cmd; 254255332Scy int mode, uid; 255255332Scy void *ctx; 256145516Sdarrenr{ 257145516Sdarrenr int err; 258153872Sguido SPL_INT(s); 259145516Sdarrenr 260145516Sdarrenr mode = mode; /* LINT */ 261145516Sdarrenr 262145516Sdarrenr SPL_NET(s); 263145516Sdarrenr 264145516Sdarrenr switch (cmd) 265145516Sdarrenr { 266145516Sdarrenr case SIOCLOOKUPADDNODE : 267145516Sdarrenr case SIOCLOOKUPADDNODEW : 268255332Scy WRITE_ENTER(&softc->ipf_poolrw); 269255332Scy err = ipf_lookup_addnode(softc, data, uid); 270255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 271145516Sdarrenr break; 272145516Sdarrenr 273145516Sdarrenr case SIOCLOOKUPDELNODE : 274145516Sdarrenr case SIOCLOOKUPDELNODEW : 275255332Scy WRITE_ENTER(&softc->ipf_poolrw); 276255332Scy err = ipf_lookup_delnode(softc, data, uid); 277255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 278145516Sdarrenr break; 279145516Sdarrenr 280145516Sdarrenr case SIOCLOOKUPADDTABLE : 281255332Scy WRITE_ENTER(&softc->ipf_poolrw); 282255332Scy err = ipf_lookup_addtable(softc, data); 283255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 284145516Sdarrenr break; 285145516Sdarrenr 286145516Sdarrenr case SIOCLOOKUPDELTABLE : 287255332Scy WRITE_ENTER(&softc->ipf_poolrw); 288255332Scy err = ipf_lookup_deltable(softc, data); 289255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 290145516Sdarrenr break; 291145516Sdarrenr 292145516Sdarrenr case SIOCLOOKUPSTAT : 293145516Sdarrenr case SIOCLOOKUPSTATW : 294255332Scy WRITE_ENTER(&softc->ipf_poolrw); 295255332Scy err = ipf_lookup_stats(softc, data); 296255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 297145516Sdarrenr break; 298145516Sdarrenr 299145516Sdarrenr case SIOCLOOKUPFLUSH : 300255332Scy WRITE_ENTER(&softc->ipf_poolrw); 301255332Scy err = ipf_lookup_flush(softc, data); 302255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 303145516Sdarrenr break; 304145516Sdarrenr 305170263Sdarrenr case SIOCLOOKUPITER : 306255332Scy err = ipf_lookup_iterate(softc, data, uid, ctx); 307170263Sdarrenr break; 308170263Sdarrenr 309172771Sdarrenr case SIOCIPFDELTOK : 310255332Scy err = ipf_lookup_deltok(softc, data, uid, ctx); 311172771Sdarrenr break; 312172771Sdarrenr 313145516Sdarrenr default : 314255332Scy IPFERROR(50001); 315145516Sdarrenr err = EINVAL; 316145516Sdarrenr break; 317145516Sdarrenr } 318145516Sdarrenr SPL_X(s); 319145516Sdarrenr return err; 320145516Sdarrenr} 321145516Sdarrenr 322145516Sdarrenr 323145516Sdarrenr/* ------------------------------------------------------------------------ */ 324255332Scy/* Function: ipf_lookup_addnode */ 325145516Sdarrenr/* Returns: int - 0 = success, else error */ 326255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 327255332Scy/* data(I) - pointer to data from ioctl call */ 328145516Sdarrenr/* */ 329145516Sdarrenr/* Add a new data node to a lookup structure. First, check to see if the */ 330145516Sdarrenr/* parent structure refered to by name exists and if it does, then go on to */ 331145516Sdarrenr/* add a node to it. */ 332145516Sdarrenr/* ------------------------------------------------------------------------ */ 333255332Scystatic int 334255332Scyipf_lookup_addnode(softc, data, uid) 335255332Scy ipf_main_softc_t *softc; 336255332Scy caddr_t data; 337255332Scy int uid; 338145516Sdarrenr{ 339255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 340145516Sdarrenr iplookupop_t op; 341255332Scy ipf_lookup_t **l; 342145516Sdarrenr int err; 343255332Scy int i; 344145516Sdarrenr 345170263Sdarrenr err = BCOPYIN(data, &op, sizeof(op)); 346255332Scy if (err != 0) { 347255332Scy IPFERROR(50002); 348170263Sdarrenr return EFAULT; 349255332Scy } 350170263Sdarrenr 351255332Scy if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && 352255332Scy (op.iplo_unit != IPLT_ALL)) { 353255332Scy IPFERROR(50003); 354170263Sdarrenr return EINVAL; 355255332Scy } 356170263Sdarrenr 357145516Sdarrenr op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; 358145516Sdarrenr 359255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 360255332Scy if (op.iplo_type == (*l)->ipfl_type) { 361255332Scy err = (*(*l)->ipfl_node_add)(softc, 362255332Scy softl->ipf_back[i], 363255332Scy &op, uid); 364255332Scy break; 365255332Scy } 366255332Scy } 367145516Sdarrenr 368255332Scy if (i == MAX_BACKENDS) { 369255332Scy IPFERROR(50012); 370145516Sdarrenr err = EINVAL; 371145516Sdarrenr } 372255332Scy 373145516Sdarrenr return err; 374145516Sdarrenr} 375145516Sdarrenr 376145516Sdarrenr 377145516Sdarrenr/* ------------------------------------------------------------------------ */ 378255332Scy/* Function: ipf_lookup_delnode */ 379145516Sdarrenr/* Returns: int - 0 = success, else error */ 380255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 381255332Scy/* data(I) - pointer to data from ioctl call */ 382145516Sdarrenr/* */ 383145516Sdarrenr/* Delete a node from a lookup table by first looking for the table it is */ 384145516Sdarrenr/* in and then deleting the entry that gets found. */ 385145516Sdarrenr/* ------------------------------------------------------------------------ */ 386255332Scystatic int 387255332Scyipf_lookup_delnode(softc, data, uid) 388255332Scy ipf_main_softc_t *softc; 389255332Scy caddr_t data; 390255332Scy int uid; 391145516Sdarrenr{ 392255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 393145516Sdarrenr iplookupop_t op; 394255332Scy ipf_lookup_t **l; 395145516Sdarrenr int err; 396255332Scy int i; 397145516Sdarrenr 398172771Sdarrenr err = BCOPYIN(data, &op, sizeof(op)); 399255332Scy if (err != 0) { 400255332Scy IPFERROR(50042); 401172771Sdarrenr return EFAULT; 402255332Scy } 403145516Sdarrenr 404255332Scy if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && 405255332Scy (op.iplo_unit != IPLT_ALL)) { 406255332Scy IPFERROR(50013); 407170263Sdarrenr return EINVAL; 408255332Scy } 409170263Sdarrenr 410145516Sdarrenr op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; 411145516Sdarrenr 412255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 413255332Scy if (op.iplo_type == (*l)->ipfl_type) { 414255332Scy err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i], 415255332Scy &op, uid); 416255332Scy break; 417255332Scy } 418255332Scy } 419145516Sdarrenr 420255332Scy if (i == MAX_BACKENDS) { 421255332Scy IPFERROR(50021); 422145516Sdarrenr err = EINVAL; 423145516Sdarrenr } 424145516Sdarrenr return err; 425145516Sdarrenr} 426145516Sdarrenr 427145516Sdarrenr 428145516Sdarrenr/* ------------------------------------------------------------------------ */ 429255332Scy/* Function: ipf_lookup_addtable */ 430145516Sdarrenr/* Returns: int - 0 = success, else error */ 431255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 432255332Scy/* data(I) - pointer to data from ioctl call */ 433145516Sdarrenr/* */ 434145516Sdarrenr/* Create a new lookup table, if one doesn't already exist using the name */ 435145516Sdarrenr/* for this one. */ 436145516Sdarrenr/* ------------------------------------------------------------------------ */ 437255332Scystatic int 438255332Scyipf_lookup_addtable(softc, data) 439255332Scy ipf_main_softc_t *softc; 440255332Scy caddr_t data; 441145516Sdarrenr{ 442255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 443145516Sdarrenr iplookupop_t op; 444255332Scy ipf_lookup_t **l; 445255332Scy int err, i; 446145516Sdarrenr 447170263Sdarrenr err = BCOPYIN(data, &op, sizeof(op)); 448255332Scy if (err != 0) { 449255332Scy IPFERROR(50022); 450170263Sdarrenr return EFAULT; 451255332Scy } 452145516Sdarrenr 453255332Scy if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && 454255332Scy (op.iplo_unit != IPLT_ALL)) { 455255332Scy IPFERROR(50023); 456170263Sdarrenr return EINVAL; 457255332Scy } 458170263Sdarrenr 459145516Sdarrenr op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; 460145516Sdarrenr 461255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 462255332Scy if (op.iplo_type == (*l)->ipfl_type) { 463255332Scy err = (*(*l)->ipfl_table_add)(softc, 464255332Scy softl->ipf_back[i], 465255332Scy &op); 466255332Scy break; 467255332Scy } 468255332Scy } 469145516Sdarrenr 470255332Scy if (i == MAX_BACKENDS) { 471255332Scy IPFERROR(50026); 472145516Sdarrenr err = EINVAL; 473145516Sdarrenr } 474153872Sguido 475153872Sguido /* 476153872Sguido * For anonymous pools, copy back the operation struct because in the 477153872Sguido * case of success it will contain the new table's name. 478153872Sguido */ 479170263Sdarrenr if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) { 480170263Sdarrenr err = BCOPYOUT(&op, data, sizeof(op)); 481255332Scy if (err != 0) { 482255332Scy IPFERROR(50027); 483170263Sdarrenr err = EFAULT; 484255332Scy } 485153872Sguido } 486153872Sguido 487145516Sdarrenr return err; 488145516Sdarrenr} 489145516Sdarrenr 490145516Sdarrenr 491145516Sdarrenr/* ------------------------------------------------------------------------ */ 492255332Scy/* Function: ipf_lookup_deltable */ 493145516Sdarrenr/* Returns: int - 0 = success, else error */ 494255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 495255332Scy/* data(I) - pointer to data from ioctl call */ 496145516Sdarrenr/* */ 497145516Sdarrenr/* Decodes ioctl request to remove a particular hash table or pool and */ 498145516Sdarrenr/* calls the relevant function to do the cleanup. */ 499145516Sdarrenr/* ------------------------------------------------------------------------ */ 500255332Scystatic int 501255332Scyipf_lookup_deltable(softc, data) 502255332Scy ipf_main_softc_t *softc; 503255332Scy caddr_t data; 504145516Sdarrenr{ 505255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 506145516Sdarrenr iplookupop_t op; 507255332Scy ipf_lookup_t **l; 508255332Scy int err, i; 509145516Sdarrenr 510170263Sdarrenr err = BCOPYIN(data, &op, sizeof(op)); 511255332Scy if (err != 0) { 512255332Scy IPFERROR(50028); 513170263Sdarrenr return EFAULT; 514255332Scy } 515170263Sdarrenr 516255332Scy if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && 517255332Scy (op.iplo_unit != IPLT_ALL)) { 518255332Scy IPFERROR(50029); 519170263Sdarrenr return EINVAL; 520255332Scy } 521170263Sdarrenr 522145516Sdarrenr op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; 523145516Sdarrenr 524255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 525255332Scy if (op.iplo_type == (*l)->ipfl_type) { 526255332Scy err = (*(*l)->ipfl_table_del)(softc, 527255332Scy softl->ipf_back[i], 528255332Scy &op); 529255332Scy break; 530255332Scy } 531255332Scy } 532145516Sdarrenr 533255332Scy if (i == MAX_BACKENDS) { 534255332Scy IPFERROR(50030); 535145516Sdarrenr err = EINVAL; 536145516Sdarrenr } 537145516Sdarrenr return err; 538145516Sdarrenr} 539145516Sdarrenr 540145516Sdarrenr 541145516Sdarrenr/* ------------------------------------------------------------------------ */ 542255332Scy/* Function: ipf_lookup_stats */ 543145516Sdarrenr/* Returns: int - 0 = success, else error */ 544255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 545255332Scy/* data(I) - pointer to data from ioctl call */ 546145516Sdarrenr/* */ 547145516Sdarrenr/* Copy statistical information from inside the kernel back to user space. */ 548145516Sdarrenr/* ------------------------------------------------------------------------ */ 549255332Scystatic int 550255332Scyipf_lookup_stats(softc, data) 551255332Scy ipf_main_softc_t *softc; 552255332Scy caddr_t data; 553145516Sdarrenr{ 554255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 555145516Sdarrenr iplookupop_t op; 556255332Scy ipf_lookup_t **l; 557145516Sdarrenr int err; 558255332Scy int i; 559145516Sdarrenr 560170263Sdarrenr err = BCOPYIN(data, &op, sizeof(op)); 561255332Scy if (err != 0) { 562255332Scy IPFERROR(50031); 563170263Sdarrenr return EFAULT; 564255332Scy } 565145516Sdarrenr 566255332Scy if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && 567255332Scy (op.iplo_unit != IPLT_ALL)) { 568255332Scy IPFERROR(50032); 569170263Sdarrenr return EINVAL; 570255332Scy } 571170263Sdarrenr 572255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 573255332Scy if (op.iplo_type == (*l)->ipfl_type) { 574255332Scy err = (*(*l)->ipfl_stats_get)(softc, 575255332Scy softl->ipf_back[i], 576255332Scy &op); 577255332Scy break; 578255332Scy } 579255332Scy } 580145516Sdarrenr 581255332Scy if (i == MAX_BACKENDS) { 582255332Scy IPFERROR(50033); 583145516Sdarrenr err = EINVAL; 584145516Sdarrenr } 585255332Scy 586145516Sdarrenr return err; 587145516Sdarrenr} 588145516Sdarrenr 589145516Sdarrenr 590145516Sdarrenr/* ------------------------------------------------------------------------ */ 591255332Scy/* Function: ipf_lookup_flush */ 592145516Sdarrenr/* Returns: int - 0 = success, else error */ 593255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 594255332Scy/* data(I) - pointer to data from ioctl call */ 595145516Sdarrenr/* */ 596145516Sdarrenr/* A flush is called when we want to flush all the nodes from a particular */ 597145516Sdarrenr/* entry in the hash table/pool or want to remove all groups from those. */ 598145516Sdarrenr/* ------------------------------------------------------------------------ */ 599255332Scystatic int 600255332Scyipf_lookup_flush(softc, data) 601255332Scy ipf_main_softc_t *softc; 602255332Scy caddr_t data; 603145516Sdarrenr{ 604255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 605255332Scy int err, unit, num, type, i; 606145516Sdarrenr iplookupflush_t flush; 607255332Scy ipf_lookup_t **l; 608145516Sdarrenr 609170263Sdarrenr err = BCOPYIN(data, &flush, sizeof(flush)); 610255332Scy if (err != 0) { 611255332Scy IPFERROR(50034); 612170263Sdarrenr return EFAULT; 613255332Scy } 614145516Sdarrenr 615145516Sdarrenr unit = flush.iplf_unit; 616255332Scy if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) { 617255332Scy IPFERROR(50035); 618145516Sdarrenr return EINVAL; 619255332Scy } 620145516Sdarrenr 621170263Sdarrenr flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0'; 622170263Sdarrenr 623145516Sdarrenr type = flush.iplf_type; 624255332Scy IPFERROR(50036); 625145516Sdarrenr err = EINVAL; 626145516Sdarrenr num = 0; 627145516Sdarrenr 628255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 629255332Scy if (type == (*l)->ipfl_type || type == IPLT_ALL) { 630255332Scy err = 0; 631255332Scy num += (*(*l)->ipfl_flush)(softc, 632255332Scy softl->ipf_back[i], 633255332Scy &flush); 634255332Scy } 635145516Sdarrenr } 636145516Sdarrenr 637145516Sdarrenr if (err == 0) { 638145516Sdarrenr flush.iplf_count = num; 639170263Sdarrenr err = BCOPYOUT(&flush, data, sizeof(flush)); 640255332Scy if (err != 0) { 641255332Scy IPFERROR(50037); 642170263Sdarrenr err = EFAULT; 643255332Scy } 644145516Sdarrenr } 645145516Sdarrenr return err; 646145516Sdarrenr} 647145516Sdarrenr 648145516Sdarrenr 649170263Sdarrenr/* ------------------------------------------------------------------------ */ 650255332Scy/* Function: ipf_lookup_delref */ 651170263Sdarrenr/* Returns: void */ 652255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 653255332Scy/* type(I) - table type to operate on */ 654170263Sdarrenr/* ptr(I) - pointer to object to remove reference for */ 655170263Sdarrenr/* */ 656170263Sdarrenr/* This function organises calling the correct deref function for a given */ 657170263Sdarrenr/* type of object being passed into it. */ 658170263Sdarrenr/* ------------------------------------------------------------------------ */ 659255332Scyvoid 660255332Scyipf_lookup_deref(softc, type, ptr) 661255332Scy ipf_main_softc_t *softc; 662255332Scy int type; 663255332Scy void *ptr; 664145516Sdarrenr{ 665255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 666255332Scy int i; 667255332Scy 668145516Sdarrenr if (ptr == NULL) 669145516Sdarrenr return; 670145516Sdarrenr 671255332Scy for (i = 0; i < MAX_BACKENDS; i++) { 672255332Scy if (type == backends[i]->ipfl_type) { 673255332Scy WRITE_ENTER(&softc->ipf_poolrw); 674255332Scy (*backends[i]->ipfl_table_deref)(softc, 675255332Scy softl->ipf_back[i], 676255332Scy ptr); 677255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 678255332Scy break; 679255332Scy } 680145516Sdarrenr } 681145516Sdarrenr} 682145516Sdarrenr 683145516Sdarrenr 684170263Sdarrenr/* ------------------------------------------------------------------------ */ 685255332Scy/* Function: ipf_lookup_iterate */ 686170263Sdarrenr/* Returns: int - 0 = success, else error */ 687255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 688255332Scy/* data(I) - pointer to data from ioctl call */ 689172771Sdarrenr/* uid(I) - uid of caller */ 690172771Sdarrenr/* ctx(I) - pointer to give the uid context */ 691170263Sdarrenr/* */ 692170263Sdarrenr/* Decodes ioctl request to step through either hash tables or pools. */ 693170263Sdarrenr/* ------------------------------------------------------------------------ */ 694255332Scystatic int 695255332Scyipf_lookup_iterate(softc, data, uid, ctx) 696255332Scy ipf_main_softc_t *softc; 697255332Scy void *data; 698255332Scy int uid; 699255332Scy void *ctx; 700170263Sdarrenr{ 701255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 702170263Sdarrenr ipflookupiter_t iter; 703170263Sdarrenr ipftoken_t *token; 704255332Scy int err, i; 705170263Sdarrenr SPL_INT(s); 706170263Sdarrenr 707255332Scy err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER); 708170263Sdarrenr if (err != 0) 709170263Sdarrenr return err; 710170263Sdarrenr 711255332Scy if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) { 712255332Scy IPFERROR(50038); 713170263Sdarrenr return EINVAL; 714255332Scy } 715170263Sdarrenr 716255332Scy if (iter.ili_ival != IPFGENITER_LOOKUP) { 717255332Scy IPFERROR(50039); 718170263Sdarrenr return EINVAL; 719255332Scy } 720170263Sdarrenr 721170263Sdarrenr SPL_SCHED(s); 722255332Scy token = ipf_token_find(softc, iter.ili_key, uid, ctx); 723170263Sdarrenr if (token == NULL) { 724170263Sdarrenr SPL_X(s); 725255332Scy IPFERROR(50040); 726170263Sdarrenr return ESRCH; 727170263Sdarrenr } 728170263Sdarrenr 729255332Scy for (i = 0; i < MAX_BACKENDS; i++) { 730255332Scy if (iter.ili_type == backends[i]->ipfl_type) { 731255332Scy err = (*backends[i]->ipfl_iter_next)(softc, 732255332Scy softl->ipf_back[i], 733255332Scy token, &iter); 734255332Scy break; 735255332Scy } 736170263Sdarrenr } 737170263Sdarrenr SPL_X(s); 738170263Sdarrenr 739255332Scy if (i == MAX_BACKENDS) { 740255332Scy IPFERROR(50041); 741255332Scy err = EINVAL; 742255332Scy } 743255332Scy 744255332Scy WRITE_ENTER(&softc->ipf_tokens); 745255332Scy ipf_token_deref(softc, token); 746255332Scy RWLOCK_EXIT(&softc->ipf_tokens); 747255332Scy 748170263Sdarrenr return err; 749170263Sdarrenr} 750170263Sdarrenr 751170263Sdarrenr 752170263Sdarrenr/* ------------------------------------------------------------------------ */ 753255332Scy/* Function: ipf_lookup_iterderef */ 754255332Scy/* Returns: void */ 755255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 756255332Scy/* type(I) - backend type to iterate through */ 757255332Scy/* data(I) - pointer to data from ioctl call */ 758170263Sdarrenr/* */ 759170263Sdarrenr/* Decodes ioctl request to remove a particular hash table or pool and */ 760170263Sdarrenr/* calls the relevant function to do the cleanup. */ 761255332Scy/* Because each of the backend types has a different data structure, */ 762255332Scy/* iteration is limited to one type at a time (i.e. it is not permitted to */ 763255332Scy/* go on from pool types to hash types as part of the "get next".) */ 764170263Sdarrenr/* ------------------------------------------------------------------------ */ 765255332Scyvoid 766255332Scyipf_lookup_iterderef(softc, type, data) 767255332Scy ipf_main_softc_t *softc; 768255332Scy u_32_t type; 769255332Scy void *data; 770170263Sdarrenr{ 771255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 772255332Scy struct iplookupiterkey *lkey; 773255332Scy iplookupiterkey_t key; 774255332Scy int i; 775170263Sdarrenr 776170263Sdarrenr key.ilik_key = type; 777255332Scy lkey = &key.ilik_unstr; 778170263Sdarrenr 779255332Scy if (lkey->ilik_ival != IPFGENITER_LOOKUP) 780170263Sdarrenr return; 781170263Sdarrenr 782255332Scy WRITE_ENTER(&softc->ipf_poolrw); 783255332Scy 784255332Scy for (i = 0; i < MAX_BACKENDS; i++) { 785255332Scy if (lkey->ilik_type == backends[i]->ipfl_type) { 786255332Scy (*backends[i]->ipfl_iter_deref)(softc, 787255332Scy softl->ipf_back[i], 788255332Scy lkey->ilik_otype, 789255332Scy lkey->ilik_unit, 790255332Scy data); 791255332Scy break; 792255332Scy } 793170263Sdarrenr } 794255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 795170263Sdarrenr} 796170263Sdarrenr 797170263Sdarrenr 798172771Sdarrenr/* ------------------------------------------------------------------------ */ 799255332Scy/* Function: ipf_lookup_deltok */ 800172771Sdarrenr/* Returns: int - 0 = success, else error */ 801255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 802255332Scy/* data(I) - pointer to data from ioctl call */ 803172771Sdarrenr/* uid(I) - uid of caller */ 804172771Sdarrenr/* ctx(I) - pointer to give the uid context */ 805172771Sdarrenr/* */ 806172771Sdarrenr/* Deletes the token identified by the combination of (type,uid,ctx) */ 807172771Sdarrenr/* "key" is a combination of the table type, iterator type and the unit for */ 808172771Sdarrenr/* which the token was being used. */ 809172771Sdarrenr/* ------------------------------------------------------------------------ */ 810255332Scyint 811255332Scyipf_lookup_deltok(softc, data, uid, ctx) 812255332Scy ipf_main_softc_t *softc; 813255332Scy void *data; 814255332Scy int uid; 815255332Scy void *ctx; 816172771Sdarrenr{ 817172771Sdarrenr int error, key; 818172771Sdarrenr SPL_INT(s); 819170263Sdarrenr 820172771Sdarrenr SPL_SCHED(s); 821255332Scy error = BCOPYIN(data, &key, sizeof(key)); 822172771Sdarrenr if (error == 0) 823255332Scy error = ipf_token_del(softc, key, uid, ctx); 824172771Sdarrenr SPL_X(s); 825172771Sdarrenr return error; 826172771Sdarrenr} 827172771Sdarrenr 828172771Sdarrenr 829255332Scy/* ------------------------------------------------------------------------ */ 830255332Scy/* Function: ipf_lookup_res_num */ 831255332Scy/* Returns: void * - NULL = failure, else success. */ 832255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 833255332Scy/* unit(I) - device for which this is for */ 834255332Scy/* type(I) - type of lookup these parameters are for. */ 835255332Scy/* number(I) - table number to use when searching */ 836255332Scy/* funcptr(IO) - pointer to pointer for storing IP address */ 837255332Scy/* searching function. */ 838255332Scy/* */ 839255332Scy/* Search for the "table" number passed in amongst those configured for */ 840255332Scy/* that particular type. If the type is recognised then the function to */ 841255332Scy/* call to do the IP address search will be change, regardless of whether */ 842255332Scy/* or not the "table" number exists. */ 843255332Scy/* ------------------------------------------------------------------------ */ 844255332Scyvoid * 845255332Scyipf_lookup_res_num(softc, unit, type, number, funcptr) 846255332Scy ipf_main_softc_t *softc; 847255332Scy int unit; 848255332Scy u_int type; 849255332Scy u_int number; 850255332Scy lookupfunc_t *funcptr; 851255332Scy{ 852255332Scy char name[FR_GROUPLEN]; 853145516Sdarrenr 854255332Scy#if defined(SNPRINTF) && defined(_KERNEL) 855255332Scy SNPRINTF(name, sizeof(name), "%u", number); 856255332Scy#else 857255332Scy (void) sprintf(name, "%u", number); 858255332Scy#endif 859255332Scy 860255332Scy return ipf_lookup_res_name(softc, unit, type, name, funcptr); 861255332Scy} 862255332Scy 863255332Scy 864255332Scy/* ------------------------------------------------------------------------ */ 865255332Scy/* Function: ipf_lookup_res_name */ 866255332Scy/* Returns: void * - NULL = failure, else success. */ 867255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 868255332Scy/* unit(I) - device for which this is for */ 869255332Scy/* type(I) - type of lookup these parameters are for. */ 870255332Scy/* name(I) - table name to use when searching */ 871255332Scy/* funcptr(IO) - pointer to pointer for storing IP address */ 872255332Scy/* searching function. */ 873255332Scy/* */ 874255332Scy/* Search for the "table" number passed in amongst those configured for */ 875255332Scy/* that particular type. If the type is recognised then the function to */ 876255332Scy/* call to do the IP address search will be changed, regardless of whether */ 877255332Scy/* or not the "table" number exists. */ 878255332Scy/* ------------------------------------------------------------------------ */ 879255332Scyvoid * 880255332Scyipf_lookup_res_name(softc, unit, type, name, funcptr) 881255332Scy ipf_main_softc_t *softc; 882255332Scy int unit; 883255332Scy u_int type; 884255332Scy char *name; 885255332Scy lookupfunc_t *funcptr; 886255332Scy{ 887255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 888255332Scy ipf_lookup_t **l; 889255332Scy void *ptr = NULL; 890255332Scy int i; 891255332Scy 892255332Scy READ_ENTER(&softc->ipf_poolrw); 893255332Scy 894255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { 895255332Scy if (type == (*l)->ipfl_type) { 896255332Scy ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i], 897255332Scy unit, name); 898255332Scy if (ptr != NULL && funcptr != NULL) { 899255332Scy *funcptr = (*l)->ipfl_addr_find; 900255332Scy } 901255332Scy break; 902255332Scy } 903255332Scy } 904255332Scy 905255332Scy if (i == MAX_BACKENDS) { 906255332Scy ptr = NULL; 907255332Scy if (funcptr != NULL) 908255332Scy *funcptr = NULL; 909255332Scy } 910255332Scy 911255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 912255332Scy 913255332Scy return ptr; 914255332Scy} 915255332Scy 916255332Scy 917255332Scy/* ------------------------------------------------------------------------ */ 918255332Scy/* Function: ipf_lookup_find_htable */ 919255332Scy/* Returns: void * - NULL = failure, else success. */ 920255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 921255332Scy/* unit(I) - device for which this is for */ 922255332Scy/* name(I) - table name to use when searching */ 923255332Scy/* */ 924255332Scy/* To support the group-map feature, where a hash table maps address */ 925255332Scy/* networks to rule group numbers, we need to expose a function that uses */ 926255332Scy/* only the hash table backend. */ 927255332Scy/* ------------------------------------------------------------------------ */ 928255332Scyvoid * 929255332Scyipf_lookup_find_htable(softc, unit, name) 930255332Scy ipf_main_softc_t *softc; 931255332Scy int unit; 932255332Scy char *name; 933255332Scy{ 934255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 935255332Scy ipf_lookup_t **l; 936255332Scy void *tab = NULL; 937255332Scy int i; 938255332Scy 939255332Scy READ_ENTER(&softc->ipf_poolrw); 940255332Scy 941255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) 942255332Scy if (IPLT_HASH == (*l)->ipfl_type) { 943255332Scy tab = ipf_htable_find(softl->ipf_back[i], unit, name); 944255332Scy break; 945255332Scy } 946255332Scy 947255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 948255332Scy 949255332Scy return tab; 950255332Scy} 951255332Scy 952255332Scy 953255332Scy/* ------------------------------------------------------------------------ */ 954255332Scy/* Function: ipf_lookup_sync */ 955255332Scy/* Returns: void */ 956255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 957255332Scy/* */ 958255332Scy/* This function is the interface that the machine dependent sync functions */ 959255332Scy/* call when a network interface name change occurs. It then calls the sync */ 960255332Scy/* functions of the lookup implementations - if they have one. */ 961255332Scy/* ------------------------------------------------------------------------ */ 962145516Sdarrenr/*ARGSUSED*/ 963255332Scyvoid 964255332Scyipf_lookup_sync(softc, ifp) 965255332Scy ipf_main_softc_t *softc; 966255332Scy void *ifp; 967145516Sdarrenr{ 968255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 969255332Scy ipf_lookup_t **l; 970255332Scy int i; 971255332Scy 972255332Scy READ_ENTER(&softc->ipf_poolrw); 973255332Scy 974255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) 975255332Scy if ((*l)->ipfl_sync != NULL) 976255332Scy (*(*l)->ipfl_sync)(softc, softl->ipf_back[i]); 977255332Scy 978255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 979145516Sdarrenr} 980255332Scy 981255332Scy 982255332Scy#ifndef _KERNEL 983255332Scyvoid 984255332Scyipf_lookup_dump(softc, arg) 985255332Scy ipf_main_softc_t *softc; 986255332Scy void *arg; 987255332Scy{ 988255332Scy ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; 989255332Scy ipf_lookup_t **l; 990255332Scy int i; 991255332Scy 992255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) 993255332Scy if (IPLT_POOL == (*l)->ipfl_type) { 994255332Scy ipf_pool_dump(softc, softl->ipf_back[i]); 995255332Scy break; 996255332Scy } 997255332Scy 998255332Scy for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) 999255332Scy if (IPLT_HASH == (*l)->ipfl_type) { 1000255332Scy ipf_htable_dump(softc, softl->ipf_back[i]); 1001255332Scy break; 1002255332Scy } 1003255332Scy} 1004255332Scy#endif 1005