2 * Copyright (C) 2002-2003 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
6 #if defined(KERNEL) || defined(_KERNEL)
13 # define _PROTO_NET_H_
15 #include <sys/param.h>
16 #include <sys/errno.h>
17 #include <sys/types.h>
20 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
21 # include <sys/fcntl.h>
22 # include <sys/filio.h>
24 # include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
37 # include "radix_ipf_local.h"
41 #if defined(__FreeBSD__)
42 # include <sys/cdefs.h>
43 # include <sys/proc.h>
46 # include <sys/systm.h>
47 # if !defined(__SVR4) && !defined(__svr4__)
48 # include <sys/mbuf.h>
51 #include <netinet/in.h>
53 #include "netinet/ip_compat.h"
54 #include "netinet/ip_fil.h"
55 #include "netinet/ip_pool.h"
56 #include "netinet/ip_htable.h"
57 #include "netinet/ip_lookup.h"
61 static const char rcsid[] = "@(#)$Id: ip_lookup.c,v 2.35.2.19 2007/10/11 09:05:51 darrenr Exp $";
64 #ifdef IPFILTER_LOOKUP
65 int ip_lookup_inited = 0;
67 static int iplookup_addnode __P((caddr_t));
68 static int iplookup_delnode __P((caddr_t data));
69 static int iplookup_addtable __P((caddr_t));
70 static int iplookup_deltable __P((caddr_t));
71 static int iplookup_stats __P((caddr_t));
72 static int iplookup_flush __P((caddr_t));
73 static int iplookup_iterate __P((void *, int, void *));
74 static int iplookup_deltok __P((void *, int, void *));
77 /* ------------------------------------------------------------------------ */
78 /* Function: iplookup_init */
79 /* Returns: int - 0 = success, else error */
82 /* Initialise all of the subcomponents of the lookup infrstructure. */
83 /* ------------------------------------------------------------------------ */
87 if (ip_pool_init() == -1)
90 RWLOCK_INIT(&ip_poolrw, "ip pool rwlock");
98 /* ------------------------------------------------------------------------ */
99 /* Function: iplookup_unload */
100 /* Returns: int - 0 = success, else error */
101 /* Parameters: Nil */
103 /* Free up all pool related memory that has been allocated whilst IPFilter */
104 /* has been running. Also, do any other deinitialisation required such */
105 /* ip_lookup_init() can be called again, safely. */
106 /* ------------------------------------------------------------------------ */
107 void ip_lookup_unload()
112 if (ip_lookup_inited == 1) {
113 RW_DESTROY(&ip_poolrw);
114 ip_lookup_inited = 0;
119 /* ------------------------------------------------------------------------ */
120 /* Function: iplookup_ioctl */
121 /* Returns: int - 0 = success, else error */
122 /* Parameters: data(IO) - pointer to ioctl data to be copied to/from user */
124 /* cmd(I) - ioctl command number */
125 /* mode(I) - file mode bits used with open */
127 /* Handle ioctl commands sent to the ioctl device. For the most part, this */
128 /* involves just calling another function to handle the specifics of each */
130 /* ------------------------------------------------------------------------ */
131 int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
140 mode = mode; /* LINT */
146 case SIOCLOOKUPADDNODE :
147 case SIOCLOOKUPADDNODEW :
148 WRITE_ENTER(&ip_poolrw);
149 err = iplookup_addnode(data);
150 RWLOCK_EXIT(&ip_poolrw);
153 case SIOCLOOKUPDELNODE :
154 case SIOCLOOKUPDELNODEW :
155 WRITE_ENTER(&ip_poolrw);
156 err = iplookup_delnode(data);
157 RWLOCK_EXIT(&ip_poolrw);
160 case SIOCLOOKUPADDTABLE :
161 WRITE_ENTER(&ip_poolrw);
162 err = iplookup_addtable(data);
163 RWLOCK_EXIT(&ip_poolrw);
166 case SIOCLOOKUPDELTABLE :
167 WRITE_ENTER(&ip_poolrw);
168 err = iplookup_deltable(data);
169 RWLOCK_EXIT(&ip_poolrw);
172 case SIOCLOOKUPSTAT :
173 case SIOCLOOKUPSTATW :
174 WRITE_ENTER(&ip_poolrw);
175 err = iplookup_stats(data);
176 RWLOCK_EXIT(&ip_poolrw);
179 case SIOCLOOKUPFLUSH :
180 WRITE_ENTER(&ip_poolrw);
181 err = iplookup_flush(data);
182 RWLOCK_EXIT(&ip_poolrw);
185 case SIOCLOOKUPITER :
186 err = iplookup_iterate(data, uid, ctx);
190 err = iplookup_deltok(data, uid, ctx);
202 /* ------------------------------------------------------------------------ */
203 /* Function: iplookup_addnode */
204 /* Returns: int - 0 = success, else error */
205 /* Parameters: data(I) - pointer to data from ioctl call */
207 /* Add a new data node to a lookup structure. First, check to see if the */
208 /* parent structure refered to by name exists and if it does, then go on to */
209 /* add a node to it. */
210 /* ------------------------------------------------------------------------ */
211 static int iplookup_addnode(data)
214 ip_pool_node_t node, *m;
221 err = BCOPYIN(data, &op, sizeof(op));
225 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
228 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
230 switch (op.iplo_type)
233 if (op.iplo_size != sizeof(node))
236 err = COPYIN(op.iplo_struct, &node, sizeof(node));
240 p = ip_pool_find(op.iplo_unit, op.iplo_name);
245 * add an entry to a pool - return an error if it already
246 * exists remove an entry from a pool - if it exists
247 * - in both cases, the pool *must* exist!
249 m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
252 err = ip_pool_insert(p, &node.ipn_addr.adf_addr,
253 &node.ipn_mask.adf_addr, node.ipn_info);
257 if (op.iplo_size != sizeof(hte))
260 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
264 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
267 err = fr_addhtent(iph, &hte);
278 /* ------------------------------------------------------------------------ */
279 /* Function: iplookup_delnode */
280 /* Returns: int - 0 = success, else error */
281 /* Parameters: data(I) - pointer to data from ioctl call */
283 /* Delete a node from a lookup table by first looking for the table it is */
284 /* in and then deleting the entry that gets found. */
285 /* ------------------------------------------------------------------------ */
286 static int iplookup_delnode(data)
289 ip_pool_node_t node, *m;
296 err = BCOPYIN(data, &op, sizeof(op));
300 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
303 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
305 switch (op.iplo_type)
308 if (op.iplo_size != sizeof(node))
311 err = COPYIN(op.iplo_struct, &node, sizeof(node));
315 p = ip_pool_find(op.iplo_unit, op.iplo_name);
319 m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
322 err = ip_pool_remove(p, m);
326 if (op.iplo_size != sizeof(hte))
329 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
333 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
336 err = fr_delhtent(iph, &hte);
347 /* ------------------------------------------------------------------------ */
348 /* Function: iplookup_addtable */
349 /* Returns: int - 0 = success, else error */
350 /* Parameters: data(I) - pointer to data from ioctl call */
352 /* Create a new lookup table, if one doesn't already exist using the name */
354 /* ------------------------------------------------------------------------ */
355 static int iplookup_addtable(data)
361 err = BCOPYIN(data, &op, sizeof(op));
365 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
368 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
370 switch (op.iplo_type)
373 if (ip_pool_find(op.iplo_unit, op.iplo_name) != NULL)
376 err = ip_pool_create(&op);
380 if (fr_findhtable(op.iplo_unit, op.iplo_name) != NULL)
383 err = fr_newhtable(&op);
392 * For anonymous pools, copy back the operation struct because in the
393 * case of success it will contain the new table's name.
395 if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
396 err = BCOPYOUT(&op, data, sizeof(op));
405 /* ------------------------------------------------------------------------ */
406 /* Function: iplookup_deltable */
407 /* Returns: int - 0 = success, else error */
408 /* Parameters: data(I) - pointer to data from ioctl call */
410 /* Decodes ioctl request to remove a particular hash table or pool and */
411 /* calls the relevant function to do the cleanup. */
412 /* ------------------------------------------------------------------------ */
413 static int iplookup_deltable(data)
419 err = BCOPYIN(data, &op, sizeof(op));
423 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
426 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
429 * create a new pool - fail if one already exists with
432 switch (op.iplo_type)
435 err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
439 err = fr_removehtable(op.iplo_unit, op.iplo_name);
450 /* ------------------------------------------------------------------------ */
451 /* Function: iplookup_stats */
452 /* Returns: int - 0 = success, else error */
453 /* Parameters: data(I) - pointer to data from ioctl call */
455 /* Copy statistical information from inside the kernel back to user space. */
456 /* ------------------------------------------------------------------------ */
457 static int iplookup_stats(data)
463 err = BCOPYIN(data, &op, sizeof(op));
467 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
470 switch (op.iplo_type)
473 err = ip_pool_statistics(&op);
477 err = fr_gethtablestat(&op);
488 /* ------------------------------------------------------------------------ */
489 /* Function: iplookup_flush */
490 /* Returns: int - 0 = success, else error */
491 /* Parameters: data(I) - pointer to data from ioctl call */
493 /* A flush is called when we want to flush all the nodes from a particular */
494 /* entry in the hash table/pool or want to remove all groups from those. */
495 /* ------------------------------------------------------------------------ */
496 static int iplookup_flush(data)
499 int err, unit, num, type;
500 iplookupflush_t flush;
502 err = BCOPYIN(data, &flush, sizeof(flush));
506 unit = flush.iplf_unit;
507 if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL))
510 flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
512 type = flush.iplf_type;
516 if (type == IPLT_POOL || type == IPLT_ALL) {
518 num = ip_pool_flush(&flush);
521 if (type == IPLT_HASH || type == IPLT_ALL) {
523 num += fr_flushhtable(&flush);
527 flush.iplf_count = num;
528 err = BCOPYOUT(&flush, data, sizeof(flush));
536 /* ------------------------------------------------------------------------ */
537 /* Function: ip_lookup_delref */
539 /* Parameters: type(I) - table type to operate on */
540 /* ptr(I) - pointer to object to remove reference for */
542 /* This function organises calling the correct deref function for a given */
543 /* type of object being passed into it. */
544 /* ------------------------------------------------------------------------ */
545 void ip_lookup_deref(type, ptr)
552 WRITE_ENTER(&ip_poolrw);
563 RWLOCK_EXIT(&ip_poolrw);
567 /* ------------------------------------------------------------------------ */
568 /* Function: iplookup_iterate */
569 /* Returns: int - 0 = success, else error */
570 /* Parameters: data(I) - pointer to data from ioctl call */
571 /* uid(I) - uid of caller */
572 /* ctx(I) - pointer to give the uid context */
574 /* Decodes ioctl request to step through either hash tables or pools. */
575 /* ------------------------------------------------------------------------ */
576 static int iplookup_iterate(data, uid, ctx)
581 ipflookupiter_t iter;
586 err = fr_inobj(data, &iter, IPFOBJ_LOOKUPITER);
590 if (iter.ili_unit > IPL_LOGMAX)
593 if (iter.ili_ival != IPFGENITER_LOOKUP)
597 token = ipf_findtoken(iter.ili_key, uid, ctx);
599 RWLOCK_EXIT(&ipf_tokens);
604 switch (iter.ili_type)
607 err = ip_pool_getnext(token, &iter);
610 err = fr_htable_getnext(token, &iter);
616 RWLOCK_EXIT(&ipf_tokens);
623 /* ------------------------------------------------------------------------ */
624 /* Function: iplookup_iterderef */
625 /* Returns: int - 0 = success, else error */
626 /* Parameters: data(I) - pointer to data from ioctl call */
628 /* Decodes ioctl request to remove a particular hash table or pool and */
629 /* calls the relevant function to do the cleanup. */
630 /* ------------------------------------------------------------------------ */
631 void ip_lookup_iterderef(type, data)
635 iplookupiterkey_t key;
639 if (key.ilik_unstr.ilik_ival != IPFGENITER_LOOKUP)
642 switch (key.ilik_unstr.ilik_type)
645 fr_htable_iterderef((u_int)key.ilik_unstr.ilik_otype,
646 (int)key.ilik_unstr.ilik_unit, data);
649 ip_pool_iterderef((u_int)key.ilik_unstr.ilik_otype,
650 (int)key.ilik_unstr.ilik_unit, data);
656 /* ------------------------------------------------------------------------ */
657 /* Function: iplookup_deltok */
658 /* Returns: int - 0 = success, else error */
659 /* Parameters: data(I) - pointer to data from ioctl call */
660 /* uid(I) - uid of caller */
661 /* ctx(I) - pointer to give the uid context */
663 /* Deletes the token identified by the combination of (type,uid,ctx) */
664 /* "key" is a combination of the table type, iterator type and the unit for */
665 /* which the token was being used. */
666 /* ------------------------------------------------------------------------ */
667 static int iplookup_deltok(data, uid, ctx)
676 error = BCOPYIN(data, &key, sizeof(key));
678 error = ipf_deltoken(key, uid, ctx);
684 #else /* IPFILTER_LOOKUP */
687 int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
695 #endif /* IPFILTER_LOOKUP */