1 /*
2 * Copyright (C) 2012 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 */
6 #if defined(KERNEL) || defined(_KERNEL)
7 # undef KERNEL
8 # undef _KERNEL
9 # define KERNEL 1
10 # define _KERNEL 1
11 #endif
12 #include <sys/param.h>
13 #include <sys/errno.h>
14 #include <sys/types.h>
15 #include <sys/time.h>
16 #include <sys/file.h>
17 #if defined(__FreeBSD__) && defined(_KERNEL)
18 # include <sys/fcntl.h>
19 # include <sys/filio.h>
20 #else
21 # include <sys/ioctl.h>
22 #endif
23 #if !defined(_KERNEL)
24 # include <stdio.h>
25 # include <string.h>
26 # include <stdlib.h>
27 # define _KERNEL
28 # include <sys/uio.h>
29 # undef _KERNEL
30 #endif
31 #include <sys/socket.h>
32 #include <net/if.h>
33 #if defined(__FreeBSD__)
34 # include <sys/cdefs.h>
35 # include <sys/proc.h>
36 #endif
37 #if defined(_KERNEL)
38 # include <sys/systm.h>
39 # if !defined(__SVR4)
40 # include <sys/mbuf.h>
41 # endif
42 #else
43 # include "ipf.h"
44 #endif
45 #include <netinet/in.h>
46
47 #include "netinet/ip_compat.h"
48 #include "netinet/ip_fil.h"
49 #include "netinet/ip_lookup.h"
50 #include "netinet/ip_pool.h"
51 #include "netinet/ip_htable.h"
52 #include "netinet/ip_dstlist.h"
53 /* END OF INCLUDES */
54
55
56 /*
57 * In this file, ip_pool.c, ip_htable.c and ip_dstlist.c, you will find the
58 * range for unit is [-1,IPL_LOGMAX]. The -1 is considered to be a valid number
59 * and represents a "wildcard" or "all" units (IPL_LOGALL). The reason for not
60 * starting the numbering at 0 is because the numbers [0,IPL_LOGMAX] correspond
61 * to the minor device number for their respective device. Thus where there is
62 * array indexing on the unit, +1 is used to map [-1.IPL_LOGMAX] to
63 * [0.POOL_LOOKUP_MAX].
64 */
65 static int ipf_lookup_addnode(ipf_main_softc_t *, caddr_t, int);
66 static int ipf_lookup_delnode(ipf_main_softc_t *, caddr_t, int);
67 static int ipf_lookup_addtable(ipf_main_softc_t *, caddr_t);
68 static int ipf_lookup_deltable(ipf_main_softc_t *, caddr_t);
69 static int ipf_lookup_stats(ipf_main_softc_t *, caddr_t);
70 static int ipf_lookup_flush(ipf_main_softc_t *, caddr_t);
71 static int ipf_lookup_iterate(ipf_main_softc_t *, void *, int, void *);
72 static int ipf_lookup_deltok(ipf_main_softc_t *, void *, int, void *);
73
74 #define MAX_BACKENDS 3
75 static ipf_lookup_t *backends[MAX_BACKENDS] = {
76 &ipf_pool_backend,
77 &ipf_htable_backend,
78 &ipf_dstlist_backend
79 };
80
81
82 typedef struct ipf_lookup_softc_s {
83 void *ipf_back[MAX_BACKENDS];
84 } ipf_lookup_softc_t;
85
86
87 /* ------------------------------------------------------------------------ */
88 /* Function: ipf_lookup_init */
89 /* Returns: int - 0 = success, else error */
90 /* Parameters: softc(I) - pointer to soft context main structure */
91 /* */
92 /* Initialise all of the subcomponents of the lookup infrstructure. */
93 /* ------------------------------------------------------------------------ */
94 void *
ipf_lookup_soft_create(ipf_main_softc_t * softc)95 ipf_lookup_soft_create(ipf_main_softc_t *softc)
96 {
97 ipf_lookup_softc_t *softl;
98 ipf_lookup_t **l;
99 int i;
100
101 KMALLOC(softl, ipf_lookup_softc_t *);
102 if (softl == NULL)
103 return (NULL);
104
105 bzero((char *)softl, sizeof(*softl));
106
107 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
108 softl->ipf_back[i] = (*(*l)->ipfl_create)(softc);
109 if (softl->ipf_back[i] == NULL) {
110 ipf_lookup_soft_destroy(softc, softl);
111 return (NULL);
112 }
113 }
114
115 return (softl);
116 }
117
118
119 /* ------------------------------------------------------------------------ */
120 /* Function: ipf_lookup_soft_init */
121 /* Returns: int - 0 = success, else error */
122 /* Parameters: softc(I) - pointer to soft context main structure */
123 /* arg(I) - pointer to local context to use */
124 /* */
125 /* Initialise all of the subcomponents of the lookup infrstructure. */
126 /* ------------------------------------------------------------------------ */
127 int
ipf_lookup_soft_init(ipf_main_softc_t * softc,void * arg)128 ipf_lookup_soft_init(ipf_main_softc_t *softc, void *arg)
129 {
130 ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
131 int err = 0;
132 int i;
133
134 for (i = 0; i < MAX_BACKENDS; i++) {
135 err = (*backends[i]->ipfl_init)(softc, softl->ipf_back[i]);
136 if (err != 0)
137 break;
138 }
139
140 return (err);
141 }
142
143
144 /* ------------------------------------------------------------------------ */
145 /* Function: ipf_lookup_soft_fini */
146 /* Returns: int - 0 = success, else error */
147 /* Parameters: softc(I) - pointer to soft context main structure */
148 /* arg(I) - pointer to local context to use */
149 /* */
150 /* Call the fini function in each backend to cleanup all allocated data. */
151 /* ------------------------------------------------------------------------ */
152 int
ipf_lookup_soft_fini(ipf_main_softc_t * softc,void * arg)153 ipf_lookup_soft_fini(ipf_main_softc_t *softc, void *arg)
154 {
155 ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
156 int i;
157
158 for (i = 0; i < MAX_BACKENDS; i++) {
159 if (softl->ipf_back[i] != NULL)
160 (*backends[i]->ipfl_fini)(softc,
161 softl->ipf_back[i]);
162 }
163
164 return (0);
165 }
166
167
168 /* ------------------------------------------------------------------------ */
169 /* Function: ipf_lookup_expire */
170 /* Returns: Nil */
171 /* Parameters: softc(I) - pointer to soft context main structure */
172 /* */
173 /* Step through each of the backends and call their expire functions, */
174 /* allowing them to delete any lifetime limited data. */
175 /* ------------------------------------------------------------------------ */
176 void
ipf_lookup_expire(ipf_main_softc_t * softc)177 ipf_lookup_expire(ipf_main_softc_t *softc)
178 {
179 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
180 int i;
181
182 WRITE_ENTER(&softc->ipf_poolrw);
183 for (i = 0; i < MAX_BACKENDS; i++)
184 (*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]);
185 RWLOCK_EXIT(&softc->ipf_poolrw);
186 }
187
188
189 /* ------------------------------------------------------------------------ */
190 /* Function: ipf_lookup_softc_destroy */
191 /* Returns: int - 0 = success, else error */
192 /* Parameters: softc(I) - pointer to soft context main structure */
193 /* arg(I) - pointer to local context to use */
194 /* */
195 /* Free up all pool related memory that has been allocated whilst IPFilter */
196 /* has been running. Also, do any other deinitialisation required such */
197 /* ipf_lookup_init() can be called again, safely. */
198 /* ------------------------------------------------------------------------ */
199 void
ipf_lookup_soft_destroy(ipf_main_softc_t * softc,void * arg)200 ipf_lookup_soft_destroy(ipf_main_softc_t *softc, void *arg)
201 {
202 ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
203 int i;
204
205 for (i = 0; i < MAX_BACKENDS; i++) {
206 if (softl->ipf_back[i] != NULL)
207 (*backends[i]->ipfl_destroy)(softc,
208 softl->ipf_back[i]);
209 }
210
211 KFREE(softl);
212 }
213
214
215 /* ------------------------------------------------------------------------ */
216 /* Function: ipf_lookup_ioctl */
217 /* Returns: int - 0 = success, else error */
218 /* Parameters: softc(I) - pointer to soft context main structure */
219 /* arg(I) - pointer to local context to use */
220 /* data(IO) - pointer to ioctl data to be copied to/from user */
221 /* space. */
222 /* cmd(I) - ioctl command number */
223 /* mode(I) - file mode bits used with open */
224 /* uid(I) - uid of process doing ioctl */
225 /* ctx(I) - pointer that represents context for uid */
226 /* */
227 /* Handle ioctl commands sent to the ioctl device. For the most part, this */
228 /* involves just calling another function to handle the specifics of each */
229 /* command. */
230 /* ------------------------------------------------------------------------ */
231 int
ipf_lookup_ioctl(ipf_main_softc_t * softc,caddr_t data,ioctlcmd_t cmd,int mode __unused,int uid,void * ctx)232 ipf_lookup_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd,
233 int mode __unused, int uid, void *ctx)
234 {
235 int err;
236 SPL_INT(s);
237
238 SPL_NET(s);
239
240 switch (cmd)
241 {
242 case SIOCLOOKUPADDNODE :
243 case SIOCLOOKUPADDNODEW :
244 WRITE_ENTER(&softc->ipf_poolrw);
245 err = ipf_lookup_addnode(softc, data, uid);
246 RWLOCK_EXIT(&softc->ipf_poolrw);
247 break;
248
249 case SIOCLOOKUPDELNODE :
250 case SIOCLOOKUPDELNODEW :
251 WRITE_ENTER(&softc->ipf_poolrw);
252 err = ipf_lookup_delnode(softc, data, uid);
253 RWLOCK_EXIT(&softc->ipf_poolrw);
254 break;
255
256 case SIOCLOOKUPADDTABLE :
257 WRITE_ENTER(&softc->ipf_poolrw);
258 err = ipf_lookup_addtable(softc, data);
259 RWLOCK_EXIT(&softc->ipf_poolrw);
260 break;
261
262 case SIOCLOOKUPDELTABLE :
263 WRITE_ENTER(&softc->ipf_poolrw);
264 err = ipf_lookup_deltable(softc, data);
265 RWLOCK_EXIT(&softc->ipf_poolrw);
266 break;
267
268 case SIOCLOOKUPSTAT :
269 case SIOCLOOKUPSTATW :
270 WRITE_ENTER(&softc->ipf_poolrw);
271 err = ipf_lookup_stats(softc, data);
272 RWLOCK_EXIT(&softc->ipf_poolrw);
273 break;
274
275 case SIOCLOOKUPFLUSH :
276 WRITE_ENTER(&softc->ipf_poolrw);
277 err = ipf_lookup_flush(softc, data);
278 RWLOCK_EXIT(&softc->ipf_poolrw);
279 break;
280
281 case SIOCLOOKUPITER :
282 err = ipf_lookup_iterate(softc, data, uid, ctx);
283 break;
284
285 case SIOCIPFDELTOK :
286 err = ipf_lookup_deltok(softc, data, uid, ctx);
287 break;
288
289 default :
290 IPFERROR(50001);
291 err = EINVAL;
292 break;
293 }
294 SPL_X(s);
295 return (err);
296 }
297
298
299 /* ------------------------------------------------------------------------ */
300 /* Function: ipf_lookup_addnode */
301 /* Returns: int - 0 = success, else error */
302 /* Parameters: softc(I) - pointer to soft context main structure */
303 /* data(I) - pointer to data from ioctl call */
304 /* */
305 /* Add a new data node to a lookup structure. First, check to see if the */
306 /* parent structure refered to by name exists and if it does, then go on to */
307 /* add a node to it. */
308 /* ------------------------------------------------------------------------ */
309 static int
ipf_lookup_addnode(ipf_main_softc_t * softc,caddr_t data,int uid)310 ipf_lookup_addnode(ipf_main_softc_t *softc, caddr_t data, int uid)
311 {
312 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
313 iplookupop_t op;
314 ipf_lookup_t **l;
315 int err;
316 int i;
317
318 err = BCOPYIN(data, &op, sizeof(op));
319 if (err != 0) {
320 IPFERROR(50002);
321 return (EFAULT);
322 }
323
324 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
325 (op.iplo_unit != IPLT_ALL)) {
326 IPFERROR(50003);
327 return (EINVAL);
328 }
329
330 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
331
332 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
333 if (op.iplo_type == (*l)->ipfl_type) {
334 err = (*(*l)->ipfl_node_add)(softc,
335 softl->ipf_back[i],
336 &op, uid);
337 break;
338 }
339 }
340
341 if (i == MAX_BACKENDS) {
342 IPFERROR(50012);
343 err = EINVAL;
344 }
345
346 return (err);
347 }
348
349
350 /* ------------------------------------------------------------------------ */
351 /* Function: ipf_lookup_delnode */
352 /* Returns: int - 0 = success, else error */
353 /* Parameters: softc(I) - pointer to soft context main structure */
354 /* data(I) - pointer to data from ioctl call */
355 /* */
356 /* Delete a node from a lookup table by first looking for the table it is */
357 /* in and then deleting the entry that gets found. */
358 /* ------------------------------------------------------------------------ */
359 static int
ipf_lookup_delnode(ipf_main_softc_t * softc,caddr_t data,int uid)360 ipf_lookup_delnode(ipf_main_softc_t *softc, caddr_t data, int uid)
361 {
362 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
363 iplookupop_t op;
364 ipf_lookup_t **l;
365 int err;
366 int i;
367
368 err = BCOPYIN(data, &op, sizeof(op));
369 if (err != 0) {
370 IPFERROR(50042);
371 return (EFAULT);
372 }
373
374 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
375 (op.iplo_unit != IPLT_ALL)) {
376 IPFERROR(50013);
377 return (EINVAL);
378 }
379
380 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
381
382 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
383 if (op.iplo_type == (*l)->ipfl_type) {
384 err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i],
385 &op, uid);
386 break;
387 }
388 }
389
390 if (i == MAX_BACKENDS) {
391 IPFERROR(50021);
392 err = EINVAL;
393 }
394 return (err);
395 }
396
397
398 /* ------------------------------------------------------------------------ */
399 /* Function: ipf_lookup_addtable */
400 /* Returns: int - 0 = success, else error */
401 /* Parameters: softc(I) - pointer to soft context main structure */
402 /* data(I) - pointer to data from ioctl call */
403 /* */
404 /* Create a new lookup table, if one doesn't already exist using the name */
405 /* for this one. */
406 /* ------------------------------------------------------------------------ */
407 static int
ipf_lookup_addtable(ipf_main_softc_t * softc,caddr_t data)408 ipf_lookup_addtable(ipf_main_softc_t *softc, caddr_t data)
409 {
410 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
411 iplookupop_t op;
412 ipf_lookup_t **l;
413 int err, i;
414
415 err = BCOPYIN(data, &op, sizeof(op));
416 if (err != 0) {
417 IPFERROR(50022);
418 return (EFAULT);
419 }
420
421 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
422 (op.iplo_unit != IPLT_ALL)) {
423 IPFERROR(50023);
424 return (EINVAL);
425 }
426
427 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
428
429 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
430 if (op.iplo_type == (*l)->ipfl_type) {
431 err = (*(*l)->ipfl_table_add)(softc,
432 softl->ipf_back[i],
433 &op);
434 break;
435 }
436 }
437
438 if (i == MAX_BACKENDS) {
439 IPFERROR(50026);
440 err = EINVAL;
441 }
442
443 /*
444 * For anonymous pools, copy back the operation struct because in the
445 * case of success it will contain the new table's name.
446 */
447 if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
448 err = BCOPYOUT(&op, data, sizeof(op));
449 if (err != 0) {
450 IPFERROR(50027);
451 err = EFAULT;
452 }
453 }
454
455 return (err);
456 }
457
458
459 /* ------------------------------------------------------------------------ */
460 /* Function: ipf_lookup_deltable */
461 /* Returns: int - 0 = success, else error */
462 /* Parameters: softc(I) - pointer to soft context main structure */
463 /* data(I) - pointer to data from ioctl call */
464 /* */
465 /* Decodes ioctl request to remove a particular hash table or pool and */
466 /* calls the relevant function to do the cleanup. */
467 /* ------------------------------------------------------------------------ */
468 static int
ipf_lookup_deltable(ipf_main_softc_t * softc,caddr_t data)469 ipf_lookup_deltable(ipf_main_softc_t *softc, caddr_t data)
470 {
471 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
472 iplookupop_t op;
473 ipf_lookup_t **l;
474 int err, i;
475
476 err = BCOPYIN(data, &op, sizeof(op));
477 if (err != 0) {
478 IPFERROR(50028);
479 return (EFAULT);
480 }
481
482 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
483 (op.iplo_unit != IPLT_ALL)) {
484 IPFERROR(50029);
485 return (EINVAL);
486 }
487
488 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
489
490 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
491 if (op.iplo_type == (*l)->ipfl_type) {
492 err = (*(*l)->ipfl_table_del)(softc,
493 softl->ipf_back[i],
494 &op);
495 break;
496 }
497 }
498
499 if (i == MAX_BACKENDS) {
500 IPFERROR(50030);
501 err = EINVAL;
502 }
503 return (err);
504 }
505
506
507 /* ------------------------------------------------------------------------ */
508 /* Function: ipf_lookup_stats */
509 /* Returns: int - 0 = success, else error */
510 /* Parameters: softc(I) - pointer to soft context main structure */
511 /* data(I) - pointer to data from ioctl call */
512 /* */
513 /* Copy statistical information from inside the kernel back to user space. */
514 /* ------------------------------------------------------------------------ */
515 static int
ipf_lookup_stats(ipf_main_softc_t * softc,caddr_t data)516 ipf_lookup_stats(ipf_main_softc_t *softc, caddr_t data)
517 {
518 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
519 iplookupop_t op;
520 ipf_lookup_t **l;
521 int err;
522 int i;
523
524 err = BCOPYIN(data, &op, sizeof(op));
525 if (err != 0) {
526 IPFERROR(50031);
527 return (EFAULT);
528 }
529
530 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
531 (op.iplo_unit != IPLT_ALL)) {
532 IPFERROR(50032);
533 return (EINVAL);
534 }
535
536 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
537 if (op.iplo_type == (*l)->ipfl_type) {
538 err = (*(*l)->ipfl_stats_get)(softc,
539 softl->ipf_back[i],
540 &op);
541 break;
542 }
543 }
544
545 if (i == MAX_BACKENDS) {
546 IPFERROR(50033);
547 err = EINVAL;
548 }
549
550 return (err);
551 }
552
553
554 /* ------------------------------------------------------------------------ */
555 /* Function: ipf_lookup_flush */
556 /* Returns: int - 0 = success, else error */
557 /* Parameters: softc(I) - pointer to soft context main structure */
558 /* data(I) - pointer to data from ioctl call */
559 /* */
560 /* A flush is called when we want to flush all the nodes from a particular */
561 /* entry in the hash table/pool or want to remove all groups from those. */
562 /* ------------------------------------------------------------------------ */
563 static int
ipf_lookup_flush(ipf_main_softc_t * softc,caddr_t data)564 ipf_lookup_flush(ipf_main_softc_t *softc, caddr_t data)
565 {
566 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
567 int err, unit, num, type, i;
568 iplookupflush_t flush;
569 ipf_lookup_t **l;
570
571 err = BCOPYIN(data, &flush, sizeof(flush));
572 if (err != 0) {
573 IPFERROR(50034);
574 return (EFAULT);
575 }
576
577 unit = flush.iplf_unit;
578 if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) {
579 IPFERROR(50035);
580 return (EINVAL);
581 }
582
583 flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
584
585 type = flush.iplf_type;
586 IPFERROR(50036);
587 err = EINVAL;
588 num = 0;
589
590 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
591 if (type == (*l)->ipfl_type || type == IPLT_ALL) {
592 err = 0;
593 num += (*(*l)->ipfl_flush)(softc,
594 softl->ipf_back[i],
595 &flush);
596 }
597 }
598
599 if (err == 0) {
600 flush.iplf_count = num;
601 err = BCOPYOUT(&flush, data, sizeof(flush));
602 if (err != 0) {
603 IPFERROR(50037);
604 err = EFAULT;
605 }
606 }
607 return (err);
608 }
609
610
611 /* ------------------------------------------------------------------------ */
612 /* Function: ipf_lookup_delref */
613 /* Returns: void */
614 /* Parameters: softc(I) - pointer to soft context main structure */
615 /* type(I) - table type to operate on */
616 /* ptr(I) - pointer to object to remove reference for */
617 /* */
618 /* This function organises calling the correct deref function for a given */
619 /* type of object being passed into it. */
620 /* ------------------------------------------------------------------------ */
621 void
ipf_lookup_deref(ipf_main_softc_t * softc,int type,void * ptr)622 ipf_lookup_deref(ipf_main_softc_t *softc, int type, void *ptr)
623 {
624 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
625 int i;
626
627 if (ptr == NULL)
628 return;
629
630 for (i = 0; i < MAX_BACKENDS; i++) {
631 if (type == backends[i]->ipfl_type) {
632 WRITE_ENTER(&softc->ipf_poolrw);
633 (*backends[i]->ipfl_table_deref)(softc,
634 softl->ipf_back[i],
635 ptr);
636 RWLOCK_EXIT(&softc->ipf_poolrw);
637 break;
638 }
639 }
640 }
641
642
643 /* ------------------------------------------------------------------------ */
644 /* Function: ipf_lookup_iterate */
645 /* Returns: int - 0 = success, else error */
646 /* Parameters: softc(I) - pointer to soft context main structure */
647 /* data(I) - pointer to data from ioctl call */
648 /* uid(I) - uid of caller */
649 /* ctx(I) - pointer to give the uid context */
650 /* */
651 /* Decodes ioctl request to step through either hash tables or pools. */
652 /* ------------------------------------------------------------------------ */
653 static int
ipf_lookup_iterate(ipf_main_softc_t * softc,void * data,int uid,void * ctx)654 ipf_lookup_iterate(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
655 {
656 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
657 ipflookupiter_t iter;
658 ipftoken_t *token;
659 int err, i;
660 SPL_INT(s);
661
662 err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER);
663 if (err != 0)
664 return (err);
665
666 if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) {
667 IPFERROR(50038);
668 return (EINVAL);
669 }
670
671 if (iter.ili_ival != IPFGENITER_LOOKUP) {
672 IPFERROR(50039);
673 return (EINVAL);
674 }
675
676 SPL_SCHED(s);
677 token = ipf_token_find(softc, iter.ili_key, uid, ctx);
678 if (token == NULL) {
679 SPL_X(s);
680 IPFERROR(50040);
681 return (ESRCH);
682 }
683
684 for (i = 0; i < MAX_BACKENDS; i++) {
685 if (iter.ili_type == backends[i]->ipfl_type) {
686 err = (*backends[i]->ipfl_iter_next)(softc,
687 softl->ipf_back[i],
688 token, &iter);
689 break;
690 }
691 }
692 SPL_X(s);
693
694 if (i == MAX_BACKENDS) {
695 IPFERROR(50041);
696 err = EINVAL;
697 }
698
699 WRITE_ENTER(&softc->ipf_tokens);
700 ipf_token_deref(softc, token);
701 RWLOCK_EXIT(&softc->ipf_tokens);
702
703 return (err);
704 }
705
706
707 /* ------------------------------------------------------------------------ */
708 /* Function: ipf_lookup_iterderef */
709 /* Returns: void */
710 /* Parameters: softc(I) - pointer to soft context main structure */
711 /* type(I) - backend type to iterate through */
712 /* data(I) - pointer to data from ioctl call */
713 /* */
714 /* Decodes ioctl request to remove a particular hash table or pool and */
715 /* calls the relevant function to do the cleanup. */
716 /* Because each of the backend types has a different data structure, */
717 /* iteration is limited to one type at a time (i.e. it is not permitted to */
718 /* go on from pool types to hash types as part of the "get next".) */
719 /* ------------------------------------------------------------------------ */
720 void
ipf_lookup_iterderef(ipf_main_softc_t * softc,u_32_t type,void * data)721 ipf_lookup_iterderef(ipf_main_softc_t *softc, u_32_t type, void *data)
722 {
723 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
724 struct iplookupiterkey *lkey;
725 iplookupiterkey_t key;
726 int i;
727
728 key.ilik_key = type;
729 lkey = &key.ilik_unstr;
730
731 if (lkey->ilik_ival != IPFGENITER_LOOKUP)
732 return;
733
734 WRITE_ENTER(&softc->ipf_poolrw);
735
736 for (i = 0; i < MAX_BACKENDS; i++) {
737 if (lkey->ilik_type == backends[i]->ipfl_type) {
738 (*backends[i]->ipfl_iter_deref)(softc,
739 softl->ipf_back[i],
740 lkey->ilik_otype,
741 lkey->ilik_unit,
742 data);
743 break;
744 }
745 }
746 RWLOCK_EXIT(&softc->ipf_poolrw);
747 }
748
749
750 /* ------------------------------------------------------------------------ */
751 /* Function: ipf_lookup_deltok */
752 /* Returns: int - 0 = success, else error */
753 /* Parameters: softc(I) - pointer to soft context main structure */
754 /* data(I) - pointer to data from ioctl call */
755 /* uid(I) - uid of caller */
756 /* ctx(I) - pointer to give the uid context */
757 /* */
758 /* Deletes the token identified by the combination of (type,uid,ctx) */
759 /* "key" is a combination of the table type, iterator type and the unit for */
760 /* which the token was being used. */
761 /* ------------------------------------------------------------------------ */
762 int
ipf_lookup_deltok(ipf_main_softc_t * softc,void * data,int uid,void * ctx)763 ipf_lookup_deltok(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
764 {
765 int error, key;
766 SPL_INT(s);
767
768 SPL_SCHED(s);
769 error = BCOPYIN(data, &key, sizeof(key));
770 if (error == 0)
771 error = ipf_token_del(softc, key, uid, ctx);
772 SPL_X(s);
773 return (error);
774 }
775
776
777 /* ------------------------------------------------------------------------ */
778 /* Function: ipf_lookup_res_num */
779 /* Returns: void * - NULL = failure, else success. */
780 /* Parameters: softc(I) - pointer to soft context main structure */
781 /* unit(I) - device for which this is for */
782 /* type(I) - type of lookup these parameters are for. */
783 /* number(I) - table number to use when searching */
784 /* funcptr(IO) - pointer to pointer for storing IP address */
785 /* searching function. */
786 /* */
787 /* Search for the "table" number passed in amongst those configured for */
788 /* that particular type. If the type is recognised then the function to */
789 /* call to do the IP address search will be change, regardless of whether */
790 /* or not the "table" number exists. */
791 /* ------------------------------------------------------------------------ */
792 void *
ipf_lookup_res_num(ipf_main_softc_t * softc,int unit,u_int type,u_int number,lookupfunc_t * funcptr)793 ipf_lookup_res_num(ipf_main_softc_t *softc, int unit, u_int type, u_int number,
794 lookupfunc_t *funcptr)
795 {
796 char name[FR_GROUPLEN];
797
798 (void) snprintf(name, sizeof(name), "%u", number);
799
800 return (ipf_lookup_res_name(softc, unit, type, name, funcptr));
801 }
802
803
804 /* ------------------------------------------------------------------------ */
805 /* Function: ipf_lookup_res_name */
806 /* Returns: void * - NULL = failure, else success. */
807 /* Parameters: softc(I) - pointer to soft context main structure */
808 /* unit(I) - device for which this is for */
809 /* type(I) - type of lookup these parameters are for. */
810 /* name(I) - table name to use when searching */
811 /* funcptr(IO) - pointer to pointer for storing IP address */
812 /* searching function. */
813 /* */
814 /* Search for the "table" number passed in amongst those configured for */
815 /* that particular type. If the type is recognised then the function to */
816 /* call to do the IP address search will be changed, regardless of whether */
817 /* or not the "table" number exists. */
818 /* ------------------------------------------------------------------------ */
819 void *
ipf_lookup_res_name(ipf_main_softc_t * softc,int unit,u_int type,char * name,lookupfunc_t * funcptr)820 ipf_lookup_res_name(ipf_main_softc_t *softc, int unit, u_int type, char *name,
821 lookupfunc_t *funcptr)
822 {
823 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
824 ipf_lookup_t **l;
825 void *ptr = NULL;
826 int i;
827
828 READ_ENTER(&softc->ipf_poolrw);
829
830 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
831 if (type == (*l)->ipfl_type) {
832 ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i],
833 unit, name);
834 if (ptr != NULL && funcptr != NULL) {
835 *funcptr = (*l)->ipfl_addr_find;
836 }
837 break;
838 }
839 }
840
841 if (i == MAX_BACKENDS) {
842 ptr = NULL;
843 if (funcptr != NULL)
844 *funcptr = NULL;
845 }
846
847 RWLOCK_EXIT(&softc->ipf_poolrw);
848
849 return (ptr);
850 }
851
852
853 /* ------------------------------------------------------------------------ */
854 /* Function: ipf_lookup_find_htable */
855 /* Returns: void * - NULL = failure, else success. */
856 /* Parameters: softc(I) - pointer to soft context main structure */
857 /* unit(I) - device for which this is for */
858 /* name(I) - table name to use when searching */
859 /* */
860 /* To support the group-map feature, where a hash table maps address */
861 /* networks to rule group numbers, we need to expose a function that uses */
862 /* only the hash table backend. */
863 /* ------------------------------------------------------------------------ */
864 void *
ipf_lookup_find_htable(ipf_main_softc_t * softc,int unit,char * name)865 ipf_lookup_find_htable(ipf_main_softc_t *softc, int unit, char *name)
866 {
867 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
868 ipf_lookup_t **l;
869 void *tab = NULL;
870 int i;
871
872 READ_ENTER(&softc->ipf_poolrw);
873
874 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
875 if (IPLT_HASH == (*l)->ipfl_type) {
876 tab = ipf_htable_find(softl->ipf_back[i], unit, name);
877 break;
878 }
879
880 RWLOCK_EXIT(&softc->ipf_poolrw);
881
882 return (tab);
883 }
884
885
886 /* ------------------------------------------------------------------------ */
887 /* Function: ipf_lookup_sync */
888 /* Returns: void */
889 /* Parameters: softc(I) - pointer to soft context main structure */
890 /* */
891 /* This function is the interface that the machine dependent sync functions */
892 /* call when a network interface name change occurs. It then calls the sync */
893 /* functions of the lookup implementations - if they have one. */
894 /* ------------------------------------------------------------------------ */
895 /*ARGSUSED*/
896 void
ipf_lookup_sync(ipf_main_softc_t * softc,void * ifp)897 ipf_lookup_sync(ipf_main_softc_t *softc, void *ifp)
898 {
899 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
900 ipf_lookup_t **l;
901 int i;
902
903 READ_ENTER(&softc->ipf_poolrw);
904
905 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
906 if ((*l)->ipfl_sync != NULL)
907 (*(*l)->ipfl_sync)(softc, softl->ipf_back[i]);
908
909 RWLOCK_EXIT(&softc->ipf_poolrw);
910 }
911
912
913 #ifndef _KERNEL
914 void
ipf_lookup_dump(ipf_main_softc_t * softc,void * arg)915 ipf_lookup_dump(ipf_main_softc_t *softc, void *arg)
916 {
917 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
918 ipf_lookup_t **l;
919 int i;
920
921 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
922 if (IPLT_POOL == (*l)->ipfl_type) {
923 ipf_pool_dump(softc, softl->ipf_back[i]);
924 break;
925 }
926
927 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
928 if (IPLT_HASH == (*l)->ipfl_type) {
929 ipf_htable_dump(softc, softl->ipf_back[i]);
930 break;
931 }
932 }
933 #endif
934