4 * Copyright (C) 2002-2003 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
8 #if defined(KERNEL) || defined(_KERNEL)
15 # define _PROTO_NET_H_
17 #include <sys/param.h>
18 #if defined(__NetBSD__)
19 # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
20 # include "opt_ipfilter.h"
23 #include <sys/errno.h>
24 #include <sys/types.h>
27 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
28 # include <sys/fcntl.h>
29 # include <sys/filio.h>
31 # include <sys/ioctl.h>
42 #include <sys/socket.h>
43 #if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
44 # include "radix_ipf_local.h"
48 #if defined(__FreeBSD__)
49 # include <sys/cdefs.h>
50 # include <sys/proc.h>
53 # include <sys/systm.h>
54 # if !defined(__SVR4) && !defined(__svr4__)
55 # include <sys/mbuf.h>
58 #include <netinet/in.h>
60 #include "netinet/ip_compat.h"
61 #include "netinet/ip_fil.h"
62 #include "netinet/ip_pool.h"
63 #include "netinet/ip_htable.h"
64 #include "netinet/ip_lookup.h"
68 #if defined(__NetBSD__)
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD$");
72 static const char rcsid
[] = "@(#)Id: ip_lookup.c,v 2.35.2.21 2009/05/13 18:31:15 darrenr Exp";
76 #ifdef IPFILTER_LOOKUP
77 int ip_lookup_inited
= 0;
79 static int iplookup_addnode
__P((void *));
80 static int iplookup_delnode
__P((void *data
));
81 static int iplookup_addtable
__P((void *));
82 static int iplookup_deltable
__P((void *));
83 static int iplookup_stats
__P((void *));
84 static int iplookup_flush
__P((void *));
85 static int iplookup_iterate
__P((void *, int, void *));
86 static int iplookup_deltok
__P((void *, int, void *));
89 /* ------------------------------------------------------------------------ */
90 /* Function: iplookup_init */
91 /* Returns: int - 0 = success, else error */
94 /* Initialise all of the subcomponents of the lookup infrstructure. */
95 /* ------------------------------------------------------------------------ */
99 if (ip_pool_init() == -1)
102 RWLOCK_INIT(&ip_poolrw
, "ip pool rwlock");
104 ip_lookup_inited
= 1;
110 /* ------------------------------------------------------------------------ */
111 /* Function: iplookup_unload */
112 /* Returns: int - 0 = success, else error */
113 /* Parameters: Nil */
115 /* Free up all pool related memory that has been allocated whilst IPFilter */
116 /* has been running. Also, do any other deinitialisation required such */
117 /* ip_lookup_init() can be called again, safely. */
118 /* ------------------------------------------------------------------------ */
119 void ip_lookup_unload()
124 if (ip_lookup_inited
== 1) {
125 RW_DESTROY(&ip_poolrw
);
126 ip_lookup_inited
= 0;
131 /* ------------------------------------------------------------------------ */
132 /* Function: iplookup_ioctl */
133 /* Returns: int - 0 = success, else error */
134 /* Parameters: data(IO) - pointer to ioctl data to be copied to/from user */
136 /* cmd(I) - ioctl command number */
137 /* mode(I) - file mode bits used with open */
139 /* Handle ioctl commands sent to the ioctl device. For the most part, this */
140 /* involves just calling another function to handle the specifics of each */
142 /* ------------------------------------------------------------------------ */
143 int ip_lookup_ioctl(data
, cmd
, mode
, uid
, ctx
)
152 mode
= mode
; /* LINT */
158 case SIOCLOOKUPADDNODE
:
159 case SIOCLOOKUPADDNODEW
:
160 WRITE_ENTER(&ip_poolrw
);
161 err
= iplookup_addnode(data
);
162 RWLOCK_EXIT(&ip_poolrw
);
165 case SIOCLOOKUPDELNODE
:
166 case SIOCLOOKUPDELNODEW
:
167 WRITE_ENTER(&ip_poolrw
);
168 err
= iplookup_delnode(data
);
169 RWLOCK_EXIT(&ip_poolrw
);
172 case SIOCLOOKUPADDTABLE
:
173 WRITE_ENTER(&ip_poolrw
);
174 err
= iplookup_addtable(data
);
175 RWLOCK_EXIT(&ip_poolrw
);
178 case SIOCLOOKUPDELTABLE
:
179 WRITE_ENTER(&ip_poolrw
);
180 err
= iplookup_deltable(data
);
181 RWLOCK_EXIT(&ip_poolrw
);
184 case SIOCLOOKUPSTAT
:
185 case SIOCLOOKUPSTATW
:
186 WRITE_ENTER(&ip_poolrw
);
187 err
= iplookup_stats(data
);
188 RWLOCK_EXIT(&ip_poolrw
);
191 case SIOCLOOKUPFLUSH
:
192 WRITE_ENTER(&ip_poolrw
);
193 err
= iplookup_flush(data
);
194 RWLOCK_EXIT(&ip_poolrw
);
197 case SIOCLOOKUPITER
:
198 err
= iplookup_iterate(data
, uid
, ctx
);
202 err
= iplookup_deltok(data
, uid
, ctx
);
214 /* ------------------------------------------------------------------------ */
215 /* Function: iplookup_addnode */
216 /* Returns: int - 0 = success, else error */
217 /* Parameters: data(I) - pointer to data from ioctl call */
219 /* Add a new data node to a lookup structure. First, check to see if the */
220 /* parent structure refered to by name exists and if it does, then go on to */
221 /* add a node to it. */
222 /* ------------------------------------------------------------------------ */
223 static int iplookup_addnode(data
)
226 ip_pool_node_t node
, *m
;
233 err
= BCOPYIN(data
, &op
, sizeof(op
));
237 if (op
.iplo_unit
< 0 || op
.iplo_unit
> IPL_LOGMAX
)
240 op
.iplo_name
[sizeof(op
.iplo_name
) - 1] = '\0';
242 switch (op
.iplo_type
)
245 if (op
.iplo_size
!= sizeof(node
))
248 err
= COPYIN(op
.iplo_struct
, &node
, sizeof(node
));
252 p
= ip_pool_find(op
.iplo_unit
, op
.iplo_name
);
257 * add an entry to a pool - return an error if it already
258 * exists remove an entry from a pool - if it exists
259 * - in both cases, the pool *must* exist!
261 m
= ip_pool_findeq(p
, &node
.ipn_addr
, &node
.ipn_mask
);
264 err
= ip_pool_insert(p
, &node
.ipn_addr
.adf_addr
,
265 &node
.ipn_mask
.adf_addr
, node
.ipn_info
);
269 if (op
.iplo_size
!= sizeof(hte
))
272 err
= COPYIN(op
.iplo_struct
, &hte
, sizeof(hte
));
276 iph
= fr_findhtable(op
.iplo_unit
, op
.iplo_name
);
279 err
= fr_addhtent(iph
, &hte
);
290 /* ------------------------------------------------------------------------ */
291 /* Function: iplookup_delnode */
292 /* Returns: int - 0 = success, else error */
293 /* Parameters: data(I) - pointer to data from ioctl call */
295 /* Delete a node from a lookup table by first looking for the table it is */
296 /* in and then deleting the entry that gets found. */
297 /* ------------------------------------------------------------------------ */
298 static int iplookup_delnode(data
)
301 ip_pool_node_t node
, *m
;
308 err
= BCOPYIN(data
, &op
, sizeof(op
));
312 if (op
.iplo_unit
< 0 || op
.iplo_unit
> IPL_LOGMAX
)
315 op
.iplo_name
[sizeof(op
.iplo_name
) - 1] = '\0';
317 switch (op
.iplo_type
)
320 if (op
.iplo_size
!= sizeof(node
))
323 err
= COPYIN(op
.iplo_struct
, &node
, sizeof(node
));
327 p
= ip_pool_find(op
.iplo_unit
, op
.iplo_name
);
331 m
= ip_pool_findeq(p
, &node
.ipn_addr
, &node
.ipn_mask
);
334 err
= ip_pool_remove(p
, m
);
338 if (op
.iplo_size
!= sizeof(hte
))
341 err
= COPYIN(op
.iplo_struct
, &hte
, sizeof(hte
));
345 iph
= fr_findhtable(op
.iplo_unit
, op
.iplo_name
);
348 err
= fr_delhtent(iph
, &hte
);
359 /* ------------------------------------------------------------------------ */
360 /* Function: iplookup_addtable */
361 /* Returns: int - 0 = success, else error */
362 /* Parameters: data(I) - pointer to data from ioctl call */
364 /* Create a new lookup table, if one doesn't already exist using the name */
366 /* ------------------------------------------------------------------------ */
367 static int iplookup_addtable(data
)
373 err
= BCOPYIN(data
, &op
, sizeof(op
));
377 if (op
.iplo_unit
< 0 || op
.iplo_unit
> IPL_LOGMAX
)
380 op
.iplo_name
[sizeof(op
.iplo_name
) - 1] = '\0';
382 switch (op
.iplo_type
)
385 if (ip_pool_find(op
.iplo_unit
, op
.iplo_name
) != NULL
)
388 err
= ip_pool_create(&op
);
392 if (fr_findhtable(op
.iplo_unit
, op
.iplo_name
) != NULL
)
395 err
= fr_newhtable(&op
);
404 * For anonymous pools, copy back the operation struct because in the
405 * case of success it will contain the new table's name.
407 if ((err
== 0) && ((op
.iplo_arg
& LOOKUP_ANON
) != 0)) {
408 err
= BCOPYOUT(&op
, data
, sizeof(op
));
417 /* ------------------------------------------------------------------------ */
418 /* Function: iplookup_deltable */
419 /* Returns: int - 0 = success, else error */
420 /* Parameters: data(I) - pointer to data from ioctl call */
422 /* Decodes ioctl request to remove a particular hash table or pool and */
423 /* calls the relevant function to do the cleanup. */
424 /* ------------------------------------------------------------------------ */
425 static int iplookup_deltable(data
)
431 err
= BCOPYIN(data
, &op
, sizeof(op
));
435 if (op
.iplo_unit
< 0 || op
.iplo_unit
> IPL_LOGMAX
)
438 op
.iplo_name
[sizeof(op
.iplo_name
) - 1] = '\0';
441 * create a new pool - fail if one already exists with
444 switch (op
.iplo_type
)
447 err
= ip_pool_destroy(op
.iplo_unit
, op
.iplo_name
);
451 err
= fr_removehtable(op
.iplo_unit
, op
.iplo_name
);
462 /* ------------------------------------------------------------------------ */
463 /* Function: iplookup_stats */
464 /* Returns: int - 0 = success, else error */
465 /* Parameters: data(I) - pointer to data from ioctl call */
467 /* Copy statistical information from inside the kernel back to user space. */
468 /* ------------------------------------------------------------------------ */
469 static int iplookup_stats(data
)
475 err
= BCOPYIN(data
, &op
, sizeof(op
));
479 if (op
.iplo_unit
< 0 || op
.iplo_unit
> IPL_LOGMAX
)
482 switch (op
.iplo_type
)
485 err
= ip_pool_statistics(&op
);
489 err
= fr_gethtablestat(&op
);
500 /* ------------------------------------------------------------------------ */
501 /* Function: iplookup_flush */
502 /* Returns: int - 0 = success, else error */
503 /* Parameters: data(I) - pointer to data from ioctl call */
505 /* A flush is called when we want to flush all the nodes from a particular */
506 /* entry in the hash table/pool or want to remove all groups from those. */
507 /* ------------------------------------------------------------------------ */
508 static int iplookup_flush(data
)
511 int err
, unit
, num
, type
;
512 iplookupflush_t flush
;
514 err
= BCOPYIN(data
, &flush
, sizeof(flush
));
518 unit
= flush
.iplf_unit
;
519 if ((unit
< 0 || unit
> IPL_LOGMAX
) && (unit
!= IPLT_ALL
))
522 flush
.iplf_name
[sizeof(flush
.iplf_name
) - 1] = '\0';
524 type
= flush
.iplf_type
;
528 if (type
== IPLT_POOL
|| type
== IPLT_ALL
) {
530 num
= ip_pool_flush(&flush
);
533 if (type
== IPLT_HASH
|| type
== IPLT_ALL
) {
535 num
+= fr_flushhtable(&flush
);
539 flush
.iplf_count
= num
;
540 err
= BCOPYOUT(&flush
, data
, sizeof(flush
));
548 /* ------------------------------------------------------------------------ */
549 /* Function: ip_lookup_delref */
551 /* Parameters: type(I) - table type to operate on */
552 /* ptr(I) - pointer to object to remove reference for */
554 /* This function organises calling the correct deref function for a given */
555 /* type of object being passed into it. */
556 /* ------------------------------------------------------------------------ */
557 void ip_lookup_deref(type
, ptr
)
564 WRITE_ENTER(&ip_poolrw
);
575 RWLOCK_EXIT(&ip_poolrw
);
579 /* ------------------------------------------------------------------------ */
580 /* Function: iplookup_iterate */
581 /* Returns: int - 0 = success, else error */
582 /* Parameters: data(I) - pointer to data from ioctl call */
583 /* uid(I) - uid of caller */
584 /* ctx(I) - pointer to give the uid context */
586 /* Decodes ioctl request to step through either hash tables or pools. */
587 /* ------------------------------------------------------------------------ */
588 static int iplookup_iterate(data
, uid
, ctx
)
593 ipflookupiter_t iter
;
598 err
= fr_inobj(data
, &iter
, IPFOBJ_LOOKUPITER
);
602 if (iter
.ili_unit
> IPL_LOGMAX
)
605 if (iter
.ili_ival
!= IPFGENITER_LOOKUP
)
609 token
= ipf_findtoken(iter
.ili_key
, uid
, ctx
);
611 RWLOCK_EXIT(&ipf_tokens
);
616 switch (iter
.ili_type
)
619 err
= ip_pool_getnext(token
, &iter
);
622 err
= fr_htable_getnext(token
, &iter
);
629 WRITE_ENTER(&ipf_tokens
);
630 ipf_dereftoken(token
);
631 RWLOCK_EXIT(&ipf_tokens
);
638 /* ------------------------------------------------------------------------ */
639 /* Function: iplookup_iterderef */
640 /* Returns: int - 0 = success, else error */
641 /* Parameters: data(I) - pointer to data from ioctl call */
643 /* Decodes ioctl request to remove a particular hash table or pool and */
644 /* calls the relevant function to do the cleanup. */
645 /* ------------------------------------------------------------------------ */
646 void ip_lookup_iterderef(type
, data
)
650 iplookupiterkey_t key
;
654 if (key
.ilik_unstr
.ilik_ival
!= IPFGENITER_LOOKUP
)
657 switch (key
.ilik_unstr
.ilik_type
)
660 fr_htable_iterderef((u_int
)key
.ilik_unstr
.ilik_otype
,
661 (int)key
.ilik_unstr
.ilik_unit
, data
);
664 ip_pool_iterderef((u_int
)key
.ilik_unstr
.ilik_otype
,
665 (int)key
.ilik_unstr
.ilik_unit
, data
);
671 /* ------------------------------------------------------------------------ */
672 /* Function: iplookup_deltok */
673 /* Returns: int - 0 = success, else error */
674 /* Parameters: data(I) - pointer to data from ioctl call */
675 /* uid(I) - uid of caller */
676 /* ctx(I) - pointer to give the uid context */
678 /* Deletes the token identified by the combination of (type,uid,ctx) */
679 /* "key" is a combination of the table type, iterator type and the unit for */
680 /* which the token was being used. */
681 /* ------------------------------------------------------------------------ */
682 static int iplookup_deltok(data
, uid
, ctx
)
691 error
= BCOPYIN(data
, &key
, sizeof(key
));
693 error
= ipf_deltoken(key
, uid
, ctx
);
699 #else /* IPFILTER_LOOKUP */
702 int ip_lookup_ioctl(data
, cmd
, mode
, uid
, ctx
)
710 #endif /* IPFILTER_LOOKUP */