| /* |
| * Copyright (C) 2010 by Darren Reed. |
| * |
| * See the IPFILTER.LICENCE file for details on licencing. |
| */ |
| #if defined(KERNEL) || defined(_KERNEL) |
| # undef KERNEL |
| # undef _KERNEL |
| # define KERNEL 1 |
| # define _KERNEL 1 |
| #endif |
| #if defined(__osf__) |
| # define _PROTO_NET_H_ |
| #endif |
| #include <sys/param.h> |
| #include <sys/errno.h> |
| #include <sys/types.h> |
| #include <sys/time.h> |
| #include <sys/file.h> |
| #if __FreeBSD_version >= 220000 && defined(_KERNEL) |
| # include <sys/fcntl.h> |
| # include <sys/filio.h> |
| #else |
| # include <sys/ioctl.h> |
| #endif |
| #if !defined(_KERNEL) |
| # include <stdio.h> |
| # include <string.h> |
| # include <stdlib.h> |
| # define _KERNEL |
| # ifdef __OpenBSD__ |
| struct file; |
| # endif |
| # include <sys/uio.h> |
| # undef _KERNEL |
| #endif |
| #include <sys/socket.h> |
| #include <net/if.h> |
| #if defined(__FreeBSD__) |
| # include <sys/cdefs.h> |
| # include <sys/proc.h> |
| #endif |
| #if defined(_KERNEL) |
| # include <sys/systm.h> |
| # if !defined(__SVR4) && !defined(__svr4__) |
| # include <sys/mbuf.h> |
| # endif |
| #else |
| # include "ipf.h" |
| #endif |
| #include <netinet/in.h> |
| |
| #include "netinet/ip_compat.h" |
| #include "netinet/ip_fil.h" |
| #include "netinet/ip_lookup.h" |
| #include "netinet/ip_pool.h" |
| #include "netinet/ip_htable.h" |
| #include "netinet/ip_dstlist.h" |
| /* END OF INCLUDES */ |
| |
| #if !defined(lint) |
| static const char rcsid[] = "@(#)$Id$"; |
| #endif |
| |
| /* |
| * In this file, ip_pool.c, ip_htable.c and ip_dstlist.c, you will find the |
| * range for unit is [-1,IPL_LOGMAX]. The -1 is considered to be a valid number |
| * and represents a "wildcard" or "all" units (IPL_LOGALL). The reason for not |
| * starting the numbering at 0 is because the numbers [0,IPL_LOGMAX] correspond |
| * to the minor device number for their respective device. Thus where there is |
| * array indexing on the unit, +1 is used to map [-1.IPL_LOGMAX] to |
| * [0.POOL_LOOKUP_MAX]. |
| */ |
| static int ipf_lookup_addnode __P((ipf_main_softc_t *, caddr_t, int)); |
| static int ipf_lookup_delnode __P((ipf_main_softc_t *, caddr_t, int)); |
| static int ipf_lookup_addtable __P((ipf_main_softc_t *, caddr_t)); |
| static int ipf_lookup_deltable __P((ipf_main_softc_t *, caddr_t)); |
| static int ipf_lookup_stats __P((ipf_main_softc_t *, caddr_t)); |
| static int ipf_lookup_flush __P((ipf_main_softc_t *, caddr_t)); |
| static int ipf_lookup_iterate __P((ipf_main_softc_t *, void *, int, void *)); |
| static int ipf_lookup_deltok __P((ipf_main_softc_t *, void *, int, void *)); |
| |
| #define MAX_BACKENDS 3 |
| static ipf_lookup_t *backends[MAX_BACKENDS] = { |
| &ipf_pool_backend, |
| &ipf_htable_backend, |
| &ipf_dstlist_backend |
| }; |
| |
| |
| typedef struct ipf_lookup_softc_s { |
| void *ipf_back[MAX_BACKENDS]; |
| } ipf_lookup_softc_t; |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_init */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* */ |
| /* Initialise all of the subcomponents of the lookup infrstructure. */ |
| /* ------------------------------------------------------------------------ */ |
| void * |
| ipf_lookup_soft_create(softc) |
| ipf_main_softc_t *softc; |
| { |
| ipf_lookup_softc_t *softl; |
| ipf_lookup_t **l; |
| int i; |
| |
| KMALLOC(softl, ipf_lookup_softc_t *); |
| if (softl == NULL) |
| return NULL; |
| |
| bzero((char *)softl, sizeof(*softl)); |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { |
| softl->ipf_back[i] = (*(*l)->ipfl_create)(softc); |
| if (softl->ipf_back[i] == NULL) { |
| ipf_lookup_soft_destroy(softc, softl); |
| return NULL; |
| } |
| } |
| |
| return softl; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_soft_init */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* arg(I) - pointer to local context to use */ |
| /* */ |
| /* Initialise all of the subcomponents of the lookup infrstructure. */ |
| /* ------------------------------------------------------------------------ */ |
| int |
| ipf_lookup_soft_init(softc, arg) |
| ipf_main_softc_t *softc; |
| void *arg; |
| { |
| ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; |
| int err = 0; |
| int i; |
| |
| for (i = 0; i < MAX_BACKENDS; i++) { |
| err = (*backends[i]->ipfl_init)(softc, softl->ipf_back[i]); |
| if (err != 0) |
| break; |
| } |
| |
| return err; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_soft_fini */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* arg(I) - pointer to local context to use */ |
| /* */ |
| /* Call the fini function in each backend to cleanup all allocated data. */ |
| /* ------------------------------------------------------------------------ */ |
| int |
| ipf_lookup_soft_fini(softc, arg) |
| ipf_main_softc_t *softc; |
| void *arg; |
| { |
| ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; |
| int i; |
| |
| for (i = 0; i < MAX_BACKENDS; i++) { |
| if (softl->ipf_back[i] != NULL) |
| (*backends[i]->ipfl_fini)(softc, |
| softl->ipf_back[i]); |
| } |
| |
| return 0; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_expire */ |
| /* Returns: Nil */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* */ |
| /* Step through each of the backends and call their expire functions, */ |
| /* allowing them to delete any lifetime limited data. */ |
| /* ------------------------------------------------------------------------ */ |
| void |
| ipf_lookup_expire(softc) |
| ipf_main_softc_t *softc; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| int i; |
| |
| WRITE_ENTER(&softc->ipf_poolrw); |
| for (i = 0; i < MAX_BACKENDS; i++) |
| (*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]); |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_softc_destroy */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* arg(I) - pointer to local context to use */ |
| /* */ |
| /* Free up all pool related memory that has been allocated whilst IPFilter */ |
| /* has been running. Also, do any other deinitialisation required such */ |
| /* ipf_lookup_init() can be called again, safely. */ |
| /* ------------------------------------------------------------------------ */ |
| void |
| ipf_lookup_soft_destroy(softc, arg) |
| ipf_main_softc_t *softc; |
| void *arg; |
| { |
| ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; |
| int i; |
| |
| for (i = 0; i < MAX_BACKENDS; i++) { |
| if (softl->ipf_back[i] != NULL) |
| (*backends[i]->ipfl_destroy)(softc, |
| softl->ipf_back[i]); |
| } |
| |
| KFREE(softl); |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_ioctl */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* arg(I) - pointer to local context to use */ |
| /* data(IO) - pointer to ioctl data to be copied to/from user */ |
| /* space. */ |
| /* cmd(I) - ioctl command number */ |
| /* mode(I) - file mode bits used with open */ |
| /* uid(I) - uid of process doing ioctl */ |
| /* ctx(I) - pointer that represents context for uid */ |
| /* */ |
| /* Handle ioctl commands sent to the ioctl device. For the most part, this */ |
| /* involves just calling another function to handle the specifics of each */ |
| /* command. */ |
| /* ------------------------------------------------------------------------ */ |
| int |
| ipf_lookup_ioctl(softc, data, cmd, mode, uid, ctx) |
| ipf_main_softc_t *softc; |
| caddr_t data; |
| ioctlcmd_t cmd; |
| int mode, uid; |
| void *ctx; |
| { |
| int err; |
| SPL_INT(s); |
| |
| mode = mode; /* LINT */ |
| |
| SPL_NET(s); |
| |
| switch (cmd) |
| { |
| case SIOCLOOKUPADDNODE : |
| case SIOCLOOKUPADDNODEW : |
| WRITE_ENTER(&softc->ipf_poolrw); |
| err = ipf_lookup_addnode(softc, data, uid); |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| break; |
| |
| case SIOCLOOKUPDELNODE : |
| case SIOCLOOKUPDELNODEW : |
| WRITE_ENTER(&softc->ipf_poolrw); |
| err = ipf_lookup_delnode(softc, data, uid); |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| break; |
| |
| case SIOCLOOKUPADDTABLE : |
| WRITE_ENTER(&softc->ipf_poolrw); |
| err = ipf_lookup_addtable(softc, data); |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| break; |
| |
| case SIOCLOOKUPDELTABLE : |
| WRITE_ENTER(&softc->ipf_poolrw); |
| err = ipf_lookup_deltable(softc, data); |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| break; |
| |
| case SIOCLOOKUPSTAT : |
| case SIOCLOOKUPSTATW : |
| WRITE_ENTER(&softc->ipf_poolrw); |
| err = ipf_lookup_stats(softc, data); |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| break; |
| |
| case SIOCLOOKUPFLUSH : |
| WRITE_ENTER(&softc->ipf_poolrw); |
| err = ipf_lookup_flush(softc, data); |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| break; |
| |
| case SIOCLOOKUPITER : |
| err = ipf_lookup_iterate(softc, data, uid, ctx); |
| break; |
| |
| case SIOCIPFDELTOK : |
| err = ipf_lookup_deltok(softc, data, uid, ctx); |
| break; |
| |
| default : |
| softc->ipf_interror = 50001; |
| err = EINVAL; |
| break; |
| } |
| SPL_X(s); |
| return err; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_addnode */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* data(I) - pointer to data from ioctl call */ |
| /* */ |
| /* Add a new data node to a lookup structure. First, check to see if the */ |
| /* parent structure refered to by name exists and if it does, then go on to */ |
| /* add a node to it. */ |
| /* ------------------------------------------------------------------------ */ |
| static int |
| ipf_lookup_addnode(softc, data, uid) |
| ipf_main_softc_t *softc; |
| caddr_t data; |
| int uid; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| iplookupop_t op; |
| ipf_lookup_t **l; |
| int err; |
| int i; |
| |
| err = BCOPYIN(data, &op, sizeof(op)); |
| if (err != 0) { |
| softc->ipf_interror = 50002; |
| return EFAULT; |
| } |
| |
| if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && |
| (op.iplo_unit != IPLT_ALL)) { |
| softc->ipf_interror = 50003; |
| return EINVAL; |
| } |
| |
| op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { |
| if (op.iplo_type == (*l)->ipfl_type) { |
| err = (*(*l)->ipfl_node_add)(softc, |
| softl->ipf_back[i], |
| &op, uid); |
| break; |
| } |
| } |
| |
| if (i == MAX_BACKENDS) { |
| softc->ipf_interror = 50012; |
| err = EINVAL; |
| } |
| |
| return err; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_delnode */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* data(I) - pointer to data from ioctl call */ |
| /* */ |
| /* Delete a node from a lookup table by first looking for the table it is */ |
| /* in and then deleting the entry that gets found. */ |
| /* ------------------------------------------------------------------------ */ |
| static int |
| ipf_lookup_delnode(softc, data, uid) |
| ipf_main_softc_t *softc; |
| caddr_t data; |
| int uid; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| iplookupop_t op; |
| ipf_lookup_t **l; |
| int err; |
| int i; |
| |
| err = BCOPYIN(data, &op, sizeof(op)); |
| if (err != 0) { |
| softc->ipf_interror = 50042; |
| return EFAULT; |
| } |
| |
| if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && |
| (op.iplo_unit != IPLT_ALL)) { |
| softc->ipf_interror = 50013; |
| return EINVAL; |
| } |
| |
| op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { |
| if (op.iplo_type == (*l)->ipfl_type) { |
| err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i], |
| &op, uid); |
| break; |
| } |
| } |
| |
| if (i == MAX_BACKENDS) { |
| softc->ipf_interror = 50021; |
| err = EINVAL; |
| } |
| return err; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_addtable */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* data(I) - pointer to data from ioctl call */ |
| /* */ |
| /* Create a new lookup table, if one doesn't already exist using the name */ |
| /* for this one. */ |
| /* ------------------------------------------------------------------------ */ |
| static int |
| ipf_lookup_addtable(softc, data) |
| ipf_main_softc_t *softc; |
| caddr_t data; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| iplookupop_t op; |
| ipf_lookup_t **l; |
| int err, i; |
| |
| err = BCOPYIN(data, &op, sizeof(op)); |
| if (err != 0) { |
| softc->ipf_interror = 50022; |
| return EFAULT; |
| } |
| |
| if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && |
| (op.iplo_unit != IPLT_ALL)) { |
| softc->ipf_interror = 50023; |
| return EINVAL; |
| } |
| |
| op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { |
| if (op.iplo_type == (*l)->ipfl_type) { |
| err = (*(*l)->ipfl_table_add)(softc, |
| softl->ipf_back[i], |
| &op); |
| break; |
| } |
| } |
| |
| if (i == MAX_BACKENDS) { |
| softc->ipf_interror = 50026; |
| err = EINVAL; |
| } |
| |
| /* |
| * For anonymous pools, copy back the operation struct because in the |
| * case of success it will contain the new table's name. |
| */ |
| if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) { |
| err = BCOPYOUT(&op, data, sizeof(op)); |
| if (err != 0) { |
| softc->ipf_interror = 50027; |
| err = EFAULT; |
| } |
| } |
| |
| return err; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_deltable */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* data(I) - pointer to data from ioctl call */ |
| /* */ |
| /* Decodes ioctl request to remove a particular hash table or pool and */ |
| /* calls the relevant function to do the cleanup. */ |
| /* ------------------------------------------------------------------------ */ |
| static int |
| ipf_lookup_deltable(softc, data) |
| ipf_main_softc_t *softc; |
| caddr_t data; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| iplookupop_t op; |
| ipf_lookup_t **l; |
| int err, i; |
| |
| err = BCOPYIN(data, &op, sizeof(op)); |
| if (err != 0) { |
| softc->ipf_interror = 50028; |
| return EFAULT; |
| } |
| |
| if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && |
| (op.iplo_unit != IPLT_ALL)) { |
| softc->ipf_interror = 50029; |
| return EINVAL; |
| } |
| |
| op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { |
| if (op.iplo_type == (*l)->ipfl_type) { |
| err = (*(*l)->ipfl_table_del)(softc, |
| softl->ipf_back[i], |
| &op); |
| break; |
| } |
| } |
| |
| if (i == MAX_BACKENDS) { |
| softc->ipf_interror = 50030; |
| err = EINVAL; |
| } |
| return err; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_stats */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* data(I) - pointer to data from ioctl call */ |
| /* */ |
| /* Copy statistical information from inside the kernel back to user space. */ |
| /* ------------------------------------------------------------------------ */ |
| static int |
| ipf_lookup_stats(softc, data) |
| ipf_main_softc_t *softc; |
| caddr_t data; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| iplookupop_t op; |
| ipf_lookup_t **l; |
| int err; |
| int i; |
| |
| err = BCOPYIN(data, &op, sizeof(op)); |
| if (err != 0) { |
| softc->ipf_interror = 50031; |
| return EFAULT; |
| } |
| |
| if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && |
| (op.iplo_unit != IPLT_ALL)) { |
| softc->ipf_interror = 50032; |
| return EINVAL; |
| } |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { |
| if (op.iplo_type == (*l)->ipfl_type) { |
| err = (*(*l)->ipfl_stats_get)(softc, |
| softl->ipf_back[i], |
| &op); |
| break; |
| } |
| } |
| |
| if (i == MAX_BACKENDS) { |
| softc->ipf_interror = 50033; |
| err = EINVAL; |
| } |
| |
| return err; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_flush */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* data(I) - pointer to data from ioctl call */ |
| /* */ |
| /* A flush is called when we want to flush all the nodes from a particular */ |
| /* entry in the hash table/pool or want to remove all groups from those. */ |
| /* ------------------------------------------------------------------------ */ |
| static int |
| ipf_lookup_flush(softc, data) |
| ipf_main_softc_t *softc; |
| caddr_t data; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| int err, unit, num, type, i; |
| iplookupflush_t flush; |
| ipf_lookup_t **l; |
| |
| err = BCOPYIN(data, &flush, sizeof(flush)); |
| if (err != 0) { |
| softc->ipf_interror = 50034; |
| return EFAULT; |
| } |
| |
| unit = flush.iplf_unit; |
| if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) { |
| softc->ipf_interror = 50035; |
| return EINVAL; |
| } |
| |
| flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0'; |
| |
| type = flush.iplf_type; |
| softc->ipf_interror = 50036; |
| err = EINVAL; |
| num = 0; |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { |
| if (type == (*l)->ipfl_type || type == IPLT_ALL) { |
| err = 0; |
| num += (*(*l)->ipfl_flush)(softc, |
| softl->ipf_back[i], |
| &flush); |
| } |
| } |
| |
| if (err == 0) { |
| flush.iplf_count = num; |
| err = BCOPYOUT(&flush, data, sizeof(flush)); |
| if (err != 0) { |
| softc->ipf_interror = 50037; |
| err = EFAULT; |
| } |
| } |
| return err; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_delref */ |
| /* Returns: void */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* type(I) - table type to operate on */ |
| /* ptr(I) - pointer to object to remove reference for */ |
| /* */ |
| /* This function organises calling the correct deref function for a given */ |
| /* type of object being passed into it. */ |
| /* ------------------------------------------------------------------------ */ |
| void |
| ipf_lookup_deref(softc, type, ptr) |
| ipf_main_softc_t *softc; |
| int type; |
| void *ptr; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| int i; |
| |
| if (ptr == NULL) |
| return; |
| |
| for (i = 0; i < MAX_BACKENDS; i++) { |
| if (type == backends[i]->ipfl_type) { |
| WRITE_ENTER(&softc->ipf_poolrw); |
| (*backends[i]->ipfl_table_deref)(softc, |
| softl->ipf_back[i], |
| ptr); |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| break; |
| } |
| } |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_iterate */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* data(I) - pointer to data from ioctl call */ |
| /* uid(I) - uid of caller */ |
| /* ctx(I) - pointer to give the uid context */ |
| /* */ |
| /* Decodes ioctl request to step through either hash tables or pools. */ |
| /* ------------------------------------------------------------------------ */ |
| static int |
| ipf_lookup_iterate(softc, data, uid, ctx) |
| ipf_main_softc_t *softc; |
| void *data; |
| int uid; |
| void *ctx; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| ipflookupiter_t iter; |
| ipftoken_t *token; |
| int err, i; |
| SPL_INT(s); |
| |
| err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER); |
| if (err != 0) |
| return err; |
| |
| if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) { |
| softc->ipf_interror = 50038; |
| return EINVAL; |
| } |
| |
| if (iter.ili_ival != IPFGENITER_LOOKUP) { |
| softc->ipf_interror = 50039; |
| return EINVAL; |
| } |
| |
| SPL_SCHED(s); |
| token = ipf_token_find(softc, iter.ili_key, uid, ctx); |
| if (token == NULL) { |
| SPL_X(s); |
| softc->ipf_interror = 50040; |
| return ESRCH; |
| } |
| |
| for (i = 0; i < MAX_BACKENDS; i++) { |
| if (iter.ili_type == backends[i]->ipfl_type) { |
| err = (*backends[i]->ipfl_iter_next)(softc, |
| softl->ipf_back[i], |
| token, &iter); |
| break; |
| } |
| } |
| SPL_X(s); |
| |
| if (i == MAX_BACKENDS) { |
| softc->ipf_interror = 50041; |
| err = EINVAL; |
| } |
| |
| WRITE_ENTER(&softc->ipf_tokens); |
| ipf_token_deref(softc, token); |
| RWLOCK_EXIT(&softc->ipf_tokens); |
| |
| return err; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_iterderef */ |
| /* Returns: void */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* type(I) - backend type to iterate through */ |
| /* data(I) - pointer to data from ioctl call */ |
| /* */ |
| /* Decodes ioctl request to remove a particular hash table or pool and */ |
| /* calls the relevant function to do the cleanup. */ |
| /* Because each of the backend types has a different data structure, */ |
| /* iteration is limited to one type at a time (i.e. it is not permitted to */ |
| /* go on from pool types to hash types as part of the "get next".) */ |
| /* ------------------------------------------------------------------------ */ |
| void |
| ipf_lookup_iterderef(softc, type, data) |
| ipf_main_softc_t *softc; |
| u_32_t type; |
| void *data; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| struct iplookupiterkey *lkey; |
| iplookupiterkey_t key; |
| int i; |
| |
| key.ilik_key = type; |
| lkey = &key.ilik_unstr; |
| |
| if (lkey->ilik_ival != IPFGENITER_LOOKUP) |
| return; |
| |
| WRITE_ENTER(&softc->ipf_poolrw); |
| |
| for (i = 0; i < MAX_BACKENDS; i++) { |
| if (type == backends[i]->ipfl_type) { |
| (*backends[i]->ipfl_iter_deref)(softc, |
| softl->ipf_back[i], |
| lkey->ilik_otype, |
| lkey->ilik_unit, |
| data); |
| break; |
| } |
| } |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_deltok */ |
| /* Returns: int - 0 = success, else error */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* data(I) - pointer to data from ioctl call */ |
| /* uid(I) - uid of caller */ |
| /* ctx(I) - pointer to give the uid context */ |
| /* */ |
| /* Deletes the token identified by the combination of (type,uid,ctx) */ |
| /* "key" is a combination of the table type, iterator type and the unit for */ |
| /* which the token was being used. */ |
| /* ------------------------------------------------------------------------ */ |
| int |
| ipf_lookup_deltok(softc, data, uid, ctx) |
| ipf_main_softc_t *softc; |
| void *data; |
| int uid; |
| void *ctx; |
| { |
| int error, key; |
| SPL_INT(s); |
| |
| SPL_SCHED(s); |
| error = BCOPYIN(data, &key, sizeof(key)); |
| if (error == 0) |
| error = ipf_token_del(softc, key, uid, ctx); |
| SPL_X(s); |
| return error; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_res_num */ |
| /* Returns: void * - NULL = failure, else success. */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* unit(I) - device for which this is for */ |
| /* type(I) - type of lookup these parameters are for. */ |
| /* number(I) - table number to use when searching */ |
| /* funcptr(IO) - pointer to pointer for storing IP address */ |
| /* searching function. */ |
| /* */ |
| /* Search for the "table" number passed in amongst those configured for */ |
| /* that particular type. If the type is recognised then the function to */ |
| /* call to do the IP address search will be change, regardless of whether */ |
| /* or not the "table" number exists. */ |
| /* ------------------------------------------------------------------------ */ |
| void * |
| ipf_lookup_res_num(softc, unit, type, number, funcptr) |
| ipf_main_softc_t *softc; |
| int unit; |
| u_int type; |
| u_int number; |
| lookupfunc_t *funcptr; |
| { |
| char name[FR_GROUPLEN]; |
| |
| #if defined(SNPRINTF) && defined(_KERNEL) |
| SNPRINTF(name, sizeof(name), "%u", number); |
| #else |
| (void) sprintf(name, "%u", number); |
| #endif |
| |
| return ipf_lookup_res_name(softc, unit, type, name, funcptr); |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_res_name */ |
| /* Returns: void * - NULL = failure, else success. */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* unit(I) - device for which this is for */ |
| /* type(I) - type of lookup these parameters are for. */ |
| /* name(I) - table name to use when searching */ |
| /* funcptr(IO) - pointer to pointer for storing IP address */ |
| /* searching function. */ |
| /* */ |
| /* Search for the "table" number passed in amongst those configured for */ |
| /* that particular type. If the type is recognised then the function to */ |
| /* call to do the IP address search will be change, regardless of whether */ |
| /* or not the "table" number exists. */ |
| /* ------------------------------------------------------------------------ */ |
| void * |
| ipf_lookup_res_name(softc, unit, type, name, funcptr) |
| ipf_main_softc_t *softc; |
| int unit; |
| u_int type; |
| char *name; |
| lookupfunc_t *funcptr; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| ipf_lookup_t **l; |
| void *ptr = NULL; |
| int i; |
| |
| READ_ENTER(&softc->ipf_poolrw); |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { |
| if (type == (*l)->ipfl_type) { |
| ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i], |
| unit, name); |
| if (ptr != NULL && funcptr != NULL) { |
| *funcptr = (*l)->ipfl_addr_find; |
| } |
| break; |
| } |
| } |
| |
| if (i == MAX_BACKENDS) { |
| ptr = NULL; |
| if (funcptr != NULL) |
| *funcptr = NULL; |
| } |
| |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| |
| return ptr; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_find_htable */ |
| /* Returns: void * - NULL = failure, else success. */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* unit(I) - device for which this is for */ |
| /* name(I) - table name to use when searching */ |
| /* */ |
| /* To support the group-map feature, where a hash table maps address */ |
| /* networks to rule group numbers, we need to expose a function that uses */ |
| /* only the hash table backend. */ |
| /* ------------------------------------------------------------------------ */ |
| void * |
| ipf_lookup_find_htable(softc, unit, name) |
| ipf_main_softc_t *softc; |
| int unit; |
| char *name; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| ipf_lookup_t **l; |
| void *tab = NULL; |
| int i; |
| |
| READ_ENTER(&softc->ipf_poolrw); |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) |
| if (IPLT_HASH == (*l)->ipfl_type) { |
| tab = ipf_htable_find(softl->ipf_back[i], unit, name); |
| break; |
| } |
| |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| |
| return tab; |
| } |
| |
| |
| /* ------------------------------------------------------------------------ */ |
| /* Function: ipf_lookup_sync */ |
| /* Returns: void */ |
| /* Parameters: softc(I) - pointer to soft context main structure */ |
| /* */ |
| /* This function is the interface that the machine dependent sync functions */ |
| /* call when a network interface name change occurs. It then calls the sync */ |
| /* functions of the lookup implementations - if they have one. */ |
| /* ------------------------------------------------------------------------ */ |
| /*ARGSUSED*/ |
| void |
| ipf_lookup_sync(softc, ifp) |
| ipf_main_softc_t *softc; |
| void *ifp; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| ipf_lookup_t **l; |
| int i; |
| |
| READ_ENTER(&softc->ipf_poolrw); |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) |
| if ((*l)->ipfl_sync != NULL) |
| (*(*l)->ipfl_sync)(softc, softl->ipf_back[i]); |
| |
| RWLOCK_EXIT(&softc->ipf_poolrw); |
| } |
| |
| |
| #ifndef _KERNEL |
| void |
| ipf_lookup_dump(softc, arg) |
| ipf_main_softc_t *softc; |
| void *arg; |
| { |
| ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; |
| ipf_lookup_t **l; |
| int i; |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) |
| if (IPLT_POOL == (*l)->ipfl_type) { |
| ipf_pool_dump(softc, softl->ipf_back[i]); |
| break; |
| } |
| |
| for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) |
| if (IPLT_HASH == (*l)->ipfl_type) { |
| ipf_htable_dump(softc, softl->ipf_back[i]); |
| break; |
| } |
| } |
| #endif |