snj doesn't like my accent, so use proper English month names.
[netbsd-mini2440.git] / dist / ipf / ip_lookup.c
blobdceb9c1c6970c1b9a1f6b2038a87efe845108e81
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2002-2003 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef _KERNEL
11 # define KERNEL 1
12 # define _KERNEL 1
13 #endif
14 #if defined(__osf__)
15 # define _PROTO_NET_H_
16 #endif
17 #include <sys/param.h>
18 #include <sys/errno.h>
19 #include <sys/types.h>
20 #include <sys/time.h>
21 #include <sys/file.h>
22 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
23 # include <sys/fcntl.h>
24 # include <sys/filio.h>
25 #else
26 # include <sys/ioctl.h>
27 #endif
28 #if !defined(_KERNEL)
29 # include <string.h>
30 # define _KERNEL
31 # ifdef __OpenBSD__
32 struct file;
33 # endif
34 # include <sys/uio.h>
35 # undef _KERNEL
36 #endif
37 #include <sys/socket.h>
38 #if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
39 # include "radix_ipf_local.h"
40 # define _RADIX_H_
41 #endif
42 #include <net/if.h>
43 #if defined(__FreeBSD__)
44 # include <sys/cdefs.h>
45 # include <sys/proc.h>
46 #endif
47 #if defined(_KERNEL)
48 # include <sys/systm.h>
49 # if !defined(__SVR4) && !defined(__svr4__)
50 # include <sys/mbuf.h>
51 # endif
52 #endif
53 #include <netinet/in.h>
55 #include "netinet/ip_compat.h"
56 #include "netinet/ip_fil.h"
57 #include "netinet/ip_pool.h"
58 #include "netinet/ip_htable.h"
59 #include "netinet/ip_lookup.h"
60 /* END OF INCLUDES */
62 #if !defined(lint)
63 static const char rcsid[] = "@(#)Id: ip_lookup.c,v 2.35.2.21 2009/05/13 18:31:15 darrenr Exp";
64 #endif
66 #ifdef IPFILTER_LOOKUP
67 int ip_lookup_inited = 0;
69 static int iplookup_addnode __P((caddr_t));
70 static int iplookup_delnode __P((caddr_t data));
71 static int iplookup_addtable __P((caddr_t));
72 static int iplookup_deltable __P((caddr_t));
73 static int iplookup_stats __P((caddr_t));
74 static int iplookup_flush __P((caddr_t));
75 static int iplookup_iterate __P((void *, int, void *));
76 static int iplookup_deltok __P((void *, int, void *));
79 /* ------------------------------------------------------------------------ */
80 /* Function: iplookup_init */
81 /* Returns: int - 0 = success, else error */
82 /* Parameters: Nil */
83 /* */
84 /* Initialise all of the subcomponents of the lookup infrstructure. */
85 /* ------------------------------------------------------------------------ */
86 int ip_lookup_init()
89 if (ip_pool_init() == -1)
90 return -1;
92 RWLOCK_INIT(&ip_poolrw, "ip pool rwlock");
94 ip_lookup_inited = 1;
96 return 0;
100 /* ------------------------------------------------------------------------ */
101 /* Function: iplookup_unload */
102 /* Returns: int - 0 = success, else error */
103 /* Parameters: Nil */
104 /* */
105 /* Free up all pool related memory that has been allocated whilst IPFilter */
106 /* has been running. Also, do any other deinitialisation required such */
107 /* ip_lookup_init() can be called again, safely. */
108 /* ------------------------------------------------------------------------ */
109 void ip_lookup_unload()
111 ip_pool_fini();
112 fr_htable_unload();
114 if (ip_lookup_inited == 1) {
115 RW_DESTROY(&ip_poolrw);
116 ip_lookup_inited = 0;
121 /* ------------------------------------------------------------------------ */
122 /* Function: iplookup_ioctl */
123 /* Returns: int - 0 = success, else error */
124 /* Parameters: data(IO) - pointer to ioctl data to be copied to/from user */
125 /* space. */
126 /* cmd(I) - ioctl command number */
127 /* mode(I) - file mode bits used with open */
128 /* */
129 /* Handle ioctl commands sent to the ioctl device. For the most part, this */
130 /* involves just calling another function to handle the specifics of each */
131 /* command. */
132 /* ------------------------------------------------------------------------ */
133 int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
134 caddr_t data;
135 ioctlcmd_t cmd;
136 int mode, uid;
137 void *ctx;
139 int err;
140 SPL_INT(s);
142 mode = mode; /* LINT */
144 SPL_NET(s);
146 switch (cmd)
148 case SIOCLOOKUPADDNODE :
149 case SIOCLOOKUPADDNODEW :
150 WRITE_ENTER(&ip_poolrw);
151 err = iplookup_addnode(data);
152 RWLOCK_EXIT(&ip_poolrw);
153 break;
155 case SIOCLOOKUPDELNODE :
156 case SIOCLOOKUPDELNODEW :
157 WRITE_ENTER(&ip_poolrw);
158 err = iplookup_delnode(data);
159 RWLOCK_EXIT(&ip_poolrw);
160 break;
162 case SIOCLOOKUPADDTABLE :
163 WRITE_ENTER(&ip_poolrw);
164 err = iplookup_addtable(data);
165 RWLOCK_EXIT(&ip_poolrw);
166 break;
168 case SIOCLOOKUPDELTABLE :
169 WRITE_ENTER(&ip_poolrw);
170 err = iplookup_deltable(data);
171 RWLOCK_EXIT(&ip_poolrw);
172 break;
174 case SIOCLOOKUPSTAT :
175 case SIOCLOOKUPSTATW :
176 WRITE_ENTER(&ip_poolrw);
177 err = iplookup_stats(data);
178 RWLOCK_EXIT(&ip_poolrw);
179 break;
181 case SIOCLOOKUPFLUSH :
182 WRITE_ENTER(&ip_poolrw);
183 err = iplookup_flush(data);
184 RWLOCK_EXIT(&ip_poolrw);
185 break;
187 case SIOCLOOKUPITER :
188 err = iplookup_iterate(data, uid, ctx);
189 break;
191 case SIOCIPFDELTOK :
192 err = iplookup_deltok(data, uid, ctx);
193 break;
195 default :
196 err = EINVAL;
197 break;
199 SPL_X(s);
200 return err;
204 /* ------------------------------------------------------------------------ */
205 /* Function: iplookup_addnode */
206 /* Returns: int - 0 = success, else error */
207 /* Parameters: data(I) - pointer to data from ioctl call */
208 /* */
209 /* Add a new data node to a lookup structure. First, check to see if the */
210 /* parent structure refered to by name exists and if it does, then go on to */
211 /* add a node to it. */
212 /* ------------------------------------------------------------------------ */
213 static int iplookup_addnode(data)
214 caddr_t data;
216 ip_pool_node_t node, *m;
217 iplookupop_t op;
218 iphtable_t *iph;
219 iphtent_t hte;
220 ip_pool_t *p;
221 int err;
223 err = BCOPYIN(data, &op, sizeof(op));
224 if (err != 0)
225 return EFAULT;
227 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
228 return EINVAL;
230 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
232 switch (op.iplo_type)
234 case IPLT_POOL :
235 if (op.iplo_size != sizeof(node))
236 return EINVAL;
238 err = COPYIN(op.iplo_struct, &node, sizeof(node));
239 if (err != 0)
240 return EFAULT;
242 p = ip_pool_find(op.iplo_unit, op.iplo_name);
243 if (p == NULL)
244 return ESRCH;
247 * add an entry to a pool - return an error if it already
248 * exists remove an entry from a pool - if it exists
249 * - in both cases, the pool *must* exist!
251 m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
252 if (m)
253 return EEXIST;
254 err = ip_pool_insert(p, &node.ipn_addr.adf_addr,
255 &node.ipn_mask.adf_addr, node.ipn_info);
256 break;
258 case IPLT_HASH :
259 if (op.iplo_size != sizeof(hte))
260 return EINVAL;
262 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
263 if (err != 0)
264 return EFAULT;
266 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
267 if (iph == NULL)
268 return ESRCH;
269 err = fr_addhtent(iph, &hte);
270 break;
272 default :
273 err = EINVAL;
274 break;
276 return err;
280 /* ------------------------------------------------------------------------ */
281 /* Function: iplookup_delnode */
282 /* Returns: int - 0 = success, else error */
283 /* Parameters: data(I) - pointer to data from ioctl call */
284 /* */
285 /* Delete a node from a lookup table by first looking for the table it is */
286 /* in and then deleting the entry that gets found. */
287 /* ------------------------------------------------------------------------ */
288 static int iplookup_delnode(data)
289 caddr_t data;
291 ip_pool_node_t node, *m;
292 iplookupop_t op;
293 iphtable_t *iph;
294 iphtent_t hte;
295 ip_pool_t *p;
296 int err;
298 err = BCOPYIN(data, &op, sizeof(op));
299 if (err != 0)
300 return EFAULT;
302 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
303 return EINVAL;
305 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
307 switch (op.iplo_type)
309 case IPLT_POOL :
310 if (op.iplo_size != sizeof(node))
311 return EINVAL;
313 err = COPYIN(op.iplo_struct, &node, sizeof(node));
314 if (err != 0)
315 return EFAULT;
317 p = ip_pool_find(op.iplo_unit, op.iplo_name);
318 if (!p)
319 return ESRCH;
321 m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
322 if (m == NULL)
323 return ENOENT;
324 err = ip_pool_remove(p, m);
325 break;
327 case IPLT_HASH :
328 if (op.iplo_size != sizeof(hte))
329 return EINVAL;
331 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
332 if (err != 0)
333 return EFAULT;
335 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
336 if (iph == NULL)
337 return ESRCH;
338 err = fr_delhtent(iph, &hte);
339 break;
341 default :
342 err = EINVAL;
343 break;
345 return err;
349 /* ------------------------------------------------------------------------ */
350 /* Function: iplookup_addtable */
351 /* Returns: int - 0 = success, else error */
352 /* Parameters: data(I) - pointer to data from ioctl call */
353 /* */
354 /* Create a new lookup table, if one doesn't already exist using the name */
355 /* for this one. */
356 /* ------------------------------------------------------------------------ */
357 static int iplookup_addtable(data)
358 caddr_t data;
360 iplookupop_t op;
361 int err;
363 err = BCOPYIN(data, &op, sizeof(op));
364 if (err != 0)
365 return EFAULT;
367 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
368 return EINVAL;
370 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
372 switch (op.iplo_type)
374 case IPLT_POOL :
375 if (ip_pool_find(op.iplo_unit, op.iplo_name) != NULL)
376 err = EEXIST;
377 else
378 err = ip_pool_create(&op);
379 break;
381 case IPLT_HASH :
382 if (fr_findhtable(op.iplo_unit, op.iplo_name) != NULL)
383 err = EEXIST;
384 else
385 err = fr_newhtable(&op);
386 break;
388 default :
389 err = EINVAL;
390 break;
394 * For anonymous pools, copy back the operation struct because in the
395 * case of success it will contain the new table's name.
397 if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
398 err = BCOPYOUT(&op, data, sizeof(op));
399 if (err != 0)
400 err = EFAULT;
403 return err;
407 /* ------------------------------------------------------------------------ */
408 /* Function: iplookup_deltable */
409 /* Returns: int - 0 = success, else error */
410 /* Parameters: data(I) - pointer to data from ioctl call */
411 /* */
412 /* Decodes ioctl request to remove a particular hash table or pool and */
413 /* calls the relevant function to do the cleanup. */
414 /* ------------------------------------------------------------------------ */
415 static int iplookup_deltable(data)
416 caddr_t data;
418 iplookupop_t op;
419 int err;
421 err = BCOPYIN(data, &op, sizeof(op));
422 if (err != 0)
423 return EFAULT;
425 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
426 return EINVAL;
428 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
431 * create a new pool - fail if one already exists with
432 * the same #
434 switch (op.iplo_type)
436 case IPLT_POOL :
437 err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
438 break;
440 case IPLT_HASH :
441 err = fr_removehtable(op.iplo_unit, op.iplo_name);
442 break;
444 default :
445 err = EINVAL;
446 break;
448 return err;
452 /* ------------------------------------------------------------------------ */
453 /* Function: iplookup_stats */
454 /* Returns: int - 0 = success, else error */
455 /* Parameters: data(I) - pointer to data from ioctl call */
456 /* */
457 /* Copy statistical information from inside the kernel back to user space. */
458 /* ------------------------------------------------------------------------ */
459 static int iplookup_stats(data)
460 caddr_t data;
462 iplookupop_t op;
463 int err;
465 err = BCOPYIN(data, &op, sizeof(op));
466 if (err != 0)
467 return EFAULT;
469 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
470 return EINVAL;
472 switch (op.iplo_type)
474 case IPLT_POOL :
475 err = ip_pool_statistics(&op);
476 break;
478 case IPLT_HASH :
479 err = fr_gethtablestat(&op);
480 break;
482 default :
483 err = EINVAL;
484 break;
486 return err;
490 /* ------------------------------------------------------------------------ */
491 /* Function: iplookup_flush */
492 /* Returns: int - 0 = success, else error */
493 /* Parameters: data(I) - pointer to data from ioctl call */
494 /* */
495 /* A flush is called when we want to flush all the nodes from a particular */
496 /* entry in the hash table/pool or want to remove all groups from those. */
497 /* ------------------------------------------------------------------------ */
498 static int iplookup_flush(data)
499 caddr_t data;
501 int err, unit, num, type;
502 iplookupflush_t flush;
504 err = BCOPYIN(data, &flush, sizeof(flush));
505 if (err != 0)
506 return EFAULT;
508 unit = flush.iplf_unit;
509 if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL))
510 return EINVAL;
512 flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
514 type = flush.iplf_type;
515 err = EINVAL;
516 num = 0;
518 if (type == IPLT_POOL || type == IPLT_ALL) {
519 err = 0;
520 num = ip_pool_flush(&flush);
523 if (type == IPLT_HASH || type == IPLT_ALL) {
524 err = 0;
525 num += fr_flushhtable(&flush);
528 if (err == 0) {
529 flush.iplf_count = num;
530 err = BCOPYOUT(&flush, data, sizeof(flush));
531 if (err != 0)
532 err = EFAULT;
534 return err;
538 /* ------------------------------------------------------------------------ */
539 /* Function: ip_lookup_delref */
540 /* Returns: void */
541 /* Parameters: type(I) - table type to operate on */
542 /* ptr(I) - pointer to object to remove reference for */
543 /* */
544 /* This function organises calling the correct deref function for a given */
545 /* type of object being passed into it. */
546 /* ------------------------------------------------------------------------ */
547 void ip_lookup_deref(type, ptr)
548 int type;
549 void *ptr;
551 if (ptr == NULL)
552 return;
554 WRITE_ENTER(&ip_poolrw);
555 switch (type)
557 case IPLT_POOL :
558 ip_pool_deref(ptr);
559 break;
561 case IPLT_HASH :
562 fr_derefhtable(ptr);
563 break;
565 RWLOCK_EXIT(&ip_poolrw);
569 /* ------------------------------------------------------------------------ */
570 /* Function: iplookup_iterate */
571 /* Returns: int - 0 = success, else error */
572 /* Parameters: data(I) - pointer to data from ioctl call */
573 /* uid(I) - uid of caller */
574 /* ctx(I) - pointer to give the uid context */
575 /* */
576 /* Decodes ioctl request to step through either hash tables or pools. */
577 /* ------------------------------------------------------------------------ */
578 static int iplookup_iterate(data, uid, ctx)
579 void *data;
580 int uid;
581 void *ctx;
583 ipflookupiter_t iter;
584 ipftoken_t *token;
585 int err;
586 SPL_INT(s);
588 err = fr_inobj(data, &iter, IPFOBJ_LOOKUPITER);
589 if (err != 0)
590 return err;
592 if (iter.ili_unit > IPL_LOGMAX)
593 return EINVAL;
595 if (iter.ili_ival != IPFGENITER_LOOKUP)
596 return EINVAL;
598 SPL_SCHED(s);
599 token = ipf_findtoken(iter.ili_key, uid, ctx);
600 if (token == NULL) {
601 RWLOCK_EXIT(&ipf_tokens);
602 SPL_X(s);
603 return ESRCH;
606 switch (iter.ili_type)
608 case IPLT_POOL :
609 err = ip_pool_getnext(token, &iter);
610 break;
611 case IPLT_HASH :
612 err = fr_htable_getnext(token, &iter);
613 break;
614 default :
615 err = EINVAL;
616 break;
619 WRITE_ENTER(&ipf_tokens);
620 ipf_dereftoken(token);
621 RWLOCK_EXIT(&ipf_tokens);
622 SPL_X(s);
624 return err;
628 /* ------------------------------------------------------------------------ */
629 /* Function: iplookup_iterderef */
630 /* Returns: int - 0 = success, else error */
631 /* Parameters: data(I) - pointer to data from ioctl call */
632 /* */
633 /* Decodes ioctl request to remove a particular hash table or pool and */
634 /* calls the relevant function to do the cleanup. */
635 /* ------------------------------------------------------------------------ */
636 void ip_lookup_iterderef(type, data)
637 u_32_t type;
638 void *data;
640 iplookupiterkey_t key;
642 key.ilik_key = type;
644 if (key.ilik_unstr.ilik_ival != IPFGENITER_LOOKUP)
645 return;
647 switch (key.ilik_unstr.ilik_type)
649 case IPLT_HASH :
650 fr_htable_iterderef((u_int)key.ilik_unstr.ilik_otype,
651 (int)key.ilik_unstr.ilik_unit, data);
652 break;
653 case IPLT_POOL :
654 ip_pool_iterderef((u_int)key.ilik_unstr.ilik_otype,
655 (int)key.ilik_unstr.ilik_unit, data);
656 break;
661 /* ------------------------------------------------------------------------ */
662 /* Function: iplookup_deltok */
663 /* Returns: int - 0 = success, else error */
664 /* Parameters: data(I) - pointer to data from ioctl call */
665 /* uid(I) - uid of caller */
666 /* ctx(I) - pointer to give the uid context */
667 /* */
668 /* Deletes the token identified by the combination of (type,uid,ctx) */
669 /* "key" is a combination of the table type, iterator type and the unit for */
670 /* which the token was being used. */
671 /* ------------------------------------------------------------------------ */
672 static int iplookup_deltok(data, uid, ctx)
673 void *data;
674 int uid;
675 void *ctx;
677 int error, key;
678 SPL_INT(s);
680 SPL_SCHED(s);
681 error = BCOPYIN(data, &key, sizeof(key));
682 if (error == 0)
683 error = ipf_deltoken(key, uid, ctx);
684 SPL_X(s);
685 return error;
689 #else /* IPFILTER_LOOKUP */
691 /*ARGSUSED*/
692 int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
693 caddr_t data;
694 ioctlcmd_t cmd;
695 int mode, uid;
696 void *ctx;
698 return EIO;
700 #endif /* IPFILTER_LOOKUP */