Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dist / ipf / netinet / ip_lookup.c
blobd725451a80d33ccdfbf0108a706a4c0bfc34a9c6
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 #if defined(__NetBSD__)
19 # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
20 # include "opt_ipfilter.h"
21 # endif
22 #endif
23 #include <sys/errno.h>
24 #include <sys/types.h>
25 #include <sys/time.h>
26 #include <sys/file.h>
27 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
28 # include <sys/fcntl.h>
29 # include <sys/filio.h>
30 #else
31 # include <sys/ioctl.h>
32 #endif
33 #if !defined(_KERNEL)
34 # include <string.h>
35 # define _KERNEL
36 # ifdef __OpenBSD__
37 struct file;
38 # endif
39 # include <sys/uio.h>
40 # undef _KERNEL
41 #endif
42 #include <sys/socket.h>
43 #if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
44 # include "radix_ipf_local.h"
45 # define _RADIX_H_
46 #endif
47 #include <net/if.h>
48 #if defined(__FreeBSD__)
49 # include <sys/cdefs.h>
50 # include <sys/proc.h>
51 #endif
52 #if defined(_KERNEL)
53 # include <sys/systm.h>
54 # if !defined(__SVR4) && !defined(__svr4__)
55 # include <sys/mbuf.h>
56 # endif
57 #endif
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"
65 /* END OF INCLUDES */
67 #if !defined(lint)
68 #if defined(__NetBSD__)
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD$");
71 #else
72 static const char rcsid[] = "@(#)Id: ip_lookup.c,v 2.35.2.21 2009/05/13 18:31:15 darrenr Exp";
73 #endif
74 #endif
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 */
92 /* Parameters: Nil */
93 /* */
94 /* Initialise all of the subcomponents of the lookup infrstructure. */
95 /* ------------------------------------------------------------------------ */
96 int ip_lookup_init()
99 if (ip_pool_init() == -1)
100 return -1;
102 RWLOCK_INIT(&ip_poolrw, "ip pool rwlock");
104 ip_lookup_inited = 1;
106 return 0;
110 /* ------------------------------------------------------------------------ */
111 /* Function: iplookup_unload */
112 /* Returns: int - 0 = success, else error */
113 /* Parameters: Nil */
114 /* */
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()
121 ip_pool_fini();
122 fr_htable_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 */
135 /* space. */
136 /* cmd(I) - ioctl command number */
137 /* mode(I) - file mode bits used with open */
138 /* */
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 */
141 /* command. */
142 /* ------------------------------------------------------------------------ */
143 int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
144 void * data;
145 ioctlcmd_t cmd;
146 int mode, uid;
147 void *ctx;
149 int err;
150 SPL_INT(s);
152 mode = mode; /* LINT */
154 SPL_NET(s);
156 switch (cmd)
158 case SIOCLOOKUPADDNODE :
159 case SIOCLOOKUPADDNODEW :
160 WRITE_ENTER(&ip_poolrw);
161 err = iplookup_addnode(data);
162 RWLOCK_EXIT(&ip_poolrw);
163 break;
165 case SIOCLOOKUPDELNODE :
166 case SIOCLOOKUPDELNODEW :
167 WRITE_ENTER(&ip_poolrw);
168 err = iplookup_delnode(data);
169 RWLOCK_EXIT(&ip_poolrw);
170 break;
172 case SIOCLOOKUPADDTABLE :
173 WRITE_ENTER(&ip_poolrw);
174 err = iplookup_addtable(data);
175 RWLOCK_EXIT(&ip_poolrw);
176 break;
178 case SIOCLOOKUPDELTABLE :
179 WRITE_ENTER(&ip_poolrw);
180 err = iplookup_deltable(data);
181 RWLOCK_EXIT(&ip_poolrw);
182 break;
184 case SIOCLOOKUPSTAT :
185 case SIOCLOOKUPSTATW :
186 WRITE_ENTER(&ip_poolrw);
187 err = iplookup_stats(data);
188 RWLOCK_EXIT(&ip_poolrw);
189 break;
191 case SIOCLOOKUPFLUSH :
192 WRITE_ENTER(&ip_poolrw);
193 err = iplookup_flush(data);
194 RWLOCK_EXIT(&ip_poolrw);
195 break;
197 case SIOCLOOKUPITER :
198 err = iplookup_iterate(data, uid, ctx);
199 break;
201 case SIOCIPFDELTOK :
202 err = iplookup_deltok(data, uid, ctx);
203 break;
205 default :
206 err = EINVAL;
207 break;
209 SPL_X(s);
210 return err;
214 /* ------------------------------------------------------------------------ */
215 /* Function: iplookup_addnode */
216 /* Returns: int - 0 = success, else error */
217 /* Parameters: data(I) - pointer to data from ioctl call */
218 /* */
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)
224 void *data;
226 ip_pool_node_t node, *m;
227 iplookupop_t op;
228 iphtable_t *iph;
229 iphtent_t hte;
230 ip_pool_t *p;
231 int err;
233 err = BCOPYIN(data, &op, sizeof(op));
234 if (err != 0)
235 return EFAULT;
237 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
238 return EINVAL;
240 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
242 switch (op.iplo_type)
244 case IPLT_POOL :
245 if (op.iplo_size != sizeof(node))
246 return EINVAL;
248 err = COPYIN(op.iplo_struct, &node, sizeof(node));
249 if (err != 0)
250 return EFAULT;
252 p = ip_pool_find(op.iplo_unit, op.iplo_name);
253 if (p == NULL)
254 return ESRCH;
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);
262 if (m)
263 return EEXIST;
264 err = ip_pool_insert(p, &node.ipn_addr.adf_addr,
265 &node.ipn_mask.adf_addr, node.ipn_info);
266 break;
268 case IPLT_HASH :
269 if (op.iplo_size != sizeof(hte))
270 return EINVAL;
272 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
273 if (err != 0)
274 return EFAULT;
276 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
277 if (iph == NULL)
278 return ESRCH;
279 err = fr_addhtent(iph, &hte);
280 break;
282 default :
283 err = EINVAL;
284 break;
286 return err;
290 /* ------------------------------------------------------------------------ */
291 /* Function: iplookup_delnode */
292 /* Returns: int - 0 = success, else error */
293 /* Parameters: data(I) - pointer to data from ioctl call */
294 /* */
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)
299 void *data;
301 ip_pool_node_t node, *m;
302 iplookupop_t op;
303 iphtable_t *iph;
304 iphtent_t hte;
305 ip_pool_t *p;
306 int err;
308 err = BCOPYIN(data, &op, sizeof(op));
309 if (err != 0)
310 return EFAULT;
312 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
313 return EINVAL;
315 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
317 switch (op.iplo_type)
319 case IPLT_POOL :
320 if (op.iplo_size != sizeof(node))
321 return EINVAL;
323 err = COPYIN(op.iplo_struct, &node, sizeof(node));
324 if (err != 0)
325 return EFAULT;
327 p = ip_pool_find(op.iplo_unit, op.iplo_name);
328 if (!p)
329 return ESRCH;
331 m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
332 if (m == NULL)
333 return ENOENT;
334 err = ip_pool_remove(p, m);
335 break;
337 case IPLT_HASH :
338 if (op.iplo_size != sizeof(hte))
339 return EINVAL;
341 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
342 if (err != 0)
343 return EFAULT;
345 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
346 if (iph == NULL)
347 return ESRCH;
348 err = fr_delhtent(iph, &hte);
349 break;
351 default :
352 err = EINVAL;
353 break;
355 return err;
359 /* ------------------------------------------------------------------------ */
360 /* Function: iplookup_addtable */
361 /* Returns: int - 0 = success, else error */
362 /* Parameters: data(I) - pointer to data from ioctl call */
363 /* */
364 /* Create a new lookup table, if one doesn't already exist using the name */
365 /* for this one. */
366 /* ------------------------------------------------------------------------ */
367 static int iplookup_addtable(data)
368 void *data;
370 iplookupop_t op;
371 int err;
373 err = BCOPYIN(data, &op, sizeof(op));
374 if (err != 0)
375 return EFAULT;
377 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
378 return EINVAL;
380 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
382 switch (op.iplo_type)
384 case IPLT_POOL :
385 if (ip_pool_find(op.iplo_unit, op.iplo_name) != NULL)
386 err = EEXIST;
387 else
388 err = ip_pool_create(&op);
389 break;
391 case IPLT_HASH :
392 if (fr_findhtable(op.iplo_unit, op.iplo_name) != NULL)
393 err = EEXIST;
394 else
395 err = fr_newhtable(&op);
396 break;
398 default :
399 err = EINVAL;
400 break;
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));
409 if (err != 0)
410 err = EFAULT;
413 return err;
417 /* ------------------------------------------------------------------------ */
418 /* Function: iplookup_deltable */
419 /* Returns: int - 0 = success, else error */
420 /* Parameters: data(I) - pointer to data from ioctl call */
421 /* */
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)
426 void *data;
428 iplookupop_t op;
429 int err;
431 err = BCOPYIN(data, &op, sizeof(op));
432 if (err != 0)
433 return EFAULT;
435 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
436 return EINVAL;
438 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
441 * create a new pool - fail if one already exists with
442 * the same #
444 switch (op.iplo_type)
446 case IPLT_POOL :
447 err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
448 break;
450 case IPLT_HASH :
451 err = fr_removehtable(op.iplo_unit, op.iplo_name);
452 break;
454 default :
455 err = EINVAL;
456 break;
458 return err;
462 /* ------------------------------------------------------------------------ */
463 /* Function: iplookup_stats */
464 /* Returns: int - 0 = success, else error */
465 /* Parameters: data(I) - pointer to data from ioctl call */
466 /* */
467 /* Copy statistical information from inside the kernel back to user space. */
468 /* ------------------------------------------------------------------------ */
469 static int iplookup_stats(data)
470 void *data;
472 iplookupop_t op;
473 int err;
475 err = BCOPYIN(data, &op, sizeof(op));
476 if (err != 0)
477 return EFAULT;
479 if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
480 return EINVAL;
482 switch (op.iplo_type)
484 case IPLT_POOL :
485 err = ip_pool_statistics(&op);
486 break;
488 case IPLT_HASH :
489 err = fr_gethtablestat(&op);
490 break;
492 default :
493 err = EINVAL;
494 break;
496 return err;
500 /* ------------------------------------------------------------------------ */
501 /* Function: iplookup_flush */
502 /* Returns: int - 0 = success, else error */
503 /* Parameters: data(I) - pointer to data from ioctl call */
504 /* */
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)
509 void *data;
511 int err, unit, num, type;
512 iplookupflush_t flush;
514 err = BCOPYIN(data, &flush, sizeof(flush));
515 if (err != 0)
516 return EFAULT;
518 unit = flush.iplf_unit;
519 if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL))
520 return EINVAL;
522 flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
524 type = flush.iplf_type;
525 err = EINVAL;
526 num = 0;
528 if (type == IPLT_POOL || type == IPLT_ALL) {
529 err = 0;
530 num = ip_pool_flush(&flush);
533 if (type == IPLT_HASH || type == IPLT_ALL) {
534 err = 0;
535 num += fr_flushhtable(&flush);
538 if (err == 0) {
539 flush.iplf_count = num;
540 err = BCOPYOUT(&flush, data, sizeof(flush));
541 if (err != 0)
542 err = EFAULT;
544 return err;
548 /* ------------------------------------------------------------------------ */
549 /* Function: ip_lookup_delref */
550 /* Returns: void */
551 /* Parameters: type(I) - table type to operate on */
552 /* ptr(I) - pointer to object to remove reference for */
553 /* */
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)
558 int type;
559 void *ptr;
561 if (ptr == NULL)
562 return;
564 WRITE_ENTER(&ip_poolrw);
565 switch (type)
567 case IPLT_POOL :
568 ip_pool_deref(ptr);
569 break;
571 case IPLT_HASH :
572 fr_derefhtable(ptr);
573 break;
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 */
585 /* */
586 /* Decodes ioctl request to step through either hash tables or pools. */
587 /* ------------------------------------------------------------------------ */
588 static int iplookup_iterate(data, uid, ctx)
589 void *data;
590 int uid;
591 void *ctx;
593 ipflookupiter_t iter;
594 ipftoken_t *token;
595 int err;
596 SPL_INT(s);
598 err = fr_inobj(data, &iter, IPFOBJ_LOOKUPITER);
599 if (err != 0)
600 return err;
602 if (iter.ili_unit > IPL_LOGMAX)
603 return EINVAL;
605 if (iter.ili_ival != IPFGENITER_LOOKUP)
606 return EINVAL;
608 SPL_SCHED(s);
609 token = ipf_findtoken(iter.ili_key, uid, ctx);
610 if (token == NULL) {
611 RWLOCK_EXIT(&ipf_tokens);
612 SPL_X(s);
613 return ESRCH;
616 switch (iter.ili_type)
618 case IPLT_POOL :
619 err = ip_pool_getnext(token, &iter);
620 break;
621 case IPLT_HASH :
622 err = fr_htable_getnext(token, &iter);
623 break;
624 default :
625 err = EINVAL;
626 break;
629 WRITE_ENTER(&ipf_tokens);
630 ipf_dereftoken(token);
631 RWLOCK_EXIT(&ipf_tokens);
632 SPL_X(s);
634 return err;
638 /* ------------------------------------------------------------------------ */
639 /* Function: iplookup_iterderef */
640 /* Returns: int - 0 = success, else error */
641 /* Parameters: data(I) - pointer to data from ioctl call */
642 /* */
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)
647 u_32_t type;
648 void *data;
650 iplookupiterkey_t key;
652 key.ilik_key = type;
654 if (key.ilik_unstr.ilik_ival != IPFGENITER_LOOKUP)
655 return;
657 switch (key.ilik_unstr.ilik_type)
659 case IPLT_HASH :
660 fr_htable_iterderef((u_int)key.ilik_unstr.ilik_otype,
661 (int)key.ilik_unstr.ilik_unit, data);
662 break;
663 case IPLT_POOL :
664 ip_pool_iterderef((u_int)key.ilik_unstr.ilik_otype,
665 (int)key.ilik_unstr.ilik_unit, data);
666 break;
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 */
677 /* */
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)
683 void *data;
684 int uid;
685 void *ctx;
687 int error, key;
688 SPL_INT(s);
690 SPL_SCHED(s);
691 error = BCOPYIN(data, &key, sizeof(key));
692 if (error == 0)
693 error = ipf_deltoken(key, uid, ctx);
694 SPL_X(s);
695 return error;
699 #else /* IPFILTER_LOOKUP */
701 /*ARGSUSED*/
702 int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
703 void * data;
704 ioctlcmd_t cmd;
705 int mode, uid;
706 void *ctx;
708 return EIO;
710 #endif /* IPFILTER_LOOKUP */