ip_pool.c revision 170263
1145516Sdarrenr/* 2145516Sdarrenr * Copyright (C) 1993-2001, 2003 by Darren Reed. 3145516Sdarrenr * 4145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 5145516Sdarrenr */ 6145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL) 7145516Sdarrenr# undef KERNEL 8145516Sdarrenr# undef _KERNEL 9145516Sdarrenr# define KERNEL 1 10145516Sdarrenr# define _KERNEL 1 11145516Sdarrenr#endif 12145516Sdarrenr#if defined(__osf__) 13145516Sdarrenr# define _PROTO_NET_H_ 14145516Sdarrenr#endif 15145516Sdarrenr#include <sys/errno.h> 16145516Sdarrenr#include <sys/types.h> 17145516Sdarrenr#include <sys/param.h> 18145516Sdarrenr#include <sys/file.h> 19145516Sdarrenr#if !defined(_KERNEL) && !defined(__KERNEL__) 20145516Sdarrenr# include <stdio.h> 21145516Sdarrenr# include <stdlib.h> 22145516Sdarrenr# include <string.h> 23145516Sdarrenr# define _KERNEL 24145516Sdarrenr# ifdef __OpenBSD__ 25145516Sdarrenrstruct file; 26145516Sdarrenr# endif 27145516Sdarrenr# include <sys/uio.h> 28145516Sdarrenr# undef _KERNEL 29145516Sdarrenr#else 30145516Sdarrenr# include <sys/systm.h> 31145516Sdarrenr# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000) 32145516Sdarrenr# include <sys/proc.h> 33145516Sdarrenr# endif 34145516Sdarrenr#endif 35145516Sdarrenr#include <sys/time.h> 36145516Sdarrenr#if !defined(linux) 37145516Sdarrenr# include <sys/protosw.h> 38145516Sdarrenr#endif 39145516Sdarrenr#include <sys/socket.h> 40145516Sdarrenr#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__)) 41145516Sdarrenr# include <sys/mbuf.h> 42145516Sdarrenr#endif 43145516Sdarrenr#if defined(__SVR4) || defined(__svr4__) 44145516Sdarrenr# include <sys/filio.h> 45145516Sdarrenr# include <sys/byteorder.h> 46145516Sdarrenr# ifdef _KERNEL 47145516Sdarrenr# include <sys/dditypes.h> 48145516Sdarrenr# endif 49145516Sdarrenr# include <sys/stream.h> 50145516Sdarrenr# include <sys/kmem.h> 51145516Sdarrenr#endif 52145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 53145516Sdarrenr# include <sys/malloc.h> 54145516Sdarrenr#endif 55145516Sdarrenr 56153872Sguido#if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \ 57153872Sguido defined(__hpux) || defined(__sgi)) 58145516Sdarrenr# include "radix_ipf_local.h" 59145516Sdarrenr# define _RADIX_H_ 60145516Sdarrenr#endif 61145516Sdarrenr#include <net/if.h> 62145516Sdarrenr#include <netinet/in.h> 63145516Sdarrenr 64145516Sdarrenr#include "netinet/ip_compat.h" 65145516Sdarrenr#include "netinet/ip_fil.h" 66145516Sdarrenr#include "netinet/ip_pool.h" 67145516Sdarrenr 68145516Sdarrenr#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \ 69145516Sdarrenr ((BSD >= 198911) && !defined(__osf__) && \ 70145516Sdarrenr !defined(__hpux) && !defined(__sgi)) 71145516Sdarrenrstatic int rn_freenode __P((struct radix_node *, void *)); 72145516Sdarrenr#endif 73145516Sdarrenr 74145516Sdarrenr/* END OF INCLUDES */ 75145516Sdarrenr 76145516Sdarrenr#if !defined(lint) 77145516Sdarrenrstatic const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 78170263Sdarrenrstatic const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.20 2007/05/31 12:27:35 darrenr Exp $"; 79145516Sdarrenr#endif 80145516Sdarrenr 81145516Sdarrenr#ifdef IPFILTER_LOOKUP 82145516Sdarrenr 83145516Sdarrenr# ifndef RADIX_NODE_HEAD_LOCK 84145516Sdarrenr# define RADIX_NODE_HEAD_LOCK(x) ; 85145516Sdarrenr# endif 86145516Sdarrenr# ifndef RADIX_NODE_HEAD_UNLOCK 87145516Sdarrenr# define RADIX_NODE_HEAD_UNLOCK(x) ; 88145516Sdarrenr# endif 89145516Sdarrenr 90170263Sdarrenrstatic void ip_pool_clearnodes __P((ip_pool_t *)); 91170263Sdarrenrstatic void *ip_pool_exists __P((int, char *)); 92170263Sdarrenr 93145516Sdarrenrip_pool_stat_t ipoolstat; 94145516Sdarrenripfrwlock_t ip_poolrw; 95145516Sdarrenr 96145516Sdarrenr/* 97145516Sdarrenr * Binary tree routines from Sedgewick and enhanced to do ranges of addresses. 98145516Sdarrenr * NOTE: Insertion *MUST* be from greatest range to least for it to work! 99145516Sdarrenr * These should be replaced, eventually, by something else - most notably a 100145516Sdarrenr * interval searching method. The important feature is to be able to find 101145516Sdarrenr * the best match. 102145516Sdarrenr * 103145516Sdarrenr * So why not use a radix tree for this? As the first line implies, it 104145516Sdarrenr * has been written to work with a _range_ of addresses. A range is not 105145516Sdarrenr * necessarily a match with any given netmask so what we end up dealing 106145516Sdarrenr * with is an interval tree. Implementations of these are hard to find 107145516Sdarrenr * and the one herein is far from bug free. 108145516Sdarrenr * 109145516Sdarrenr * Sigh, in the end I became convinced that the bugs the code contained did 110145516Sdarrenr * not make it worthwhile not using radix trees. For now the radix tree from 111145516Sdarrenr * 4.4 BSD is used, but this is not viewed as a long term solution. 112145516Sdarrenr */ 113145516Sdarrenrip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL, 114145516Sdarrenr NULL, NULL, NULL, NULL }; 115145516Sdarrenr 116145516Sdarrenr 117145516Sdarrenr#ifdef TEST_POOL 118145516Sdarrenrvoid treeprint __P((ip_pool_t *)); 119145516Sdarrenr 120145516Sdarrenrint 121145516Sdarrenrmain(argc, argv) 122145516Sdarrenr int argc; 123145516Sdarrenr char *argv[]; 124145516Sdarrenr{ 125145516Sdarrenr addrfamily_t a, b; 126145516Sdarrenr iplookupop_t op; 127145516Sdarrenr ip_pool_t *ipo; 128145516Sdarrenr i6addr_t ip; 129145516Sdarrenr 130145516Sdarrenr RWLOCK_INIT(&ip_poolrw, "poolrw"); 131145516Sdarrenr ip_pool_init(); 132145516Sdarrenr 133145516Sdarrenr bzero((char *)&a, sizeof(a)); 134145516Sdarrenr bzero((char *)&b, sizeof(b)); 135145516Sdarrenr bzero((char *)&ip, sizeof(ip)); 136145516Sdarrenr bzero((char *)&op, sizeof(op)); 137145516Sdarrenr strcpy(op.iplo_name, "0"); 138145516Sdarrenr 139145516Sdarrenr if (ip_pool_create(&op) == 0) 140170263Sdarrenr ipo = ip_pool_exists(0, "0"); 141145516Sdarrenr 142145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a010203; 143145516Sdarrenr b.adf_addr.in4.s_addr = 0xffffffff; 144145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 145145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 146145516Sdarrenr 147145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a000000; 148145516Sdarrenr b.adf_addr.in4.s_addr = 0xff000000; 149145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); 150145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); 151145516Sdarrenr 152145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a010100; 153145516Sdarrenr b.adf_addr.in4.s_addr = 0xffffff00; 154145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 155145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 156145516Sdarrenr 157145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a010200; 158145516Sdarrenr b.adf_addr.in4.s_addr = 0xffffff00; 159145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); 160145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); 161145516Sdarrenr 162145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a010000; 163145516Sdarrenr b.adf_addr.in4.s_addr = 0xffff0000; 164145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 165145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 166145516Sdarrenr 167145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a01020f; 168145516Sdarrenr b.adf_addr.in4.s_addr = 0xffffffff; 169145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 170145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 171145516Sdarrenr#ifdef DEBUG_POOL 172145516Sdarrenrtreeprint(ipo); 173145516Sdarrenr#endif 174145516Sdarrenr ip.in4.s_addr = 0x0a00aabb; 175145516Sdarrenr printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 176145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 177145516Sdarrenr 178145516Sdarrenr ip.in4.s_addr = 0x0a000001; 179145516Sdarrenr printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 180145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 181145516Sdarrenr 182145516Sdarrenr ip.in4.s_addr = 0x0a000101; 183145516Sdarrenr printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 184145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 185145516Sdarrenr 186145516Sdarrenr ip.in4.s_addr = 0x0a010001; 187145516Sdarrenr printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 188145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 189145516Sdarrenr 190145516Sdarrenr ip.in4.s_addr = 0x0a010101; 191145516Sdarrenr printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 192145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 193145516Sdarrenr 194145516Sdarrenr ip.in4.s_addr = 0x0a010201; 195145516Sdarrenr printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 196145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 197145516Sdarrenr 198145516Sdarrenr ip.in4.s_addr = 0x0a010203; 199145516Sdarrenr printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 200145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 201145516Sdarrenr 202145516Sdarrenr ip.in4.s_addr = 0x0a01020f; 203145516Sdarrenr printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 204145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 205145516Sdarrenr 206145516Sdarrenr ip.in4.s_addr = 0x0b00aabb; 207145516Sdarrenr printf("search(%#x) = %d (-1)\n", ip.in4.s_addr, 208145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 209145516Sdarrenr 210145516Sdarrenr#ifdef DEBUG_POOL 211145516Sdarrenrtreeprint(ipo); 212145516Sdarrenr#endif 213145516Sdarrenr 214145516Sdarrenr ip_pool_fini(); 215145516Sdarrenr 216145516Sdarrenr return 0; 217145516Sdarrenr} 218145516Sdarrenr 219145516Sdarrenr 220145516Sdarrenrvoid 221145516Sdarrenrtreeprint(ipo) 222145516Sdarrenrip_pool_t *ipo; 223145516Sdarrenr{ 224145516Sdarrenr ip_pool_node_t *c; 225145516Sdarrenr 226145516Sdarrenr for (c = ipo->ipo_list; c != NULL; c = c->ipn_next) 227145516Sdarrenr printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n", 228145516Sdarrenr c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr, 229145516Sdarrenr c->ipn_mask.adf_addr.in4.s_addr, 230145516Sdarrenr c->ipn_info, c->ipn_hits); 231145516Sdarrenr} 232145516Sdarrenr#endif /* TEST_POOL */ 233145516Sdarrenr 234145516Sdarrenr 235145516Sdarrenr/* ------------------------------------------------------------------------ */ 236145516Sdarrenr/* Function: ip_pool_init */ 237145516Sdarrenr/* Returns: int - 0 = success, else error */ 238145516Sdarrenr/* */ 239145516Sdarrenr/* Initialise the routing table data structures where required. */ 240145516Sdarrenr/* ------------------------------------------------------------------------ */ 241145516Sdarrenrint ip_pool_init() 242145516Sdarrenr{ 243145516Sdarrenr 244145516Sdarrenr bzero((char *)&ipoolstat, sizeof(ipoolstat)); 245145516Sdarrenr 246145516Sdarrenr#if (!defined(_KERNEL) || (BSD < 199306)) 247145516Sdarrenr rn_init(); 248145516Sdarrenr#endif 249145516Sdarrenr return 0; 250145516Sdarrenr} 251145516Sdarrenr 252145516Sdarrenr 253145516Sdarrenr/* ------------------------------------------------------------------------ */ 254145516Sdarrenr/* Function: ip_pool_fini */ 255145516Sdarrenr/* Returns: int - 0 = success, else error */ 256145516Sdarrenr/* Locks: WRITE(ipf_global) */ 257145516Sdarrenr/* */ 258145516Sdarrenr/* Clean up all the pool data structures allocated and call the cleanup */ 259145516Sdarrenr/* function for the radix tree that supports the pools. ip_pool_destroy() is*/ 260145516Sdarrenr/* used to delete the pools one by one to ensure they're properly freed up. */ 261145516Sdarrenr/* ------------------------------------------------------------------------ */ 262145516Sdarrenrvoid ip_pool_fini() 263145516Sdarrenr{ 264145516Sdarrenr ip_pool_t *p, *q; 265145516Sdarrenr int i; 266145516Sdarrenr 267145516Sdarrenr ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0); 268145516Sdarrenr 269145516Sdarrenr for (i = 0; i <= IPL_LOGMAX; i++) { 270145516Sdarrenr for (q = ip_pool_list[i]; (p = q) != NULL; ) { 271145516Sdarrenr q = p->ipo_next; 272170263Sdarrenr (void) ip_pool_destroy(i, p->ipo_name); 273145516Sdarrenr } 274145516Sdarrenr } 275145516Sdarrenr 276145516Sdarrenr#if (!defined(_KERNEL) || (BSD < 199306)) 277145516Sdarrenr rn_fini(); 278145516Sdarrenr#endif 279145516Sdarrenr} 280145516Sdarrenr 281145516Sdarrenr 282145516Sdarrenr/* ------------------------------------------------------------------------ */ 283145516Sdarrenr/* Function: ip_pool_statistics */ 284145516Sdarrenr/* Returns: int - 0 = success, else error */ 285145516Sdarrenr/* Parameters: op(I) - pointer to lookup operation arguments */ 286145516Sdarrenr/* */ 287145516Sdarrenr/* Copy the current statistics out into user space, collecting pool list */ 288145516Sdarrenr/* pointers as appropriate for later use. */ 289145516Sdarrenr/* ------------------------------------------------------------------------ */ 290145516Sdarrenrint ip_pool_statistics(op) 291145516Sdarrenriplookupop_t *op; 292145516Sdarrenr{ 293145516Sdarrenr ip_pool_stat_t stats; 294145516Sdarrenr int unit, i, err = 0; 295145516Sdarrenr 296145516Sdarrenr if (op->iplo_size != sizeof(ipoolstat)) 297145516Sdarrenr return EINVAL; 298145516Sdarrenr 299145516Sdarrenr bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats)); 300145516Sdarrenr unit = op->iplo_unit; 301145516Sdarrenr if (unit == IPL_LOGALL) { 302145516Sdarrenr for (i = 0; i < IPL_LOGSIZE; i++) 303145516Sdarrenr stats.ipls_list[i] = ip_pool_list[i]; 304145516Sdarrenr } else if (unit >= 0 && unit < IPL_LOGSIZE) { 305145516Sdarrenr if (op->iplo_name[0] != '\0') 306170263Sdarrenr stats.ipls_list[unit] = ip_pool_exists(unit, 307170263Sdarrenr op->iplo_name); 308145516Sdarrenr else 309145516Sdarrenr stats.ipls_list[unit] = ip_pool_list[unit]; 310145516Sdarrenr } else 311145516Sdarrenr err = EINVAL; 312145516Sdarrenr if (err == 0) 313145516Sdarrenr err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); 314145516Sdarrenr return err; 315145516Sdarrenr} 316145516Sdarrenr 317145516Sdarrenr 318145516Sdarrenr/* ------------------------------------------------------------------------ */ 319170263Sdarrenr/* Function: ip_pool_exists */ 320145516Sdarrenr/* Returns: int - 0 = success, else error */ 321145516Sdarrenr/* Parameters: ipo(I) - pointer to the pool getting the new node. */ 322145516Sdarrenr/* */ 323145516Sdarrenr/* Find a matching pool inside the collection of pools for a particular */ 324145516Sdarrenr/* device, indicated by the unit number. */ 325145516Sdarrenr/* ------------------------------------------------------------------------ */ 326170263Sdarrenrstatic void *ip_pool_exists(unit, name) 327145516Sdarrenrint unit; 328145516Sdarrenrchar *name; 329145516Sdarrenr{ 330145516Sdarrenr ip_pool_t *p; 331145516Sdarrenr 332145516Sdarrenr for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next) 333145516Sdarrenr if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0) 334145516Sdarrenr break; 335145516Sdarrenr return p; 336145516Sdarrenr} 337145516Sdarrenr 338145516Sdarrenr 339145516Sdarrenr/* ------------------------------------------------------------------------ */ 340170263Sdarrenr/* Function: ip_pool_find */ 341170263Sdarrenr/* Returns: int - 0 = success, else error */ 342170263Sdarrenr/* Parameters: ipo(I) - pointer to the pool getting the new node. */ 343170263Sdarrenr/* */ 344170263Sdarrenr/* Find a matching pool inside the collection of pools for a particular */ 345170263Sdarrenr/* device, indicated by the unit number. If it is marked for deletion then */ 346170263Sdarrenr/* pretend it does not exist. */ 347170263Sdarrenr/* ------------------------------------------------------------------------ */ 348170263Sdarrenrvoid *ip_pool_find(unit, name) 349170263Sdarrenrint unit; 350170263Sdarrenrchar *name; 351170263Sdarrenr{ 352170263Sdarrenr ip_pool_t *p; 353170263Sdarrenr 354170263Sdarrenr p = ip_pool_exists(unit, name); 355170263Sdarrenr if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE)) 356170263Sdarrenr return NULL; 357170263Sdarrenr 358170263Sdarrenr return p; 359170263Sdarrenr} 360170263Sdarrenr 361170263Sdarrenr 362170263Sdarrenr/* ------------------------------------------------------------------------ */ 363145516Sdarrenr/* Function: ip_pool_findeq */ 364145516Sdarrenr/* Returns: int - 0 = success, else error */ 365145516Sdarrenr/* Parameters: ipo(I) - pointer to the pool getting the new node. */ 366145516Sdarrenr/* addr(I) - pointer to address information to delete */ 367145516Sdarrenr/* mask(I) - */ 368145516Sdarrenr/* */ 369145516Sdarrenr/* Searches for an exact match of an entry in the pool. */ 370145516Sdarrenr/* ------------------------------------------------------------------------ */ 371145516Sdarrenrip_pool_node_t *ip_pool_findeq(ipo, addr, mask) 372145516Sdarrenrip_pool_t *ipo; 373145516Sdarrenraddrfamily_t *addr, *mask; 374145516Sdarrenr{ 375145516Sdarrenr struct radix_node *n; 376153872Sguido SPL_INT(s); 377145516Sdarrenr 378145516Sdarrenr SPL_NET(s); 379145516Sdarrenr RADIX_NODE_HEAD_LOCK(ipo->ipo_head); 380145516Sdarrenr n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head); 381145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); 382145516Sdarrenr SPL_X(s); 383145516Sdarrenr return (ip_pool_node_t *)n; 384145516Sdarrenr} 385145516Sdarrenr 386145516Sdarrenr 387145516Sdarrenr/* ------------------------------------------------------------------------ */ 388145516Sdarrenr/* Function: ip_pool_search */ 389145516Sdarrenr/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ 390145516Sdarrenr/* Parameters: tptr(I) - pointer to the pool to search */ 391145516Sdarrenr/* version(I) - IP protocol version (4 or 6) */ 392145516Sdarrenr/* dptr(I) - pointer to address information */ 393145516Sdarrenr/* */ 394145516Sdarrenr/* Search the pool for a given address and return a search result. */ 395145516Sdarrenr/* ------------------------------------------------------------------------ */ 396170263Sdarrenrint ip_pool_search(tptr, ipversion, dptr) 397145516Sdarrenrvoid *tptr; 398170263Sdarrenrint ipversion; 399145516Sdarrenrvoid *dptr; 400145516Sdarrenr{ 401145516Sdarrenr struct radix_node *rn; 402145516Sdarrenr ip_pool_node_t *m; 403145516Sdarrenr i6addr_t *addr; 404145516Sdarrenr addrfamily_t v; 405145516Sdarrenr ip_pool_t *ipo; 406145516Sdarrenr int rv; 407145516Sdarrenr 408145516Sdarrenr ipo = tptr; 409145516Sdarrenr if (ipo == NULL) 410145516Sdarrenr return -1; 411145516Sdarrenr 412145516Sdarrenr rv = 1; 413145516Sdarrenr m = NULL; 414145516Sdarrenr addr = (i6addr_t *)dptr; 415145516Sdarrenr bzero(&v, sizeof(v)); 416145516Sdarrenr v.adf_len = offsetof(addrfamily_t, adf_addr); 417145516Sdarrenr 418170263Sdarrenr if (ipversion == 4) { 419145516Sdarrenr v.adf_len += sizeof(addr->in4); 420145516Sdarrenr v.adf_addr.in4 = addr->in4; 421145516Sdarrenr#ifdef USE_INET6 422170263Sdarrenr } else if (ipversion == 6) { 423145516Sdarrenr v.adf_len += sizeof(addr->in6); 424145516Sdarrenr v.adf_addr.in6 = addr->in6; 425145516Sdarrenr#endif 426145516Sdarrenr } else 427145516Sdarrenr return -1; 428145516Sdarrenr 429145516Sdarrenr READ_ENTER(&ip_poolrw); 430145516Sdarrenr 431145516Sdarrenr RADIX_NODE_HEAD_LOCK(ipo->ipo_head); 432145516Sdarrenr rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head); 433145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); 434145516Sdarrenr 435145516Sdarrenr if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) { 436145516Sdarrenr m = (ip_pool_node_t *)rn; 437145516Sdarrenr ipo->ipo_hits++; 438145516Sdarrenr m->ipn_hits++; 439145516Sdarrenr rv = m->ipn_info; 440145516Sdarrenr } 441145516Sdarrenr RWLOCK_EXIT(&ip_poolrw); 442145516Sdarrenr return rv; 443145516Sdarrenr} 444145516Sdarrenr 445145516Sdarrenr 446145516Sdarrenr/* ------------------------------------------------------------------------ */ 447145516Sdarrenr/* Function: ip_pool_insert */ 448145516Sdarrenr/* Returns: int - 0 = success, else error */ 449145516Sdarrenr/* Parameters: ipo(I) - pointer to the pool getting the new node. */ 450145516Sdarrenr/* addr(I) - address being added as a node */ 451145516Sdarrenr/* mask(I) - netmask to with the node being added */ 452145516Sdarrenr/* info(I) - extra information to store in this node. */ 453145516Sdarrenr/* Locks: WRITE(ip_poolrw) */ 454145516Sdarrenr/* */ 455145516Sdarrenr/* Add another node to the pool given by ipo. The three parameters passed */ 456145516Sdarrenr/* in (addr, mask, info) shold all be stored in the node. */ 457145516Sdarrenr/* ------------------------------------------------------------------------ */ 458145516Sdarrenrint ip_pool_insert(ipo, addr, mask, info) 459145516Sdarrenrip_pool_t *ipo; 460145516Sdarrenri6addr_t *addr, *mask; 461145516Sdarrenrint info; 462145516Sdarrenr{ 463145516Sdarrenr struct radix_node *rn; 464145516Sdarrenr ip_pool_node_t *x; 465145516Sdarrenr 466145516Sdarrenr ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 467145516Sdarrenr 468145516Sdarrenr KMALLOC(x, ip_pool_node_t *); 469145516Sdarrenr if (x == NULL) { 470145516Sdarrenr return ENOMEM; 471145516Sdarrenr } 472145516Sdarrenr 473145516Sdarrenr bzero(x, sizeof(*x)); 474145516Sdarrenr 475145516Sdarrenr x->ipn_info = info; 476145516Sdarrenr (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name)); 477145516Sdarrenr 478145516Sdarrenr bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr)); 479145516Sdarrenr x->ipn_addr.adf_len = sizeof(x->ipn_addr); 480145516Sdarrenr bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask)); 481145516Sdarrenr x->ipn_mask.adf_len = sizeof(x->ipn_mask); 482145516Sdarrenr 483145516Sdarrenr RADIX_NODE_HEAD_LOCK(ipo->ipo_head); 484145516Sdarrenr rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask, 485145516Sdarrenr ipo->ipo_head, x->ipn_nodes); 486145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); 487145516Sdarrenr#ifdef DEBUG_POOL 488145516Sdarrenr printf("Added %p at %p\n", x, rn); 489145516Sdarrenr#endif 490145516Sdarrenr 491145516Sdarrenr if (rn == NULL) { 492145516Sdarrenr KFREE(x); 493145516Sdarrenr return ENOMEM; 494145516Sdarrenr } 495145516Sdarrenr 496170263Sdarrenr x->ipn_ref = 1; 497145516Sdarrenr x->ipn_next = ipo->ipo_list; 498145516Sdarrenr x->ipn_pnext = &ipo->ipo_list; 499145516Sdarrenr if (ipo->ipo_list != NULL) 500145516Sdarrenr ipo->ipo_list->ipn_pnext = &x->ipn_next; 501145516Sdarrenr ipo->ipo_list = x; 502145516Sdarrenr 503145516Sdarrenr ipoolstat.ipls_nodes++; 504145516Sdarrenr 505145516Sdarrenr return 0; 506145516Sdarrenr} 507145516Sdarrenr 508145516Sdarrenr 509145516Sdarrenr/* ------------------------------------------------------------------------ */ 510145516Sdarrenr/* Function: ip_pool_create */ 511145516Sdarrenr/* Returns: int - 0 = success, else error */ 512145516Sdarrenr/* Parameters: op(I) - pointer to iplookup struct with call details */ 513145516Sdarrenr/* Locks: WRITE(ip_poolrw) */ 514145516Sdarrenr/* */ 515145516Sdarrenr/* Creates a new group according to the paramters passed in via the */ 516145516Sdarrenr/* iplookupop structure. Does not check to see if the group already exists */ 517145516Sdarrenr/* when being inserted - assume this has already been done. If the pool is */ 518145516Sdarrenr/* marked as being anonymous, give it a new, unique, identifier. Call any */ 519145516Sdarrenr/* other functions required to initialise the structure. */ 520170263Sdarrenr/* */ 521170263Sdarrenr/* If the structure is flagged for deletion then reset the flag and return, */ 522170263Sdarrenr/* as this likely means we've tried to free a pool that is in use (flush) */ 523170263Sdarrenr/* and now want to repopulate it with "new" data. */ 524145516Sdarrenr/* ------------------------------------------------------------------------ */ 525145516Sdarrenrint ip_pool_create(op) 526145516Sdarrenriplookupop_t *op; 527145516Sdarrenr{ 528145516Sdarrenr char name[FR_GROUPLEN]; 529145516Sdarrenr int poolnum, unit; 530145516Sdarrenr ip_pool_t *h; 531145516Sdarrenr 532145516Sdarrenr ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 533145516Sdarrenr 534170263Sdarrenr unit = op->iplo_unit; 535145516Sdarrenr 536170263Sdarrenr if ((op->iplo_arg & LOOKUP_ANON) == 0) 537170263Sdarrenr h = ip_pool_exists(unit, op->iplo_name); 538170263Sdarrenr else 539170263Sdarrenr h = NULL; 540170263Sdarrenr 541170263Sdarrenr if (h != NULL) { 542170263Sdarrenr if ((h->ipo_flags & IPOOL_DELETE) != 0) { 543170263Sdarrenr h->ipo_flags &= ~IPOOL_DELETE; 544170263Sdarrenr return 0; 545170263Sdarrenr } 546170263Sdarrenr return EEXIST; 547170263Sdarrenr } else { 548170263Sdarrenr KMALLOC(h, ip_pool_t *); 549170263Sdarrenr if (h == NULL) 550170263Sdarrenr return ENOMEM; 551170263Sdarrenr bzero(h, sizeof(*h)); 552170263Sdarrenr 553170263Sdarrenr if (rn_inithead((void **)&h->ipo_head, 554170263Sdarrenr offsetof(addrfamily_t, adf_addr) << 3) == 0) { 555170263Sdarrenr KFREE(h); 556170263Sdarrenr return ENOMEM; 557170263Sdarrenr } 558145516Sdarrenr } 559145516Sdarrenr 560170263Sdarrenr if ((op->iplo_arg & LOOKUP_ANON) != 0) { 561145516Sdarrenr ip_pool_t *p; 562145516Sdarrenr 563170263Sdarrenr h->ipo_flags |= IPOOL_ANON; 564170263Sdarrenr poolnum = LOOKUP_ANON; 565145516Sdarrenr 566145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL) 567145516Sdarrenr SNPRINTF(name, sizeof(name), "%x", poolnum); 568145516Sdarrenr#else 569145516Sdarrenr (void)sprintf(name, "%x", poolnum); 570145516Sdarrenr#endif 571145516Sdarrenr 572145516Sdarrenr for (p = ip_pool_list[unit]; p != NULL; ) { 573145516Sdarrenr if (strncmp(name, p->ipo_name, 574145516Sdarrenr sizeof(p->ipo_name)) == 0) { 575145516Sdarrenr poolnum++; 576145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL) 577145516Sdarrenr SNPRINTF(name, sizeof(name), "%x", poolnum); 578145516Sdarrenr#else 579145516Sdarrenr (void)sprintf(name, "%x", poolnum); 580145516Sdarrenr#endif 581145516Sdarrenr p = ip_pool_list[unit]; 582145516Sdarrenr } else 583145516Sdarrenr p = p->ipo_next; 584145516Sdarrenr } 585145516Sdarrenr 586145516Sdarrenr (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name)); 587153872Sguido (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name)); 588145516Sdarrenr } else { 589170263Sdarrenr (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name)); 590145516Sdarrenr } 591145516Sdarrenr 592170263Sdarrenr if ((h->ipo_flags & IPOOL_DELETE) == 0) { 593170263Sdarrenr h->ipo_ref = 1; 594170263Sdarrenr h->ipo_list = NULL; 595170263Sdarrenr h->ipo_unit = unit; 596170263Sdarrenr h->ipo_next = ip_pool_list[unit]; 597170263Sdarrenr if (ip_pool_list[unit] != NULL) 598170263Sdarrenr ip_pool_list[unit]->ipo_pnext = &h->ipo_next; 599170263Sdarrenr h->ipo_pnext = &ip_pool_list[unit]; 600170263Sdarrenr ip_pool_list[unit] = h; 601145516Sdarrenr 602170263Sdarrenr ipoolstat.ipls_pools++; 603170263Sdarrenr } 604145516Sdarrenr 605145516Sdarrenr return 0; 606145516Sdarrenr} 607145516Sdarrenr 608145516Sdarrenr 609145516Sdarrenr/* ------------------------------------------------------------------------ */ 610145516Sdarrenr/* Function: ip_pool_remove */ 611145516Sdarrenr/* Returns: int - 0 = success, else error */ 612145516Sdarrenr/* Parameters: ipo(I) - pointer to the pool to remove the node from. */ 613145516Sdarrenr/* ipe(I) - address being deleted as a node */ 614145516Sdarrenr/* Locks: WRITE(ip_poolrw) */ 615145516Sdarrenr/* */ 616170263Sdarrenr/* Remove a node from the pool given by ipo. */ 617145516Sdarrenr/* ------------------------------------------------------------------------ */ 618145516Sdarrenrint ip_pool_remove(ipo, ipe) 619145516Sdarrenrip_pool_t *ipo; 620145516Sdarrenrip_pool_node_t *ipe; 621145516Sdarrenr{ 622145516Sdarrenr 623145516Sdarrenr ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 624145516Sdarrenr 625170263Sdarrenr if (ipe->ipn_pnext != NULL) 626170263Sdarrenr *ipe->ipn_pnext = ipe->ipn_next; 627170263Sdarrenr if (ipe->ipn_next != NULL) 628170263Sdarrenr ipe->ipn_next->ipn_pnext = ipe->ipn_pnext; 629145516Sdarrenr 630145516Sdarrenr RADIX_NODE_HEAD_LOCK(ipo->ipo_head); 631170263Sdarrenr ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask, 632145516Sdarrenr ipo->ipo_head); 633145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); 634145516Sdarrenr 635170263Sdarrenr ip_pool_node_deref(ipe); 636145516Sdarrenr 637145516Sdarrenr return 0; 638145516Sdarrenr} 639145516Sdarrenr 640145516Sdarrenr 641145516Sdarrenr/* ------------------------------------------------------------------------ */ 642145516Sdarrenr/* Function: ip_pool_destroy */ 643145516Sdarrenr/* Returns: int - 0 = success, else error */ 644145516Sdarrenr/* Parameters: op(I) - information about the pool to remove */ 645145516Sdarrenr/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 646145516Sdarrenr/* */ 647145516Sdarrenr/* Search for a pool using paramters passed in and if it's not otherwise */ 648170263Sdarrenr/* busy, free it. If it is busy, clear all of its nodes, mark it for being */ 649170263Sdarrenr/* deleted and return an error saying it is busy. */ 650145516Sdarrenr/* */ 651170263Sdarrenr/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */ 652145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking */ 653145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 654145516Sdarrenr/* ------------------------------------------------------------------------ */ 655170263Sdarrenrint ip_pool_destroy(unit, name) 656170263Sdarrenrint unit; 657170263Sdarrenrchar *name; 658145516Sdarrenr{ 659145516Sdarrenr ip_pool_t *ipo; 660145516Sdarrenr 661170263Sdarrenr ipo = ip_pool_exists(unit, name); 662145516Sdarrenr if (ipo == NULL) 663145516Sdarrenr return ESRCH; 664145516Sdarrenr 665170263Sdarrenr if (ipo->ipo_ref != 1) { 666170263Sdarrenr ip_pool_clearnodes(ipo); 667170263Sdarrenr ipo->ipo_flags |= IPOOL_DELETE; 668170263Sdarrenr return 0; 669170263Sdarrenr } 670145516Sdarrenr 671145516Sdarrenr ip_pool_free(ipo); 672145516Sdarrenr return 0; 673145516Sdarrenr} 674145516Sdarrenr 675145516Sdarrenr 676145516Sdarrenr/* ------------------------------------------------------------------------ */ 677145516Sdarrenr/* Function: ip_pool_flush */ 678145516Sdarrenr/* Returns: int - number of pools deleted */ 679145516Sdarrenr/* Parameters: fp(I) - which pool(s) to flush */ 680145516Sdarrenr/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 681145516Sdarrenr/* */ 682145516Sdarrenr/* Free all pools associated with the device that matches the unit number */ 683145516Sdarrenr/* passed in with operation. */ 684145516Sdarrenr/* */ 685170263Sdarrenr/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */ 686145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking */ 687145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 688145516Sdarrenr/* ------------------------------------------------------------------------ */ 689145516Sdarrenrint ip_pool_flush(fp) 690145516Sdarrenriplookupflush_t *fp; 691145516Sdarrenr{ 692145516Sdarrenr int i, num = 0, unit, err; 693145516Sdarrenr ip_pool_t *p, *q; 694145516Sdarrenr iplookupop_t op; 695145516Sdarrenr 696145516Sdarrenr unit = fp->iplf_unit; 697145516Sdarrenr 698145516Sdarrenr for (i = 0; i <= IPL_LOGMAX; i++) { 699145516Sdarrenr if (unit != IPLT_ALL && i != unit) 700145516Sdarrenr continue; 701145516Sdarrenr for (q = ip_pool_list[i]; (p = q) != NULL; ) { 702145516Sdarrenr op.iplo_unit = i; 703145516Sdarrenr (void)strncpy(op.iplo_name, p->ipo_name, 704145516Sdarrenr sizeof(op.iplo_name)); 705145516Sdarrenr q = p->ipo_next; 706170263Sdarrenr err = ip_pool_destroy(op.iplo_unit, op.iplo_name); 707145516Sdarrenr if (err == 0) 708145516Sdarrenr num++; 709145516Sdarrenr else 710145516Sdarrenr break; 711145516Sdarrenr } 712145516Sdarrenr } 713145516Sdarrenr return num; 714145516Sdarrenr} 715145516Sdarrenr 716145516Sdarrenr 717145516Sdarrenr/* ------------------------------------------------------------------------ */ 718145516Sdarrenr/* Function: ip_pool_free */ 719145516Sdarrenr/* Returns: void */ 720145516Sdarrenr/* Parameters: ipo(I) - pointer to pool structure */ 721145516Sdarrenr/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 722145516Sdarrenr/* */ 723145516Sdarrenr/* Deletes the pool strucutre passed in from the list of pools and deletes */ 724145516Sdarrenr/* all of the address information stored in it, including any tree data */ 725145516Sdarrenr/* structures also allocated. */ 726145516Sdarrenr/* */ 727170263Sdarrenr/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */ 728145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking */ 729145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 730145516Sdarrenr/* ------------------------------------------------------------------------ */ 731145516Sdarrenrvoid ip_pool_free(ipo) 732145516Sdarrenrip_pool_t *ipo; 733145516Sdarrenr{ 734170263Sdarrenr 735170263Sdarrenr ip_pool_clearnodes(ipo); 736170263Sdarrenr 737170263Sdarrenr if (ipo->ipo_next != NULL) 738170263Sdarrenr ipo->ipo_next->ipo_pnext = ipo->ipo_pnext; 739170263Sdarrenr *ipo->ipo_pnext = ipo->ipo_next; 740170263Sdarrenr rn_freehead(ipo->ipo_head); 741170263Sdarrenr KFREE(ipo); 742170263Sdarrenr 743170263Sdarrenr ipoolstat.ipls_pools--; 744170263Sdarrenr} 745170263Sdarrenr 746170263Sdarrenr 747170263Sdarrenr/* ------------------------------------------------------------------------ */ 748170263Sdarrenr/* Function: ip_pool_clearnodes */ 749170263Sdarrenr/* Returns: void */ 750170263Sdarrenr/* Parameters: ipo(I) - pointer to pool structure */ 751170263Sdarrenr/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 752170263Sdarrenr/* */ 753170263Sdarrenr/* Deletes all nodes stored in a pool structure. */ 754170263Sdarrenr/* ------------------------------------------------------------------------ */ 755170263Sdarrenrstatic void ip_pool_clearnodes(ipo) 756170263Sdarrenrip_pool_t *ipo; 757170263Sdarrenr{ 758145516Sdarrenr ip_pool_node_t *n; 759145516Sdarrenr 760145516Sdarrenr RADIX_NODE_HEAD_LOCK(ipo->ipo_head); 761145516Sdarrenr while ((n = ipo->ipo_list) != NULL) { 762145516Sdarrenr ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask, 763145516Sdarrenr ipo->ipo_head); 764145516Sdarrenr 765145516Sdarrenr *n->ipn_pnext = n->ipn_next; 766145516Sdarrenr if (n->ipn_next) 767145516Sdarrenr n->ipn_next->ipn_pnext = n->ipn_pnext; 768145516Sdarrenr 769145516Sdarrenr KFREE(n); 770145516Sdarrenr 771145516Sdarrenr ipoolstat.ipls_nodes--; 772145516Sdarrenr } 773145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); 774145516Sdarrenr 775145516Sdarrenr ipo->ipo_list = NULL; 776145516Sdarrenr} 777145516Sdarrenr 778145516Sdarrenr 779145516Sdarrenr/* ------------------------------------------------------------------------ */ 780145516Sdarrenr/* Function: ip_pool_deref */ 781145516Sdarrenr/* Returns: void */ 782145516Sdarrenr/* Parameters: ipo(I) - pointer to pool structure */ 783145516Sdarrenr/* Locks: WRITE(ip_poolrw) */ 784145516Sdarrenr/* */ 785145516Sdarrenr/* Drop the number of known references to this pool structure by one and if */ 786145516Sdarrenr/* we arrive at zero known references, free it. */ 787145516Sdarrenr/* ------------------------------------------------------------------------ */ 788145516Sdarrenrvoid ip_pool_deref(ipo) 789145516Sdarrenrip_pool_t *ipo; 790145516Sdarrenr{ 791145516Sdarrenr 792145516Sdarrenr ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 793145516Sdarrenr 794145516Sdarrenr ipo->ipo_ref--; 795170263Sdarrenr 796145516Sdarrenr if (ipo->ipo_ref == 0) 797145516Sdarrenr ip_pool_free(ipo); 798170263Sdarrenr 799170263Sdarrenr else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE)) 800170263Sdarrenr ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name); 801145516Sdarrenr} 802145516Sdarrenr 803145516Sdarrenr 804170263Sdarrenr/* ------------------------------------------------------------------------ */ 805170263Sdarrenr/* Function: ip_pool_node_deref */ 806170263Sdarrenr/* Returns: void */ 807170263Sdarrenr/* Parameters: ipn(I) - pointer to pool structure */ 808170263Sdarrenr/* Locks: WRITE(ip_poolrw) */ 809170263Sdarrenr/* */ 810170263Sdarrenr/* Drop a reference to the pool node passed in and if we're the last, free */ 811170263Sdarrenr/* it all up and adjust the stats accordingly. */ 812170263Sdarrenr/* ------------------------------------------------------------------------ */ 813170263Sdarrenrvoid ip_pool_node_deref(ipn) 814170263Sdarrenrip_pool_node_t *ipn; 815170263Sdarrenr{ 816170263Sdarrenr 817170263Sdarrenr ipn->ipn_ref--; 818170263Sdarrenr 819170263Sdarrenr if (ipn->ipn_ref == 0) { 820170263Sdarrenr KFREE(ipn); 821170263Sdarrenr ipoolstat.ipls_nodes--; 822170263Sdarrenr } 823170263Sdarrenr} 824170263Sdarrenr 825170263Sdarrenr 826170263Sdarrenr/* ------------------------------------------------------------------------ */ 827170263Sdarrenr/* Function: ip_pool_getnext */ 828170263Sdarrenr/* Returns: void */ 829170263Sdarrenr/* Parameters: token(I) - pointer to pool structure */ 830170263Sdarrenr/* Parameters: ilp(IO) - pointer to pool iterating structure */ 831170263Sdarrenr/* */ 832170263Sdarrenr/* ------------------------------------------------------------------------ */ 833170263Sdarrenrint ip_pool_getnext(token, ilp) 834170263Sdarrenripftoken_t *token; 835170263Sdarrenripflookupiter_t *ilp; 836170263Sdarrenr{ 837170263Sdarrenr ip_pool_node_t *node, zn, *nextnode; 838170263Sdarrenr ip_pool_t *ipo, zp, *nextipo; 839170263Sdarrenr int err; 840170263Sdarrenr 841170263Sdarrenr err = 0; 842170263Sdarrenr node = NULL; 843170263Sdarrenr nextnode = NULL; 844170263Sdarrenr ipo = NULL; 845170263Sdarrenr nextipo = NULL; 846170263Sdarrenr 847170263Sdarrenr READ_ENTER(&ip_poolrw); 848170263Sdarrenr 849170263Sdarrenr switch (ilp->ili_otype) 850170263Sdarrenr { 851170263Sdarrenr case IPFLOOKUPITER_LIST : 852170263Sdarrenr ipo = token->ipt_data; 853170263Sdarrenr if (ipo == NULL) { 854170263Sdarrenr nextipo = ip_pool_list[(int)ilp->ili_unit]; 855170263Sdarrenr } else { 856170263Sdarrenr nextipo = ipo->ipo_next; 857170263Sdarrenr } 858170263Sdarrenr 859170263Sdarrenr if (nextipo != NULL) { 860170263Sdarrenr ATOMIC_INC(nextipo->ipo_ref); 861170263Sdarrenr if (nextipo->ipo_next == NULL) 862170263Sdarrenr token->ipt_alive = 0; 863170263Sdarrenr } else { 864170263Sdarrenr bzero((char *)&zp, sizeof(zp)); 865170263Sdarrenr nextipo = &zp; 866170263Sdarrenr } 867170263Sdarrenr break; 868170263Sdarrenr 869170263Sdarrenr case IPFLOOKUPITER_NODE : 870170263Sdarrenr node = token->ipt_data; 871170263Sdarrenr if (node == NULL) { 872170263Sdarrenr ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name); 873170263Sdarrenr if (ipo == NULL) 874170263Sdarrenr err = ESRCH; 875170263Sdarrenr else { 876170263Sdarrenr nextnode = ipo->ipo_list; 877170263Sdarrenr ipo = NULL; 878170263Sdarrenr } 879170263Sdarrenr } else { 880170263Sdarrenr nextnode = node->ipn_next; 881170263Sdarrenr } 882170263Sdarrenr 883170263Sdarrenr if (nextnode != NULL) { 884170263Sdarrenr ATOMIC_INC(nextnode->ipn_ref); 885170263Sdarrenr if (nextnode->ipn_next == NULL) 886170263Sdarrenr token->ipt_alive = 0; 887170263Sdarrenr } else { 888170263Sdarrenr bzero((char *)&zn, sizeof(zn)); 889170263Sdarrenr nextnode = &zn; 890170263Sdarrenr } 891170263Sdarrenr break; 892170263Sdarrenr default : 893170263Sdarrenr err = EINVAL; 894170263Sdarrenr break; 895170263Sdarrenr } 896170263Sdarrenr 897170263Sdarrenr RWLOCK_EXIT(&ip_poolrw); 898170263Sdarrenr 899170263Sdarrenr if (err != 0) 900170263Sdarrenr return err; 901170263Sdarrenr 902170263Sdarrenr switch (ilp->ili_otype) 903170263Sdarrenr { 904170263Sdarrenr case IPFLOOKUPITER_LIST : 905170263Sdarrenr if (ipo != NULL) { 906170263Sdarrenr WRITE_ENTER(&ip_poolrw); 907170263Sdarrenr ip_pool_deref(ipo); 908170263Sdarrenr RWLOCK_EXIT(&ip_poolrw); 909170263Sdarrenr } 910170263Sdarrenr token->ipt_data = nextipo; 911170263Sdarrenr err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo)); 912170263Sdarrenr if (err != 0) 913170263Sdarrenr err = EFAULT; 914170263Sdarrenr break; 915170263Sdarrenr 916170263Sdarrenr case IPFLOOKUPITER_NODE : 917170263Sdarrenr if (node != NULL) { 918170263Sdarrenr WRITE_ENTER(&ip_poolrw); 919170263Sdarrenr ip_pool_node_deref(node); 920170263Sdarrenr RWLOCK_EXIT(&ip_poolrw); 921170263Sdarrenr } 922170263Sdarrenr token->ipt_data = nextnode; 923170263Sdarrenr err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); 924170263Sdarrenr if (err != 0) 925170263Sdarrenr err = EFAULT; 926170263Sdarrenr break; 927170263Sdarrenr } 928170263Sdarrenr 929170263Sdarrenr return err; 930170263Sdarrenr} 931170263Sdarrenr 932170263Sdarrenr 933170263Sdarrenr/* ------------------------------------------------------------------------ */ 934170263Sdarrenr/* Function: ip_pool_iterderef */ 935170263Sdarrenr/* Returns: void */ 936170263Sdarrenr/* Parameters: ipn(I) - pointer to pool structure */ 937170263Sdarrenr/* Locks: WRITE(ip_poolrw) */ 938170263Sdarrenr/* */ 939170263Sdarrenr/* ------------------------------------------------------------------------ */ 940170263Sdarrenrvoid ip_pool_iterderef(otype, unit, data) 941170263Sdarrenru_int otype; 942170263Sdarrenrint unit; 943170263Sdarrenrvoid *data; 944170263Sdarrenr{ 945170263Sdarrenr 946170263Sdarrenr if (data == NULL) 947170263Sdarrenr return; 948170263Sdarrenr 949170263Sdarrenr if (unit < 0 || unit > IPL_LOGMAX) 950170263Sdarrenr return; 951170263Sdarrenr 952170263Sdarrenr switch (otype) 953170263Sdarrenr { 954170263Sdarrenr case IPFLOOKUPITER_LIST : 955170263Sdarrenr WRITE_ENTER(&ip_poolrw); 956170263Sdarrenr ip_pool_deref((ip_pool_t *)data); 957170263Sdarrenr RWLOCK_EXIT(&ip_poolrw); 958170263Sdarrenr break; 959170263Sdarrenr 960170263Sdarrenr case IPFLOOKUPITER_NODE : 961170263Sdarrenr WRITE_ENTER(&ip_poolrw); 962170263Sdarrenr ip_pool_node_deref((ip_pool_node_t *)data); 963170263Sdarrenr RWLOCK_EXIT(&ip_poolrw); 964170263Sdarrenr break; 965170263Sdarrenr default : 966170263Sdarrenr break; 967170263Sdarrenr } 968170263Sdarrenr} 969170263Sdarrenr 970170263Sdarrenr 971145516Sdarrenr# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \ 972145516Sdarrenr !defined(__hpux) && !defined(__sgi)) 973145516Sdarrenrstatic int 974145516Sdarrenrrn_freenode(struct radix_node *n, void *p) 975145516Sdarrenr{ 976145516Sdarrenr struct radix_node_head *rnh = p; 977145516Sdarrenr struct radix_node *d; 978145516Sdarrenr 979145516Sdarrenr d = rnh->rnh_deladdr(n->rn_key, NULL, rnh); 980145516Sdarrenr if (d != NULL) { 981145516Sdarrenr FreeS(d, max_keylen + 2 * sizeof (*d)); 982145516Sdarrenr } 983145516Sdarrenr return 0; 984145516Sdarrenr} 985145516Sdarrenr 986145516Sdarrenr 987145516Sdarrenrvoid 988145516Sdarrenrrn_freehead(rnh) 989145516Sdarrenr struct radix_node_head *rnh; 990145516Sdarrenr{ 991145516Sdarrenr 992145516Sdarrenr RADIX_NODE_HEAD_LOCK(rnh); 993145516Sdarrenr (*rnh->rnh_walktree)(rnh, rn_freenode, rnh); 994145516Sdarrenr 995145516Sdarrenr rnh->rnh_addaddr = NULL; 996145516Sdarrenr rnh->rnh_deladdr = NULL; 997145516Sdarrenr rnh->rnh_matchaddr = NULL; 998145516Sdarrenr rnh->rnh_lookup = NULL; 999145516Sdarrenr rnh->rnh_walktree = NULL; 1000145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(rnh); 1001145516Sdarrenr 1002145516Sdarrenr Free(rnh); 1003145516Sdarrenr} 1004145516Sdarrenr# endif 1005145516Sdarrenr#endif /* IPFILTER_LOOKUP */ 1006