1 /* $NetBSD: ip_lookup.c,v 1.1.1.1.2.2 2004/08/13 03:55:35 jmc Exp $ */
2
3 /*
4 * Copyright (C) 2002-2003 by Darren Reed.
5 *
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(__hpux) || defined(__sgi)) && defined(_KERNEL)
39 # ifdef __osf__
40 # include <net/radix.h>
41 # endif
42 # include "radix_ipf_local.h"
43 # define _RADIX_H_
44 #endif
45 #include <net/if.h>
46 #if defined(__FreeBSD__)
47 # include <sys/cdefs.h>
48 # include <sys/proc.h>
49 #endif
50 #if defined(_KERNEL)
51 # include <sys/systm.h>
52 # if !defined(__SVR4) && !defined(__svr4__)
53 # include <sys/mbuf.h>
54 # endif
55 #endif
56 #include <netinet/in.h>
57
58 #include "netinet/ip_compat.h"
59 #include "netinet/ip_fil.h"
60 #include "netinet/ip_pool.h"
61 #include "netinet/ip_htable.h"
62 #include "netinet/ip_lookup.h"
63 /* END OF INCLUDES */
64
65 #if !defined(lint)
66 static const char rcsid[] = "@(#)Id: ip_lookup.c,v 2.35.2.5 2004/07/06 11:16:25 darrenr Exp";
67 #endif
68
69 #ifdef IPFILTER_LOOKUP
70 int ip_lookup_inited = 0;
71
72 static int iplookup_addnode __P((caddr_t));
73 static int iplookup_delnode __P((caddr_t data));
74 static int iplookup_addtable __P((caddr_t));
75 static int iplookup_deltable __P((caddr_t));
76 static int iplookup_stats __P((caddr_t));
77 static int iplookup_flush __P((caddr_t));
78
79
80 /* ------------------------------------------------------------------------ */
81 /* Function: iplookup_init */
82 /* Returns: int - 0 = success, else error */
83 /* Parameters: Nil */
84 /* */
85 /* Initialise all of the subcomponents of the lookup infrstructure. */
86 /* ------------------------------------------------------------------------ */
87 int ip_lookup_init()
88 {
89
90 if (ip_pool_init() == -1)
91 return -1;
92
93 RWLOCK_INIT(&ip_poolrw, "ip pool rwlock");
94
95 ip_lookup_inited = 1;
96
97 return 0;
98 }
99
100
101 /* ------------------------------------------------------------------------ */
102 /* Function: iplookup_unload */
103 /* Returns: int - 0 = success, else error */
104 /* Parameters: Nil */
105 /* */
106 /* Free up all pool related memory that has been allocated whilst IPFilter */
107 /* has been running. Also, do any other deinitialisation required such */
108 /* ip_lookup_init() can be called again, safely. */
109 /* ------------------------------------------------------------------------ */
110 void ip_lookup_unload()
111 {
112 ip_pool_fini();
113 fr_htable_unload();
114
115 if (ip_lookup_inited == 1) {
116 RW_DESTROY(&ip_poolrw);
117 ip_lookup_inited = 0;
118 }
119 }
120
121
122 /* ------------------------------------------------------------------------ */
123 /* Function: iplookup_ioctl */
124 /* Returns: int - 0 = success, else error */
125 /* Parameters: data(IO) - pointer to ioctl data to be copied to/from user */
126 /* space. */
127 /* cmd(I) - ioctl command number */
128 /* mode(I) - file mode bits used with open */
129 /* */
130 /* Handle ioctl commands sent to the ioctl device. For the most part, this */
131 /* involves just calling another function to handle the specifics of each */
132 /* command. */
133 /* ------------------------------------------------------------------------ */
134 int ip_lookup_ioctl(data, cmd, mode)
135 caddr_t data;
136 ioctlcmd_t cmd;
137 int mode;
138 {
139 int err;
140 # if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
141 int s;
142 # endif
143
144 mode = mode; /* LINT */
145
146 SPL_NET(s);
147
148 switch (cmd)
149 {
150 case SIOCLOOKUPADDNODE :
151 case SIOCLOOKUPADDNODEW :
152 WRITE_ENTER(&ip_poolrw);
153 err = iplookup_addnode(data);
154 RWLOCK_EXIT(&ip_poolrw);
155 break;
156
157 case SIOCLOOKUPDELNODE :
158 case SIOCLOOKUPDELNODEW :
159 WRITE_ENTER(&ip_poolrw);
160 err = iplookup_delnode(data);
161 RWLOCK_EXIT(&ip_poolrw);
162 break;
163
164 case SIOCLOOKUPADDTABLE :
165 WRITE_ENTER(&ip_poolrw);
166 err = iplookup_addtable(data);
167 RWLOCK_EXIT(&ip_poolrw);
168 break;
169
170 case SIOCLOOKUPDELTABLE :
171 WRITE_ENTER(&ip_poolrw);
172 err = iplookup_deltable(data);
173 RWLOCK_EXIT(&ip_poolrw);
174 break;
175
176 case SIOCLOOKUPSTAT :
177 case SIOCLOOKUPSTATW :
178 WRITE_ENTER(&ip_poolrw);
179 err = iplookup_stats(data);
180 RWLOCK_EXIT(&ip_poolrw);
181 break;
182
183 case SIOCLOOKUPFLUSH :
184 WRITE_ENTER(&ip_poolrw);
185 err = iplookup_flush(data);
186 RWLOCK_EXIT(&ip_poolrw);
187 break;
188
189 default :
190 err = EINVAL;
191 break;
192 }
193 SPL_X(s);
194 return err;
195 }
196
197
198 /* ------------------------------------------------------------------------ */
199 /* Function: iplookup_addnode */
200 /* Returns: int - 0 = success, else error */
201 /* Parameters: data(I) - pointer to data from ioctl call */
202 /* */
203 /* Add a new data node to a lookup structure. First, check to see if the */
204 /* parent structure refered to by name exists and if it does, then go on to */
205 /* add a node to it. */
206 /* ------------------------------------------------------------------------ */
207 static int iplookup_addnode(data)
208 caddr_t data;
209 {
210 ip_pool_node_t node, *m;
211 iplookupop_t op;
212 iphtable_t *iph;
213 iphtent_t hte;
214 ip_pool_t *p;
215 int err;
216
217 err = 0;
218 BCOPYIN(data, &op, sizeof(op));
219 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
220
221 switch (op.iplo_type)
222 {
223 case IPLT_POOL :
224 if (op.iplo_size != sizeof(node))
225 return EINVAL;
226
227 err = COPYIN(op.iplo_struct, &node, sizeof(node));
228 if (err != 0)
229 return EFAULT;
230
231 p = ip_pool_find(op.iplo_unit, op.iplo_name);
232 if (p == NULL)
233 return ESRCH;
234
235 /*
236 * add an entry to a pool - return an error if it already
237 * exists remove an entry from a pool - if it exists
238 * - in both cases, the pool *must* exist!
239 */
240 m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
241 if (m)
242 return EEXIST;
243 err = ip_pool_insert(p, &node.ipn_addr.adf_addr,
244 &node.ipn_mask.adf_addr, node.ipn_info);
245 break;
246
247 case IPLT_HASH :
248 if (op.iplo_size != sizeof(hte))
249 return EINVAL;
250
251 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
252 if (err != 0)
253 return EFAULT;
254
255 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
256 if (iph == NULL)
257 return ESRCH;
258 err = fr_addhtent(iph, &hte);
259 break;
260
261 default :
262 err = EINVAL;
263 break;
264 }
265 return err;
266 }
267
268
269 /* ------------------------------------------------------------------------ */
270 /* Function: iplookup_delnode */
271 /* Returns: int - 0 = success, else error */
272 /* Parameters: data(I) - pointer to data from ioctl call */
273 /* */
274 /* Delete a node from a lookup table by first looking for the table it is */
275 /* in and then deleting the entry that gets found. */
276 /* ------------------------------------------------------------------------ */
277 static int iplookup_delnode(data)
278 caddr_t data;
279 {
280 ip_pool_node_t node, *m;
281 iplookupop_t op;
282 iphtable_t *iph;
283 iphtent_t hte;
284 ip_pool_t *p;
285 int err;
286
287 err = 0;
288 BCOPYIN(data, &op, sizeof(op));
289
290 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
291
292 switch (op.iplo_type)
293 {
294 case IPLT_POOL :
295 if (op.iplo_size != sizeof(node))
296 return EINVAL;
297
298 err = COPYIN(op.iplo_struct, &node, sizeof(node));
299 if (err != 0)
300 return EFAULT;
301
302 p = ip_pool_find(op.iplo_unit, op.iplo_name);
303 if (!p)
304 return ESRCH;
305
306 m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
307 if (m == NULL)
308 return ENOENT;
309 err = ip_pool_remove(p, m);
310 break;
311
312 case IPLT_HASH :
313 if (op.iplo_size != sizeof(hte))
314 return EINVAL;
315
316 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
317 if (err != 0)
318 return EFAULT;
319
320 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
321 if (iph == NULL)
322 return ESRCH;
323 err = fr_delhtent(iph, &hte);
324 break;
325
326 default :
327 err = EINVAL;
328 break;
329 }
330 return err;
331 }
332
333
334 /* ------------------------------------------------------------------------ */
335 /* Function: iplookup_addtable */
336 /* Returns: int - 0 = success, else error */
337 /* Parameters: data(I) - pointer to data from ioctl call */
338 /* */
339 /* Create a new lookup table, if one doesn't already exist using the name */
340 /* for this one. */
341 /* ------------------------------------------------------------------------ */
342 static int iplookup_addtable(data)
343 caddr_t data;
344 {
345 iplookupop_t op;
346 int err;
347
348 err = 0;
349 BCOPYIN(data, &op, sizeof(op));
350
351 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
352
353 switch (op.iplo_type)
354 {
355 case IPLT_POOL :
356 if (ip_pool_find(op.iplo_unit, op.iplo_name) != NULL)
357 err = EEXIST;
358 else
359 err = ip_pool_create(&op);
360 break;
361
362 case IPLT_HASH :
363 if (fr_findhtable(op.iplo_unit, op.iplo_name) != NULL)
364 err = EEXIST;
365 else
366 err = fr_newhtable(&op);
367 break;
368
369 default :
370 err = EINVAL;
371 break;
372 }
373 return err;
374 }
375
376
377 /* ------------------------------------------------------------------------ */
378 /* Function: iplookup_deltable */
379 /* Returns: int - 0 = success, else error */
380 /* Parameters: data(I) - pointer to data from ioctl call */
381 /* */
382 /* Decodes ioctl request to remove a particular hash table or pool and */
383 /* calls the relevant function to do the cleanup. */
384 /* ------------------------------------------------------------------------ */
385 static int iplookup_deltable(data)
386 caddr_t data;
387 {
388 iplookupop_t op;
389 int err;
390
391 BCOPYIN(data, &op, sizeof(op));
392 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
393
394 if (op.iplo_arg & IPLT_ANON)
395 op.iplo_arg &= IPLT_ANON;
396
397 /*
398 * create a new pool - fail if one already exists with
399 * the same #
400 */
401 switch (op.iplo_type)
402 {
403 case IPLT_POOL :
404 err = ip_pool_destroy(&op);
405 break;
406
407 case IPLT_HASH :
408 err = fr_removehtable(&op);
409 break;
410
411 default :
412 err = EINVAL;
413 break;
414 }
415 return err;
416 }
417
418
419 /* ------------------------------------------------------------------------ */
420 /* Function: iplookup_stats */
421 /* Returns: int - 0 = success, else error */
422 /* Parameters: data(I) - pointer to data from ioctl call */
423 /* */
424 /* Copy statistical information from inside the kernel back to user space. */
425 /* ------------------------------------------------------------------------ */
426 static int iplookup_stats(data)
427 caddr_t data;
428 {
429 iplookupop_t op;
430 int err;
431
432 err = 0;
433 BCOPYIN(data, &op, sizeof(op));
434
435 switch (op.iplo_type)
436 {
437 case IPLT_POOL :
438 err = ip_pool_statistics(&op);
439 break;
440
441 case IPLT_HASH :
442 err = fr_gethtablestat(&op);
443 break;
444
445 default :
446 err = EINVAL;
447 break;
448 }
449 return err;
450 }
451
452
453 /* ------------------------------------------------------------------------ */
454 /* Function: iplookup_flush */
455 /* Returns: int - 0 = success, else error */
456 /* Parameters: data(I) - pointer to data from ioctl call */
457 /* */
458 /* A flush is called when we want to flush all the nodes from a particular */
459 /* entry in the hash table/pool or want to remove all groups from those. */
460 /* ------------------------------------------------------------------------ */
461 static int iplookup_flush(data)
462 caddr_t data;
463 {
464 int err, unit, num, type;
465 iplookupflush_t flush;
466
467 err = 0;
468 BCOPYIN(data, &flush, sizeof(flush));
469
470 flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
471
472 unit = flush.iplf_unit;
473 if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL))
474 return EINVAL;
475
476 type = flush.iplf_type;
477 err = EINVAL;
478 num = 0;
479
480 if (type == IPLT_POOL || type == IPLT_ALL) {
481 err = 0;
482 num = ip_pool_flush(&flush);
483 }
484
485 if (type == IPLT_HASH || type == IPLT_ALL) {
486 err = 0;
487 num += fr_flushhtable(&flush);
488 }
489
490 if (err == 0) {
491 flush.iplf_count = num;
492 err = COPYOUT(&flush, data, sizeof(flush));
493 }
494 return err;
495 }
496
497
498 void ip_lookup_deref(type, ptr)
499 int type;
500 void *ptr;
501 {
502 if (ptr == NULL)
503 return;
504
505 WRITE_ENTER(&ip_poolrw);
506 switch (type)
507 {
508 case IPLT_POOL :
509 ip_pool_deref(ptr);
510 break;
511
512 case IPLT_HASH :
513 fr_derefhtable(ptr);
514 break;
515 }
516 RWLOCK_EXIT(&ip_poolrw);
517 }
518
519
520 #else /* IPFILTER_LOOKUP */
521
522 /*ARGSUSED*/
523 int ip_lookup_ioctl(data, cmd, mode)
524 caddr_t data;
525 ioctlcmd_t cmd;
526 int mode;
527 {
528 return EIO;
529 }
530 #endif /* IPFILTER_LOOKUP */
Cache object: df509aeb000f38d706f9059ef74deb43
|