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,int uid,void * ctx)232 ipf_lookup_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd,
233 int mode, int uid, void *ctx)
234 {
235 int err;
236 SPL_INT(s);
237
238 mode = mode; /* LINT */
239
240 SPL_NET(s);
241
242 switch (cmd)
243 {
244 case SIOCLOOKUPADDNODE :
245 case SIOCLOOKUPADDNODEW :
246 WRITE_ENTER(&softc->ipf_poolrw);
247 err = ipf_lookup_addnode(softc, data, uid);
248 RWLOCK_EXIT(&softc->ipf_poolrw);
249 break;
250
251 case SIOCLOOKUPDELNODE :
252 case SIOCLOOKUPDELNODEW :
253 WRITE_ENTER(&softc->ipf_poolrw);
254 err = ipf_lookup_delnode(softc, data, uid);
255 RWLOCK_EXIT(&softc->ipf_poolrw);
256 break;
257
258 case SIOCLOOKUPADDTABLE :
259 WRITE_ENTER(&softc->ipf_poolrw);
260 err = ipf_lookup_addtable(softc, data);
261 RWLOCK_EXIT(&softc->ipf_poolrw);
262 break;
263
264 case SIOCLOOKUPDELTABLE :
265 WRITE_ENTER(&softc->ipf_poolrw);
266 err = ipf_lookup_deltable(softc, data);
267 RWLOCK_EXIT(&softc->ipf_poolrw);
268 break;
269
270 case SIOCLOOKUPSTAT :
271 case SIOCLOOKUPSTATW :
272 WRITE_ENTER(&softc->ipf_poolrw);
273 err = ipf_lookup_stats(softc, data);
274 RWLOCK_EXIT(&softc->ipf_poolrw);
275 break;
276
277 case SIOCLOOKUPFLUSH :
278 WRITE_ENTER(&softc->ipf_poolrw);
279 err = ipf_lookup_flush(softc, data);
280 RWLOCK_EXIT(&softc->ipf_poolrw);
281 break;
282
283 case SIOCLOOKUPITER :
284 err = ipf_lookup_iterate(softc, data, uid, ctx);
285 break;
286
287 case SIOCIPFDELTOK :
288 err = ipf_lookup_deltok(softc, data, uid, ctx);
289 break;
290
291 default :
292 IPFERROR(50001);
293 err = EINVAL;
294 break;
295 }
296 SPL_X(s);
297 return (err);
298 }
299
300
301 /* ------------------------------------------------------------------------ */
302 /* Function: ipf_lookup_addnode */
303 /* Returns: int - 0 = success, else error */
304 /* Parameters: softc(I) - pointer to soft context main structure */
305 /* data(I) - pointer to data from ioctl call */
306 /* */
307 /* Add a new data node to a lookup structure. First, check to see if the */
308 /* parent structure refered to by name exists and if it does, then go on to */
309 /* add a node to it. */
310 /* ------------------------------------------------------------------------ */
311 static int
ipf_lookup_addnode(ipf_main_softc_t * softc,caddr_t data,int uid)312 ipf_lookup_addnode(ipf_main_softc_t *softc, caddr_t data, int uid)
313 {
314 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
315 iplookupop_t op;
316 ipf_lookup_t **l;
317 int err;
318 int i;
319
320 err = BCOPYIN(data, &op, sizeof(op));
321 if (err != 0) {
322 IPFERROR(50002);
323 return (EFAULT);
324 }
325
326 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
327 (op.iplo_unit != IPLT_ALL)) {
328 IPFERROR(50003);
329 return (EINVAL);
330 }
331
332 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
333
334 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
335 if (op.iplo_type == (*l)->ipfl_type) {
336 err = (*(*l)->ipfl_node_add)(softc,
337 softl->ipf_back[i],
338 &op, uid);
339 break;
340 }
341 }
342
343 if (i == MAX_BACKENDS) {
344 IPFERROR(50012);
345 err = EINVAL;
346 }
347
348 return (err);
349 }
350
351
352 /* ------------------------------------------------------------------------ */
353 /* Function: ipf_lookup_delnode */
354 /* Returns: int - 0 = success, else error */
355 /* Parameters: softc(I) - pointer to soft context main structure */
356 /* data(I) - pointer to data from ioctl call */
357 /* */
358 /* Delete a node from a lookup table by first looking for the table it is */
359 /* in and then deleting the entry that gets found. */
360 /* ------------------------------------------------------------------------ */
361 static int
ipf_lookup_delnode(ipf_main_softc_t * softc,caddr_t data,int uid)362 ipf_lookup_delnode(ipf_main_softc_t *softc, caddr_t data, int uid)
363 {
364 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
365 iplookupop_t op;
366 ipf_lookup_t **l;
367 int err;
368 int i;
369
370 err = BCOPYIN(data, &op, sizeof(op));
371 if (err != 0) {
372 IPFERROR(50042);
373 return (EFAULT);
374 }
375
376 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
377 (op.iplo_unit != IPLT_ALL)) {
378 IPFERROR(50013);
379 return (EINVAL);
380 }
381
382 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
383
384 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
385 if (op.iplo_type == (*l)->ipfl_type) {
386 err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i],
387 &op, uid);
388 break;
389 }
390 }
391
392 if (i == MAX_BACKENDS) {
393 IPFERROR(50021);
394 err = EINVAL;
395 }
396 return (err);
397 }
398
399
400 /* ------------------------------------------------------------------------ */
401 /* Function: ipf_lookup_addtable */
402 /* Returns: int - 0 = success, else error */
403 /* Parameters: softc(I) - pointer to soft context main structure */
404 /* data(I) - pointer to data from ioctl call */
405 /* */
406 /* Create a new lookup table, if one doesn't already exist using the name */
407 /* for this one. */
408 /* ------------------------------------------------------------------------ */
409 static int
ipf_lookup_addtable(ipf_main_softc_t * softc,caddr_t data)410 ipf_lookup_addtable(ipf_main_softc_t *softc, caddr_t data)
411 {
412 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
413 iplookupop_t op;
414 ipf_lookup_t **l;
415 int err, i;
416
417 err = BCOPYIN(data, &op, sizeof(op));
418 if (err != 0) {
419 IPFERROR(50022);
420 return (EFAULT);
421 }
422
423 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
424 (op.iplo_unit != IPLT_ALL)) {
425 IPFERROR(50023);
426 return (EINVAL);
427 }
428
429 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
430
431 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
432 if (op.iplo_type == (*l)->ipfl_type) {
433 err = (*(*l)->ipfl_table_add)(softc,
434 softl->ipf_back[i],
435 &op);
436 break;
437 }
438 }
439
440 if (i == MAX_BACKENDS) {
441 IPFERROR(50026);
442 err = EINVAL;
443 }
444
445 /*
446 * For anonymous pools, copy back the operation struct because in the
447 * case of success it will contain the new table's name.
448 */
449 if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
450 err = BCOPYOUT(&op, data, sizeof(op));
451 if (err != 0) {
452 IPFERROR(50027);
453 err = EFAULT;
454 }
455 }
456
457 return (err);
458 }
459
460
461 /* ------------------------------------------------------------------------ */
462 /* Function: ipf_lookup_deltable */
463 /* Returns: int - 0 = success, else error */
464 /* Parameters: softc(I) - pointer to soft context main structure */
465 /* data(I) - pointer to data from ioctl call */
466 /* */
467 /* Decodes ioctl request to remove a particular hash table or pool and */
468 /* calls the relevant function to do the cleanup. */
469 /* ------------------------------------------------------------------------ */
470 static int
ipf_lookup_deltable(ipf_main_softc_t * softc,caddr_t data)471 ipf_lookup_deltable(ipf_main_softc_t *softc, caddr_t data)
472 {
473 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
474 iplookupop_t op;
475 ipf_lookup_t **l;
476 int err, i;
477
478 err = BCOPYIN(data, &op, sizeof(op));
479 if (err != 0) {
480 IPFERROR(50028);
481 return (EFAULT);
482 }
483
484 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
485 (op.iplo_unit != IPLT_ALL)) {
486 IPFERROR(50029);
487 return (EINVAL);
488 }
489
490 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
491
492 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
493 if (op.iplo_type == (*l)->ipfl_type) {
494 err = (*(*l)->ipfl_table_del)(softc,
495 softl->ipf_back[i],
496 &op);
497 break;
498 }
499 }
500
501 if (i == MAX_BACKENDS) {
502 IPFERROR(50030);
503 err = EINVAL;
504 }
505 return (err);
506 }
507
508
509 /* ------------------------------------------------------------------------ */
510 /* Function: ipf_lookup_stats */
511 /* Returns: int - 0 = success, else error */
512 /* Parameters: softc(I) - pointer to soft context main structure */
513 /* data(I) - pointer to data from ioctl call */
514 /* */
515 /* Copy statistical information from inside the kernel back to user space. */
516 /* ------------------------------------------------------------------------ */
517 static int
ipf_lookup_stats(ipf_main_softc_t * softc,caddr_t data)518 ipf_lookup_stats(ipf_main_softc_t *softc, caddr_t data)
519 {
520 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
521 iplookupop_t op;
522 ipf_lookup_t **l;
523 int err;
524 int i;
525
526 err = BCOPYIN(data, &op, sizeof(op));
527 if (err != 0) {
528 IPFERROR(50031);
529 return (EFAULT);
530 }
531
532 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
533 (op.iplo_unit != IPLT_ALL)) {
534 IPFERROR(50032);
535 return (EINVAL);
536 }
537
538 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
539 if (op.iplo_type == (*l)->ipfl_type) {
540 err = (*(*l)->ipfl_stats_get)(softc,
541 softl->ipf_back[i],
542 &op);
543 break;
544 }
545 }
546
547 if (i == MAX_BACKENDS) {
548 IPFERROR(50033);
549 err = EINVAL;
550 }
551
552 return (err);
553 }
554
555
556 /* ------------------------------------------------------------------------ */
557 /* Function: ipf_lookup_flush */
558 /* Returns: int - 0 = success, else error */
559 /* Parameters: softc(I) - pointer to soft context main structure */
560 /* data(I) - pointer to data from ioctl call */
561 /* */
562 /* A flush is called when we want to flush all the nodes from a particular */
563 /* entry in the hash table/pool or want to remove all groups from those. */
564 /* ------------------------------------------------------------------------ */
565 static int
ipf_lookup_flush(ipf_main_softc_t * softc,caddr_t data)566 ipf_lookup_flush(ipf_main_softc_t *softc, caddr_t data)
567 {
568 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
569 int err, unit, num, type, i;
570 iplookupflush_t flush;
571 ipf_lookup_t **l;
572
573 err = BCOPYIN(data, &flush, sizeof(flush));
574 if (err != 0) {
575 IPFERROR(50034);
576 return (EFAULT);
577 }
578
579 unit = flush.iplf_unit;
580 if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) {
581 IPFERROR(50035);
582 return (EINVAL);
583 }
584
585 flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
586
587 type = flush.iplf_type;
588 IPFERROR(50036);
589 err = EINVAL;
590 num = 0;
591
592 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
593 if (type == (*l)->ipfl_type || type == IPLT_ALL) {
594 err = 0;
595 num += (*(*l)->ipfl_flush)(softc,
596 softl->ipf_back[i],
597 &flush);
598 }
599 }
600
601 if (err == 0) {
602 flush.iplf_count = num;
603 err = BCOPYOUT(&flush, data, sizeof(flush));
604 if (err != 0) {
605 IPFERROR(50037);
606 err = EFAULT;
607 }
608 }
609 return (err);
610 }
611
612
613 /* ------------------------------------------------------------------------ */
614 /* Function: ipf_lookup_delref */
615 /* Returns: void */
616 /* Parameters: softc(I) - pointer to soft context main structure */
617 /* type(I) - table type to operate on */
618 /* ptr(I) - pointer to object to remove reference for */
619 /* */
620 /* This function organises calling the correct deref function for a given */
621 /* type of object being passed into it. */
622 /* ------------------------------------------------------------------------ */
623 void
ipf_lookup_deref(ipf_main_softc_t * softc,int type,void * ptr)624 ipf_lookup_deref(ipf_main_softc_t *softc, int type, void *ptr)
625 {
626 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
627 int i;
628
629 if (ptr == NULL)
630 return;
631
632 for (i = 0; i < MAX_BACKENDS; i++) {
633 if (type == backends[i]->ipfl_type) {
634 WRITE_ENTER(&softc->ipf_poolrw);
635 (*backends[i]->ipfl_table_deref)(softc,
636 softl->ipf_back[i],
637 ptr);
638 RWLOCK_EXIT(&softc->ipf_poolrw);
639 break;
640 }
641 }
642 }
643
644
645 /* ------------------------------------------------------------------------ */
646 /* Function: ipf_lookup_iterate */
647 /* Returns: int - 0 = success, else error */
648 /* Parameters: softc(I) - pointer to soft context main structure */
649 /* data(I) - pointer to data from ioctl call */
650 /* uid(I) - uid of caller */
651 /* ctx(I) - pointer to give the uid context */
652 /* */
653 /* Decodes ioctl request to step through either hash tables or pools. */
654 /* ------------------------------------------------------------------------ */
655 static int
ipf_lookup_iterate(ipf_main_softc_t * softc,void * data,int uid,void * ctx)656 ipf_lookup_iterate(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
657 {
658 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
659 ipflookupiter_t iter;
660 ipftoken_t *token;
661 int err, i;
662 SPL_INT(s);
663
664 err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER);
665 if (err != 0)
666 return (err);
667
668 if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) {
669 IPFERROR(50038);
670 return (EINVAL);
671 }
672
673 if (iter.ili_ival != IPFGENITER_LOOKUP) {
674 IPFERROR(50039);
675 return (EINVAL);
676 }
677
678 SPL_SCHED(s);
679 token = ipf_token_find(softc, iter.ili_key, uid, ctx);
680 if (token == NULL) {
681 SPL_X(s);
682 IPFERROR(50040);
683 return (ESRCH);
684 }
685
686 for (i = 0; i < MAX_BACKENDS; i++) {
687 if (iter.ili_type == backends[i]->ipfl_type) {
688 err = (*backends[i]->ipfl_iter_next)(softc,
689 softl->ipf_back[i],
690 token, &iter);
691 break;
692 }
693 }
694 SPL_X(s);
695
696 if (i == MAX_BACKENDS) {
697 IPFERROR(50041);
698 err = EINVAL;
699 }
700
701 WRITE_ENTER(&softc->ipf_tokens);
702 ipf_token_deref(softc, token);
703 RWLOCK_EXIT(&softc->ipf_tokens);
704
705 return (err);
706 }
707
708
709 /* ------------------------------------------------------------------------ */
710 /* Function: ipf_lookup_iterderef */
711 /* Returns: void */
712 /* Parameters: softc(I) - pointer to soft context main structure */
713 /* type(I) - backend type to iterate through */
714 /* data(I) - pointer to data from ioctl call */
715 /* */
716 /* Decodes ioctl request to remove a particular hash table or pool and */
717 /* calls the relevant function to do the cleanup. */
718 /* Because each of the backend types has a different data structure, */
719 /* iteration is limited to one type at a time (i.e. it is not permitted to */
720 /* go on from pool types to hash types as part of the "get next".) */
721 /* ------------------------------------------------------------------------ */
722 void
ipf_lookup_iterderef(ipf_main_softc_t * softc,u_32_t type,void * data)723 ipf_lookup_iterderef(ipf_main_softc_t *softc, u_32_t type, void *data)
724 {
725 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
726 struct iplookupiterkey *lkey;
727 iplookupiterkey_t key;
728 int i;
729
730 key.ilik_key = type;
731 lkey = &key.ilik_unstr;
732
733 if (lkey->ilik_ival != IPFGENITER_LOOKUP)
734 return;
735
736 WRITE_ENTER(&softc->ipf_poolrw);
737
738 for (i = 0; i < MAX_BACKENDS; i++) {
739 if (lkey->ilik_type == backends[i]->ipfl_type) {
740 (*backends[i]->ipfl_iter_deref)(softc,
741 softl->ipf_back[i],
742 lkey->ilik_otype,
743 lkey->ilik_unit,
744 data);
745 break;
746 }
747 }
748 RWLOCK_EXIT(&softc->ipf_poolrw);
749 }
750
751
752 /* ------------------------------------------------------------------------ */
753 /* Function: ipf_lookup_deltok */
754 /* Returns: int - 0 = success, else error */
755 /* Parameters: softc(I) - pointer to soft context main structure */
756 /* data(I) - pointer to data from ioctl call */
757 /* uid(I) - uid of caller */
758 /* ctx(I) - pointer to give the uid context */
759 /* */
760 /* Deletes the token identified by the combination of (type,uid,ctx) */
761 /* "key" is a combination of the table type, iterator type and the unit for */
762 /* which the token was being used. */
763 /* ------------------------------------------------------------------------ */
764 int
ipf_lookup_deltok(ipf_main_softc_t * softc,void * data,int uid,void * ctx)765 ipf_lookup_deltok(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
766 {
767 int error, key;
768 SPL_INT(s);
769
770 SPL_SCHED(s);
771 error = BCOPYIN(data, &key, sizeof(key));
772 if (error == 0)
773 error = ipf_token_del(softc, key, uid, ctx);
774 SPL_X(s);
775 return (error);
776 }
777
778
779 /* ------------------------------------------------------------------------ */
780 /* Function: ipf_lookup_res_num */
781 /* Returns: void * - NULL = failure, else success. */
782 /* Parameters: softc(I) - pointer to soft context main structure */
783 /* unit(I) - device for which this is for */
784 /* type(I) - type of lookup these parameters are for. */
785 /* number(I) - table number to use when searching */
786 /* funcptr(IO) - pointer to pointer for storing IP address */
787 /* searching function. */
788 /* */
789 /* Search for the "table" number passed in amongst those configured for */
790 /* that particular type. If the type is recognised then the function to */
791 /* call to do the IP address search will be change, regardless of whether */
792 /* or not the "table" number exists. */
793 /* ------------------------------------------------------------------------ */
794 void *
ipf_lookup_res_num(ipf_main_softc_t * softc,int unit,u_int type,u_int number,lookupfunc_t * funcptr)795 ipf_lookup_res_num(ipf_main_softc_t *softc, int unit, u_int type, u_int number,
796 lookupfunc_t *funcptr)
797 {
798 char name[FR_GROUPLEN];
799
800 (void) snprintf(name, sizeof(name), "%u", number);
801
802 return (ipf_lookup_res_name(softc, unit, type, name, funcptr));
803 }
804
805
806 /* ------------------------------------------------------------------------ */
807 /* Function: ipf_lookup_res_name */
808 /* Returns: void * - NULL = failure, else success. */
809 /* Parameters: softc(I) - pointer to soft context main structure */
810 /* unit(I) - device for which this is for */
811 /* type(I) - type of lookup these parameters are for. */
812 /* name(I) - table name to use when searching */
813 /* funcptr(IO) - pointer to pointer for storing IP address */
814 /* searching function. */
815 /* */
816 /* Search for the "table" number passed in amongst those configured for */
817 /* that particular type. If the type is recognised then the function to */
818 /* call to do the IP address search will be changed, regardless of whether */
819 /* or not the "table" number exists. */
820 /* ------------------------------------------------------------------------ */
821 void *
ipf_lookup_res_name(ipf_main_softc_t * softc,int unit,u_int type,char * name,lookupfunc_t * funcptr)822 ipf_lookup_res_name(ipf_main_softc_t *softc, int unit, u_int type, char *name,
823 lookupfunc_t *funcptr)
824 {
825 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
826 ipf_lookup_t **l;
827 void *ptr = NULL;
828 int i;
829
830 READ_ENTER(&softc->ipf_poolrw);
831
832 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
833 if (type == (*l)->ipfl_type) {
834 ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i],
835 unit, name);
836 if (ptr != NULL && funcptr != NULL) {
837 *funcptr = (*l)->ipfl_addr_find;
838 }
839 break;
840 }
841 }
842
843 if (i == MAX_BACKENDS) {
844 ptr = NULL;
845 if (funcptr != NULL)
846 *funcptr = NULL;
847 }
848
849 RWLOCK_EXIT(&softc->ipf_poolrw);
850
851 return (ptr);
852 }
853
854
855 /* ------------------------------------------------------------------------ */
856 /* Function: ipf_lookup_find_htable */
857 /* Returns: void * - NULL = failure, else success. */
858 /* Parameters: softc(I) - pointer to soft context main structure */
859 /* unit(I) - device for which this is for */
860 /* name(I) - table name to use when searching */
861 /* */
862 /* To support the group-map feature, where a hash table maps address */
863 /* networks to rule group numbers, we need to expose a function that uses */
864 /* only the hash table backend. */
865 /* ------------------------------------------------------------------------ */
866 void *
ipf_lookup_find_htable(ipf_main_softc_t * softc,int unit,char * name)867 ipf_lookup_find_htable(ipf_main_softc_t *softc, int unit, char *name)
868 {
869 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
870 ipf_lookup_t **l;
871 void *tab = NULL;
872 int i;
873
874 READ_ENTER(&softc->ipf_poolrw);
875
876 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
877 if (IPLT_HASH == (*l)->ipfl_type) {
878 tab = ipf_htable_find(softl->ipf_back[i], unit, name);
879 break;
880 }
881
882 RWLOCK_EXIT(&softc->ipf_poolrw);
883
884 return (tab);
885 }
886
887
888 /* ------------------------------------------------------------------------ */
889 /* Function: ipf_lookup_sync */
890 /* Returns: void */
891 /* Parameters: softc(I) - pointer to soft context main structure */
892 /* */
893 /* This function is the interface that the machine dependent sync functions */
894 /* call when a network interface name change occurs. It then calls the sync */
895 /* functions of the lookup implementations - if they have one. */
896 /* ------------------------------------------------------------------------ */
897 /*ARGSUSED*/
898 void
ipf_lookup_sync(ipf_main_softc_t * softc,void * ifp)899 ipf_lookup_sync(ipf_main_softc_t *softc, void *ifp)
900 {
901 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
902 ipf_lookup_t **l;
903 int i;
904
905 READ_ENTER(&softc->ipf_poolrw);
906
907 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
908 if ((*l)->ipfl_sync != NULL)
909 (*(*l)->ipfl_sync)(softc, softl->ipf_back[i]);
910
911 RWLOCK_EXIT(&softc->ipf_poolrw);
912 }
913
914
915 #ifndef _KERNEL
916 void
ipf_lookup_dump(ipf_main_softc_t * softc,void * arg)917 ipf_lookup_dump(ipf_main_softc_t *softc, void *arg)
918 {
919 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
920 ipf_lookup_t **l;
921 int i;
922
923 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
924 if (IPLT_POOL == (*l)->ipfl_type) {
925 ipf_pool_dump(softc, softl->ipf_back[i]);
926 break;
927 }
928
929 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
930 if (IPLT_HASH == (*l)->ipfl_type) {
931 ipf_htable_dump(softc, softl->ipf_back[i]);
932 break;
933 }
934 }
935 #endif
936