diff options
Diffstat (limited to 'contrib/ipfilter/radix.c')
-rw-r--r-- | contrib/ipfilter/radix.c | 1212 |
1 files changed, 0 insertions, 1212 deletions
diff --git a/contrib/ipfilter/radix.c b/contrib/ipfilter/radix.c deleted file mode 100644 index f9fc20c..0000000 --- a/contrib/ipfilter/radix.c +++ /dev/null @@ -1,1212 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)radix.c 8.6 (Berkeley) 10/17/95 - */ - -/* - * Routines to build and maintain radix trees for routing lookups. - */ -#if defined(KERNEL) || defined(_KERNEL) -# undef KERNEL -# undef _KERNEL -# define KERNEL 1 -# define _KERNEL 1 -#endif -#define __SYS_ATOMIC_OPS_H__ -#if !defined(__svr4__) && !defined(__SVR4) && !defined(__osf__) && \ - !defined(__hpux) && !defined(__sgi) -#include <sys/cdefs.h> -#endif -#ifndef __P -# ifdef __STDC__ -# define __P(x) x -# else -# define __P(x) () -# endif -#endif -#ifdef __osf__ -# define CONST -# define _IPV6_SWTAB_H -# define _PROTO_NET_H_ -# define _PROTO_IPV6_H -# include <sys/malloc.h> -#endif - -#include <sys/param.h> -#ifdef _KERNEL -#include <sys/systm.h> -#else -void panic __P((char *str)); -#include <stdlib.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#endif -#ifdef __hpux -#include <syslog.h> -#else -#include <sys/syslog.h> -#endif -#include <sys/time.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <net/if.h> -#ifdef SOLARIS2 -# define _RADIX_H_ -#endif -#include "netinet/ip_compat.h" -#include "netinet/ip_fil.h" -#ifdef SOLARIS2 -# undef _RADIX_H_ -#endif -/* END OF INCLUDES */ -#include "radix_ipf.h" -#ifndef min -# define min MIN -#endif -#ifndef max -# define max MAX -#endif - -int max_keylen = 16; -static struct radix_mask *rn_mkfreelist; -static struct radix_node_head *mask_rnhead; -static char *addmask_key; -static u_char normal_chars[] = {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; -static char *rn_zeros = NULL, *rn_ones = NULL; - -#define rn_masktop (mask_rnhead->rnh_treetop) -#undef Bcmp -#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l)) - -static int rn_satisfies_leaf __P((char *, struct radix_node *, int)); -static int rn_lexobetter __P((void *, void *)); -static struct radix_mask *rn_new_radix_mask __P((struct radix_node *, - struct radix_mask *)); -static int rn_freenode __P((struct radix_node *, void *)); -#if defined(AIX) && !defined(_KERNEL) -struct radix_node *rn_match __P((void *, struct radix_node_head *)); -struct radix_node *rn_addmask __P((int, int, void *)); -#define FreeS(x, y) KFREES(x, y) -#define Bcopy(x, y, z) bcopy(x, y, z) -#endif - -/* - * The data structure for the keys is a radix tree with one way - * branching removed. The index rn_b at an internal node n represents a bit - * position to be tested. The tree is arranged so that all descendants - * of a node n have keys whose bits all agree up to position rn_b - 1. - * (We say the index of n is rn_b.) - * - * There is at least one descendant which has a one bit at position rn_b, - * and at least one with a zero there. - * - * A route is determined by a pair of key and mask. We require that the - * bit-wise logical and of the key and mask to be the key. - * We define the index of a route to associated with the mask to be - * the first bit number in the mask where 0 occurs (with bit number 0 - * representing the highest order bit). - * - * We say a mask is normal if every bit is 0, past the index of the mask. - * If a node n has a descendant (k, m) with index(m) == index(n) == rn_b, - * and m is a normal mask, then the route applies to every descendant of n. - * If the index(m) < rn_b, this implies the trailing last few bits of k - * before bit b are all 0, (and hence consequently true of every descendant - * of n), so the route applies to all descendants of the node as well. - * - * Similar logic shows that a non-normal mask m such that - * index(m) <= index(n) could potentially apply to many children of n. - * Thus, for each non-host route, we attach its mask to a list at an internal - * node as high in the tree as we can go. - * - * The present version of the code makes use of normal routes in short- - * circuiting an explicit mask and compare operation when testing whether - * a key satisfies a normal route, and also in remembering the unique leaf - * that governs a subtree. - */ - -struct radix_node * -rn_search(v_arg, head) - void *v_arg; - struct radix_node *head; -{ - struct radix_node *x; - caddr_t v; - - for (x = head, v = v_arg; x->rn_b >= 0;) { - if (x->rn_bmask & v[x->rn_off]) - x = x->rn_r; - else - x = x->rn_l; - } - return (x); -} - -struct radix_node * -rn_search_m(v_arg, head, m_arg) - struct radix_node *head; - void *v_arg, *m_arg; -{ - struct radix_node *x; - caddr_t v = v_arg, m = m_arg; - - for (x = head; x->rn_b >= 0;) { - if ((x->rn_bmask & m[x->rn_off]) && - (x->rn_bmask & v[x->rn_off])) - x = x->rn_r; - else - x = x->rn_l; - } - return x; -} - -int -rn_refines(m_arg, n_arg) - void *m_arg, *n_arg; -{ - caddr_t m = m_arg, n = n_arg; - caddr_t lim, lim2 = lim = n + *(u_char *)n; - int longer = (*(u_char *)n++) - (int)(*(u_char *)m++); - int masks_are_equal = 1; - - if (longer > 0) - lim -= longer; - while (n < lim) { - if (*n & ~(*m)) - return 0; - if (*n++ != *m++) - masks_are_equal = 0; - } - while (n < lim2) - if (*n++) - return 0; - if (masks_are_equal && (longer < 0)) - for (lim2 = m - longer; m < lim2; ) - if (*m++) - return 1; - return (!masks_are_equal); -} - -struct radix_node * -rn_lookup(v_arg, m_arg, head) - void *v_arg, *m_arg; - struct radix_node_head *head; -{ - struct radix_node *x; - caddr_t netmask = 0; - - if (m_arg) { - if ((x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_off)) == 0) - return (0); - netmask = x->rn_key; - } - x = rn_match(v_arg, head); - if (x && netmask) { - while (x && x->rn_mask != netmask) - x = x->rn_dupedkey; - } - return x; -} - -static int -rn_satisfies_leaf(trial, leaf, skip) - char *trial; - struct radix_node *leaf; - int skip; -{ - char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask; - char *cplim; - int length = min(*(u_char *)cp, *(u_char *)cp2); - - if (cp3 == 0) - cp3 = rn_ones; - else - length = min(length, *(u_char *)cp3); - cplim = cp + length; - cp3 += skip; - cp2 += skip; - for (cp += skip; cp < cplim; cp++, cp2++, cp3++) - if ((*cp ^ *cp2) & *cp3) - return 0; - return 1; -} - -struct radix_node * -rn_match(v_arg, head) - void *v_arg; - struct radix_node_head *head; -{ - caddr_t v = v_arg; - struct radix_node *t = head->rnh_treetop, *x; - caddr_t cp = v, cp2; - caddr_t cplim; - struct radix_node *saved_t, *top = t; - int off = t->rn_off, vlen = *(u_char *)cp, matched_off; - int test, b, rn_b; - - /* - * Open code rn_search(v, top) to avoid overhead of extra - * subroutine call. - */ - for (; t->rn_b >= 0; ) { - if (t->rn_bmask & cp[t->rn_off]) - t = t->rn_r; - else - t = t->rn_l; - } - /* - * See if we match exactly as a host destination - * or at least learn how many bits match, for normal mask finesse. - * - * It doesn't hurt us to limit how many bytes to check - * to the length of the mask, since if it matches we had a genuine - * match and the leaf we have is the most specific one anyway; - * if it didn't match with a shorter length it would fail - * with a long one. This wins big for class B&C netmasks which - * are probably the most common case... - */ - if (t->rn_mask) - vlen = *(u_char *)t->rn_mask; - cp += off; - cp2 = t->rn_key + off; - cplim = v + vlen; - for (; cp < cplim; cp++, cp2++) - if (*cp != *cp2) - goto on1; - /* - * This extra grot is in case we are explicitly asked - * to look up the default. Ugh! - */ - if ((t->rn_flags & RNF_ROOT) && t->rn_dupedkey) - t = t->rn_dupedkey; - return t; -on1: - test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */ - for (b = 7; (test >>= 1) > 0;) - b--; - matched_off = cp - v; - b += matched_off << 3; - rn_b = -1 - b; - /* - * If there is a host route in a duped-key chain, it will be first. - */ - if ((saved_t = t)->rn_mask == 0) - t = t->rn_dupedkey; - for (; t; t = t->rn_dupedkey) - /* - * Even if we don't match exactly as a host, - * we may match if the leaf we wound up at is - * a route to a net. - */ - if (t->rn_flags & RNF_NORMAL) { - if (rn_b <= t->rn_b) - return t; - } else if (rn_satisfies_leaf(v, t, matched_off)) - return t; - t = saved_t; - /* start searching up the tree */ - do { - struct radix_mask *m; - t = t->rn_p; - m = t->rn_mklist; - if (m) { - /* - * If non-contiguous masks ever become important - * we can restore the masking and open coding of - * the search and satisfaction test and put the - * calculation of "off" back before the "do". - */ - do { - if (m->rm_flags & RNF_NORMAL) { - if (rn_b <= m->rm_b) - return (m->rm_leaf); - } else { - off = min(t->rn_off, matched_off); - x = rn_search_m(v, t, m->rm_mask); - while (x && x->rn_mask != m->rm_mask) - x = x->rn_dupedkey; - if (x && rn_satisfies_leaf(v, x, off)) - return x; - } - m = m->rm_mklist; - } while (m); - } - } while (t != top); - return 0; -} - -#ifdef RN_DEBUG -int rn_nodenum; -struct radix_node *rn_clist; -int rn_saveinfo; -int rn_debug = 1; -#endif - -struct radix_node * -rn_newpair(v, b, nodes) - void *v; - int b; - struct radix_node nodes[2]; -{ - struct radix_node *tt = nodes, *t = tt + 1; - t->rn_b = b; - t->rn_bmask = 0x80 >> (b & 7); - t->rn_l = tt; - t->rn_off = b >> 3; - tt->rn_b = -1; - tt->rn_key = (caddr_t)v; - tt->rn_p = t; - tt->rn_flags = t->rn_flags = RNF_ACTIVE; -#ifdef RN_DEBUG - tt->rn_info = rn_nodenum++; - t->rn_info = rn_nodenum++; - tt->rn_twin = t; - tt->rn_ybro = rn_clist; - rn_clist = tt; -#endif - return t; -} - -struct radix_node * -rn_insert(v_arg, head, dupentry, nodes) - void *v_arg; - struct radix_node_head *head; - int *dupentry; - struct radix_node nodes[2]; -{ - caddr_t v = v_arg; - struct radix_node *top = head->rnh_treetop; - int head_off = top->rn_off, vlen = (int)*((u_char *)v); - struct radix_node *t = rn_search(v_arg, top); - caddr_t cp = v + head_off; - int b; - struct radix_node *tt; - -#ifdef RN_DEBUG - if (rn_debug) - log(LOG_DEBUG, "rn_insert(%p,%p,%p,%p)\n", v_arg, head, dupentry, nodes); -#endif - /* - * Find first bit at which v and t->rn_key differ - */ - { - caddr_t cp2 = t->rn_key + head_off; - int cmp_res; - caddr_t cplim = v + vlen; - - while (cp < cplim) - if (*cp2++ != *cp++) - goto on1; - *dupentry = 1; - return t; -on1: - *dupentry = 0; - cmp_res = (cp[-1] ^ cp2[-1]) & 0xff; - for (b = (cp - v) << 3; cmp_res; b--) - cmp_res >>= 1; - } - { - struct radix_node *p, *x = top; - cp = v; - do { - p = x; - if (cp[x->rn_off] & x->rn_bmask) - x = x->rn_r; - else - x = x->rn_l; - } while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */ -#ifdef RN_DEBUG - if (rn_debug) - log(LOG_DEBUG, "rn_insert: Going In:\n"); // traverse(p); -#endif - t = rn_newpair(v_arg, b, nodes); - tt = t->rn_l; - if ((cp[p->rn_off] & p->rn_bmask) == 0) - p->rn_l = t; - else - p->rn_r = t; - x->rn_p = t; - t->rn_p = p; /* frees x, p as temp vars below */ - if ((cp[t->rn_off] & t->rn_bmask) == 0) { - t->rn_r = x; - } else { - t->rn_r = tt; - t->rn_l = x; - } -#ifdef RN_DEBUG - if (rn_debug) - log(LOG_DEBUG, "rn_insert: Coming Out:\n"); // traverse(p); -#endif - } - return (tt); -} - -struct radix_node * -rn_addmask(n_arg, search, skip) - int search, skip; - void *n_arg; -{ - caddr_t netmask = (caddr_t)n_arg; - struct radix_node *x; - caddr_t cp, cplim; - int b = 0, mlen, j; - int maskduplicated, m0, isnormal; - struct radix_node *saved_x; - static int last_zeroed = 0; - -#ifdef RN_DEBUG - if (rn_debug) - log(LOG_DEBUG, "rn_addmask(%p,%d,%d)\n", n_arg, search, skip); -#endif - mlen = *(u_char *)netmask; - if ((mlen = *(u_char *)netmask) > max_keylen) - mlen = max_keylen; - if (skip == 0) - skip = 1; - if (mlen <= skip) - return (mask_rnhead->rnh_nodes); - if (skip > 1) - Bcopy(rn_ones + 1, addmask_key + 1, skip - 1); - if ((m0 = mlen) > skip) - Bcopy(netmask + skip, addmask_key + skip, mlen - skip); - /* - * Trim trailing zeroes. - */ - for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;) - cp--; - mlen = cp - addmask_key; - if (mlen <= skip) { - if (m0 >= last_zeroed) - last_zeroed = mlen; - return (mask_rnhead->rnh_nodes); - } - if (m0 < last_zeroed) - Bzero(addmask_key + m0, last_zeroed - m0); - *addmask_key = last_zeroed = mlen; - x = rn_search(addmask_key, rn_masktop); - if (Bcmp(addmask_key, x->rn_key, mlen) != 0) - x = 0; - if (x || search) - return (x); - R_Malloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x)); - if ((saved_x = x) == 0) - return (0); - Bzero(x, max_keylen + 2 * sizeof (*x)); - netmask = cp = (caddr_t)(x + 2); - Bcopy(addmask_key, cp, mlen); - x = rn_insert(cp, mask_rnhead, &maskduplicated, x); - if (maskduplicated) { -#if 0 - log(LOG_ERR, "rn_addmask: mask impossibly already in tree\n"); -#endif - Free(saved_x); - return (x); - } - /* - * Calculate index of mask, and check for normalcy. - */ - cplim = netmask + mlen; - isnormal = 1; - for (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;) - cp++; - if (cp != cplim) { - for (j = 0x80; (j & *cp) != 0; j >>= 1) - b++; - if (*cp != normal_chars[b] || cp != (cplim - 1)) - isnormal = 0; - } - b += (cp - netmask) << 3; - x->rn_b = -1 - b; - if (isnormal) - x->rn_flags |= RNF_NORMAL; - return (x); -} - -static int /* XXX: arbitrary ordering for non-contiguous masks */ -rn_lexobetter(m_arg, n_arg) - void *m_arg, *n_arg; -{ - u_char *mp = m_arg, *np = n_arg, *lim; - - if (*mp > *np) - return 1; /* not really, but need to check longer one first */ - if (*mp == *np) - for (lim = mp + *mp; mp < lim;) - if (*mp++ > *np++) - return 1; - return 0; -} - -static struct radix_mask * -rn_new_radix_mask(tt, next) - struct radix_node *tt; - struct radix_mask *next; -{ - struct radix_mask *m; - - MKGet(m); - if (m == 0) { -#if 0 - log(LOG_ERR, "Mask for route not entered\n"); -#endif - return (0); - } - Bzero(m, sizeof *m); - m->rm_b = tt->rn_b; - m->rm_flags = tt->rn_flags; - if (tt->rn_flags & RNF_NORMAL) - m->rm_leaf = tt; - else - m->rm_mask = tt->rn_mask; - m->rm_mklist = next; - tt->rn_mklist = m; - return m; -} - -struct radix_node * -rn_addroute(v_arg, n_arg, head, treenodes) - void *v_arg, *n_arg; - struct radix_node_head *head; - struct radix_node treenodes[2]; -{ - caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg; - struct radix_node *t, *x = NULL, *tt; - struct radix_node *saved_tt, *top = head->rnh_treetop; - short b = 0, b_leaf = 0; - int keyduplicated; - caddr_t mmask; - struct radix_mask *m, **mp; - -#ifdef RN_DEBUG - if (rn_debug) - log(LOG_DEBUG, "rn_addroute(%p,%p,%p,%p)\n", v_arg, n_arg, head, treenodes); -#endif - /* - * In dealing with non-contiguous masks, there may be - * many different routes which have the same mask. - * We will find it useful to have a unique pointer to - * the mask to speed avoiding duplicate references at - * nodes and possibly save time in calculating indices. - */ - if (netmask) { - if ((x = rn_addmask(netmask, 0, top->rn_off)) == 0) - return (0); - b_leaf = x->rn_b; - b = -1 - x->rn_b; - netmask = x->rn_key; - } - /* - * Deal with duplicated keys: attach node to previous instance - */ - saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes); - if (keyduplicated) { - for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) { - if (tt->rn_mask == netmask) - return (0); - if (netmask == 0 || - (tt->rn_mask && - ((b_leaf < tt->rn_b) || /* index(netmask) > node */ - rn_refines(netmask, tt->rn_mask) || - rn_lexobetter(netmask, tt->rn_mask)))) - break; - } - /* - * If the mask is not duplicated, we wouldn't - * find it among possible duplicate key entries - * anyway, so the above test doesn't hurt. - * - * We sort the masks for a duplicated key the same way as - * in a masklist -- most specific to least specific. - * This may require the unfortunate nuisance of relocating - * the head of the list. - * - * We also reverse, or doubly link the list through the - * parent pointer. - */ - if (tt == saved_tt) { - struct radix_node *xx = x; - /* link in at head of list */ - (tt = treenodes)->rn_dupedkey = t; - tt->rn_flags = t->rn_flags; - tt->rn_p = x = t->rn_p; - t->rn_p = tt; - if (x->rn_l == t) - x->rn_l = tt; - else - x->rn_r = tt; - saved_tt = tt; - x = xx; - } else { - (tt = treenodes)->rn_dupedkey = t->rn_dupedkey; - t->rn_dupedkey = tt; - tt->rn_p = t; - if (tt->rn_dupedkey) - tt->rn_dupedkey->rn_p = tt; - } -#ifdef RN_DEBUG - t=tt+1; - tt->rn_info = rn_nodenum++; - t->rn_info = rn_nodenum++; - tt->rn_twin = t; - tt->rn_ybro = rn_clist; - rn_clist = tt; -#endif - tt->rn_key = (caddr_t) v; - tt->rn_b = -1; - tt->rn_flags = RNF_ACTIVE; - } - /* - * Put mask in tree. - */ - if (netmask) { - tt->rn_mask = netmask; - tt->rn_b = x->rn_b; - tt->rn_flags |= x->rn_flags & RNF_NORMAL; - } - t = saved_tt->rn_p; - if (keyduplicated) - goto on2; - b_leaf = -1 - t->rn_b; - if (t->rn_r == saved_tt) - x = t->rn_l; - else - x = t->rn_r; - /* Promote general routes from below */ - if (x->rn_b < 0) { - for (mp = &t->rn_mklist; x; x = x->rn_dupedkey) - if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) { - *mp = m = rn_new_radix_mask(x, 0); - if (m) - mp = &m->rm_mklist; - } - } else if (x->rn_mklist) { - /* - * Skip over masks whose index is > that of new node - */ - for (mp = &x->rn_mklist; (m = *mp) != NULL; mp = &m->rm_mklist) - if (m->rm_b >= b_leaf) - break; - t->rn_mklist = m; - *mp = 0; - } -on2: - /* Add new route to highest possible ancestor's list */ - if ((netmask == 0) || (b > t->rn_b )) - return tt; /* can't lift at all */ - b_leaf = tt->rn_b; - do { - x = t; - t = t->rn_p; - } while (b <= t->rn_b && x != top); - /* - * Search through routes associated with node to - * insert new route according to index. - * Need same criteria as when sorting dupedkeys to avoid - * double loop on deletion. - */ - for (mp = &x->rn_mklist; (m = *mp) != NULL; mp = &m->rm_mklist) { - if (m->rm_b < b_leaf) - continue; - if (m->rm_b > b_leaf) - break; - if (m->rm_flags & RNF_NORMAL) { - mmask = m->rm_leaf->rn_mask; - if (tt->rn_flags & RNF_NORMAL) { -#if 0 - log(LOG_ERR, "Non-unique normal route," - " mask not entered\n"); -#endif - return tt; - } - } else - mmask = m->rm_mask; - if (mmask == netmask) { - m->rm_refs++; - tt->rn_mklist = m; - return tt; - } - if (rn_refines(netmask, mmask) - || rn_lexobetter(netmask, mmask)) - break; - } - *mp = rn_new_radix_mask(tt, *mp); - return tt; -} - -struct radix_node * -rn_delete(v_arg, netmask_arg, head) - void *v_arg, *netmask_arg; - struct radix_node_head *head; -{ - struct radix_node *t, *p, *x, *tt; - struct radix_mask *m, *saved_m, **mp; - struct radix_node *dupedkey, *saved_tt, *top; - caddr_t v, netmask; - int b, head_off, vlen; - - v = v_arg; - netmask = netmask_arg; - x = head->rnh_treetop; - tt = rn_search(v, x); - head_off = x->rn_off; - vlen = *(u_char *)v; - saved_tt = tt; - top = x; - if (tt == 0 || - Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off)) - return (0); - /* - * Delete our route from mask lists. - */ - if (netmask) { - if ((x = rn_addmask(netmask, 1, head_off)) == 0) - return (0); - netmask = x->rn_key; - while (tt->rn_mask != netmask) - if ((tt = tt->rn_dupedkey) == 0) - return (0); - } - if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0) - goto on1; - if (tt->rn_flags & RNF_NORMAL) { - if (m->rm_leaf != tt || m->rm_refs > 0) { -#if 0 - log(LOG_ERR, "rn_delete: inconsistent annotation\n"); -#endif - return 0; /* dangling ref could cause disaster */ - } - } else { - if (m->rm_mask != tt->rn_mask) { -#if 0 - log(LOG_ERR, "rn_delete: inconsistent annotation\n"); -#endif - goto on1; - } - if (--m->rm_refs >= 0) - goto on1; - } - b = -1 - tt->rn_b; - t = saved_tt->rn_p; - if (b > t->rn_b) - goto on1; /* Wasn't lifted at all */ - do { - x = t; - t = t->rn_p; - } while (b <= t->rn_b && x != top); - for (mp = &x->rn_mklist; (m = *mp) != NULL; mp = &m->rm_mklist) - if (m == saved_m) { - *mp = m->rm_mklist; - MKFree(m); - break; - } - if (m == 0) { -#if 0 - log(LOG_ERR, "rn_delete: couldn't find our annotation\n"); -#endif - if (tt->rn_flags & RNF_NORMAL) - return (0); /* Dangling ref to us */ - } -on1: - /* - * Eliminate us from tree - */ - if (tt->rn_flags & RNF_ROOT) - return (0); -#ifdef RN_DEBUG - /* Get us out of the creation list */ - for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) - ; - if (t) t->rn_ybro = tt->rn_ybro; -#endif - t = tt->rn_p; - dupedkey = saved_tt->rn_dupedkey; - if (dupedkey) { - /* - * Here, tt is the deletion target and - * saved_tt is the head of the dupedkey chain. - */ - if (tt == saved_tt) { - x = dupedkey; - x->rn_p = t; - if (t->rn_l == tt) - t->rn_l = x; - else - t->rn_r = x; - } else { - /* find node in front of tt on the chain */ - for (x = p = saved_tt; p && p->rn_dupedkey != tt;) - p = p->rn_dupedkey; - if (p) { - p->rn_dupedkey = tt->rn_dupedkey; - if (tt->rn_dupedkey) - tt->rn_dupedkey->rn_p = p; - } -#if 0 - else - log(LOG_ERR, "rn_delete: couldn't find us\n"); -#endif - } - t = tt + 1; - if (t->rn_flags & RNF_ACTIVE) { -#ifndef RN_DEBUG - *++x = *t; - p = t->rn_p; -#else - b = t->rn_info; - *++x = *t; - t->rn_info = b; - p = t->rn_p; -#endif - if (p->rn_l == t) - p->rn_l = x; - else - p->rn_r = x; - x->rn_l->rn_p = x; - x->rn_r->rn_p = x; - } - goto out; - } - if (t->rn_l == tt) - x = t->rn_r; - else - x = t->rn_l; - p = t->rn_p; - if (p->rn_r == t) - p->rn_r = x; - else - p->rn_l = x; - x->rn_p = p; - /* - * Demote routes attached to us. - */ - if (t->rn_mklist) { - if (x->rn_b >= 0) { - for (mp = &x->rn_mklist; (m = *mp) != NULL;) - mp = &m->rm_mklist; - *mp = t->rn_mklist; - } else { - /* If there are any key,mask pairs in a sibling - duped-key chain, some subset will appear sorted - in the same order attached to our mklist */ - for (m = t->rn_mklist; m && x; x = x->rn_dupedkey) - if (m == x->rn_mklist) { - struct radix_mask *mm = m->rm_mklist; - x->rn_mklist = 0; - if (--(m->rm_refs) < 0) - MKFree(m); - m = mm; - } -#if 0 - if (m) - log(LOG_ERR, "%s %p at %p\n", - "rn_delete: Orphaned Mask", m, x); -#endif - } - } - /* - * We may be holding an active internal node in the tree. - */ - x = tt + 1; - if (t != x) { -#ifndef RN_DEBUG - *t = *x; -#else - b = t->rn_info; - *t = *x; - t->rn_info = b; -#endif - t->rn_l->rn_p = t; - t->rn_r->rn_p = t; - p = x->rn_p; - if (p->rn_l == x) - p->rn_l = t; - else - p->rn_r = t; - } -out: - tt->rn_flags &= ~RNF_ACTIVE; - tt[1].rn_flags &= ~RNF_ACTIVE; - return (tt); -} - -int -rn_walktree(h, f, w) - struct radix_node_head *h; - int (*f) __P((struct radix_node *, void *)); - void *w; -{ - int error; - struct radix_node *base, *next; - struct radix_node *rn = h->rnh_treetop; - /* - * This gets complicated because we may delete the node - * while applying the function f to it, so we need to calculate - * the successor node in advance. - */ - /* First time through node, go left */ - while (rn->rn_b >= 0) - rn = rn->rn_l; - for (;;) { - base = rn; - /* If at right child go back up, otherwise, go right */ - while (rn->rn_p->rn_r == rn && (rn->rn_flags & RNF_ROOT) == 0) - rn = rn->rn_p; - /* Find the next *leaf* since next node might vanish, too */ - for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;) - rn = rn->rn_l; - next = rn; - /* Process leaves */ - while ((rn = base) != NULL) { - base = rn->rn_dupedkey; - if (!(rn->rn_flags & RNF_ROOT) - && (error = (*f)(rn, w))) - return (error); - } - rn = next; - if (rn->rn_flags & RNF_ROOT) - return (0); - } - /* NOTREACHED */ -} - -int -rn_inithead(head, off) - void **head; - int off; -{ - struct radix_node_head *rnh; - - if (*head) - return (1); - R_Malloc(rnh, struct radix_node_head *, sizeof (*rnh)); - if (rnh == 0) - return (0); - *head = rnh; - return rn_inithead0(rnh, off); -} - -int -rn_inithead0(rnh, off) - struct radix_node_head *rnh; - int off; -{ - struct radix_node *t, *tt, *ttt; - - Bzero(rnh, sizeof (*rnh)); - t = rn_newpair(rn_zeros, off, rnh->rnh_nodes); - ttt = rnh->rnh_nodes + 2; - t->rn_r = ttt; - t->rn_p = t; - tt = t->rn_l; - tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE; - tt->rn_b = -1 - off; - *ttt = *tt; - ttt->rn_key = rn_ones; - rnh->rnh_addaddr = rn_addroute; - rnh->rnh_deladdr = rn_delete; - rnh->rnh_matchaddr = rn_match; - rnh->rnh_lookup = rn_lookup; - rnh->rnh_walktree = rn_walktree; - rnh->rnh_treetop = t; - return (1); -} - -void -rn_init() -{ - char *cp, *cplim; - - if (max_keylen == 0) { -#if 0 - log(LOG_ERR, - "rn_init: radix functions require max_keylen be set\n"); -#endif - return; - } - if (rn_zeros == NULL) { - R_Malloc(rn_zeros, char *, 3 * max_keylen); - } - if (rn_zeros == NULL) - panic("rn_init"); - Bzero(rn_zeros, 3 * max_keylen); - rn_ones = cp = rn_zeros + max_keylen; - addmask_key = cplim = rn_ones + max_keylen; - while (cp < cplim) - *cp++ = -1; - if (rn_inithead((void *)&mask_rnhead, 0) == 0) - panic("rn_init 2"); -} - - -static int -rn_freenode(struct radix_node *n, void *p) -{ - struct radix_node_head *rnh = p; - struct radix_node *d; - - d = rnh->rnh_deladdr(n->rn_key, NULL, rnh); - if (d != NULL) { - FreeS(d, max_keylen + 2 * sizeof (*d)); - } - return 0; -} - - -void -rn_freehead(rnh) - struct radix_node_head *rnh; -{ - - (void)rn_walktree(rnh, rn_freenode, rnh); - - rnh->rnh_addaddr = NULL; - rnh->rnh_deladdr = NULL; - rnh->rnh_matchaddr = NULL; - rnh->rnh_lookup = NULL; - rnh->rnh_walktree = NULL; - - Free(rnh); -} - - -void -rn_fini() -{ - struct radix_mask *m; - - if (rn_zeros != NULL) { - FreeS(rn_zeros, 3 * max_keylen); - rn_zeros = NULL; - } - - if (mask_rnhead != NULL) { - rn_freehead(mask_rnhead); - mask_rnhead = NULL; - } - - while ((m = rn_mkfreelist) != NULL) { - rn_mkfreelist = m->rm_mklist; - KFREE(m); - } -} - - -#ifdef USE_MAIN - -typedef struct myst { - addrfamily_t dst; - addrfamily_t mask; - struct radix_node nodes[2]; -} myst_t; - -int -main(int argc, char *argv[]) -{ - struct radix_node_head *rnh; - struct radix_node *rn; - addrfamily_t af, mf; - myst_t st1, st2, *stp; - - memset(&st1, 0, sizeof(st1)); - memset(&st2, 0, sizeof(st2)); - memset(&af, 0, sizeof(af)); - - rn_init(); - - rnh = NULL; - rn_inithead(&rnh, offsetof(addrfamily_t, adf_addr) << 3); - - st1.dst.adf_len = sizeof(st1); - st1.mask.adf_len = sizeof(st1); - st1.dst.adf_addr.in4.s_addr = inet_addr("127.0.0.0"); - st1.mask.adf_addr.in4.s_addr = inet_addr("255.0.0.0"); - rn = rnh->rnh_addaddr(&st1.dst, &st1.mask, rnh, st1.nodes); - printf("add.1 %p\n", rn); - - st2.dst.adf_len = sizeof(st2); - st2.mask.adf_len = sizeof(st2); - st2.dst.adf_addr.in4.s_addr = inet_addr("127.0.1.0"); - st2.mask.adf_addr.in4.s_addr = inet_addr("255.255.255.0"); - rn = rnh->rnh_addaddr(&st2.dst, &st2.mask, rnh, st2.nodes); - printf("add.2 %p\n", rn); - - af.adf_len = sizeof(af); - af.adf_addr.in4.s_addr = inet_addr("127.0.1.0"); - rn = rnh->rnh_matchaddr(&af, rnh); - if (rn != NULL) { - printf("1.lookup = %p key %p mask %p\n", rn, rn->rn_key, rn->rn_mask); - stp = rn->rn_key; - printf("%s/", inet_ntoa(stp->dst.adf_addr.in4)); - stp = rn->rn_mask; - printf("%s\n", inet_ntoa(stp->dst.adf_addr.in4)); - } - - mf.adf_len = sizeof(mf); - mf.adf_addr.in4.s_addr = inet_addr("255.255.255.0"); - rn = rnh->rnh_lookup(&af, &mf, rnh); - if (rn != NULL) { - printf("2.lookup = %p key %p mask %p\n", rn, rn->rn_key, rn->rn_mask); - stp = rn->rn_key; - printf("%s/", inet_ntoa(stp->dst.adf_addr.in4)); - stp = rn->rn_mask; - printf("%s\n", inet_ntoa(stp->dst.adf_addr.in4)); - } - - af.adf_len = sizeof(af); - af.adf_addr.in4.s_addr = inet_addr("126.0.0.1"); - rn = rnh->rnh_matchaddr(&af, rnh); - if (rn != NULL) { - printf("3.lookup = %p key %p mask %p\n", rn, rn->rn_key, rn->rn_mask); - stp = rn->rn_key; - printf("%s/", inet_ntoa(stp->dst.adf_addr.in4)); - stp = rn->rn_mask; - printf("%s\n", inet_ntoa(stp->dst.adf_addr.in4)); - } - - return 0; -} - - -void -log(int level, char *format, ...) -{ - va_list ap; - - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} -#endif - - -#ifndef _KERNEL -void -panic(char *str) -{ - fputs(str, stderr); - abort(); -} -#endif |