|  | /* | 
|  | * 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 : | 
|  | IPFERROR(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) { | 
|  | IPFERROR(50002); | 
|  | return EFAULT; | 
|  | } | 
|  |  | 
|  | if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && | 
|  | (op.iplo_unit != IPLT_ALL)) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(50042); | 
|  | return EFAULT; | 
|  | } | 
|  |  | 
|  | if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && | 
|  | (op.iplo_unit != IPLT_ALL)) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(50022); | 
|  | return EFAULT; | 
|  | } | 
|  |  | 
|  | if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && | 
|  | (op.iplo_unit != IPLT_ALL)) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(50028); | 
|  | return EFAULT; | 
|  | } | 
|  |  | 
|  | if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && | 
|  | (op.iplo_unit != IPLT_ALL)) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(50031); | 
|  | return EFAULT; | 
|  | } | 
|  |  | 
|  | if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && | 
|  | (op.iplo_unit != IPLT_ALL)) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(50034); | 
|  | return EFAULT; | 
|  | } | 
|  |  | 
|  | unit = flush.iplf_unit; | 
|  | if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) { | 
|  | IPFERROR(50035); | 
|  | return EINVAL; | 
|  | } | 
|  |  | 
|  | flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0'; | 
|  |  | 
|  | type = flush.iplf_type; | 
|  | IPFERROR(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) { | 
|  | IPFERROR(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) { | 
|  | IPFERROR(50038); | 
|  | return EINVAL; | 
|  | } | 
|  |  | 
|  | if (iter.ili_ival != IPFGENITER_LOOKUP) { | 
|  | IPFERROR(50039); | 
|  | return EINVAL; | 
|  | } | 
|  |  | 
|  | SPL_SCHED(s); | 
|  | token = ipf_token_find(softc, iter.ili_key, uid, ctx); | 
|  | if (token == NULL) { | 
|  | SPL_X(s); | 
|  | IPFERROR(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) { | 
|  | IPFERROR(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 |