📄 radij.c
字号:
char radij_c_version[] = "RCSID $Id: radij.c,v 1.47 2004/07/10 19:11:18 mcr Exp $";/* * This file is defived from ${SRC}/sys/net/radix.c of BSD 4.4lite * * Variable and procedure names have been modified so that they don't * conflict with the original BSD code, as a small number of modifications * have been introduced and we may want to reuse this code in BSD. * * The `j' in `radij' is pronounced as a voiceless guttural (like a Greek * chi or a German ch sound (as `doch', not as in `milch'), or even a * spanish j as in Juan. It is not as far back in the throat like * the corresponding Hebrew sound, nor is it a soft breath like the English h. * It has nothing to do with the Dutch ij sound. * * Here is the appropriate copyright notice: *//* * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * 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.2 (Berkeley) 1/4/94 *//* * Routines to build and maintain radix trees for routing lookups. */#include <linux/config.h>#include <linux/version.h>#include <linux/kernel.h> /* printk() */#include "openswan/ipsec_param.h"#ifdef MALLOC_SLAB# include <linux/slab.h> /* kmalloc() */#else /* MALLOC_SLAB */# include <linux/malloc.h> /* kmalloc() */#endif /* MALLOC_SLAB */#include <linux/errno.h> /* error codes */#include <linux/types.h> /* size_t */#include <linux/interrupt.h> /* mark_bh */#include <linux/netdevice.h> /* struct device, and other headers */#include <linux/etherdevice.h> /* eth_type_trans */#include <linux/ip.h> /* struct iphdr */#include <linux/skbuff.h>#ifdef NET_21# include <asm/uaccess.h># include <linux/in6.h>#endif /* NET_21 */#include <asm/checksum.h>#include <net/ip.h>#include <openswan.h>#include "openswan/radij.h"#include "openswan/ipsec_encap.h"#include "openswan/ipsec_radij.h"int maj_keylen;struct radij_mask *rj_mkfreelist;struct radij_node_head *mask_rjhead;static int gotOddMasks;static char *maskedKey;static char *rj_zeroes, *rj_ones;#define rj_masktop (mask_rjhead->rnh_treetop)#ifdef Bcmp# undef Bcmp#endif /* Bcmp */#define Bcmp(a, b, l) (l == 0 ? 0 : memcmp((caddr_t)(b), (caddr_t)(a), (size_t)l))/* * The data structure for the keys is a radix tree with one way * branching removed. The index rj_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 rj_b - 1. * (We say the index of n is rj_b.) * * There is at least one descendant which has a one bit at position rj_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) == rj_b, * and m is a normal mask, then the route applies to every descendant of n. * If the index(m) < rj_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. * * The present version of the code makes no use of normal routes, * but 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. */struct radij_node *rj_search(v_arg, head) void *v_arg; struct radij_node *head;{ register struct radij_node *x; register caddr_t v; for (x = head, v = v_arg; x->rj_b >= 0;) { if (x->rj_bmask & v[x->rj_off]) x = x->rj_r; else x = x->rj_l; } return (x);};struct radij_node *rj_search_m(v_arg, head, m_arg) struct radij_node *head; void *v_arg, *m_arg;{ register struct radij_node *x; register caddr_t v = v_arg, m = m_arg; for (x = head; x->rj_b >= 0;) { if ((x->rj_bmask & m[x->rj_off]) && (x->rj_bmask & v[x->rj_off])) x = x->rj_r; else x = x->rj_l; } return x;};intrj_refines(m_arg, n_arg) void *m_arg, *n_arg;{ register caddr_t m = m_arg, n = n_arg; register 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 radij_node *rj_match(v_arg, head) void *v_arg; struct radij_node_head *head;{ caddr_t v = v_arg; register struct radij_node *t = head->rnh_treetop, *x; register caddr_t cp = v, cp2, cp3; caddr_t cplim, mstart; struct radij_node *saved_t, *top = t; int off = t->rj_off, vlen = *(u_char *)cp, matched_off; /* * Open code rj_search(v, top) to avoid overhead of extra * subroutine call. */ for (; t->rj_b >= 0; ) { if (t->rj_bmask & cp[t->rj_off]) t = t->rj_r; else t = t->rj_l; } /* * See if we match exactly as a host destination */ KLIPS_PRINT(debug_radij, "klips_debug:rj_match: " "* See if we match exactly as a host destination\n"); cp += off; cp2 = t->rj_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->rj_flags & RJF_ROOT) && t->rj_dupedkey) t = t->rj_dupedkey; return t;on1: matched_off = cp - v; saved_t = t; KLIPS_PRINT(debug_radij, "klips_debug:rj_match: " "** try to match a leaf, t=0p%p\n", t); do { if (t->rj_mask) { /* * Even if we don't match exactly as a hosts; * we may match if the leaf we wound up at is * a route to a net. */ cp3 = matched_off + t->rj_mask; cp2 = matched_off + t->rj_key; for (; cp < cplim; cp++) if ((*cp2++ ^ *cp) & *cp3++) break; if (cp == cplim) return t; cp = matched_off + v; } } while ((t = t->rj_dupedkey)); t = saved_t; /* start searching up the tree */ KLIPS_PRINT(debug_radij, "klips_debug:rj_match: " "*** start searching up the tree, t=0p%p\n", t); do { register struct radij_mask *m; t = t->rj_p; KLIPS_PRINT(debug_radij, "klips_debug:rj_match: " "**** t=0p%p\n", t); if ((m = t->rj_mklist)) { /* * After doing measurements here, it may * turn out to be faster to open code * rj_search_m here instead of always * copying and masking. */ /* off = min(t->rj_off, matched_off); */ off = t->rj_off; if (matched_off < off) off = matched_off; mstart = maskedKey + off; do { cp2 = mstart; cp3 = m->rm_mask + off; KLIPS_PRINT(debug_radij, "klips_debug:rj_match: " "***** cp2=0p%p cp3=0p%p\n", cp2, cp3); for (cp = v + off; cp < cplim;) *cp2++ = *cp++ & *cp3++; x = rj_search(maskedKey, t); while (x && x->rj_mask != m->rm_mask) x = x->rj_dupedkey; if (x && (Bcmp(mstart, x->rj_key + off, vlen - off) == 0)) return x; } while ((m = m->rm_mklist)); } } while (t != top); KLIPS_PRINT(debug_radij, "klips_debug:rj_match: " "***** not found.\n"); return 0;}; #ifdef RJ_DEBUGint rj_nodenum;struct radij_node *rj_clist;int rj_saveinfo;DEBUG_NO_STATIC void traverse(struct radij_node *);#ifdef RJ_DEBUG2int rj_debug = 1;#elseint rj_debug = 0;#endif /* RJ_DEBUG2 */#endif /* RJ_DEBUG */struct radij_node *rj_newpair(v, b, nodes) void *v; int b; struct radij_node nodes[2];{ register struct radij_node *tt = nodes, *t = tt + 1; t->rj_b = b; t->rj_bmask = 0x80 >> (b & 7); t->rj_l = tt; t->rj_off = b >> 3; tt->rj_b = -1; tt->rj_key = (caddr_t)v; tt->rj_p = t; tt->rj_flags = t->rj_flags = RJF_ACTIVE;#ifdef RJ_DEBUG tt->rj_info = rj_nodenum++; t->rj_info = rj_nodenum++; tt->rj_twin = t; tt->rj_ybro = rj_clist; rj_clist = tt;#endif /* RJ_DEBUG */ return t;}struct radij_node *rj_insert(v_arg, head, dupentry, nodes) void *v_arg; struct radij_node_head *head; int *dupentry; struct radij_node nodes[2];{ caddr_t v = v_arg; struct radij_node *top = head->rnh_treetop; int head_off = top->rj_off, vlen = (int)*((u_char *)v); register struct radij_node *t = rj_search(v_arg, top); register caddr_t cp = v + head_off; register int b; struct radij_node *tt; /* *find first bit at which v and t->rj_key differ */ { register caddr_t cp2 = t->rj_key + head_off; register 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; } { register struct radij_node *p, *x = top; cp = v; do { p = x; if (cp[x->rj_off] & x->rj_bmask) x = x->rj_r; else x = x->rj_l; } while (b > (unsigned) x->rj_b); /* x->rj_b < b && x->rj_b >= 0 */#ifdef RJ_DEBUG if (rj_debug) printk("klips_debug:rj_insert: Going In:\n"), traverse(p);#endif /* RJ_DEBUG */ t = rj_newpair(v_arg, b, nodes); tt = t->rj_l; if ((cp[p->rj_off] & p->rj_bmask) == 0) p->rj_l = t; else p->rj_r = t; x->rj_p = t; t->rj_p = p; /* frees x, p as temp vars below */ if ((cp[t->rj_off] & t->rj_bmask) == 0) { t->rj_r = x; } else { t->rj_r = tt; t->rj_l = x; }#ifdef RJ_DEBUG if (rj_debug) printk("klips_debug:rj_insert: Coming out:\n"), traverse(p);#endif /* RJ_DEBUG */ } return (tt);}struct radij_node *rj_addmask(n_arg, search, skip) int search, skip; void *n_arg;{ caddr_t netmask = (caddr_t)n_arg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -