Home | History | Annotate | Line # | Download | only in netinet
      1  1.6  christos /*	$NetBSD: radix_ipf.c,v 1.6 2015/12/15 12:30:34 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * Copyright (C) 2012 by Darren Reed.
      5  1.1  christos  *
      6  1.1  christos  * See the IPFILTER.LICENCE file for details on licencing.
      7  1.1  christos  */
      8  1.1  christos #include <sys/types.h>
      9  1.1  christos #include <sys/time.h>
     10  1.1  christos #include <sys/socket.h>
     11  1.1  christos #include <sys/param.h>
     12  1.1  christos #include <netinet/in.h>
     13  1.1  christos #include <net/if.h>
     14  1.1  christos #if !defined(_KERNEL)
     15  1.1  christos # include <stddef.h>
     16  1.1  christos # include <stdlib.h>
     17  1.1  christos # include <strings.h>
     18  1.1  christos # include <string.h>
     19  1.1  christos #endif
     20  1.1  christos #include "netinet/ip_compat.h"
     21  1.1  christos #include "netinet/ip_fil.h"
     22  1.1  christos #ifdef RDX_DEBUG
     23  1.1  christos # include <arpa/inet.h>
     24  1.1  christos # include <stdlib.h>
     25  1.1  christos # include <stdio.h>
     26  1.1  christos #endif
     27  1.1  christos #include "netinet/radix_ipf.h"
     28  1.1  christos 
     29  1.1  christos #define	ADF_OFF	offsetof(addrfamily_t, adf_addr)
     30  1.2  christos #define	ADF_OFF_BITS	((ADF_OFF << 3) & 0xffff)
     31  1.1  christos 
     32  1.2  christos static ipf_rdx_node_t *ipf_rx_insert(ipf_rdx_head_t *,
     33  1.2  christos 					  ipf_rdx_node_t nodes[2], int *);
     34  1.2  christos static void ipf_rx_attach_mask(ipf_rdx_node_t *, ipf_rdx_mask_t *);
     35  1.2  christos static int count_mask_bits(addrfamily_t *, u_32_t **);
     36  1.2  christos static void buildnodes(addrfamily_t *, addrfamily_t *,
     37  1.2  christos 			    ipf_rdx_node_t n[2]);
     38  1.2  christos static ipf_rdx_node_t *ipf_rx_find_addr(ipf_rdx_node_t *, u_32_t *);
     39  1.2  christos static ipf_rdx_node_t *ipf_rx_lookup(ipf_rdx_head_t *, addrfamily_t *,
     40  1.2  christos 					  addrfamily_t *);
     41  1.2  christos static ipf_rdx_node_t *ipf_rx_match(ipf_rdx_head_t *, addrfamily_t *);
     42  1.1  christos 
     43  1.1  christos /*
     44  1.1  christos  * Foreword.
     45  1.1  christos  * ---------
     46  1.1  christos  * The code in this file has been written to target using the addrfamily_t
     47  1.1  christos  * data structure to house the address information and no other. Thus there
     48  1.1  christos  * are certain aspects of thise code (such as offsets to the address itself)
     49  1.1  christos  * that are hard coded here whilst they might be more variable elsewhere.
     50  1.1  christos  * Similarly, this code enforces no maximum key length as that's implied by
     51  1.1  christos  * all keys needing to be stored in addrfamily_t.
     52  1.1  christos  */
     53  1.1  christos 
     54  1.1  christos /* ------------------------------------------------------------------------ */
     55  1.1  christos /* Function:    count_mask_bits                                             */
     56  1.1  christos /* Returns:     number of consecutive bits starting at "mask".              */
     57  1.1  christos /*                                                                          */
     58  1.1  christos /* Count the number of bits set in the address section of addrfamily_t and  */
     59  1.1  christos /* return both that number and a pointer to the last word with a bit set if */
     60  1.1  christos /* lastp is not NULL. The bit count is performed using network byte order   */
     61  1.1  christos /* as the guide for which bit is the most significant bit.                  */
     62  1.1  christos /* ------------------------------------------------------------------------ */
     63  1.1  christos static int
     64  1.2  christos count_mask_bits(addrfamily_t *mask, u_32_t **lastp)
     65  1.1  christos {
     66  1.1  christos 	u_32_t *mp = (u_32_t *)&mask->adf_addr;
     67  1.1  christos 	u_32_t m;
     68  1.1  christos 	int count = 0;
     69  1.1  christos 	int mlen;
     70  1.1  christos 
     71  1.1  christos 	mlen = mask->adf_len - offsetof(addrfamily_t, adf_addr);
     72  1.3   darrenr 	for (; mlen > 0; mlen -= 4, mp++) {
     73  1.1  christos 		if ((m = ntohl(*mp)) == 0)
     74  1.1  christos 			break;
     75  1.1  christos 		if (lastp != NULL)
     76  1.1  christos 			*lastp = mp;
     77  1.1  christos 		for (; m & 0x80000000; m <<= 1)
     78  1.1  christos 			count++;
     79  1.1  christos 	}
     80  1.1  christos 
     81  1.1  christos 	return count;
     82  1.1  christos }
     83  1.1  christos 
     84  1.1  christos 
     85  1.1  christos /* ------------------------------------------------------------------------ */
     86  1.1  christos /* Function:    buildnodes                                                  */
     87  1.1  christos /* Returns:     Nil                                                         */
     88  1.1  christos /* Parameters:  addr(I)  - network address for this radix node              */
     89  1.1  christos /*              mask(I)  - netmask associated with the above address        */
     90  1.1  christos /*              nodes(O) - pair of ipf_rdx_node_t's to initialise with data */
     91  1.1  christos /*                         associated with addr and mask.                   */
     92  1.1  christos /*                                                                          */
     93  1.1  christos /* Initialise the fields in a pair of radix tree nodes according to the     */
     94  1.1  christos /* data supplied in the paramters "addr" and "mask". It is expected that    */
     95  1.1  christos /* "mask" will contain a consecutive string of bits set. Masks with gaps in */
     96  1.1  christos /* the middle are not handled by this implementation.                       */
     97  1.1  christos /* ------------------------------------------------------------------------ */
     98  1.1  christos static void
     99  1.2  christos buildnodes(addrfamily_t *addr, addrfamily_t *mask, ipf_rdx_node_t nodes[2])
    100  1.1  christos {
    101  1.1  christos 	u_32_t maskbits;
    102  1.1  christos 	u_32_t lastmask;
    103  1.1  christos 	u_32_t *last;
    104  1.1  christos 	int masklen;
    105  1.1  christos 
    106  1.1  christos 	last = NULL;
    107  1.1  christos 	maskbits = count_mask_bits(mask, &last);
    108  1.1  christos 	if (last == NULL) {
    109  1.1  christos 		masklen = 0;
    110  1.1  christos 		lastmask = 0;
    111  1.1  christos 	} else {
    112  1.1  christos 		masklen = last - (u_32_t *)mask;
    113  1.1  christos 		lastmask = *last;
    114  1.1  christos 	}
    115  1.1  christos 
    116  1.1  christos 	bzero(&nodes[0], sizeof(ipf_rdx_node_t) * 2);
    117  1.1  christos 	nodes[0].maskbitcount = maskbits;
    118  1.1  christos 	nodes[0].index = -1 - (ADF_OFF_BITS + maskbits);
    119  1.1  christos 	nodes[0].addrkey = (u_32_t *)addr;
    120  1.1  christos 	nodes[0].maskkey = (u_32_t *)mask;
    121  1.1  christos 	nodes[0].addroff = nodes[0].addrkey + masklen;
    122  1.1  christos 	nodes[0].maskoff = nodes[0].maskkey + masklen;
    123  1.1  christos 	nodes[0].parent = &nodes[1];
    124  1.1  christos 	nodes[0].offset = masklen;
    125  1.1  christos 	nodes[0].lastmask = lastmask;
    126  1.1  christos 	nodes[1].offset = masklen;
    127  1.1  christos 	nodes[1].left = &nodes[0];
    128  1.1  christos 	nodes[1].maskbitcount = maskbits;
    129  1.1  christos #ifdef RDX_DEBUG
    130  1.1  christos 	(void) strcpy(nodes[0].name, "_BUILD.0");
    131  1.1  christos 	(void) strcpy(nodes[1].name, "_BUILD.1");
    132  1.1  christos #endif
    133  1.1  christos }
    134  1.1  christos 
    135  1.1  christos 
    136  1.1  christos /* ------------------------------------------------------------------------ */
    137  1.1  christos /* Function:    ipf_rx_find_addr                                            */
    138  1.1  christos /* Returns:     ipf_rdx_node_t * - pointer to a node in the radix tree.     */
    139  1.1  christos /* Parameters:  tree(I)  - pointer to first right node in tree to search    */
    140  1.1  christos /*              addr(I)  - pointer to address to match                      */
    141  1.1  christos /*                                                                          */
    142  1.1  christos /* Walk the radix tree given by "tree", looking for a leaf node that is a   */
    143  1.1  christos /* match for the address given by "addr".                                   */
    144  1.1  christos /* ------------------------------------------------------------------------ */
    145  1.1  christos static ipf_rdx_node_t *
    146  1.2  christos ipf_rx_find_addr(ipf_rdx_node_t *tree, u_32_t *addr)
    147  1.1  christos {
    148  1.1  christos 	ipf_rdx_node_t *cur;
    149  1.1  christos 
    150  1.1  christos 	for (cur = tree; cur->index >= 0;) {
    151  1.1  christos 		if (cur->bitmask & addr[cur->offset]) {
    152  1.1  christos 			cur = cur->right;
    153  1.1  christos 		} else {
    154  1.1  christos 			cur = cur->left;
    155  1.1  christos 		}
    156  1.1  christos 	}
    157  1.1  christos 
    158  1.1  christos 	return (cur);
    159  1.1  christos }
    160  1.1  christos 
    161  1.1  christos 
    162  1.1  christos /* ------------------------------------------------------------------------ */
    163  1.1  christos /* Function:    ipf_rx_match                                                */
    164  1.1  christos /* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
    165  1.1  christos /*                                 added to the tree.                       */
    166  1.1  christos /* Paramters:   head(I)  - pointer to tree head to search                   */
    167  1.1  christos /*              addr(I)  - pointer to address to find                       */
    168  1.1  christos /*                                                                          */
    169  1.1  christos /* Search the radix tree for the best match to the address pointed to by    */
    170  1.1  christos /* "addr" and return a pointer to that node. This search will not match the */
    171  1.1  christos /* address information stored in either of the root leaves as neither of    */
    172  1.1  christos /* them are considered to be part of the tree of data being stored.         */
    173  1.1  christos /* ------------------------------------------------------------------------ */
    174  1.1  christos static ipf_rdx_node_t *
    175  1.2  christos ipf_rx_match(ipf_rdx_head_t *head, addrfamily_t *addr)
    176  1.1  christos {
    177  1.1  christos 	ipf_rdx_mask_t *masknode;
    178  1.1  christos 	ipf_rdx_node_t *prev;
    179  1.1  christos 	ipf_rdx_node_t *node;
    180  1.1  christos 	ipf_rdx_node_t *cur;
    181  1.1  christos 	u_32_t *data;
    182  1.1  christos 	u_32_t *mask;
    183  1.1  christos 	u_32_t *key;
    184  1.1  christos 	u_32_t *end;
    185  1.1  christos 	int len;
    186  1.1  christos 	int i;
    187  1.1  christos 
    188  1.1  christos 	len = addr->adf_len;
    189  1.1  christos 	end = (u_32_t *)((u_char *)addr + len);
    190  1.1  christos 	node = ipf_rx_find_addr(head->root, (u_32_t *)addr);
    191  1.1  christos 
    192  1.1  christos 	/*
    193  1.1  christos 	 * Search the dupkey list for a potential match.
    194  1.1  christos 	 */
    195  1.1  christos 	for (cur = node; (cur != NULL) && (cur->root == 0); cur = cur->dupkey) {
    196  1.3   darrenr 		i = cur[0].addroff - cur[0].addrkey;
    197  1.3   darrenr 		data = cur[0].addrkey + i;
    198  1.3   darrenr 		mask = cur[0].maskkey + i;
    199  1.3   darrenr 		key = (u_32_t *)addr + i;
    200  1.1  christos 		for (; key < end; data++, key++, mask++)
    201  1.1  christos 			if ((*key & *mask) != *data)
    202  1.1  christos 				break;
    203  1.1  christos 		if ((end == key) && (cur->root == 0))
    204  1.1  christos 			return (cur);	/* Equal keys */
    205  1.1  christos 	}
    206  1.1  christos 	prev = node->parent;
    207  1.1  christos 	key = (u_32_t *)addr;
    208  1.1  christos 
    209  1.1  christos 	for (node = prev; node->root == 0; node = node->parent) {
    210  1.1  christos 		/*
    211  1.1  christos 		 * We know that the node hasn't matched so therefore only
    212  1.1  christos 		 * the entries in the mask list are searched, not the top
    213  1.1  christos 		 * node nor the dupkey list.
    214  1.1  christos 		 */
    215  1.1  christos 		masknode = node->masks;
    216  1.1  christos 		for (; masknode != NULL; masknode = masknode->next) {
    217  1.1  christos 			if (masknode->maskbitcount > node->maskbitcount)
    218  1.1  christos 				continue;
    219  1.1  christos 			cur = masknode->node;
    220  1.1  christos 			for (i = ADF_OFF >> 2; i <= node->offset; i++) {
    221  1.1  christos 				if ((key[i] & masknode->mask[i]) ==
    222  1.1  christos 				    cur->addrkey[i])
    223  1.1  christos 					return (cur);
    224  1.1  christos 			}
    225  1.1  christos 		}
    226  1.1  christos 	}
    227  1.1  christos 
    228  1.1  christos 	return NULL;
    229  1.1  christos }
    230  1.1  christos 
    231  1.1  christos 
    232  1.1  christos /* ------------------------------------------------------------------------ */
    233  1.1  christos /* Function:    ipf_rx_lookup                                               */
    234  1.1  christos /* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
    235  1.1  christos /*                                 added to the tree.                       */
    236  1.1  christos /* Paramters:   head(I)  - pointer to tree head to search                   */
    237  1.1  christos /*              addr(I)  - address part of the key to match                 */
    238  1.1  christos /*              mask(I)  - netmask part of the key to match                 */
    239  1.1  christos /*                                                                          */
    240  1.1  christos /* ipf_rx_lookup searches for an exact match on (addr,mask). The intention  */
    241  1.1  christos /* is to see if a given key is in the tree, not to see if a route exists.   */
    242  1.1  christos /* ------------------------------------------------------------------------ */
    243  1.1  christos ipf_rdx_node_t *
    244  1.2  christos ipf_rx_lookup(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask)
    245  1.1  christos {
    246  1.1  christos 	ipf_rdx_node_t *found;
    247  1.1  christos 	ipf_rdx_node_t *node;
    248  1.1  christos 	u_32_t *akey;
    249  1.1  christos 	int count;
    250  1.1  christos 
    251  1.1  christos 	found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
    252  1.1  christos 	if (found->root == 1)
    253  1.1  christos 		return NULL;
    254  1.1  christos 
    255  1.1  christos 	/*
    256  1.1  christos 	 * It is possible to find a matching address in the tree but for the
    257  1.1  christos 	 * netmask to not match. If the netmask does not match and there is
    258  1.1  christos 	 * no list of alternatives present at dupkey, return a failure.
    259  1.1  christos 	 */
    260  1.1  christos 	count = count_mask_bits(mask, NULL);
    261  1.1  christos 	if (count != found->maskbitcount && found->dupkey == NULL)
    262  1.1  christos 		return (NULL);
    263  1.1  christos 
    264  1.1  christos 	akey = (u_32_t *)addr;
    265  1.1  christos 	if ((found->addrkey[found->offset] & found->maskkey[found->offset]) !=
    266  1.1  christos 	    akey[found->offset])
    267  1.1  christos 		return NULL;
    268  1.1  christos 
    269  1.1  christos 	if (found->dupkey != NULL) {
    270  1.1  christos 		node = found;
    271  1.1  christos 		while (node != NULL && node->maskbitcount != count)
    272  1.1  christos 			node = node->dupkey;
    273  1.1  christos 		if (node == NULL)
    274  1.1  christos 			return (NULL);
    275  1.1  christos 		found = node;
    276  1.1  christos 	}
    277  1.1  christos 	return found;
    278  1.1  christos }
    279  1.1  christos 
    280  1.1  christos 
    281  1.1  christos /* ------------------------------------------------------------------------ */
    282  1.1  christos /* Function:    ipf_rx_attach_mask                                          */
    283  1.1  christos /* Returns:     Nil                                                         */
    284  1.1  christos /* Parameters:  node(I)  - pointer to a radix tree node                     */
    285  1.1  christos /*              mask(I)  - pointer to mask structure to add                 */
    286  1.1  christos /*                                                                          */
    287  1.1  christos /* Add the netmask to the given node in an ordering where the most specific */
    288  1.1  christos /* netmask is at the top of the list.                                       */
    289  1.1  christos /* ------------------------------------------------------------------------ */
    290  1.1  christos static void
    291  1.2  christos ipf_rx_attach_mask(ipf_rdx_node_t *node, ipf_rdx_mask_t *mask)
    292  1.1  christos {
    293  1.1  christos 	ipf_rdx_mask_t **pm;
    294  1.1  christos 	ipf_rdx_mask_t *m;
    295  1.1  christos 
    296  1.1  christos 	for (pm = &node->masks; (m = *pm) != NULL; pm = &m->next)
    297  1.1  christos 		if (m->maskbitcount < mask->maskbitcount)
    298  1.1  christos 			break;
    299  1.1  christos 	mask->next = *pm;
    300  1.1  christos 	*pm = mask;
    301  1.1  christos }
    302  1.1  christos 
    303  1.1  christos 
    304  1.1  christos /* ------------------------------------------------------------------------ */
    305  1.1  christos /* Function:    ipf_rx_insert                                               */
    306  1.1  christos /* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
    307  1.1  christos /*                                 added to the tree.                       */
    308  1.1  christos /* Paramters:   head(I)  - pointer to tree head to add nodes to             */
    309  1.1  christos /*              nodes(I) - pointer to radix nodes to be added               */
    310  1.1  christos /*              dup(O)   - set to 1 if node is a duplicate, else 0.         */
    311  1.1  christos /*                                                                          */
    312  1.1  christos /* Add the new radix tree entry that owns nodes[] to the tree given by head.*/
    313  1.1  christos /* If there is already a matching key in the table, "dup" will be set to 1  */
    314  1.1  christos /* and the existing node pointer returned if there is a complete key match. */
    315  1.1  christos /* A complete key match is a matching of all key data that is presented by  */
    316  1.1  christos /* by the netmask.                                                          */
    317  1.1  christos /* ------------------------------------------------------------------------ */
    318  1.1  christos static ipf_rdx_node_t *
    319  1.2  christos ipf_rx_insert(ipf_rdx_head_t *head, ipf_rdx_node_t nodes[2], int *dup)
    320  1.1  christos {
    321  1.1  christos 	ipf_rdx_mask_t **pmask;
    322  1.1  christos 	ipf_rdx_node_t *node;
    323  1.1  christos 	ipf_rdx_node_t *prev;
    324  1.1  christos 	ipf_rdx_mask_t *mask;
    325  1.1  christos 	ipf_rdx_node_t *cur;
    326  1.1  christos 	u_32_t nodemask;
    327  1.1  christos 	u_32_t *addr;
    328  1.1  christos 	u_32_t *data;
    329  1.1  christos 	int nodebits;
    330  1.1  christos 	u_32_t *key;
    331  1.1  christos 	u_32_t *end;
    332  1.1  christos 	u_32_t bits;
    333  1.1  christos 	int nodekey;
    334  1.1  christos 	int nodeoff;
    335  1.1  christos 	int nlen;
    336  1.1  christos 	int len;
    337  1.1  christos 
    338  1.1  christos 	addr = nodes[0].addrkey;
    339  1.1  christos 
    340  1.1  christos 	node = ipf_rx_find_addr(head->root, addr);
    341  1.1  christos 	len = ((addrfamily_t *)addr)->adf_len;
    342  1.1  christos 	key = (u_32_t *)&((addrfamily_t *)addr)->adf_addr;
    343  1.1  christos 	data= (u_32_t *)&((addrfamily_t *)node->addrkey)->adf_addr;
    344  1.1  christos 	end = (u_32_t *)((u_char *)addr + len);
    345  1.3   darrenr 	for (nlen = 0; key < end; data++, key++, nlen += 32)
    346  1.1  christos 		if (*key != *data)
    347  1.1  christos 			break;
    348  1.1  christos 	if (end == data) {
    349  1.1  christos 		*dup = 1;
    350  1.1  christos 		return (node);	/* Equal keys */
    351  1.1  christos 	}
    352  1.1  christos 	*dup = 0;
    353  1.1  christos 
    354  1.1  christos 	bits = (ntohl(*data) ^ ntohl(*key));
    355  1.3   darrenr 	for (; bits != 0; nlen++) {
    356  1.1  christos 		if ((bits & 0x80000000) != 0)
    357  1.1  christos 			break;
    358  1.1  christos 		bits <<= 1;
    359  1.1  christos 	}
    360  1.1  christos 	nlen += ADF_OFF_BITS;
    361  1.1  christos 	nodes[1].index = nlen;
    362  1.1  christos 	nodes[1].bitmask = htonl(0x80000000 >> (nlen & 0x1f));
    363  1.3   darrenr 	nodes[0].offset = nlen / 32;
    364  1.3   darrenr 	nodes[1].offset = nlen / 32;
    365  1.1  christos 
    366  1.1  christos 	/*
    367  1.1  christos 	 * Walk through the tree and look for the correct place to attach
    368  1.1  christos 	 * this node. ipf_rx_fin_addr is not used here because the place
    369  1.1  christos 	 * to attach this node may be an internal node (same key, different
    370  1.1  christos 	 * netmask.) Additionally, the depth of the search is forcibly limited
    371  1.1  christos 	 * here to not exceed the netmask, so that a short netmask will be
    372  1.1  christos 	 * added higher up the tree even if there are lower branches.
    373  1.1  christos 	 */
    374  1.1  christos 	cur = head->root;
    375  1.1  christos 	key = nodes[0].addrkey;
    376  1.1  christos 	do {
    377  1.1  christos 		prev = cur;
    378  1.1  christos 		if (key[cur->offset] & cur->bitmask) {
    379  1.1  christos 			cur = cur->right;
    380  1.1  christos 		} else {
    381  1.1  christos 			cur = cur->left;
    382  1.1  christos 		}
    383  1.1  christos 	} while (nlen > (unsigned)cur->index);
    384  1.1  christos 
    385  1.1  christos 	if ((key[prev->offset] & prev->bitmask) == 0) {
    386  1.1  christos 		prev->left = &nodes[1];
    387  1.1  christos 	} else {
    388  1.1  christos 		prev->right = &nodes[1];
    389  1.1  christos 	}
    390  1.1  christos 	cur->parent = &nodes[1];
    391  1.1  christos 	nodes[1].parent = prev;
    392  1.3   darrenr 	if ((key[nodes[1].offset] & nodes[1].bitmask) == 0) {
    393  1.1  christos 		nodes[1].right = cur;
    394  1.1  christos 	} else {
    395  1.1  christos 		nodes[1].right = &nodes[0];
    396  1.1  christos 		nodes[1].left = cur;
    397  1.1  christos 	}
    398  1.1  christos 
    399  1.1  christos 	nodeoff = nodes[0].offset;
    400  1.1  christos 	nodekey = nodes[0].addrkey[nodeoff];
    401  1.1  christos 	nodemask = nodes[0].lastmask;
    402  1.1  christos 	nodebits = nodes[0].maskbitcount;
    403  1.1  christos 	prev = NULL;
    404  1.1  christos 	/*
    405  1.1  christos 	 * Find the node up the tree with the largest pattern that still
    406  1.1  christos 	 * matches the node being inserted to see if this mask can be
    407  1.1  christos 	 * moved there.
    408  1.1  christos 	 */
    409  1.1  christos 	for (cur = nodes[1].parent; cur->root == 0; cur = cur->parent) {
    410  1.1  christos 		if (cur->maskbitcount <= nodebits)
    411  1.1  christos 			break;
    412  1.1  christos 		if (((cur - 1)->addrkey[nodeoff] & nodemask) != nodekey)
    413  1.1  christos 			break;
    414  1.1  christos 		prev = cur;
    415  1.1  christos 	}
    416  1.1  christos 
    417  1.1  christos 	KMALLOC(mask, ipf_rdx_mask_t *);
    418  1.1  christos 	if (mask == NULL)
    419  1.1  christos 		return NULL;
    420  1.1  christos 	bzero(mask, sizeof(*mask));
    421  1.1  christos 	mask->next = NULL;
    422  1.1  christos 	mask->node = &nodes[0];
    423  1.1  christos 	mask->maskbitcount = nodebits;
    424  1.1  christos 	mask->mask = nodes[0].maskkey;
    425  1.1  christos 	nodes[0].mymask = mask;
    426  1.1  christos 
    427  1.1  christos 	if (prev != NULL) {
    428  1.1  christos 		ipf_rdx_mask_t *m;
    429  1.1  christos 
    430  1.1  christos 		for (pmask = &prev->masks; (m = *pmask) != NULL;
    431  1.1  christos 		     pmask = &m->next) {
    432  1.1  christos 			if (m->maskbitcount < nodebits)
    433  1.1  christos 				break;
    434  1.1  christos 		}
    435  1.1  christos 	} else {
    436  1.1  christos 		/*
    437  1.1  christos 		 * No higher up nodes qualify, so attach mask locally.
    438  1.1  christos 		 */
    439  1.1  christos 		pmask = &nodes[0].masks;
    440  1.1  christos 	}
    441  1.1  christos 	mask->next = *pmask;
    442  1.1  christos 	*pmask = mask;
    443  1.1  christos 
    444  1.1  christos 	/*
    445  1.1  christos 	 * Search the mask list on each child to see if there are any masks
    446  1.1  christos 	 * there that can be moved up to this newly inserted node.
    447  1.1  christos 	 */
    448  1.1  christos 	cur = nodes[1].right;
    449  1.1  christos 	if (cur->root == 0) {
    450  1.1  christos 		for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
    451  1.1  christos 			if (mask->maskbitcount < nodebits) {
    452  1.1  christos 				*pmask = mask->next;
    453  1.1  christos 				ipf_rx_attach_mask(&nodes[0], mask);
    454  1.1  christos 			} else {
    455  1.1  christos 				pmask = &mask->next;
    456  1.1  christos 			}
    457  1.1  christos 		}
    458  1.1  christos 	}
    459  1.1  christos 	cur = nodes[1].left;
    460  1.1  christos 	if (cur->root == 0 && cur != &nodes[0]) {
    461  1.1  christos 		for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
    462  1.1  christos 			if (mask->maskbitcount < nodebits) {
    463  1.1  christos 				*pmask = mask->next;
    464  1.1  christos 				ipf_rx_attach_mask(&nodes[0], mask);
    465  1.1  christos 			} else {
    466  1.1  christos 				pmask = &mask->next;
    467  1.1  christos 			}
    468  1.1  christos 		}
    469  1.1  christos 	}
    470  1.1  christos 	return (&nodes[0]);
    471  1.1  christos }
    472  1.1  christos 
    473  1.1  christos /* ------------------------------------------------------------------------ */
    474  1.1  christos /* Function:    ipf_rx_addroute                                             */
    475  1.1  christos /* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
    476  1.1  christos /*                                 added to the tree.                       */
    477  1.1  christos /* Paramters:   head(I)  - pointer to tree head to search                   */
    478  1.1  christos /*              addr(I)  - address portion of "route" to add                */
    479  1.1  christos /*              mask(I)  - netmask portion of "route" to add                */
    480  1.1  christos /*              nodes(I) - radix tree data nodes inside allocate structure  */
    481  1.1  christos /*                                                                          */
    482  1.1  christos /* Attempt to add a node to the radix tree. The key for the node is the     */
    483  1.1  christos /* (addr,mask). No memory allocation for the radix nodes themselves is      */
    484  1.1  christos /* performed here, the data structure that this radix node is being used to */
    485  1.1  christos /* find is expected to house the node data itself however the call to       */
    486  1.1  christos /* ipf_rx_insert() will attempt to allocate memory in order for netmask to  */
    487  1.1  christos /* be promoted further up the tree.                                         */
    488  1.1  christos /* In this case, the ip_pool_node_t structure from ip_pool.h contains both  */
    489  1.1  christos /* the key material (addr,mask) and the radix tree nodes[].                 */
    490  1.1  christos /*                                                                          */
    491  1.1  christos /* The mechanics of inserting the node into the tree is handled by the      */
    492  1.1  christos /* function ipf_rx_insert() above. Here, the code deals with the case       */
    493  1.1  christos /* where the data to be inserted is a duplicate.                            */
    494  1.1  christos /* ------------------------------------------------------------------------ */
    495  1.1  christos ipf_rdx_node_t *
    496  1.2  christos ipf_rx_addroute(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask,
    497  1.2  christos     ipf_rdx_node_t *nodes)
    498  1.1  christos {
    499  1.1  christos 	ipf_rdx_node_t *node;
    500  1.1  christos 	ipf_rdx_node_t *prev;
    501  1.1  christos 	ipf_rdx_node_t *x;
    502  1.1  christos 	int dup;
    503  1.1  christos 
    504  1.1  christos 	buildnodes(addr, mask, nodes);
    505  1.1  christos 	x = ipf_rx_insert(head, nodes, &dup);
    506  1.1  christos 	if (x == NULL)
    507  1.1  christos 		return NULL;
    508  1.1  christos 
    509  1.1  christos 	if (dup == 1) {
    510  1.1  christos 		node = &nodes[0];
    511  1.1  christos 		prev = NULL;
    512  1.1  christos 		/*
    513  1.1  christos 		 * The duplicate list is kept sorted with the longest
    514  1.1  christos 		 * mask at the top, meaning that the most specific entry
    515  1.1  christos 		 * in the listis found first. This list thus allows for
    516  1.1  christos 		 * duplicates such as 128.128.0.0/32 and 128.128.0.0/16.
    517  1.1  christos 		 */
    518  1.1  christos 		while ((x != NULL) && (x->maskbitcount > node->maskbitcount)) {
    519  1.1  christos 			prev = x;
    520  1.1  christos 			x = x->dupkey;
    521  1.1  christos 		}
    522  1.1  christos 
    523  1.1  christos 		/*
    524  1.1  christos 		 * Is it a complete duplicate? If so, return NULL and
    525  1.1  christos 		 * fail the insert. Otherwise, insert it into the list
    526  1.1  christos 		 * of netmasks active for this key.
    527  1.1  christos 		 */
    528  1.1  christos 		if ((x != NULL) && (x->maskbitcount == node->maskbitcount))
    529  1.1  christos 			return (NULL);
    530  1.1  christos 
    531  1.1  christos 		if (prev != NULL) {
    532  1.1  christos 			nodes[0].dupkey = x;
    533  1.1  christos 			prev->dupkey = &nodes[0];
    534  1.1  christos 			nodes[0].parent = prev;
    535  1.1  christos 			if (x != NULL)
    536  1.1  christos 				x->parent = &nodes[0];
    537  1.1  christos 		} else {
    538  1.1  christos 			nodes[0].dupkey = x->dupkey;
    539  1.1  christos 			prev = x->parent;
    540  1.1  christos 			nodes[0].parent = prev;
    541  1.1  christos 			x->parent = &nodes[0];
    542  1.1  christos 			if (prev->left == x)
    543  1.1  christos 				prev->left = &nodes[0];
    544  1.1  christos 			else
    545  1.1  christos 				prev->right = &nodes[0];
    546  1.1  christos 		}
    547  1.1  christos 	}
    548  1.1  christos 
    549  1.1  christos 	return &nodes[0];
    550  1.1  christos }
    551  1.1  christos 
    552  1.1  christos 
    553  1.1  christos /* ------------------------------------------------------------------------ */
    554  1.1  christos /* Function:    ipf_rx_delete                                               */
    555  1.1  christos /* Returns:     ipf_rdx_node_t * - NULL on error, else node removed from    */
    556  1.1  christos /*                                 the tree.                                */
    557  1.1  christos /* Paramters:   head(I)  - pointer to tree head to search                   */
    558  1.1  christos /*              addr(I)  - pointer to the address part of the key           */
    559  1.1  christos /*              mask(I)  - pointer to the netmask part of the key           */
    560  1.1  christos /*                                                                          */
    561  1.1  christos /* Search for an entry in the radix tree that is an exact match for (addr,  */
    562  1.1  christos /* mask) and remove it if it exists. In the case where (addr,mask) is a not */
    563  1.1  christos /* a unique key, the tree structure itself is not changed - only the list   */
    564  1.1  christos /* of duplicate keys.                                                       */
    565  1.1  christos /* ------------------------------------------------------------------------ */
    566  1.1  christos ipf_rdx_node_t *
    567  1.2  christos ipf_rx_delete(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask)
    568  1.1  christos {
    569  1.1  christos 	ipf_rdx_mask_t **pmask;
    570  1.1  christos 	ipf_rdx_node_t *parent;
    571  1.1  christos 	ipf_rdx_node_t *found;
    572  1.1  christos 	ipf_rdx_node_t *prev;
    573  1.1  christos 	ipf_rdx_node_t *node;
    574  1.1  christos 	ipf_rdx_node_t *cur;
    575  1.1  christos 	ipf_rdx_mask_t *m;
    576  1.1  christos 	int count;
    577  1.1  christos 
    578  1.1  christos 	found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
    579  1.3   darrenr 	if (found == NULL)
    580  1.3   darrenr 		return NULL;
    581  1.1  christos 	if (found->root == 1)
    582  1.1  christos 		return NULL;
    583  1.1  christos 	count = count_mask_bits(mask, NULL);
    584  1.1  christos 	parent = found->parent;
    585  1.1  christos 	if (found->dupkey != NULL) {
    586  1.1  christos 		node = found;
    587  1.1  christos 		while (node != NULL && node->maskbitcount != count)
    588  1.1  christos 			node = node->dupkey;
    589  1.1  christos 		if (node == NULL)
    590  1.1  christos 			return (NULL);
    591  1.1  christos 		if (node != found) {
    592  1.1  christos 			/*
    593  1.1  christos 			 * Remove from the dupkey list. Here, "parent" is
    594  1.1  christos 			 * the previous node on the list (rather than tree)
    595  1.1  christos 			 * and "dupkey" is the next node on the list.
    596  1.1  christos 			 */
    597  1.1  christos 			parent = node->parent;
    598  1.1  christos 			parent->dupkey = node->dupkey;
    599  1.1  christos 			node->dupkey->parent = parent;
    600  1.1  christos 		} else {
    601  1.1  christos 			/*
    602  1.1  christos 			 *
    603  1.1  christos 			 * When removing the top node of the dupkey list,
    604  1.1  christos 			 * the pointers at the top of the list that point
    605  1.1  christos 			 * to other tree nodes need to be preserved and
    606  1.1  christos 			 * any children must have their parent updated.
    607  1.1  christos 			 */
    608  1.1  christos 			node = node->dupkey;
    609  1.1  christos 			node->parent = found->parent;
    610  1.1  christos 			node->right = found->right;
    611  1.1  christos 			node->left = found->left;
    612  1.1  christos 			found->right->parent = node;
    613  1.1  christos 			found->left->parent = node;
    614  1.1  christos 			if (parent->left == found)
    615  1.1  christos 				parent->left = node;
    616  1.1  christos 			else
    617  1.1  christos 				parent->right= node;
    618  1.1  christos 		}
    619  1.1  christos 	} else {
    620  1.1  christos 		if (count != found->maskbitcount)
    621  1.1  christos 			return (NULL);
    622  1.1  christos 		/*
    623  1.1  christos 		 * Remove the node from the tree and reconnect the subtree
    624  1.1  christos 		 * below.
    625  1.1  christos 		 */
    626  1.1  christos 		/*
    627  1.1  christos 		 * If there is a tree to the left, look for something to
    628  1.1  christos 		 * attach in place of "found".
    629  1.1  christos 		 */
    630  1.1  christos 		prev = found + 1;
    631  1.3   darrenr 		cur = parent->parent;
    632  1.1  christos 		if (parent != found + 1) {
    633  1.3   darrenr 			if ((found + 1)->parent->right == found + 1)
    634  1.3   darrenr 				(found + 1)->parent->right = parent;
    635  1.3   darrenr 			else
    636  1.3   darrenr 				(found + 1)->parent->left = parent;
    637  1.1  christos 			if (cur->right == parent) {
    638  1.3   darrenr 				if (parent->left == found) {
    639  1.3   darrenr 					cur->right = parent->right;
    640  1.3   darrenr 				} else if (parent->left != parent - 1) {
    641  1.3   darrenr 					cur->right = parent->left;
    642  1.3   darrenr 				} else {
    643  1.3   darrenr 					cur->right = parent - 1;
    644  1.1  christos 				}
    645  1.3   darrenr 				cur->right->parent = cur;
    646  1.3   darrenr 			} else {
    647  1.3   darrenr 				if (parent->right == found) {
    648  1.3   darrenr 					cur->left = parent->left;
    649  1.3   darrenr 				} else if (parent->right != parent - 1) {
    650  1.3   darrenr 					cur->left = parent->right;
    651  1.1  christos 				} else {
    652  1.3   darrenr 					cur->left = parent - 1;
    653  1.1  christos 				}
    654  1.3   darrenr 				cur->left->parent = cur;
    655  1.3   darrenr 			}
    656  1.3   darrenr 			parent->left = (found + 1)->left;
    657  1.3   darrenr 			if ((found + 1)->right != parent)
    658  1.3   darrenr 				parent->right = (found + 1)->right;
    659  1.3   darrenr 			parent->left->parent = parent;
    660  1.3   darrenr 			parent->right->parent = parent;
    661  1.3   darrenr 			parent->parent = (found + 1)->parent;
    662  1.1  christos 
    663  1.1  christos 			parent->bitmask = prev->bitmask;
    664  1.1  christos 			parent->offset = prev->offset;
    665  1.1  christos 			parent->index = prev->index;
    666  1.1  christos 		} else {
    667  1.1  christos 			/*
    668  1.1  christos 			 * We found an edge node.
    669  1.1  christos 			 */
    670  1.1  christos 			cur = parent->parent;
    671  1.1  christos 			if (cur->left == parent) {
    672  1.1  christos 				if (parent->left == found) {
    673  1.1  christos 					cur->left = parent->right;
    674  1.1  christos 					parent->right->parent = cur;
    675  1.1  christos 				} else {
    676  1.1  christos 					cur->left = parent->left;
    677  1.1  christos 					parent->left->parent = cur;
    678  1.1  christos 				}
    679  1.1  christos 			} else {
    680  1.1  christos 				if (parent->right != found) {
    681  1.1  christos 					cur->right = parent->right;
    682  1.1  christos 					parent->right->parent = cur;
    683  1.1  christos 				} else {
    684  1.1  christos 					cur->right = parent->left;
    685  1.1  christos 					prev->left->parent = cur;
    686  1.1  christos 				}
    687  1.1  christos 			}
    688  1.1  christos 		}
    689  1.1  christos 	}
    690  1.1  christos 
    691  1.1  christos 	/*
    692  1.1  christos 	 * Remove mask associated with this node.
    693  1.1  christos 	 */
    694  1.1  christos 	for (cur = parent; cur->root == 0; cur = cur->parent) {
    695  1.1  christos 		ipf_rdx_mask_t **pm;
    696  1.1  christos 
    697  1.1  christos 		if (cur->maskbitcount <= found->maskbitcount)
    698  1.1  christos 			break;
    699  1.1  christos 		if (((cur - 1)->addrkey[found->offset] & found->bitmask) !=
    700  1.1  christos 		    found->addrkey[found->offset])
    701  1.1  christos 			break;
    702  1.1  christos 		for (pm = &cur->masks; (m = *pm) != NULL; )
    703  1.1  christos 			if (m->node == cur) {
    704  1.1  christos 				*pm = m->next;
    705  1.1  christos 				break;
    706  1.1  christos 			} else {
    707  1.1  christos 				pm = &m->next;
    708  1.1  christos 			}
    709  1.1  christos 	}
    710  1.1  christos 	KFREE(found->mymask);
    711  1.1  christos 
    712  1.1  christos 	/*
    713  1.1  christos 	 * Masks that have been brought up to this node from below need to
    714  1.1  christos 	 * be sent back down.
    715  1.1  christos 	 */
    716  1.1  christos 	for (pmask = &parent->masks; (m = *pmask) != NULL; ) {
    717  1.1  christos 		*pmask = m->next;
    718  1.1  christos 		cur = m->node;
    719  1.1  christos 		if (cur == found)
    720  1.1  christos 			continue;
    721  1.1  christos 		if (found->addrkey[cur->offset] & cur->lastmask) {
    722  1.1  christos 			ipf_rx_attach_mask(parent->right, m);
    723  1.1  christos 		} else if (parent->left != found) {
    724  1.1  christos 			ipf_rx_attach_mask(parent->left, m);
    725  1.1  christos 		}
    726  1.1  christos 	}
    727  1.1  christos 
    728  1.1  christos 	return (found);
    729  1.1  christos }
    730  1.1  christos 
    731  1.1  christos 
    732  1.1  christos /* ------------------------------------------------------------------------ */
    733  1.1  christos /* Function:    ipf_rx_walktree                                             */
    734  1.1  christos /* Returns:     Nil                                                         */
    735  1.1  christos /* Paramters:   head(I)   - pointer to tree head to search                  */
    736  1.1  christos /*              walker(I) - function to call for each node in the tree      */
    737  1.1  christos /*              arg(I)    - parameter to pass to walker, in addition to the */
    738  1.1  christos /*                          node pointer                                    */
    739  1.1  christos /*                                                                          */
    740  1.1  christos /* A standard tree walking function except that it is iterative, rather     */
    741  1.1  christos /* than recursive and tracks the next node in case the "walker" function    */
    742  1.1  christos /* should happen to delete and free the current node. It thus goes without  */
    743  1.1  christos /* saying that the "walker" function is not permitted to cause any change   */
    744  1.1  christos /* in the validity of the data found at either the left or right child.     */
    745  1.1  christos /* ------------------------------------------------------------------------ */
    746  1.1  christos void
    747  1.2  christos ipf_rx_walktree(ipf_rdx_head_t *head, radix_walk_func_t walker, void *arg)
    748  1.1  christos {
    749  1.1  christos 	ipf_rdx_node_t *next;
    750  1.1  christos 	ipf_rdx_node_t *node = head->root;
    751  1.1  christos 	ipf_rdx_node_t *base;
    752  1.1  christos 
    753  1.1  christos 	while (node->index >= 0)
    754  1.1  christos 		node = node->left;
    755  1.1  christos 
    756  1.1  christos 	for (;;) {
    757  1.1  christos 		base = node;
    758  1.1  christos 		while ((node->parent->right == node) && (node->root == 0))
    759  1.1  christos 			node = node->parent;
    760  1.1  christos 
    761  1.1  christos 		for (node = node->parent->right; node->index >= 0; )
    762  1.1  christos 			node = node->left;
    763  1.1  christos 		next = node;
    764  1.1  christos 
    765  1.1  christos 		for (node = base; node != NULL; node = base) {
    766  1.1  christos 			base = node->dupkey;
    767  1.1  christos 			if (node->root == 0)
    768  1.1  christos 				walker(node, arg);
    769  1.1  christos 		}
    770  1.1  christos 		node = next;
    771  1.1  christos 		if (node->root)
    772  1.1  christos 			return;
    773  1.1  christos 	}
    774  1.1  christos }
    775  1.1  christos 
    776  1.1  christos 
    777  1.1  christos /* ------------------------------------------------------------------------ */
    778  1.1  christos /* Function:    ipf_rx_inithead                                             */
    779  1.1  christos /* Returns:     int       - 0 = success, else failure                       */
    780  1.1  christos /* Paramters:   softr(I)  - pointer to radix context                        */
    781  1.1  christos /*              headp(O)  - location for where to store allocated tree head */
    782  1.1  christos /*                                                                          */
    783  1.1  christos /* This function allocates and initialises a radix tree head structure.     */
    784  1.1  christos /* As a traditional radix tree, node 0 is used as the "0" sentinel and node */
    785  1.1  christos /* "2" is used as the all ones sentinel, leaving node "1" as the root from  */
    786  1.1  christos /* which the tree is hung with node "0" on its left and node "2" to the     */
    787  1.1  christos /* right. The context, "softr", is used here to provide a common source of  */
    788  1.1  christos /* the zeroes and ones data rather than have one per head.                  */
    789  1.1  christos /* ------------------------------------------------------------------------ */
    790  1.1  christos int
    791  1.2  christos ipf_rx_inithead(radix_softc_t *softr, ipf_rdx_head_t **headp)
    792  1.1  christos {
    793  1.1  christos 	ipf_rdx_head_t *ptr;
    794  1.1  christos 	ipf_rdx_node_t *node;
    795  1.1  christos 
    796  1.1  christos 	KMALLOC(ptr, ipf_rdx_head_t *);
    797  1.1  christos 	*headp = ptr;
    798  1.1  christos 	if (ptr == NULL)
    799  1.1  christos 		return -1;
    800  1.1  christos 	bzero(ptr, sizeof(*ptr));
    801  1.1  christos 	node = ptr->nodes;
    802  1.1  christos 	ptr->root = node + 1;
    803  1.1  christos 	node[0].index = ADF_OFF_BITS;
    804  1.1  christos 	node[0].index = -1 - node[0].index;
    805  1.1  christos 	node[1].index = ADF_OFF_BITS;
    806  1.1  christos 	node[2].index = node[0].index;
    807  1.1  christos 	node[0].parent = node + 1;
    808  1.1  christos 	node[1].parent = node + 1;
    809  1.1  christos 	node[2].parent = node + 1;
    810  1.1  christos 	node[1].bitmask = htonl(0x80000000);
    811  1.1  christos 	node[0].root = 1;
    812  1.1  christos 	node[1].root = 1;
    813  1.1  christos 	node[2].root = 1;
    814  1.1  christos 	node[0].offset = ADF_OFF_BITS >> 5;
    815  1.1  christos 	node[1].offset = ADF_OFF_BITS >> 5;
    816  1.1  christos 	node[2].offset = ADF_OFF_BITS >> 5;
    817  1.1  christos 	node[1].left = &node[0];
    818  1.1  christos 	node[1].right = &node[2];
    819  1.1  christos 	node[0].addrkey = (u_32_t *)softr->zeros;
    820  1.1  christos 	node[2].addrkey = (u_32_t *)softr->ones;
    821  1.1  christos #ifdef RDX_DEBUG
    822  1.1  christos 	(void) strcpy(node[0].name, "0_ROOT");
    823  1.1  christos 	(void) strcpy(node[1].name, "1_ROOT");
    824  1.1  christos 	(void) strcpy(node[2].name, "2_ROOT");
    825  1.1  christos #endif
    826  1.1  christos 
    827  1.1  christos 	ptr->addaddr = ipf_rx_addroute;
    828  1.1  christos 	ptr->deladdr = ipf_rx_delete;
    829  1.1  christos 	ptr->lookup = ipf_rx_lookup;
    830  1.1  christos 	ptr->matchaddr = ipf_rx_match;
    831  1.1  christos 	ptr->walktree = ipf_rx_walktree;
    832  1.1  christos 	return 0;
    833  1.1  christos }
    834  1.1  christos 
    835  1.3   darrenr 
    836  1.3   darrenr /* ------------------------------------------------------------------------ */
    837  1.3   darrenr /* Function:    ipf_rx_freehead                                             */
    838  1.3   darrenr /* Returns:     Nil                                                         */
    839  1.3   darrenr /* Paramters:   head(I)  - pointer to tree head to free                     */
    840  1.3   darrenr /*                                                                          */
    841  1.3   darrenr /* This function simply free's up the radix tree head. Prior to calling     */
    842  1.3   darrenr /* this function, it is expected that the tree will have been emptied.      */
    843  1.3   darrenr /* ------------------------------------------------------------------------ */
    844  1.1  christos void
    845  1.2  christos ipf_rx_freehead(ipf_rdx_head_t *head)
    846  1.1  christos {
    847  1.1  christos 	KFREE(head);
    848  1.1  christos }
    849  1.1  christos 
    850  1.3   darrenr 
    851  1.3   darrenr /* ------------------------------------------------------------------------ */
    852  1.3   darrenr /* Function:    ipf_rx_create                                               */
    853  1.3   darrenr /* Parameters:  Nil                                                         */
    854  1.3   darrenr /*                                                                          */
    855  1.3   darrenr /* ------------------------------------------------------------------------ */
    856  1.1  christos void *
    857  1.2  christos ipf_rx_create(void)
    858  1.1  christos {
    859  1.1  christos 	radix_softc_t *softr;
    860  1.1  christos 
    861  1.1  christos 	KMALLOC(softr, radix_softc_t *);
    862  1.1  christos 	if (softr == NULL)
    863  1.1  christos 		return NULL;
    864  1.1  christos 	bzero((char *)softr, sizeof(*softr));
    865  1.1  christos 
    866  1.3   darrenr 	KMALLOCS(softr->zeros, u_char *, 3 * sizeof(addrfamily_t));
    867  1.3   darrenr 	if (softr->zeros == NULL) {
    868  1.3   darrenr 		KFREE(softr);
    869  1.3   darrenr 		return (NULL);
    870  1.3   darrenr 	}
    871  1.3   darrenr 	softr->ones = softr->zeros + sizeof(addrfamily_t);
    872  1.3   darrenr 
    873  1.1  christos 	return softr;
    874  1.1  christos }
    875  1.1  christos 
    876  1.3   darrenr 
    877  1.3   darrenr /* ------------------------------------------------------------------------ */
    878  1.3   darrenr /* Function:    ipf_rx_init                                                 */
    879  1.3   darrenr /* Returns:     int       - 0 = success (always)                            */
    880  1.3   darrenr /*                                                                          */
    881  1.3   darrenr /* ------------------------------------------------------------------------ */
    882  1.1  christos int
    883  1.2  christos ipf_rx_init(void *ctx)
    884  1.1  christos {
    885  1.1  christos 	radix_softc_t *softr = ctx;
    886  1.1  christos 
    887  1.3   darrenr 	memset(softr->zeros, 0, 3 * sizeof(addrfamily_t));
    888  1.1  christos 	memset(softr->ones, 0xff, sizeof(addrfamily_t));
    889  1.3   darrenr 
    890  1.1  christos 	return (0);
    891  1.1  christos }
    892  1.1  christos 
    893  1.3   darrenr 
    894  1.3   darrenr /* ------------------------------------------------------------------------ */
    895  1.3   darrenr /* Function:    ipf_rx_destroy                                              */
    896  1.3   darrenr /* Returns:     Nil                                                         */
    897  1.3   darrenr /*                                                                          */
    898  1.3   darrenr /* ------------------------------------------------------------------------ */
    899  1.1  christos void
    900  1.2  christos ipf_rx_destroy(void *ctx)
    901  1.1  christos {
    902  1.1  christos 	radix_softc_t *softr = ctx;
    903  1.1  christos 
    904  1.1  christos 	if (softr->zeros != NULL)
    905  1.1  christos 		KFREES(softr->zeros, 3 * sizeof(addrfamily_t));
    906  1.1  christos 	KFREE(softr);
    907  1.1  christos }
    908  1.1  christos 
    909  1.1  christos /* ====================================================================== */
    910  1.1  christos 
    911  1.1  christos #ifdef RDX_DEBUG
    912  1.3   darrenr /*
    913  1.3   darrenr  * To compile this file as a standalone test unit, use -DRDX_DEBUG=1
    914  1.3   darrenr  */
    915  1.1  christos #define	NAME(x)	((x)->index < 0 ? (x)->name : (x)->name)
    916  1.1  christos #define	GNAME(y)	((y) == NULL ? "NULL" : NAME(y))
    917  1.1  christos 
    918  1.1  christos typedef struct myst {
    919  1.1  christos 	struct ipf_rdx_node nodes[2];
    920  1.1  christos 	addrfamily_t	dst;
    921  1.1  christos 	addrfamily_t	mask;
    922  1.1  christos 	struct myst	*next;
    923  1.1  christos 	int		printed;
    924  1.1  christos } myst_t;
    925  1.1  christos 
    926  1.3   darrenr typedef struct tabe_s {
    927  1.3   darrenr 	char	*host;
    928  1.3   darrenr 	char	*mask;
    929  1.3   darrenr 	char	*what;
    930  1.3   darrenr } tabe_t;
    931  1.3   darrenr 
    932  1.3   darrenr tabe_t builtin[] = {
    933  1.3   darrenr #if 1
    934  1.3   darrenr 	{ "192:168:100::0",	"48",			"d" },
    935  1.3   darrenr 	{ "192:168:100::2",	"128",			"d" },
    936  1.3   darrenr #else
    937  1.3   darrenr 	{ "127.192.0.0",	"255.255.255.0",	"d" },
    938  1.3   darrenr 	{ "127.128.0.0",	"255.255.255.0",	"d" },
    939  1.3   darrenr 	{ "127.96.0.0",		"255.255.255.0",	"d" },
    940  1.3   darrenr 	{ "127.80.0.0",		"255.255.255.0",	"d" },
    941  1.3   darrenr 	{ "127.72.0.0",		"255.255.255.0",	"d" },
    942  1.3   darrenr 	{ "127.64.0.0",		"255.255.255.0",	"d" },
    943  1.3   darrenr 	{ "127.56.0.0",		"255.255.255.0",	"d" },
    944  1.3   darrenr 	{ "127.48.0.0",		"255.255.255.0",	"d" },
    945  1.3   darrenr 	{ "127.40.0.0",		"255.255.255.0",	"d" },
    946  1.3   darrenr 	{ "127.32.0.0",		"255.255.255.0",	"d" },
    947  1.3   darrenr 	{ "127.24.0.0",		"255.255.255.0",	"d" },
    948  1.3   darrenr 	{ "127.16.0.0",		"255.255.255.0",	"d" },
    949  1.3   darrenr 	{ "127.8.0.0",		"255.255.255.0",	"d" },
    950  1.3   darrenr 	{ "124.0.0.0",		"255.0.0.0",		"d" },
    951  1.3   darrenr 	{ "125.0.0.0",		"255.0.0.0",		"d" },
    952  1.3   darrenr 	{ "126.0.0.0",		"255.0.0.0",		"d" },
    953  1.3   darrenr 	{ "127.0.0.0",		"255.0.0.0",		"d" },
    954  1.3   darrenr 	{ "10.0.0.0",		"255.0.0.0",		"d" },
    955  1.3   darrenr 	{ "128.250.0.0",	"255.255.0.0",		"d" },
    956  1.3   darrenr 	{ "192.168.0.0",	"255.255.0.0",		"d" },
    957  1.3   darrenr 	{ "192.168.1.0",	"255.255.255.0",	"d" },
    958  1.3   darrenr #endif
    959  1.3   darrenr 	{ NULL, NULL, NULL }
    960  1.3   darrenr };
    961  1.3   darrenr 
    962  1.3   darrenr char *mtable[][1] = {
    963  1.3   darrenr #if 1
    964  1.3   darrenr 	{ "192:168:100::2" },
    965  1.3   darrenr 	{ "192:168:101::2" },
    966  1.3   darrenr #else
    967  1.3   darrenr 	{ "9.0.0.0" },
    968  1.3   darrenr 	{ "9.0.0.1" },
    969  1.3   darrenr 	{ "11.0.0.0" },
    970  1.3   darrenr 	{ "11.0.0.1" },
    971  1.3   darrenr 	{ "127.0.0.1" },
    972  1.3   darrenr 	{ "127.0.1.0" },
    973  1.3   darrenr 	{ "255.255.255.0" },
    974  1.3   darrenr 	{ "126.0.0.1" },
    975  1.3   darrenr 	{ "128.251.0.0" },
    976  1.3   darrenr 	{ "128.251.0.1" },
    977  1.3   darrenr 	{ "128.251.255.255" },
    978  1.3   darrenr 	{ "129.250.0.0" },
    979  1.3   darrenr 	{ "129.250.0.1" },
    980  1.3   darrenr 	{ "192.168.255.255" },
    981  1.3   darrenr #endif
    982  1.3   darrenr 	{ NULL }
    983  1.3   darrenr };
    984  1.3   darrenr 
    985  1.3   darrenr 
    986  1.3   darrenr int forder[22] = {
    987  1.3   darrenr 	14, 13, 12,  5, 10,  3, 19,  7,  4, 20,  8,
    988  1.3   darrenr 	 2, 17,  9, 16, 11, 15,  1,  6, 18,  0, 21
    989  1.3   darrenr };
    990  1.3   darrenr 
    991  1.1  christos static int nodecount = 0;
    992  1.1  christos myst_t *myst_top = NULL;
    993  1.3   darrenr tabe_t *ttable = NULL;
    994  1.1  christos 
    995  1.1  christos void add_addr(ipf_rdx_head_t *, int , int);
    996  1.1  christos void checktree(ipf_rdx_head_t *);
    997  1.1  christos void delete_addr(ipf_rdx_head_t *rnh, int item);
    998  1.1  christos void dumptree(ipf_rdx_head_t *rnh);
    999  1.1  christos void nodeprinter(ipf_rdx_node_t *, void *);
   1000  1.1  christos void printroots(ipf_rdx_head_t *);
   1001  1.1  christos void random_add(ipf_rdx_head_t *);
   1002  1.1  christos void random_delete(ipf_rdx_head_t *);
   1003  1.3   darrenr void test_addr(ipf_rdx_head_t *rnh, int pref, addrfamily_t *, int);
   1004  1.3   darrenr 
   1005  1.1  christos 
   1006  1.1  christos static void
   1007  1.1  christos ipf_rx_freenode(node, arg)
   1008  1.1  christos 	ipf_rdx_node_t *node;
   1009  1.1  christos 	void *arg;
   1010  1.1  christos {
   1011  1.1  christos 	ipf_rdx_head_t *head = arg;
   1012  1.1  christos 	ipf_rdx_node_t *rv;
   1013  1.1  christos 	myst_t *stp;
   1014  1.1  christos 
   1015  1.1  christos 	stp = (myst_t *)node;
   1016  1.1  christos 	rv = ipf_rx_delete(head, &stp->dst, &stp->mask);
   1017  1.1  christos 	if (rv != NULL) {
   1018  1.1  christos 		free(rv);
   1019  1.1  christos 	}
   1020  1.1  christos }
   1021  1.1  christos 
   1022  1.3   darrenr 
   1023  1.3   darrenr const char *
   1024  1.3   darrenr addrname(ap)
   1025  1.3   darrenr 	addrfamily_t *ap;
   1026  1.3   darrenr {
   1027  1.3   darrenr 	static char name[80];
   1028  1.3   darrenr 	const char *txt;
   1029  1.3   darrenr 
   1030  1.3   darrenr 	bzero((char *)name, sizeof(name));
   1031  1.3   darrenr 	txt =  inet_ntop(ap->adf_family, &ap->adf_addr, name,
   1032  1.3   darrenr 			 sizeof(name));
   1033  1.3   darrenr 	return txt;
   1034  1.3   darrenr }
   1035  1.3   darrenr 
   1036  1.3   darrenr 
   1037  1.3   darrenr void
   1038  1.3   darrenr fill6bits(bits, msk)
   1039  1.3   darrenr 	int bits;
   1040  1.3   darrenr 	u_int *msk;
   1041  1.3   darrenr {
   1042  1.3   darrenr 	if (bits == 0) {
   1043  1.3   darrenr 		msk[0] = 0;
   1044  1.3   darrenr 		msk[1] = 0;
   1045  1.3   darrenr 		msk[2] = 0;
   1046  1.3   darrenr 		msk[3] = 0;
   1047  1.3   darrenr 		return;
   1048  1.3   darrenr 	}
   1049  1.3   darrenr 
   1050  1.3   darrenr 	msk[0] = 0xffffffff;
   1051  1.3   darrenr 	msk[1] = 0xffffffff;
   1052  1.3   darrenr 	msk[2] = 0xffffffff;
   1053  1.3   darrenr 	msk[3] = 0xffffffff;
   1054  1.3   darrenr 
   1055  1.3   darrenr 	if (bits == 128)
   1056  1.3   darrenr 		return;
   1057  1.3   darrenr 	if (bits > 96) {
   1058  1.3   darrenr 		msk[3] = htonl(msk[3] << (128 - bits));
   1059  1.3   darrenr 	} else if (bits > 64) {
   1060  1.3   darrenr 		msk[3] = 0;
   1061  1.3   darrenr 		msk[2] = htonl(msk[2] << (96 - bits));
   1062  1.3   darrenr 	} else if (bits > 32) {
   1063  1.3   darrenr 		msk[3] = 0;
   1064  1.3   darrenr 		msk[2] = 0;
   1065  1.3   darrenr 		msk[1] = htonl(msk[1] << (64 - bits));
   1066  1.3   darrenr 	} else {
   1067  1.3   darrenr 		msk[3] = 0;
   1068  1.3   darrenr 		msk[2] = 0;
   1069  1.3   darrenr 		msk[1] = 0;
   1070  1.3   darrenr 		msk[0] = htonl(msk[0] << (32 - bits));
   1071  1.3   darrenr 	}
   1072  1.3   darrenr }
   1073  1.3   darrenr 
   1074  1.3   darrenr 
   1075  1.3   darrenr void
   1076  1.3   darrenr setaddr(afp, str)
   1077  1.3   darrenr 	addrfamily_t *afp;
   1078  1.3   darrenr 	char *str;
   1079  1.3   darrenr {
   1080  1.3   darrenr 
   1081  1.3   darrenr 	bzero((char *)afp, sizeof(*afp));
   1082  1.3   darrenr 
   1083  1.3   darrenr 	if (strchr(str, ':') == NULL) {
   1084  1.3   darrenr 		afp->adf_family = AF_INET;
   1085  1.3   darrenr 		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
   1086  1.3   darrenr 	} else {
   1087  1.3   darrenr 		afp->adf_family = AF_INET6;
   1088  1.3   darrenr 		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
   1089  1.3   darrenr 	}
   1090  1.3   darrenr 	inet_pton(afp->adf_family, str, &afp->adf_addr);
   1091  1.3   darrenr }
   1092  1.3   darrenr 
   1093  1.3   darrenr 
   1094  1.3   darrenr void
   1095  1.3   darrenr setmask(afp, str)
   1096  1.3   darrenr 	addrfamily_t *afp;
   1097  1.3   darrenr 	char *str;
   1098  1.3   darrenr {
   1099  1.3   darrenr 	if (strchr(str, '.') != NULL) {
   1100  1.3   darrenr 		afp->adf_addr.in4.s_addr = inet_addr(str);
   1101  1.3   darrenr 		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
   1102  1.3   darrenr 	} else if (afp->adf_family == AF_INET) {
   1103  1.3   darrenr 		afp->adf_addr.i6[0] = htonl(0xffffffff << (32 - atoi(str)));
   1104  1.3   darrenr 		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
   1105  1.3   darrenr 	} else if (afp->adf_family == AF_INET6) {
   1106  1.3   darrenr 		fill6bits(atoi(str), afp->adf_addr.i6);
   1107  1.3   darrenr 		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
   1108  1.3   darrenr 	}
   1109  1.3   darrenr }
   1110  1.3   darrenr 
   1111  1.3   darrenr 
   1112  1.1  christos void
   1113  1.1  christos nodeprinter(node, arg)
   1114  1.1  christos 	ipf_rdx_node_t *node;
   1115  1.1  christos 	void *arg;
   1116  1.1  christos {
   1117  1.1  christos 	myst_t *stp = (myst_t *)node;
   1118  1.1  christos 
   1119  1.1  christos 	printf("Node %-9.9s L %-9.9s R %-9.9s P %9.9s/%-9.9s %s/%d\n",
   1120  1.1  christos 		node[0].name,
   1121  1.1  christos 		GNAME(node[1].left), GNAME(node[1].right),
   1122  1.1  christos 		GNAME(node[0].parent), GNAME(node[1].parent),
   1123  1.3   darrenr 		addrname(&stp->dst), node[0].maskbitcount);
   1124  1.3   darrenr 	if (stp->printed == -1)
   1125  1.3   darrenr 		printf("!!! %d\n", stp->printed);
   1126  1.3   darrenr 	else
   1127  1.3   darrenr 		stp->printed = 1;
   1128  1.1  christos }
   1129  1.1  christos 
   1130  1.3   darrenr 
   1131  1.1  christos void
   1132  1.1  christos printnode(stp)
   1133  1.1  christos 	myst_t *stp;
   1134  1.1  christos {
   1135  1.1  christos 	ipf_rdx_node_t *node = &stp->nodes[0];
   1136  1.1  christos 
   1137  1.1  christos 	if (stp->nodes[0].index > 0)
   1138  1.1  christos 		stp = (myst_t *)&stp->nodes[-1];
   1139  1.1  christos 
   1140  1.1  christos 	printf("Node %-9.9s ", node[0].name);
   1141  1.1  christos 	printf("L %-9.9s ", GNAME(node[1].left));
   1142  1.1  christos 	printf("R %-9.9s ", GNAME(node[1].right));
   1143  1.1  christos 	printf("P %9.9s", GNAME(node[0].parent));
   1144  1.1  christos 	printf("/%-9.9s ", GNAME(node[1].parent));
   1145  1.3   darrenr 	printf("%s P%d\n", addrname(&stp->dst), stp->printed);
   1146  1.1  christos }
   1147  1.1  christos 
   1148  1.1  christos 
   1149  1.3   darrenr void
   1150  1.3   darrenr buildtab(void)
   1151  1.3   darrenr {
   1152  1.3   darrenr 	char line[80], *s;
   1153  1.3   darrenr 	tabe_t *tab;
   1154  1.3   darrenr 	int lines;
   1155  1.3   darrenr 	FILE *fp;
   1156  1.3   darrenr 
   1157  1.3   darrenr 	lines = 0;
   1158  1.3   darrenr 	fp = fopen("hosts", "r");
   1159  1.3   darrenr 
   1160  1.3   darrenr 	while (fgets(line, sizeof(line), fp) != NULL) {
   1161  1.3   darrenr 		s = strchr(line, '\n');
   1162  1.3   darrenr 		if (s != NULL)
   1163  1.3   darrenr 			*s = '\0';
   1164  1.3   darrenr 		lines++;
   1165  1.3   darrenr 		if (lines == 1)
   1166  1.3   darrenr 			tab = malloc(sizeof(*tab) * 2);
   1167  1.3   darrenr 		else
   1168  1.3   darrenr 			tab = realloc(tab, (lines + 1) * sizeof(*tab));
   1169  1.3   darrenr 		tab[lines - 1].host = strdup(line);
   1170  1.3   darrenr 		s = strchr(tab[lines - 1].host, '/');
   1171  1.3   darrenr 		*s++ = '\0';
   1172  1.3   darrenr 		tab[lines - 1].mask = s;
   1173  1.3   darrenr 		tab[lines - 1].what = "d";
   1174  1.3   darrenr 	}
   1175  1.3   darrenr 	fclose(fp);
   1176  1.3   darrenr 
   1177  1.3   darrenr 	tab[lines].host = NULL;
   1178  1.3   darrenr 	tab[lines].mask = NULL;
   1179  1.3   darrenr 	tab[lines].what = NULL;
   1180  1.3   darrenr 	ttable = tab;
   1181  1.3   darrenr }
   1182  1.1  christos 
   1183  1.1  christos 
   1184  1.1  christos void
   1185  1.1  christos printroots(rnh)
   1186  1.1  christos 	ipf_rdx_head_t *rnh;
   1187  1.1  christos {
   1188  1.1  christos 	printf("Root.0.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
   1189  1.1  christos 		GNAME(&rnh->nodes[0]),
   1190  1.1  christos 		rnh->nodes[0].index, GNAME(rnh->nodes[0].parent),
   1191  1.1  christos 		GNAME(rnh->nodes[0].left), GNAME(rnh->nodes[0].right));
   1192  1.1  christos 	printf("Root.1.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
   1193  1.1  christos 		GNAME(&rnh->nodes[1]),
   1194  1.1  christos 		rnh->nodes[1].index, GNAME(rnh->nodes[1].parent),
   1195  1.1  christos 		GNAME(rnh->nodes[1].left), GNAME(rnh->nodes[1].right));
   1196  1.1  christos 	printf("Root.2.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
   1197  1.1  christos 		GNAME(&rnh->nodes[2]),
   1198  1.1  christos 		rnh->nodes[2].index, GNAME(rnh->nodes[2].parent),
   1199  1.1  christos 		GNAME(rnh->nodes[2].left), GNAME(rnh->nodes[2].right));
   1200  1.1  christos }
   1201  1.1  christos 
   1202  1.3   darrenr 
   1203  1.1  christos int
   1204  1.1  christos main(int argc, char *argv[])
   1205  1.1  christos {
   1206  1.3   darrenr 	addrfamily_t af;
   1207  1.1  christos 	ipf_rdx_head_t *rnh;
   1208  1.1  christos 	radix_softc_t *ctx;
   1209  1.1  christos 	int j;
   1210  1.1  christos 	int i;
   1211  1.1  christos 
   1212  1.1  christos 	rnh = NULL;
   1213  1.1  christos 
   1214  1.3   darrenr 	buildtab();
   1215  1.1  christos 	ctx = ipf_rx_create();
   1216  1.1  christos 	ipf_rx_init(ctx);
   1217  1.1  christos 	ipf_rx_inithead(ctx, &rnh);
   1218  1.1  christos 
   1219  1.1  christos 	printf("=== ADD-0 ===\n");
   1220  1.3   darrenr 	for (i = 0; ttable[i].host != NULL; i++) {
   1221  1.1  christos 		add_addr(rnh, i, i);
   1222  1.1  christos 		checktree(rnh);
   1223  1.1  christos 	}
   1224  1.3   darrenr 	printroots(rnh);
   1225  1.1  christos 	ipf_rx_walktree(rnh, nodeprinter, NULL);
   1226  1.1  christos 	printf("=== DELETE-0 ===\n");
   1227  1.3   darrenr 	for (i = 0; ttable[i].host != NULL; i++) {
   1228  1.1  christos 		delete_addr(rnh, i);
   1229  1.3   darrenr 		printroots(rnh);
   1230  1.1  christos 		ipf_rx_walktree(rnh, nodeprinter, NULL);
   1231  1.1  christos 	}
   1232  1.1  christos 	printf("=== ADD-1 ===\n");
   1233  1.3   darrenr 	for (i = 0; ttable[i].host != NULL; i++) {
   1234  1.3   darrenr 		setaddr(&af, ttable[i].host);
   1235  1.3   darrenr 		add_addr(rnh, i, i); /*forder[i]); */
   1236  1.1  christos 		checktree(rnh);
   1237  1.1  christos 	}
   1238  1.1  christos 	dumptree(rnh);
   1239  1.1  christos 	ipf_rx_walktree(rnh, nodeprinter, NULL);
   1240  1.1  christos 	printf("=== TEST-1 ===\n");
   1241  1.3   darrenr 	for (i = 0; ttable[i].host != NULL; i++) {
   1242  1.3   darrenr 		setaddr(&af, ttable[i].host);
   1243  1.3   darrenr 		test_addr(rnh, i, &af, -1);
   1244  1.1  christos 	}
   1245  1.1  christos 
   1246  1.1  christos 	printf("=== TEST-2 ===\n");
   1247  1.1  christos 	for (i = 0; mtable[i][0] != NULL; i++) {
   1248  1.3   darrenr 		setaddr(&af, mtable[i][0]);
   1249  1.3   darrenr 		test_addr(rnh, i, &af, -1);
   1250  1.1  christos 	}
   1251  1.1  christos 	printf("=== DELETE-1 ===\n");
   1252  1.3   darrenr 	for (i = 0; ttable[i].host != NULL; i++) {
   1253  1.3   darrenr 		if (ttable[i].what[0] != 'd')
   1254  1.1  christos 			continue;
   1255  1.1  christos 		delete_addr(rnh, i);
   1256  1.3   darrenr 		for (j = 0; ttable[j].host != NULL; j++) {
   1257  1.3   darrenr 			setaddr(&af, ttable[j].host);
   1258  1.3   darrenr 			test_addr(rnh, i, &af, 3);
   1259  1.1  christos 		}
   1260  1.3   darrenr 		printroots(rnh);
   1261  1.1  christos 		ipf_rx_walktree(rnh, nodeprinter, NULL);
   1262  1.1  christos 	}
   1263  1.1  christos 
   1264  1.1  christos 	dumptree(rnh);
   1265  1.1  christos 
   1266  1.1  christos 	printf("=== ADD-2 ===\n");
   1267  1.1  christos 	random_add(rnh);
   1268  1.1  christos 	checktree(rnh);
   1269  1.1  christos 	dumptree(rnh);
   1270  1.1  christos 	ipf_rx_walktree(rnh, nodeprinter, NULL);
   1271  1.1  christos 	printf("=== DELETE-2 ===\n");
   1272  1.1  christos 	random_delete(rnh);
   1273  1.1  christos 	checktree(rnh);
   1274  1.1  christos 	dumptree(rnh);
   1275  1.1  christos 
   1276  1.1  christos 	ipf_rx_walktree(rnh, ipf_rx_freenode, rnh);
   1277  1.1  christos 
   1278  1.1  christos 	return 0;
   1279  1.1  christos }
   1280  1.1  christos 
   1281  1.3   darrenr 
   1282  1.1  christos void
   1283  1.1  christos dumptree(rnh)
   1284  1.1  christos 	ipf_rdx_head_t *rnh;
   1285  1.1  christos {
   1286  1.1  christos 	myst_t *stp;
   1287  1.1  christos 
   1288  1.1  christos 	printf("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");
   1289  1.3   darrenr 	printroots(rnh);
   1290  1.1  christos 	for (stp = myst_top; stp; stp = stp->next)
   1291  1.1  christos 		printnode(stp);
   1292  1.1  christos 	printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
   1293  1.1  christos }
   1294  1.1  christos 
   1295  1.3   darrenr 
   1296  1.1  christos void
   1297  1.1  christos test_addr(rnh, pref, addr, limit)
   1298  1.1  christos 	ipf_rdx_head_t *rnh;
   1299  1.1  christos 	int pref;
   1300  1.3   darrenr 	addrfamily_t *addr;
   1301  1.1  christos {
   1302  1.1  christos 	static int extras[14] = { 0, -1, 1, 3, 5, 8, 9,
   1303  1.1  christos 				  15, 16, 19, 255, 256, 65535, 65536
   1304  1.1  christos 	};
   1305  1.1  christos 	ipf_rdx_node_t *rn;
   1306  1.1  christos 	addrfamily_t af;
   1307  1.3   darrenr 	char name[80];
   1308  1.1  christos 	myst_t *stp;
   1309  1.1  christos 	int i;
   1310  1.1  christos 
   1311  1.1  christos 	memset(&af, 0, sizeof(af));
   1312  1.3   darrenr #if 0
   1313  1.1  christos 	if (limit < 0 || limit > 14)
   1314  1.1  christos 		limit = 14;
   1315  1.1  christos 
   1316  1.1  christos 	for (i = 0; i < limit; i++) {
   1317  1.3   darrenr 		if (ttable[i].host == NULL)
   1318  1.3   darrenr 			break;
   1319  1.3   darrenr 		setaddr(&af, ttable[i].host);
   1320  1.3   darrenr 		printf("%d.%d.LOOKUP(%s)", pref, i, addrname(&af));
   1321  1.1  christos 		rn = ipf_rx_match(rnh, &af);
   1322  1.1  christos 		stp = (myst_t *)rn;
   1323  1.1  christos 		printf(" = %s (%s/%d)\n", GNAME(rn),
   1324  1.3   darrenr 			rn ? addrname(&stp->dst) : "NULL",
   1325  1.1  christos 			rn ? rn->maskbitcount : 0);
   1326  1.1  christos 	}
   1327  1.3   darrenr #else
   1328  1.3   darrenr 	printf("%d.%d.LOOKUP(%s)", pref, -1, addrname(addr));
   1329  1.3   darrenr 	rn = ipf_rx_match(rnh, addr);
   1330  1.3   darrenr 	stp = (myst_t *)rn;
   1331  1.3   darrenr 	printf(" = %s (%s/%d)\n", GNAME(rn),
   1332  1.3   darrenr 		rn ? addrname(&stp->dst) : "NULL", rn ? rn->maskbitcount : 0);
   1333  1.3   darrenr #endif
   1334  1.1  christos }
   1335  1.1  christos 
   1336  1.3   darrenr 
   1337  1.1  christos void
   1338  1.1  christos delete_addr(rnh, item)
   1339  1.1  christos 	ipf_rdx_head_t *rnh;
   1340  1.1  christos 	int item;
   1341  1.1  christos {
   1342  1.1  christos 	ipf_rdx_node_t *rn;
   1343  1.1  christos 	addrfamily_t mask;
   1344  1.1  christos 	addrfamily_t af;
   1345  1.1  christos 	myst_t **pstp;
   1346  1.1  christos 	myst_t *stp;
   1347  1.1  christos 
   1348  1.1  christos 	memset(&af, 0, sizeof(af));
   1349  1.1  christos 	memset(&mask, 0, sizeof(mask));
   1350  1.3   darrenr 	setaddr(&af, ttable[item].host);
   1351  1.3   darrenr 	mask.adf_family = af.adf_family;
   1352  1.3   darrenr 	setmask(&mask, ttable[item].mask);
   1353  1.3   darrenr 
   1354  1.3   darrenr 	printf("DELETE(%s)\n", addrname(&af));
   1355  1.1  christos 	rn = ipf_rx_delete(rnh, &af, &mask);
   1356  1.3   darrenr 	if (rn == NULL) {
   1357  1.3   darrenr 		printf("FAIL LOOKUP DELETE\n");
   1358  1.3   darrenr 		checktree(rnh);
   1359  1.3   darrenr 		for (stp = myst_top; stp != NULL; stp = stp->next)
   1360  1.3   darrenr 			if (stp->printed != -1)
   1361  1.3   darrenr 				stp->printed = -2;
   1362  1.3   darrenr 		ipf_rx_walktree(rnh, nodeprinter, NULL);
   1363  1.3   darrenr 		dumptree(rnh);
   1364  1.3   darrenr 		abort();
   1365  1.3   darrenr 	}
   1366  1.3   darrenr 	printf("%d.delete(%s) = %s\n", item, addrname(&af), GNAME(rn));
   1367  1.1  christos 
   1368  1.1  christos 	for (pstp = &myst_top; (stp = *pstp) != NULL; pstp = &stp->next)
   1369  1.1  christos 		if (stp == (myst_t *)rn)
   1370  1.1  christos 			break;
   1371  1.3   darrenr 	stp->printed = -1;
   1372  1.3   darrenr 	stp->nodes[0].parent = &stp->nodes[0];
   1373  1.3   darrenr 	stp->nodes[1].parent = &stp->nodes[1];
   1374  1.1  christos 	*pstp = stp->next;
   1375  1.1  christos 	free(stp);
   1376  1.1  christos 	nodecount--;
   1377  1.1  christos 	checktree(rnh);
   1378  1.1  christos }
   1379  1.1  christos 
   1380  1.3   darrenr 
   1381  1.1  christos void
   1382  1.1  christos add_addr(rnh, n, item)
   1383  1.1  christos 	ipf_rdx_head_t *rnh;
   1384  1.1  christos 	int n, item;
   1385  1.1  christos {
   1386  1.1  christos 	ipf_rdx_node_t *rn;
   1387  1.1  christos 	myst_t *stp;
   1388  1.1  christos 
   1389  1.1  christos 	stp = calloc(1, sizeof(*stp));
   1390  1.1  christos 	rn = (ipf_rdx_node_t *)stp;
   1391  1.3   darrenr 	setaddr(&stp->dst, ttable[item].host);
   1392  1.3   darrenr 	stp->mask.adf_family = stp->dst.adf_family;
   1393  1.3   darrenr 	setmask(&stp->mask, ttable[item].mask);
   1394  1.1  christos 	stp->next = myst_top;
   1395  1.1  christos 	myst_top = stp;
   1396  1.5  christos 	(void) snprintf(rn[0].name, sizeof(rn[0].name), "_BORN.0");
   1397  1.5  christos 	(void) snprintf(rn[1].name, sizeof(rn[1].name), "_BORN.1");
   1398  1.1  christos 	rn = ipf_rx_addroute(rnh, &stp->dst, &stp->mask, stp->nodes);
   1399  1.5  christos 	(void) snprintf(rn[0].name, sizeof(rn[0].name), "%d_NODE.0", item);
   1400  1.5  christos 	(void) snprintf(rn[1].name, sizeof(rn[1].name), "%d_NODE.1", item);
   1401  1.1  christos 	printf("ADD %d/%d %s/%s\n", n, item, rn[0].name, rn[1].name);
   1402  1.1  christos 	nodecount++;
   1403  1.1  christos 	checktree(rnh);
   1404  1.1  christos }
   1405  1.1  christos 
   1406  1.3   darrenr 
   1407  1.1  christos void
   1408  1.1  christos checktree(ipf_rdx_head_t *head)
   1409  1.1  christos {
   1410  1.1  christos 	myst_t *s1;
   1411  1.1  christos 	ipf_rdx_node_t *rn;
   1412  1.1  christos 
   1413  1.1  christos 	if (nodecount <= 1)
   1414  1.1  christos 		return;
   1415  1.1  christos 
   1416  1.1  christos 	for (s1 = myst_top; s1 != NULL; s1 = s1->next) {
   1417  1.1  christos 		int fault = 0;
   1418  1.3   darrenr 		if (s1->printed == -1)
   1419  1.3   darrenr 			continue;
   1420  1.1  christos 		rn = &s1->nodes[1];
   1421  1.1  christos 		if (rn->right->parent != rn)
   1422  1.1  christos 			fault |= 1;
   1423  1.1  christos 		if (rn->left->parent != rn)
   1424  1.1  christos 			fault |= 2;
   1425  1.1  christos 		if (rn->parent->left != rn && rn->parent->right != rn)
   1426  1.1  christos 			fault |= 4;
   1427  1.1  christos 		if (fault != 0) {
   1428  1.1  christos 			printf("FAULT %#x %s\n", fault, rn->name);
   1429  1.1  christos 			dumptree(head);
   1430  1.1  christos 			ipf_rx_walktree(head, nodeprinter, NULL);
   1431  1.3   darrenr 			fflush(stdout);
   1432  1.3   darrenr 			fflush(stderr);
   1433  1.3   darrenr 			printf("--\n");
   1434  1.3   darrenr 			abort();
   1435  1.1  christos 		}
   1436  1.1  christos 	}
   1437  1.1  christos }
   1438  1.1  christos 
   1439  1.3   darrenr 
   1440  1.1  christos int *
   1441  1.1  christos randomize(int *pnitems)
   1442  1.1  christos {
   1443  1.1  christos 	int *order;
   1444  1.1  christos 	int nitems;
   1445  1.1  christos 	int choice;
   1446  1.1  christos 	int j;
   1447  1.1  christos 	int i;
   1448  1.1  christos 
   1449  1.1  christos 	nitems = sizeof(ttable) / sizeof(ttable[0]);
   1450  1.1  christos 	*pnitems = nitems;
   1451  1.1  christos 	order = calloc(nitems, sizeof(*order));
   1452  1.1  christos 	srandom(getpid() * time(NULL));
   1453  1.1  christos 	memset(order, 0xff, nitems * sizeof(*order));
   1454  1.1  christos 	order[21] = 21;
   1455  1.1  christos 	for (i = 0; i < nitems - 1; i++) {
   1456  1.1  christos 		do {
   1457  1.1  christos 			choice = rand() % (nitems - 1);
   1458  1.1  christos 			for (j = 0; j < nitems; j++)
   1459  1.1  christos 				if (order[j] == choice)
   1460  1.1  christos 					break;
   1461  1.1  christos 		} while (j != nitems);
   1462  1.1  christos 		order[i] = choice;
   1463  1.1  christos 	}
   1464  1.1  christos 
   1465  1.1  christos 	return order;
   1466  1.1  christos }
   1467  1.1  christos 
   1468  1.3   darrenr 
   1469  1.1  christos void
   1470  1.1  christos random_add(rnh)
   1471  1.1  christos 	ipf_rdx_head_t *rnh;
   1472  1.1  christos {
   1473  1.1  christos 	int *order;
   1474  1.1  christos 	int nitems;
   1475  1.1  christos 	int i;
   1476  1.1  christos 
   1477  1.1  christos 	order = randomize(&nitems);
   1478  1.1  christos 
   1479  1.1  christos 	for (i = 0; i < nitems - 1; i++) {
   1480  1.1  christos 		add_addr(rnh, i, order[i]);
   1481  1.1  christos 		checktree(rnh);
   1482  1.1  christos 	}
   1483  1.6  christos 
   1484  1.6  christos 	free(order);
   1485  1.1  christos }
   1486  1.1  christos 
   1487  1.3   darrenr 
   1488  1.1  christos void
   1489  1.1  christos random_delete(rnh)
   1490  1.1  christos 	ipf_rdx_head_t *rnh;
   1491  1.1  christos {
   1492  1.1  christos 	int *order;
   1493  1.1  christos 	int nitems;
   1494  1.1  christos 	int i;
   1495  1.1  christos 
   1496  1.1  christos 	order = randomize(&nitems);
   1497  1.1  christos 
   1498  1.1  christos 	for (i = 0; i < nitems - 1; i++) {
   1499  1.1  christos 		delete_addr(rnh, i);
   1500  1.1  christos 		checktree(rnh);
   1501  1.1  christos 	}
   1502  1.6  christos 
   1503  1.6  christos 	free(order);
   1504  1.1  christos }
   1505  1.1  christos #endif /* RDX_DEBUG */
   1506