1254562Scy/*
2254562Scy * Copyright (C) 2012 by Darren Reed.
3254562Scy *
4254562Scy * See the IPFILTER.LICENCE file for details on licencing.
5254562Scy */
6254562Scy#include <sys/types.h>
7254562Scy#include <sys/time.h>
8254562Scy#include <sys/socket.h>
9254562Scy#include <sys/param.h>
10254562Scy#include <netinet/in.h>
11254562Scy#include <net/if.h>
12254562Scy#if !defined(_KERNEL)
13254562Scy# include <stddef.h>
14254562Scy# include <stdlib.h>
15254562Scy# include <strings.h>
16254562Scy# include <string.h>
17254562Scy#endif
18254562Scy#include "netinet/ip_compat.h"
19254562Scy#include "netinet/ip_fil.h"
20254562Scy#ifdef RDX_DEBUG
21254562Scy# include <arpa/inet.h>
22254562Scy# include <stdlib.h>
23254562Scy# include <stdio.h>
24254562Scy#endif
25254562Scy#include "netinet/radix_ipf.h"
26254562Scy
27254562Scy#define	ADF_OFF	offsetof(addrfamily_t, adf_addr)
28254562Scy#define	ADF_OFF_BITS	(ADF_OFF << 3)
29254562Scy
30254562Scystatic ipf_rdx_node_t *ipf_rx_insert __P((ipf_rdx_head_t *,
31254562Scy					  ipf_rdx_node_t nodes[2], int *));
32254562Scystatic void ipf_rx_attach_mask __P((ipf_rdx_node_t *, ipf_rdx_mask_t *));
33254562Scystatic int count_mask_bits __P((addrfamily_t *, u_32_t **));
34254562Scystatic void buildnodes __P((addrfamily_t *, addrfamily_t *,
35254562Scy			    ipf_rdx_node_t n[2]));
36254562Scystatic ipf_rdx_node_t *ipf_rx_find_addr __P((ipf_rdx_node_t *, u_32_t *));
37254562Scystatic ipf_rdx_node_t *ipf_rx_lookup __P((ipf_rdx_head_t *, addrfamily_t *,
38254562Scy					  addrfamily_t *));
39254562Scystatic ipf_rdx_node_t *ipf_rx_match __P((ipf_rdx_head_t *, addrfamily_t *));
40254562Scy
41254562Scy/*
42254562Scy * Foreword.
43254562Scy * ---------
44254562Scy * The code in this file has been written to target using the addrfamily_t
45254562Scy * data structure to house the address information and no other. Thus there
46254562Scy * are certain aspects of thise code (such as offsets to the address itself)
47254562Scy * that are hard coded here whilst they might be more variable elsewhere.
48254562Scy * Similarly, this code enforces no maximum key length as that's implied by
49254562Scy * all keys needing to be stored in addrfamily_t.
50254562Scy */
51254562Scy
52254562Scy/* ------------------------------------------------------------------------ */
53254562Scy/* Function:    count_mask_bits                                             */
54254562Scy/* Returns:     number of consecutive bits starting at "mask".              */
55254562Scy/*                                                                          */
56254562Scy/* Count the number of bits set in the address section of addrfamily_t and  */
57254562Scy/* return both that number and a pointer to the last word with a bit set if */
58254562Scy/* lastp is not NULL. The bit count is performed using network byte order   */
59254562Scy/* as the guide for which bit is the most significant bit.                  */
60254562Scy/* ------------------------------------------------------------------------ */
61254562Scystatic int
62254562Scycount_mask_bits(mask, lastp)
63254562Scy	addrfamily_t *mask;
64254562Scy	u_32_t **lastp;
65254562Scy{
66254562Scy	u_32_t *mp = (u_32_t *)&mask->adf_addr;
67254562Scy	u_32_t m;
68254562Scy	int count = 0;
69254562Scy	int mlen;
70254562Scy
71254562Scy	mlen = mask->adf_len - offsetof(addrfamily_t, adf_addr);
72254562Scy	for (; mlen > 0; mlen -= 4, mp++) {
73254562Scy		if ((m = ntohl(*mp)) == 0)
74254562Scy			break;
75254562Scy		if (lastp != NULL)
76254562Scy			*lastp = mp;
77254562Scy		for (; m & 0x80000000; m <<= 1)
78254562Scy			count++;
79254562Scy	}
80254562Scy
81254562Scy	return count;
82254562Scy}
83254562Scy
84254562Scy
85254562Scy/* ------------------------------------------------------------------------ */
86254562Scy/* Function:    buildnodes                                                  */
87254562Scy/* Returns:     Nil                                                         */
88254562Scy/* Parameters:  addr(I)  - network address for this radix node              */
89254562Scy/*              mask(I)  - netmask associated with the above address        */
90254562Scy/*              nodes(O) - pair of ipf_rdx_node_t's to initialise with data */
91254562Scy/*                         associated with addr and mask.                   */
92254562Scy/*                                                                          */
93254562Scy/* Initialise the fields in a pair of radix tree nodes according to the     */
94254562Scy/* data supplied in the paramters "addr" and "mask". It is expected that    */
95254562Scy/* "mask" will contain a consecutive string of bits set. Masks with gaps in */
96254562Scy/* the middle are not handled by this implementation.                       */
97254562Scy/* ------------------------------------------------------------------------ */
98254562Scystatic void
99254562Scybuildnodes(addr, mask, nodes)
100254562Scy	addrfamily_t *addr, *mask;
101254562Scy	ipf_rdx_node_t nodes[2];
102254562Scy{
103254562Scy	u_32_t maskbits;
104254562Scy	u_32_t lastbits;
105254562Scy	u_32_t lastmask;
106254562Scy	u_32_t *last;
107254562Scy	int masklen;
108254562Scy
109254562Scy	last = NULL;
110254562Scy	maskbits = count_mask_bits(mask, &last);
111254562Scy	if (last == NULL) {
112254562Scy		masklen = 0;
113254562Scy		lastmask = 0;
114254562Scy	} else {
115254562Scy		masklen = last - (u_32_t *)mask;
116254562Scy		lastmask = *last;
117254562Scy	}
118254562Scy	lastbits = maskbits & 0x1f;
119254562Scy
120254562Scy	bzero(&nodes[0], sizeof(ipf_rdx_node_t) * 2);
121254562Scy	nodes[0].maskbitcount = maskbits;
122254562Scy	nodes[0].index = -1 - (ADF_OFF_BITS + maskbits);
123254562Scy	nodes[0].addrkey = (u_32_t *)addr;
124254562Scy	nodes[0].maskkey = (u_32_t *)mask;
125254562Scy	nodes[0].addroff = nodes[0].addrkey + masklen;
126254562Scy	nodes[0].maskoff = nodes[0].maskkey + masklen;
127254562Scy	nodes[0].parent = &nodes[1];
128254562Scy	nodes[0].offset = masklen;
129254562Scy	nodes[0].lastmask = lastmask;
130254562Scy	nodes[1].offset = masklen;
131254562Scy	nodes[1].left = &nodes[0];
132254562Scy	nodes[1].maskbitcount = maskbits;
133254562Scy#ifdef RDX_DEBUG
134254562Scy	(void) strcpy(nodes[0].name, "_BUILD.0");
135254562Scy	(void) strcpy(nodes[1].name, "_BUILD.1");
136254562Scy#endif
137254562Scy}
138254562Scy
139254562Scy
140254562Scy/* ------------------------------------------------------------------------ */
141254562Scy/* Function:    ipf_rx_find_addr                                            */
142254562Scy/* Returns:     ipf_rdx_node_t * - pointer to a node in the radix tree.     */
143254562Scy/* Parameters:  tree(I)  - pointer to first right node in tree to search    */
144254562Scy/*              addr(I)  - pointer to address to match                      */
145254562Scy/*                                                                          */
146254562Scy/* Walk the radix tree given by "tree", looking for a leaf node that is a   */
147254562Scy/* match for the address given by "addr".                                   */
148254562Scy/* ------------------------------------------------------------------------ */
149254562Scystatic ipf_rdx_node_t *
150254562Scyipf_rx_find_addr(tree, addr)
151254562Scy	ipf_rdx_node_t *tree;
152254562Scy	u_32_t *addr;
153254562Scy{
154254562Scy	ipf_rdx_node_t *cur;
155254562Scy
156254562Scy	for (cur = tree; cur->index >= 0;) {
157254562Scy		if (cur->bitmask & addr[cur->offset]) {
158254562Scy			cur = cur->right;
159254562Scy		} else {
160254562Scy			cur = cur->left;
161254562Scy		}
162254562Scy	}
163254562Scy
164254562Scy	return (cur);
165254562Scy}
166254562Scy
167254562Scy
168254562Scy/* ------------------------------------------------------------------------ */
169254562Scy/* Function:    ipf_rx_match                                                */
170254562Scy/* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
171254562Scy/*                                 added to the tree.                       */
172254562Scy/* Paramters:   head(I)  - pointer to tree head to search                   */
173254562Scy/*              addr(I)  - pointer to address to find                       */
174254562Scy/*                                                                          */
175254562Scy/* Search the radix tree for the best match to the address pointed to by    */
176254562Scy/* "addr" and return a pointer to that node. This search will not match the */
177254562Scy/* address information stored in either of the root leaves as neither of    */
178254562Scy/* them are considered to be part of the tree of data being stored.         */
179254562Scy/* ------------------------------------------------------------------------ */
180254562Scystatic ipf_rdx_node_t *
181254562Scyipf_rx_match(head, addr)
182254562Scy	ipf_rdx_head_t *head;
183254562Scy	addrfamily_t *addr;
184254562Scy{
185254562Scy	ipf_rdx_mask_t *masknode;
186254562Scy	ipf_rdx_node_t *prev;
187254562Scy	ipf_rdx_node_t *node;
188254562Scy	ipf_rdx_node_t *cur;
189254562Scy	u_32_t *data;
190254562Scy	u_32_t *mask;
191254562Scy	u_32_t *key;
192254562Scy	u_32_t *end;
193254562Scy	int len;
194254562Scy	int i;
195254562Scy
196254562Scy	len = addr->adf_len;
197254562Scy	end = (u_32_t *)((u_char *)addr + len);
198254562Scy	node = ipf_rx_find_addr(head->root, (u_32_t *)addr);
199254562Scy
200254562Scy	/*
201254562Scy	 * Search the dupkey list for a potential match.
202254562Scy	 */
203254562Scy	for (cur = node; (cur != NULL) && (cur->root == 0); cur = cur->dupkey) {
204254562Scy		i = cur[0].addroff - cur[0].addrkey;
205254562Scy		data = cur[0].addrkey + i;
206254562Scy		mask = cur[0].maskkey + i;
207254562Scy		key = (u_32_t *)addr + i;
208254562Scy		for (; key < end; data++, key++, mask++)
209254562Scy			if ((*key & *mask) != *data)
210254562Scy				break;
211254562Scy		if ((end == key) && (cur->root == 0))
212254562Scy			return (cur);	/* Equal keys */
213254562Scy	}
214254562Scy	prev = node->parent;
215254562Scy	key = (u_32_t *)addr;
216254562Scy
217254562Scy	for (node = prev; node->root == 0; node = node->parent) {
218254562Scy		/*
219254562Scy		 * We know that the node hasn't matched so therefore only
220254562Scy		 * the entries in the mask list are searched, not the top
221254562Scy		 * node nor the dupkey list.
222254562Scy		 */
223254562Scy		masknode = node->masks;
224254562Scy		for (; masknode != NULL; masknode = masknode->next) {
225254562Scy			if (masknode->maskbitcount > node->maskbitcount)
226254562Scy				continue;
227254562Scy			cur = masknode->node;
228254562Scy			for (i = ADF_OFF >> 2; i <= node->offset; i++) {
229254562Scy				if ((key[i] & masknode->mask[i]) ==
230254562Scy				    cur->addrkey[i])
231254562Scy					return (cur);
232254562Scy			}
233254562Scy		}
234254562Scy	}
235254562Scy
236254562Scy	return NULL;
237254562Scy}
238254562Scy
239254562Scy
240254562Scy/* ------------------------------------------------------------------------ */
241254562Scy/* Function:    ipf_rx_lookup                                               */
242254562Scy/* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
243254562Scy/*                                 added to the tree.                       */
244254562Scy/* Paramters:   head(I)  - pointer to tree head to search                   */
245254562Scy/*              addr(I)  - address part of the key to match                 */
246254562Scy/*              mask(I)  - netmask part of the key to match                 */
247254562Scy/*                                                                          */
248254562Scy/* ipf_rx_lookup searches for an exact match on (addr,mask). The intention  */
249254562Scy/* is to see if a given key is in the tree, not to see if a route exists.   */
250254562Scy/* ------------------------------------------------------------------------ */
251254562Scyipf_rdx_node_t *
252254562Scyipf_rx_lookup(head, addr, mask)
253254562Scy	ipf_rdx_head_t *head;
254254562Scy	addrfamily_t *addr, *mask;
255254562Scy{
256254562Scy	ipf_rdx_node_t *found;
257254562Scy	ipf_rdx_node_t *node;
258254562Scy	u_32_t *akey;
259254562Scy	int count;
260254562Scy
261254562Scy	found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
262254562Scy	if (found->root == 1)
263254562Scy		return NULL;
264254562Scy
265254562Scy	/*
266254562Scy	 * It is possible to find a matching address in the tree but for the
267254562Scy	 * netmask to not match. If the netmask does not match and there is
268254562Scy	 * no list of alternatives present at dupkey, return a failure.
269254562Scy	 */
270254562Scy	count = count_mask_bits(mask, NULL);
271254562Scy	if (count != found->maskbitcount && found->dupkey == NULL)
272254562Scy		return (NULL);
273254562Scy
274254562Scy	akey = (u_32_t *)addr;
275254562Scy	if ((found->addrkey[found->offset] & found->maskkey[found->offset]) !=
276254562Scy	    akey[found->offset])
277254562Scy		return NULL;
278254562Scy
279254562Scy	if (found->dupkey != NULL) {
280254562Scy		node = found;
281254562Scy		while (node != NULL && node->maskbitcount != count)
282254562Scy			node = node->dupkey;
283254562Scy		if (node == NULL)
284254562Scy			return (NULL);
285254562Scy		found = node;
286254562Scy	}
287254562Scy	return found;
288254562Scy}
289254562Scy
290254562Scy
291254562Scy/* ------------------------------------------------------------------------ */
292254562Scy/* Function:    ipf_rx_attach_mask                                          */
293254562Scy/* Returns:     Nil                                                         */
294254562Scy/* Parameters:  node(I)  - pointer to a radix tree node                     */
295254562Scy/*              mask(I)  - pointer to mask structure to add                 */
296254562Scy/*                                                                          */
297254562Scy/* Add the netmask to the given node in an ordering where the most specific */
298254562Scy/* netmask is at the top of the list.                                       */
299254562Scy/* ------------------------------------------------------------------------ */
300254562Scystatic void
301254562Scyipf_rx_attach_mask(node, mask)
302254562Scy	ipf_rdx_node_t *node;
303254562Scy	ipf_rdx_mask_t *mask;
304254562Scy{
305254562Scy	ipf_rdx_mask_t **pm;
306254562Scy	ipf_rdx_mask_t *m;
307254562Scy
308254562Scy	for (pm = &node->masks; (m = *pm) != NULL; pm = &m->next)
309254562Scy		if (m->maskbitcount < mask->maskbitcount)
310254562Scy			break;
311254562Scy	mask->next = *pm;
312254562Scy	*pm = mask;
313254562Scy}
314254562Scy
315254562Scy
316254562Scy/* ------------------------------------------------------------------------ */
317254562Scy/* Function:    ipf_rx_insert                                               */
318254562Scy/* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
319254562Scy/*                                 added to the tree.                       */
320254562Scy/* Paramters:   head(I)  - pointer to tree head to add nodes to             */
321254562Scy/*              nodes(I) - pointer to radix nodes to be added               */
322254562Scy/*              dup(O)   - set to 1 if node is a duplicate, else 0.         */
323254562Scy/*                                                                          */
324254562Scy/* Add the new radix tree entry that owns nodes[] to the tree given by head.*/
325254562Scy/* If there is already a matching key in the table, "dup" will be set to 1  */
326254562Scy/* and the existing node pointer returned if there is a complete key match. */
327254562Scy/* A complete key match is a matching of all key data that is presented by  */
328254562Scy/* by the netmask.                                                          */
329254562Scy/* ------------------------------------------------------------------------ */
330254562Scystatic ipf_rdx_node_t *
331254562Scyipf_rx_insert(head, nodes, dup)
332254562Scy	ipf_rdx_head_t *head;
333254562Scy	ipf_rdx_node_t nodes[2];
334254562Scy	int *dup;
335254562Scy{
336254562Scy	ipf_rdx_mask_t **pmask;
337254562Scy	ipf_rdx_node_t *node;
338254562Scy	ipf_rdx_node_t *prev;
339254562Scy	ipf_rdx_mask_t *mask;
340254562Scy	ipf_rdx_node_t *cur;
341254562Scy	u_32_t nodemask;
342254562Scy	u_32_t *addr;
343254562Scy	u_32_t *data;
344254562Scy	int nodebits;
345254562Scy	u_32_t *key;
346254562Scy	u_32_t *end;
347254562Scy	u_32_t bits;
348254562Scy	int nodekey;
349254562Scy	int nodeoff;
350254562Scy	int nlen;
351254562Scy	int len;
352254562Scy
353254562Scy	addr = nodes[0].addrkey;
354254562Scy
355254562Scy	node = ipf_rx_find_addr(head->root, addr);
356254562Scy	len = ((addrfamily_t *)addr)->adf_len;
357254562Scy	key = (u_32_t *)&((addrfamily_t *)addr)->adf_addr;
358254562Scy	data= (u_32_t *)&((addrfamily_t *)node->addrkey)->adf_addr;
359254562Scy	end = (u_32_t *)((u_char *)addr + len);
360254562Scy	for (nlen = 0; key < end; data++, key++, nlen += 32)
361254562Scy		if (*key != *data)
362254562Scy			break;
363254562Scy	if (end == data) {
364254562Scy		*dup = 1;
365254562Scy		return (node);	/* Equal keys */
366254562Scy	}
367254562Scy	*dup = 0;
368254562Scy
369254562Scy	bits = (ntohl(*data) ^ ntohl(*key));
370254562Scy	for (; bits != 0; nlen++) {
371254562Scy		if ((bits & 0x80000000) != 0)
372254562Scy			break;
373254562Scy		bits <<= 1;
374254562Scy	}
375254562Scy	nlen += ADF_OFF_BITS;
376254562Scy	nodes[1].index = nlen;
377254562Scy	nodes[1].bitmask = htonl(0x80000000 >> (nlen & 0x1f));
378254562Scy	nodes[0].offset = nlen / 32;
379254562Scy	nodes[1].offset = nlen / 32;
380254562Scy
381254562Scy	/*
382254562Scy	 * Walk through the tree and look for the correct place to attach
383254562Scy	 * this node. ipf_rx_fin_addr is not used here because the place
384254562Scy	 * to attach this node may be an internal node (same key, different
385254562Scy	 * netmask.) Additionally, the depth of the search is forcibly limited
386254562Scy	 * here to not exceed the netmask, so that a short netmask will be
387254562Scy	 * added higher up the tree even if there are lower branches.
388254562Scy	 */
389254562Scy	cur = head->root;
390254562Scy	key = nodes[0].addrkey;
391254562Scy	do {
392254562Scy		prev = cur;
393254562Scy		if (key[cur->offset] & cur->bitmask) {
394254562Scy			cur = cur->right;
395254562Scy		} else {
396254562Scy			cur = cur->left;
397254562Scy		}
398254562Scy	} while (nlen > (unsigned)cur->index);
399254562Scy
400254562Scy	if ((key[prev->offset] & prev->bitmask) == 0) {
401254562Scy		prev->left = &nodes[1];
402254562Scy	} else {
403254562Scy		prev->right = &nodes[1];
404254562Scy	}
405254562Scy	cur->parent = &nodes[1];
406254562Scy	nodes[1].parent = prev;
407254562Scy	if ((key[nodes[1].offset] & nodes[1].bitmask) == 0) {
408254562Scy		nodes[1].right = cur;
409254562Scy	} else {
410254562Scy		nodes[1].right = &nodes[0];
411254562Scy		nodes[1].left = cur;
412254562Scy	}
413254562Scy
414254562Scy	nodeoff = nodes[0].offset;
415254562Scy	nodekey = nodes[0].addrkey[nodeoff];
416254562Scy	nodemask = nodes[0].lastmask;
417254562Scy	nodebits = nodes[0].maskbitcount;
418254562Scy	prev = NULL;
419254562Scy	/*
420254562Scy	 * Find the node up the tree with the largest pattern that still
421254562Scy	 * matches the node being inserted to see if this mask can be
422254562Scy	 * moved there.
423254562Scy	 */
424254562Scy	for (cur = nodes[1].parent; cur->root == 0; cur = cur->parent) {
425254562Scy		if (cur->maskbitcount <= nodebits)
426254562Scy			break;
427254562Scy		if (((cur - 1)->addrkey[nodeoff] & nodemask) != nodekey)
428254562Scy			break;
429254562Scy		prev = cur;
430254562Scy	}
431254562Scy
432254562Scy	KMALLOC(mask, ipf_rdx_mask_t *);
433254562Scy	if (mask == NULL)
434254562Scy		return NULL;
435254562Scy	bzero(mask, sizeof(*mask));
436254562Scy	mask->next = NULL;
437254562Scy	mask->node = &nodes[0];
438254562Scy	mask->maskbitcount = nodebits;
439254562Scy	mask->mask = nodes[0].maskkey;
440254562Scy	nodes[0].mymask = mask;
441254562Scy
442254562Scy	if (prev != NULL) {
443254562Scy		ipf_rdx_mask_t *m;
444254562Scy
445254562Scy		for (pmask = &prev->masks; (m = *pmask) != NULL;
446254562Scy		     pmask = &m->next) {
447254562Scy			if (m->maskbitcount < nodebits)
448254562Scy				break;
449254562Scy		}
450254562Scy	} else {
451254562Scy		/*
452254562Scy		 * No higher up nodes qualify, so attach mask locally.
453254562Scy		 */
454254562Scy		pmask = &nodes[0].masks;
455254562Scy	}
456254562Scy	mask->next = *pmask;
457254562Scy	*pmask = mask;
458254562Scy
459254562Scy	/*
460254562Scy	 * Search the mask list on each child to see if there are any masks
461254562Scy	 * there that can be moved up to this newly inserted node.
462254562Scy	 */
463254562Scy	cur = nodes[1].right;
464254562Scy	if (cur->root == 0) {
465254562Scy		for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
466254562Scy			if (mask->maskbitcount < nodebits) {
467254562Scy				*pmask = mask->next;
468254562Scy				ipf_rx_attach_mask(&nodes[0], mask);
469254562Scy			} else {
470254562Scy				pmask = &mask->next;
471254562Scy			}
472254562Scy		}
473254562Scy	}
474254562Scy	cur = nodes[1].left;
475254562Scy	if (cur->root == 0 && cur != &nodes[0]) {
476254562Scy		for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
477254562Scy			if (mask->maskbitcount < nodebits) {
478254562Scy				*pmask = mask->next;
479254562Scy				ipf_rx_attach_mask(&nodes[0], mask);
480254562Scy			} else {
481254562Scy				pmask = &mask->next;
482254562Scy			}
483254562Scy		}
484254562Scy	}
485254562Scy	return (&nodes[0]);
486254562Scy}
487254562Scy
488254562Scy/* ------------------------------------------------------------------------ */
489254562Scy/* Function:    ipf_rx_addroute                                             */
490254562Scy/* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
491254562Scy/*                                 added to the tree.                       */
492254562Scy/* Paramters:   head(I)  - pointer to tree head to search                   */
493254562Scy/*              addr(I)  - address portion of "route" to add                */
494254562Scy/*              mask(I)  - netmask portion of "route" to add                */
495254562Scy/*              nodes(I) - radix tree data nodes inside allocate structure  */
496254562Scy/*                                                                          */
497254562Scy/* Attempt to add a node to the radix tree. The key for the node is the     */
498254562Scy/* (addr,mask). No memory allocation for the radix nodes themselves is      */
499254562Scy/* performed here, the data structure that this radix node is being used to */
500254562Scy/* find is expected to house the node data itself however the call to       */
501254562Scy/* ipf_rx_insert() will attempt to allocate memory in order for netmask to  */
502254562Scy/* be promoted further up the tree.                                         */
503254562Scy/* In this case, the ip_pool_node_t structure from ip_pool.h contains both  */
504254562Scy/* the key material (addr,mask) and the radix tree nodes[].                 */
505254562Scy/*                                                                          */
506254562Scy/* The mechanics of inserting the node into the tree is handled by the      */
507254562Scy/* function ipf_rx_insert() above. Here, the code deals with the case       */
508254562Scy/* where the data to be inserted is a duplicate.                            */
509254562Scy/* ------------------------------------------------------------------------ */
510254562Scyipf_rdx_node_t *
511254562Scyipf_rx_addroute(head, addr, mask, nodes)
512254562Scy	ipf_rdx_head_t *head;
513254562Scy	addrfamily_t *addr, *mask;
514254562Scy	ipf_rdx_node_t *nodes;
515254562Scy{
516254562Scy	ipf_rdx_node_t *node;
517254562Scy	ipf_rdx_node_t *prev;
518254562Scy	ipf_rdx_node_t *x;
519254562Scy	int dup;
520254562Scy
521254562Scy	buildnodes(addr, mask, nodes);
522254562Scy	x = ipf_rx_insert(head, nodes, &dup);
523254562Scy	if (x == NULL)
524254562Scy		return NULL;
525254562Scy
526254562Scy	if (dup == 1) {
527254562Scy		node = &nodes[0];
528254562Scy		prev = NULL;
529254562Scy		/*
530254562Scy		 * The duplicate list is kept sorted with the longest
531254562Scy		 * mask at the top, meaning that the most specific entry
532254562Scy		 * in the listis found first. This list thus allows for
533254562Scy		 * duplicates such as 128.128.0.0/32 and 128.128.0.0/16.
534254562Scy		 */
535254562Scy		while ((x != NULL) && (x->maskbitcount > node->maskbitcount)) {
536254562Scy			prev = x;
537254562Scy			x = x->dupkey;
538254562Scy		}
539254562Scy
540254562Scy		/*
541254562Scy		 * Is it a complete duplicate? If so, return NULL and
542254562Scy		 * fail the insert. Otherwise, insert it into the list
543254562Scy		 * of netmasks active for this key.
544254562Scy		 */
545254562Scy		if ((x != NULL) && (x->maskbitcount == node->maskbitcount))
546254562Scy			return (NULL);
547254562Scy
548254562Scy		if (prev != NULL) {
549254562Scy			nodes[0].dupkey = x;
550254562Scy			prev->dupkey = &nodes[0];
551254562Scy			nodes[0].parent = prev;
552254562Scy			if (x != NULL)
553254562Scy				x->parent = &nodes[0];
554254562Scy		} else {
555254562Scy			nodes[0].dupkey = x->dupkey;
556254562Scy			prev = x->parent;
557254562Scy			nodes[0].parent = prev;
558254562Scy			x->parent = &nodes[0];
559254562Scy			if (prev->left == x)
560254562Scy				prev->left = &nodes[0];
561254562Scy			else
562254562Scy				prev->right = &nodes[0];
563254562Scy		}
564254562Scy	}
565254562Scy
566254562Scy	return &nodes[0];
567254562Scy}
568254562Scy
569254562Scy
570254562Scy/* ------------------------------------------------------------------------ */
571254562Scy/* Function:    ipf_rx_delete                                               */
572254562Scy/* Returns:     ipf_rdx_node_t * - NULL on error, else node removed from    */
573254562Scy/*                                 the tree.                                */
574254562Scy/* Paramters:   head(I)  - pointer to tree head to search                   */
575254562Scy/*              addr(I)  - pointer to the address part of the key           */
576254562Scy/*              mask(I)  - pointer to the netmask part of the key           */
577254562Scy/*                                                                          */
578254562Scy/* Search for an entry in the radix tree that is an exact match for (addr,  */
579254562Scy/* mask) and remove it if it exists. In the case where (addr,mask) is a not */
580254562Scy/* a unique key, the tree structure itself is not changed - only the list   */
581254562Scy/* of duplicate keys.                                                       */
582254562Scy/* ------------------------------------------------------------------------ */
583254562Scyipf_rdx_node_t *
584254562Scyipf_rx_delete(head, addr, mask)
585254562Scy        ipf_rdx_head_t *head;
586254562Scy        addrfamily_t *addr, *mask;
587254562Scy{
588254562Scy	ipf_rdx_mask_t **pmask;
589254562Scy	ipf_rdx_node_t *parent;
590254562Scy	ipf_rdx_node_t *found;
591254562Scy	ipf_rdx_node_t *prev;
592254562Scy	ipf_rdx_node_t *node;
593254562Scy	ipf_rdx_node_t *cur;
594254562Scy	ipf_rdx_mask_t *m;
595254562Scy	int count;
596254562Scy
597254562Scy	found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
598254562Scy	if (found == NULL)
599254562Scy		return NULL;
600254562Scy	if (found->root == 1)
601254562Scy		return NULL;
602254562Scy	count = count_mask_bits(mask, NULL);
603254562Scy	parent = found->parent;
604254562Scy	if (found->dupkey != NULL) {
605254562Scy		node = found;
606254562Scy		while (node != NULL && node->maskbitcount != count)
607254562Scy			node = node->dupkey;
608254562Scy		if (node == NULL)
609254562Scy			return (NULL);
610254562Scy		if (node != found) {
611254562Scy			/*
612254562Scy			 * Remove from the dupkey list. Here, "parent" is
613254562Scy			 * the previous node on the list (rather than tree)
614254562Scy			 * and "dupkey" is the next node on the list.
615254562Scy			 */
616254562Scy			parent = node->parent;
617254562Scy			parent->dupkey = node->dupkey;
618254562Scy			node->dupkey->parent = parent;
619254562Scy		} else {
620254562Scy			/*
621254562Scy			 *
622254562Scy			 * When removing the top node of the dupkey list,
623254562Scy			 * the pointers at the top of the list that point
624254562Scy			 * to other tree nodes need to be preserved and
625254562Scy			 * any children must have their parent updated.
626254562Scy			 */
627254562Scy			node = node->dupkey;
628254562Scy			node->parent = found->parent;
629254562Scy			node->right = found->right;
630254562Scy			node->left = found->left;
631254562Scy			found->right->parent = node;
632254562Scy			found->left->parent = node;
633254562Scy			if (parent->left == found)
634254562Scy				parent->left = node;
635254562Scy			else
636254562Scy				parent->right= node;
637254562Scy		}
638254562Scy	} else {
639254562Scy		if (count != found->maskbitcount)
640254562Scy			return (NULL);
641254562Scy		/*
642254562Scy		 * Remove the node from the tree and reconnect the subtree
643254562Scy		 * below.
644254562Scy		 */
645254562Scy		/*
646254562Scy		 * If there is a tree to the left, look for something to
647254562Scy		 * attach in place of "found".
648254562Scy		 */
649254562Scy		prev = found + 1;
650254562Scy		cur = parent->parent;
651254562Scy		if (parent != found + 1) {
652254562Scy			if ((found + 1)->parent->right == found + 1)
653254562Scy				(found + 1)->parent->right = parent;
654254562Scy			else
655254562Scy				(found + 1)->parent->left = parent;
656254562Scy			if (cur->right == parent) {
657254562Scy				if (parent->left == found) {
658254562Scy					cur->right = parent->right;
659254562Scy				} else if (parent->left != parent - 1) {
660254562Scy					cur->right = parent->left;
661254562Scy				} else {
662254562Scy					cur->right = parent - 1;
663254562Scy				}
664254562Scy				cur->right->parent = cur;
665254562Scy			} else {
666254562Scy				if (parent->right == found) {
667254562Scy					cur->left = parent->left;
668254562Scy				} else if (parent->right != parent - 1) {
669254562Scy					cur->left = parent->right;
670254562Scy				} else {
671254562Scy					cur->left = parent - 1;
672254562Scy				}
673254562Scy				cur->left->parent = cur;
674254562Scy			}
675254562Scy			parent->left = (found + 1)->left;
676254562Scy			if ((found + 1)->right != parent)
677254562Scy				parent->right = (found + 1)->right;
678254562Scy			parent->left->parent = parent;
679254562Scy			parent->right->parent = parent;
680254562Scy			parent->parent = (found + 1)->parent;
681254562Scy
682254562Scy			parent->bitmask = prev->bitmask;
683254562Scy			parent->offset = prev->offset;
684254562Scy			parent->index = prev->index;
685254562Scy		} else {
686254562Scy			/*
687254562Scy			 * We found an edge node.
688254562Scy			 */
689254562Scy			cur = parent->parent;
690254562Scy			if (cur->left == parent) {
691254562Scy				if (parent->left == found) {
692254562Scy					cur->left = parent->right;
693254562Scy					parent->right->parent = cur;
694254562Scy				} else {
695254562Scy					cur->left = parent->left;
696254562Scy					parent->left->parent = cur;
697254562Scy				}
698254562Scy			} else {
699254562Scy				if (parent->right != found) {
700254562Scy					cur->right = parent->right;
701254562Scy					parent->right->parent = cur;
702254562Scy				} else {
703254562Scy					cur->right = parent->left;
704254562Scy					prev->left->parent = cur;
705254562Scy				}
706254562Scy			}
707254562Scy		}
708254562Scy	}
709254562Scy
710254562Scy	/*
711254562Scy	 * Remove mask associated with this node.
712254562Scy	 */
713254562Scy	for (cur = parent; cur->root == 0; cur = cur->parent) {
714254562Scy		ipf_rdx_mask_t **pm;
715254562Scy
716254562Scy		if (cur->maskbitcount <= found->maskbitcount)
717254562Scy			break;
718254562Scy		if (((cur - 1)->addrkey[found->offset] & found->bitmask) !=
719254562Scy		    found->addrkey[found->offset])
720254562Scy			break;
721254562Scy		for (pm = &cur->masks; (m = *pm) != NULL; )
722254562Scy			if (m->node == cur) {
723254562Scy				*pm = m->next;
724254562Scy				break;
725254562Scy			} else {
726254562Scy				pm = &m->next;
727254562Scy			}
728254562Scy	}
729254562Scy	KFREE(found->mymask);
730254562Scy
731254562Scy	/*
732254562Scy	 * Masks that have been brought up to this node from below need to
733254562Scy	 * be sent back down.
734254562Scy	 */
735254562Scy	for (pmask = &parent->masks; (m = *pmask) != NULL; ) {
736254562Scy		*pmask = m->next;
737254562Scy		cur = m->node;
738254562Scy		if (cur == found)
739254562Scy			continue;
740254562Scy		if (found->addrkey[cur->offset] & cur->lastmask) {
741254562Scy			ipf_rx_attach_mask(parent->right, m);
742254562Scy		} else if (parent->left != found) {
743254562Scy			ipf_rx_attach_mask(parent->left, m);
744254562Scy		}
745254562Scy	}
746254562Scy
747254562Scy	return (found);
748254562Scy}
749254562Scy
750254562Scy
751254562Scy/* ------------------------------------------------------------------------ */
752254562Scy/* Function:    ipf_rx_walktree                                             */
753254562Scy/* Returns:     Nil                                                         */
754254562Scy/* Paramters:   head(I)   - pointer to tree head to search                  */
755254562Scy/*              walker(I) - function to call for each node in the tree      */
756254562Scy/*              arg(I)    - parameter to pass to walker, in addition to the */
757254562Scy/*                          node pointer                                    */
758254562Scy/*                                                                          */
759254562Scy/* A standard tree walking function except that it is iterative, rather     */
760254562Scy/* than recursive and tracks the next node in case the "walker" function    */
761254562Scy/* should happen to delete and free the current node. It thus goes without  */
762254562Scy/* saying that the "walker" function is not permitted to cause any change   */
763254562Scy/* in the validity of the data found at either the left or right child.     */
764254562Scy/* ------------------------------------------------------------------------ */
765254562Scyvoid
766254562Scyipf_rx_walktree(head, walker, arg)
767254562Scy	ipf_rdx_head_t *head;
768254562Scy	radix_walk_func_t walker;
769254562Scy	void *arg;
770254562Scy{
771254562Scy	ipf_rdx_node_t *next;
772254562Scy	ipf_rdx_node_t *node = head->root;
773254562Scy	ipf_rdx_node_t *base;
774254562Scy
775254562Scy	while (node->index >= 0)
776254562Scy		node = node->left;
777254562Scy
778254562Scy	for (;;) {
779254562Scy		base = node;
780254562Scy		while ((node->parent->right == node) && (node->root == 0))
781254562Scy			node = node->parent;
782254562Scy
783254562Scy		for (node = node->parent->right; node->index >= 0; )
784254562Scy			node = node->left;
785254562Scy		next = node;
786254562Scy
787254562Scy		for (node = base; node != NULL; node = base) {
788254562Scy			base = node->dupkey;
789254562Scy			if (node->root == 0)
790254562Scy				walker(node, arg);
791254562Scy		}
792254562Scy		node = next;
793254562Scy		if (node->root)
794254562Scy			return;
795254562Scy	}
796254562Scy}
797254562Scy
798254562Scy
799254562Scy/* ------------------------------------------------------------------------ */
800254562Scy/* Function:    ipf_rx_inithead                                             */
801254562Scy/* Returns:     int       - 0 = success, else failure                       */
802254562Scy/* Paramters:   softr(I)  - pointer to radix context                        */
803254562Scy/*              headp(O)  - location for where to store allocated tree head */
804254562Scy/*                                                                          */
805254562Scy/* This function allocates and initialises a radix tree head structure.     */
806254562Scy/* As a traditional radix tree, node 0 is used as the "0" sentinel and node */
807254562Scy/* "2" is used as the all ones sentinel, leaving node "1" as the root from  */
808254562Scy/* which the tree is hung with node "0" on its left and node "2" to the     */
809254562Scy/* right. The context, "softr", is used here to provide a common source of  */
810254562Scy/* the zeroes and ones data rather than have one per head.                  */
811254562Scy/* ------------------------------------------------------------------------ */
812254562Scyint
813254562Scyipf_rx_inithead(softr, headp)
814254562Scy	radix_softc_t *softr;
815254562Scy	ipf_rdx_head_t **headp;
816254562Scy{
817254562Scy	ipf_rdx_head_t *ptr;
818254562Scy	ipf_rdx_node_t *node;
819254562Scy
820254562Scy	KMALLOC(ptr, ipf_rdx_head_t *);
821254562Scy	*headp = ptr;
822254562Scy	if (ptr == NULL)
823254562Scy		return -1;
824254562Scy	bzero(ptr, sizeof(*ptr));
825254562Scy	node = ptr->nodes;
826254562Scy	ptr->root = node + 1;
827254562Scy	node[0].index = ADF_OFF_BITS;
828254562Scy	node[0].index = -1 - node[0].index;
829254562Scy	node[1].index = ADF_OFF_BITS;
830254562Scy	node[2].index = node[0].index;
831254562Scy	node[0].parent = node + 1;
832254562Scy	node[1].parent = node + 1;
833254562Scy	node[2].parent = node + 1;
834254562Scy	node[1].bitmask = htonl(0x80000000);
835254562Scy	node[0].root = 1;
836254562Scy	node[1].root = 1;
837254562Scy	node[2].root = 1;
838254562Scy	node[0].offset = ADF_OFF_BITS >> 5;
839254562Scy	node[1].offset = ADF_OFF_BITS >> 5;
840254562Scy	node[2].offset = ADF_OFF_BITS >> 5;
841254562Scy	node[1].left = &node[0];
842254562Scy	node[1].right = &node[2];
843254562Scy	node[0].addrkey = (u_32_t *)softr->zeros;
844254562Scy	node[2].addrkey = (u_32_t *)softr->ones;
845254562Scy#ifdef RDX_DEBUG
846254562Scy	(void) strcpy(node[0].name, "0_ROOT");
847254562Scy	(void) strcpy(node[1].name, "1_ROOT");
848254562Scy	(void) strcpy(node[2].name, "2_ROOT");
849254562Scy#endif
850254562Scy
851254562Scy	ptr->addaddr = ipf_rx_addroute;
852254562Scy	ptr->deladdr = ipf_rx_delete;
853254562Scy	ptr->lookup = ipf_rx_lookup;
854254562Scy	ptr->matchaddr = ipf_rx_match;
855254562Scy	ptr->walktree = ipf_rx_walktree;
856254562Scy	return 0;
857254562Scy}
858254562Scy
859254562Scy
860254562Scy/* ------------------------------------------------------------------------ */
861254562Scy/* Function:    ipf_rx_freehead                                             */
862254562Scy/* Returns:     Nil                                                         */
863254562Scy/* Paramters:   head(I)  - pointer to tree head to free                     */
864254562Scy/*                                                                          */
865254562Scy/* This function simply free's up the radix tree head. Prior to calling     */
866254562Scy/* this function, it is expected that the tree will have been emptied.      */
867254562Scy/* ------------------------------------------------------------------------ */
868254562Scyvoid
869254562Scyipf_rx_freehead(head)
870254562Scy	ipf_rdx_head_t *head;
871254562Scy{
872254562Scy	KFREE(head);
873254562Scy}
874254562Scy
875254562Scy
876254562Scy/* ------------------------------------------------------------------------ */
877254562Scy/* Function:    ipf_rx_create                                               */
878254562Scy/* Parameters:  Nil                                                         */
879254562Scy/*                                                                          */
880254562Scy/* ------------------------------------------------------------------------ */
881254562Scyvoid *
882254562Scyipf_rx_create()
883254562Scy{
884254562Scy	radix_softc_t *softr;
885254562Scy
886254562Scy	KMALLOC(softr, radix_softc_t *);
887254562Scy	if (softr == NULL)
888254562Scy		return NULL;
889254562Scy	bzero((char *)softr, sizeof(*softr));
890254562Scy
891254562Scy	KMALLOCS(softr->zeros, u_char *, 3 * sizeof(addrfamily_t));
892254562Scy	if (softr->zeros == NULL) {
893254562Scy		KFREE(softr);
894254562Scy		return (NULL);
895254562Scy	}
896254562Scy	softr->ones = softr->zeros + sizeof(addrfamily_t);
897254562Scy
898254562Scy	return softr;
899254562Scy}
900254562Scy
901254562Scy
902254562Scy/* ------------------------------------------------------------------------ */
903254562Scy/* Function:    ipf_rx_init                                                 */
904254562Scy/* Returns:     int       - 0 = success (always)                            */
905254562Scy/*                                                                          */
906254562Scy/* ------------------------------------------------------------------------ */
907254562Scyint
908254562Scyipf_rx_init(ctx)
909254562Scy	void *ctx;
910254562Scy{
911254562Scy	radix_softc_t *softr = ctx;
912254562Scy
913254562Scy	memset(softr->zeros, 0, 3 * sizeof(addrfamily_t));
914254562Scy	memset(softr->ones, 0xff, sizeof(addrfamily_t));
915254562Scy
916254562Scy	return (0);
917254562Scy}
918254562Scy
919254562Scy
920254562Scy/* ------------------------------------------------------------------------ */
921254562Scy/* Function:    ipf_rx_destroy                                              */
922254562Scy/* Returns:     Nil                                                         */
923254562Scy/*                                                                          */
924254562Scy/* ------------------------------------------------------------------------ */
925254562Scyvoid
926254562Scyipf_rx_destroy(ctx)
927254562Scy	void *ctx;
928254562Scy{
929254562Scy	radix_softc_t *softr = ctx;
930254562Scy
931254562Scy	if (softr->zeros != NULL)
932254562Scy		KFREES(softr->zeros, 3 * sizeof(addrfamily_t));
933254562Scy	KFREE(softr);
934254562Scy}
935254562Scy
936254562Scy/* ====================================================================== */
937254562Scy
938254562Scy#ifdef RDX_DEBUG
939254562Scy/*
940254562Scy * To compile this file as a standalone test unit, use -DRDX_DEBUG=1
941254562Scy */
942254562Scy#define	NAME(x)	((x)->index < 0 ? (x)->name : (x)->name)
943254562Scy#define	GNAME(y)	((y) == NULL ? "NULL" : NAME(y))
944254562Scy
945254562Scytypedef struct myst {
946254562Scy	struct ipf_rdx_node nodes[2];
947254562Scy	addrfamily_t	dst;
948254562Scy	addrfamily_t	mask;
949254562Scy	struct myst	*next;
950254562Scy	int		printed;
951254562Scy} myst_t;
952254562Scy
953254562Scytypedef struct tabe_s {
954254562Scy	char	*host;
955254562Scy	char	*mask;
956254562Scy	char	*what;
957254562Scy} tabe_t;
958254562Scy
959254562Scytabe_t builtin[] = {
960254562Scy#if 1
961254562Scy	{ "192:168:100::0",	"48",			"d" },
962254562Scy	{ "192:168:100::2",	"128",			"d" },
963254562Scy#else
964254562Scy	{ "127.192.0.0",	"255.255.255.0",	"d" },
965254562Scy	{ "127.128.0.0",	"255.255.255.0",	"d" },
966254562Scy	{ "127.96.0.0",		"255.255.255.0",	"d" },
967254562Scy	{ "127.80.0.0",		"255.255.255.0",	"d" },
968254562Scy	{ "127.72.0.0",		"255.255.255.0",	"d" },
969254562Scy	{ "127.64.0.0",		"255.255.255.0",	"d" },
970254562Scy	{ "127.56.0.0",		"255.255.255.0",	"d" },
971254562Scy	{ "127.48.0.0",		"255.255.255.0",	"d" },
972254562Scy	{ "127.40.0.0",		"255.255.255.0",	"d" },
973254562Scy	{ "127.32.0.0",		"255.255.255.0",	"d" },
974254562Scy	{ "127.24.0.0",		"255.255.255.0",	"d" },
975254562Scy	{ "127.16.0.0",		"255.255.255.0",	"d" },
976254562Scy	{ "127.8.0.0",		"255.255.255.0",	"d" },
977254562Scy	{ "124.0.0.0",		"255.0.0.0",		"d" },
978254562Scy	{ "125.0.0.0",		"255.0.0.0",		"d" },
979254562Scy	{ "126.0.0.0",		"255.0.0.0",		"d" },
980254562Scy	{ "127.0.0.0",		"255.0.0.0",		"d" },
981254562Scy	{ "10.0.0.0",		"255.0.0.0",		"d" },
982254562Scy	{ "128.250.0.0",	"255.255.0.0",		"d" },
983254562Scy	{ "192.168.0.0",	"255.255.0.0",		"d" },
984254562Scy	{ "192.168.1.0",	"255.255.255.0",	"d" },
985254562Scy#endif
986254562Scy	{ NULL, NULL, NULL }
987254562Scy};
988254562Scy
989254562Scychar *mtable[][1] = {
990254562Scy#if 1
991254562Scy	{ "192:168:100::2" },
992254562Scy	{ "192:168:101::2" },
993254562Scy#else
994254562Scy	{ "9.0.0.0" },
995254562Scy	{ "9.0.0.1" },
996254562Scy	{ "11.0.0.0" },
997254562Scy	{ "11.0.0.1" },
998254562Scy	{ "127.0.0.1" },
999254562Scy	{ "127.0.1.0" },
1000254562Scy	{ "255.255.255.0" },
1001254562Scy	{ "126.0.0.1" },
1002254562Scy	{ "128.251.0.0" },
1003254562Scy	{ "128.251.0.1" },
1004254562Scy	{ "128.251.255.255" },
1005254562Scy	{ "129.250.0.0" },
1006254562Scy	{ "129.250.0.1" },
1007254562Scy	{ "192.168.255.255" },
1008254562Scy#endif
1009254562Scy	{ NULL }
1010254562Scy};
1011254562Scy
1012254562Scy
1013254562Scyint forder[22] = {
1014254562Scy	14, 13, 12,  5, 10,  3, 19,  7,  4, 20,  8,
1015254562Scy	 2, 17,  9, 16, 11, 15,  1,  6, 18,  0, 21
1016254562Scy};
1017254562Scy
1018254562Scystatic int nodecount = 0;
1019254562Scymyst_t *myst_top = NULL;
1020254562Scytabe_t *ttable = NULL;
1021254562Scy
1022254562Scyvoid add_addr(ipf_rdx_head_t *, int , int);
1023254562Scyvoid checktree(ipf_rdx_head_t *);
1024254562Scyvoid delete_addr(ipf_rdx_head_t *rnh, int item);
1025254562Scyvoid dumptree(ipf_rdx_head_t *rnh);
1026254562Scyvoid nodeprinter(ipf_rdx_node_t *, void *);
1027254562Scyvoid printroots(ipf_rdx_head_t *);
1028254562Scyvoid random_add(ipf_rdx_head_t *);
1029254562Scyvoid random_delete(ipf_rdx_head_t *);
1030254562Scyvoid test_addr(ipf_rdx_head_t *rnh, int pref, addrfamily_t *, int);
1031254562Scy
1032254562Scy
1033254562Scystatic void
1034254562Scyipf_rx_freenode(node, arg)
1035254562Scy	ipf_rdx_node_t *node;
1036254562Scy	void *arg;
1037254562Scy{
1038254562Scy	ipf_rdx_head_t *head = arg;
1039254562Scy	ipf_rdx_node_t *rv;
1040254562Scy	myst_t *stp;
1041254562Scy
1042254562Scy	stp = (myst_t *)node;
1043254562Scy	rv = ipf_rx_delete(head, &stp->dst, &stp->mask);
1044254562Scy	if (rv != NULL) {
1045254562Scy		free(rv);
1046254562Scy	}
1047254562Scy}
1048254562Scy
1049254562Scy
1050254562Scyconst char *
1051254562Scyaddrname(ap)
1052254562Scy	addrfamily_t *ap;
1053254562Scy{
1054254562Scy	static char name[80];
1055254562Scy	const char *txt;
1056254562Scy
1057254562Scy	bzero((char *)name, sizeof(name));
1058254562Scy	txt =  inet_ntop(ap->adf_family, &ap->adf_addr, name,
1059254562Scy			 sizeof(name));
1060254562Scy	return txt;
1061254562Scy}
1062254562Scy
1063254562Scy
1064254562Scyvoid
1065254562Scyfill6bits(bits, msk)
1066254562Scy	int bits;
1067254562Scy	u_int *msk;
1068254562Scy{
1069254562Scy	if (bits == 0) {
1070254562Scy		msk[0] = 0;
1071254562Scy		msk[1] = 0;
1072254562Scy		msk[2] = 0;
1073254562Scy		msk[3] = 0;
1074254562Scy		return;
1075254562Scy	}
1076254562Scy
1077254562Scy	msk[0] = 0xffffffff;
1078254562Scy	msk[1] = 0xffffffff;
1079254562Scy	msk[2] = 0xffffffff;
1080254562Scy	msk[3] = 0xffffffff;
1081254562Scy
1082254562Scy	if (bits == 128)
1083254562Scy		return;
1084254562Scy	if (bits > 96) {
1085254562Scy		msk[3] = htonl(msk[3] << (128 - bits));
1086254562Scy	} else if (bits > 64) {
1087254562Scy		msk[3] = 0;
1088254562Scy		msk[2] = htonl(msk[2] << (96 - bits));
1089254562Scy	} else if (bits > 32) {
1090254562Scy		msk[3] = 0;
1091254562Scy		msk[2] = 0;
1092254562Scy		msk[1] = htonl(msk[1] << (64 - bits));
1093254562Scy	} else {
1094254562Scy		msk[3] = 0;
1095254562Scy		msk[2] = 0;
1096254562Scy		msk[1] = 0;
1097254562Scy		msk[0] = htonl(msk[0] << (32 - bits));
1098254562Scy	}
1099254562Scy}
1100254562Scy
1101254562Scy
1102254562Scyvoid
1103254562Scysetaddr(afp, str)
1104254562Scy	addrfamily_t *afp;
1105254562Scy	char *str;
1106254562Scy{
1107254562Scy
1108254562Scy	bzero((char *)afp, sizeof(*afp));
1109254562Scy
1110254562Scy	if (strchr(str, ':') == NULL) {
1111254562Scy		afp->adf_family = AF_INET;
1112254562Scy		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
1113254562Scy	} else {
1114254562Scy		afp->adf_family = AF_INET6;
1115254562Scy		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
1116254562Scy	}
1117254562Scy	inet_pton(afp->adf_family, str, &afp->adf_addr);
1118254562Scy}
1119254562Scy
1120254562Scy
1121254562Scyvoid
1122254562Scysetmask(afp, str)
1123254562Scy	addrfamily_t *afp;
1124254562Scy	char *str;
1125254562Scy{
1126254562Scy	if (strchr(str, '.') != NULL) {
1127254562Scy		afp->adf_addr.in4.s_addr = inet_addr(str);
1128254562Scy		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
1129254562Scy	} else if (afp->adf_family == AF_INET) {
1130254562Scy		afp->adf_addr.i6[0] = htonl(0xffffffff << (32 - atoi(str)));
1131254562Scy		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
1132254562Scy	} else if (afp->adf_family == AF_INET6) {
1133254562Scy		fill6bits(atoi(str), afp->adf_addr.i6);
1134254562Scy		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
1135254562Scy	}
1136254562Scy}
1137254562Scy
1138254562Scy
1139254562Scyvoid
1140254562Scynodeprinter(node, arg)
1141254562Scy	ipf_rdx_node_t *node;
1142254562Scy	void *arg;
1143254562Scy{
1144254562Scy	myst_t *stp = (myst_t *)node;
1145254562Scy
1146254562Scy	printf("Node %-9.9s L %-9.9s R %-9.9s P %9.9s/%-9.9s %s/%d\n",
1147254562Scy		node[0].name,
1148254562Scy		GNAME(node[1].left), GNAME(node[1].right),
1149254562Scy		GNAME(node[0].parent), GNAME(node[1].parent),
1150254562Scy		addrname(&stp->dst), node[0].maskbitcount);
1151254562Scy	if (stp->printed == -1)
1152254562Scy		printf("!!! %d\n", stp->printed);
1153254562Scy	else
1154254562Scy		stp->printed = 1;
1155254562Scy}
1156254562Scy
1157254562Scy
1158254562Scyvoid
1159254562Scyprintnode(stp)
1160254562Scy	myst_t *stp;
1161254562Scy{
1162254562Scy	ipf_rdx_node_t *node = &stp->nodes[0];
1163254562Scy
1164254562Scy	if (stp->nodes[0].index > 0)
1165254562Scy		stp = (myst_t *)&stp->nodes[-1];
1166254562Scy
1167254562Scy	printf("Node %-9.9s ", node[0].name);
1168254562Scy	printf("L %-9.9s ", GNAME(node[1].left));
1169254562Scy	printf("R %-9.9s ", GNAME(node[1].right));
1170254562Scy	printf("P %9.9s", GNAME(node[0].parent));
1171254562Scy	printf("/%-9.9s ", GNAME(node[1].parent));
1172254562Scy	printf("%s P%d\n", addrname(&stp->dst), stp->printed);
1173254562Scy}
1174254562Scy
1175254562Scy
1176254562Scyvoid
1177254562Scybuildtab(void)
1178254562Scy{
1179254562Scy	char line[80], *s;
1180254562Scy	tabe_t *tab;
1181254562Scy	int lines;
1182254562Scy	FILE *fp;
1183254562Scy
1184254562Scy	lines = 0;
1185254562Scy	fp = fopen("hosts", "r");
1186254562Scy
1187254562Scy	while (fgets(line, sizeof(line), fp) != NULL) {
1188254562Scy		s = strchr(line, '\n');
1189254562Scy		if (s != NULL)
1190254562Scy			*s = '\0';
1191254562Scy		lines++;
1192254562Scy		if (lines == 1)
1193254562Scy			tab = malloc(sizeof(*tab) * 2);
1194254562Scy		else
1195254562Scy			tab = realloc(tab, (lines + 1) * sizeof(*tab));
1196254562Scy		tab[lines - 1].host = strdup(line);
1197254562Scy		s = strchr(tab[lines - 1].host, '/');
1198254562Scy		*s++ = '\0';
1199254562Scy		tab[lines - 1].mask = s;
1200254562Scy		tab[lines - 1].what = "d";
1201254562Scy	}
1202254562Scy	fclose(fp);
1203254562Scy
1204254562Scy	tab[lines].host = NULL;
1205254562Scy	tab[lines].mask = NULL;
1206254562Scy	tab[lines].what = NULL;
1207254562Scy	ttable = tab;
1208254562Scy}
1209254562Scy
1210254562Scy
1211254562Scyvoid
1212254562Scyprintroots(rnh)
1213254562Scy	ipf_rdx_head_t *rnh;
1214254562Scy{
1215254562Scy	printf("Root.0.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1216254562Scy		GNAME(&rnh->nodes[0]),
1217254562Scy		rnh->nodes[0].index, GNAME(rnh->nodes[0].parent),
1218254562Scy		GNAME(rnh->nodes[0].left), GNAME(rnh->nodes[0].right));
1219254562Scy	printf("Root.1.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1220254562Scy		GNAME(&rnh->nodes[1]),
1221254562Scy		rnh->nodes[1].index, GNAME(rnh->nodes[1].parent),
1222254562Scy		GNAME(rnh->nodes[1].left), GNAME(rnh->nodes[1].right));
1223254562Scy	printf("Root.2.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1224254562Scy		GNAME(&rnh->nodes[2]),
1225254562Scy		rnh->nodes[2].index, GNAME(rnh->nodes[2].parent),
1226254562Scy		GNAME(rnh->nodes[2].left), GNAME(rnh->nodes[2].right));
1227254562Scy}
1228254562Scy
1229254562Scy
1230254562Scyint
1231254562Scymain(int argc, char *argv[])
1232254562Scy{
1233254562Scy	addrfamily_t af;
1234254562Scy	ipf_rdx_head_t *rnh;
1235254562Scy	radix_softc_t *ctx;
1236254562Scy	int j;
1237254562Scy	int i;
1238254562Scy
1239254562Scy	rnh = NULL;
1240254562Scy
1241254562Scy	buildtab();
1242254562Scy	ctx = ipf_rx_create();
1243254562Scy	ipf_rx_init(ctx);
1244254562Scy	ipf_rx_inithead(ctx, &rnh);
1245254562Scy
1246254562Scy	printf("=== ADD-0 ===\n");
1247254562Scy	for (i = 0; ttable[i].host != NULL; i++) {
1248254562Scy		add_addr(rnh, i, i);
1249254562Scy		checktree(rnh);
1250254562Scy	}
1251254562Scy	printroots(rnh);
1252254562Scy	ipf_rx_walktree(rnh, nodeprinter, NULL);
1253254562Scy	printf("=== DELETE-0 ===\n");
1254254562Scy	for (i = 0; ttable[i].host != NULL; i++) {
1255254562Scy		delete_addr(rnh, i);
1256254562Scy		printroots(rnh);
1257254562Scy		ipf_rx_walktree(rnh, nodeprinter, NULL);
1258254562Scy	}
1259254562Scy	printf("=== ADD-1 ===\n");
1260254562Scy	for (i = 0; ttable[i].host != NULL; i++) {
1261254562Scy		setaddr(&af, ttable[i].host);
1262254562Scy		add_addr(rnh, i, i); /*forder[i]); */
1263254562Scy		checktree(rnh);
1264254562Scy	}
1265254562Scy	dumptree(rnh);
1266254562Scy	ipf_rx_walktree(rnh, nodeprinter, NULL);
1267254562Scy	printf("=== TEST-1 ===\n");
1268254562Scy	for (i = 0; ttable[i].host != NULL; i++) {
1269254562Scy		setaddr(&af, ttable[i].host);
1270254562Scy		test_addr(rnh, i, &af, -1);
1271254562Scy	}
1272254562Scy
1273254562Scy	printf("=== TEST-2 ===\n");
1274254562Scy	for (i = 0; mtable[i][0] != NULL; i++) {
1275254562Scy		setaddr(&af, mtable[i][0]);
1276254562Scy		test_addr(rnh, i, &af, -1);
1277254562Scy	}
1278254562Scy	printf("=== DELETE-1 ===\n");
1279254562Scy	for (i = 0; ttable[i].host != NULL; i++) {
1280254562Scy		if (ttable[i].what[0] != 'd')
1281254562Scy			continue;
1282254562Scy		delete_addr(rnh, i);
1283254562Scy		for (j = 0; ttable[j].host != NULL; j++) {
1284254562Scy			setaddr(&af, ttable[j].host);
1285254562Scy			test_addr(rnh, i, &af, 3);
1286254562Scy		}
1287254562Scy		printroots(rnh);
1288254562Scy		ipf_rx_walktree(rnh, nodeprinter, NULL);
1289254562Scy	}
1290254562Scy
1291254562Scy	dumptree(rnh);
1292254562Scy
1293254562Scy	printf("=== ADD-2 ===\n");
1294254562Scy	random_add(rnh);
1295254562Scy	checktree(rnh);
1296254562Scy	dumptree(rnh);
1297254562Scy	ipf_rx_walktree(rnh, nodeprinter, NULL);
1298254562Scy	printf("=== DELETE-2 ===\n");
1299254562Scy	random_delete(rnh);
1300254562Scy	checktree(rnh);
1301254562Scy	dumptree(rnh);
1302254562Scy
1303254562Scy	ipf_rx_walktree(rnh, ipf_rx_freenode, rnh);
1304254562Scy
1305254562Scy	return 0;
1306254562Scy}
1307254562Scy
1308254562Scy
1309254562Scyvoid
1310254562Scydumptree(rnh)
1311254562Scy	ipf_rdx_head_t *rnh;
1312254562Scy{
1313254562Scy	myst_t *stp;
1314254562Scy
1315254562Scy	printf("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");
1316254562Scy	printroots(rnh);
1317254562Scy	for (stp = myst_top; stp; stp = stp->next)
1318254562Scy		printnode(stp);
1319254562Scy	printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
1320254562Scy}
1321254562Scy
1322254562Scy
1323254562Scyvoid
1324254562Scytest_addr(rnh, pref, addr, limit)
1325254562Scy	ipf_rdx_head_t *rnh;
1326254562Scy	int pref;
1327254562Scy	addrfamily_t *addr;
1328254562Scy{
1329254562Scy	static int extras[14] = { 0, -1, 1, 3, 5, 8, 9,
1330254562Scy				  15, 16, 19, 255, 256, 65535, 65536
1331254562Scy	};
1332254562Scy	ipf_rdx_node_t *rn;
1333254562Scy	addrfamily_t af;
1334254562Scy	char name[80];
1335254562Scy	myst_t *stp;
1336254562Scy	int i;
1337254562Scy
1338254562Scy	memset(&af, 0, sizeof(af));
1339254562Scy#if 0
1340254562Scy	if (limit < 0 || limit > 14)
1341254562Scy		limit = 14;
1342254562Scy
1343254562Scy	for (i = 0; i < limit; i++) {
1344254562Scy		if (ttable[i].host == NULL)
1345254562Scy			break;
1346254562Scy		setaddr(&af, ttable[i].host);
1347254562Scy		printf("%d.%d.LOOKUP(%s)", pref, i, addrname(&af));
1348254562Scy		rn = ipf_rx_match(rnh, &af);
1349254562Scy		stp = (myst_t *)rn;
1350254562Scy		printf(" = %s (%s/%d)\n", GNAME(rn),
1351254562Scy			rn ? addrname(&stp->dst) : "NULL",
1352254562Scy			rn ? rn->maskbitcount : 0);
1353254562Scy	}
1354254562Scy#else
1355254562Scy	printf("%d.%d.LOOKUP(%s)", pref, -1, addrname(addr));
1356254562Scy	rn = ipf_rx_match(rnh, addr);
1357254562Scy	stp = (myst_t *)rn;
1358254562Scy	printf(" = %s (%s/%d)\n", GNAME(rn),
1359254562Scy		rn ? addrname(&stp->dst) : "NULL", rn ? rn->maskbitcount : 0);
1360254562Scy#endif
1361254562Scy}
1362254562Scy
1363254562Scy
1364254562Scyvoid
1365254562Scydelete_addr(rnh, item)
1366254562Scy	ipf_rdx_head_t *rnh;
1367254562Scy	int item;
1368254562Scy{
1369254562Scy	ipf_rdx_node_t *rn;
1370254562Scy	addrfamily_t mask;
1371254562Scy	addrfamily_t af;
1372254562Scy	myst_t **pstp;
1373254562Scy	myst_t *stp;
1374254562Scy
1375254562Scy	memset(&af, 0, sizeof(af));
1376254562Scy	memset(&mask, 0, sizeof(mask));
1377254562Scy	setaddr(&af, ttable[item].host);
1378254562Scy	mask.adf_family = af.adf_family;
1379254562Scy	setmask(&mask, ttable[item].mask);
1380254562Scy
1381254562Scy	printf("DELETE(%s)\n", addrname(&af));
1382254562Scy	rn = ipf_rx_delete(rnh, &af, &mask);
1383254562Scy	if (rn == NULL) {
1384254562Scy		printf("FAIL LOOKUP DELETE\n");
1385254562Scy		checktree(rnh);
1386254562Scy		for (stp = myst_top; stp != NULL; stp = stp->next)
1387254562Scy			if (stp->printed != -1)
1388254562Scy				stp->printed = -2;
1389254562Scy		ipf_rx_walktree(rnh, nodeprinter, NULL);
1390254562Scy		dumptree(rnh);
1391254562Scy		abort();
1392254562Scy	}
1393254562Scy	printf("%d.delete(%s) = %s\n", item, addrname(&af), GNAME(rn));
1394254562Scy
1395254562Scy	for (pstp = &myst_top; (stp = *pstp) != NULL; pstp = &stp->next)
1396254562Scy		if (stp == (myst_t *)rn)
1397254562Scy			break;
1398254562Scy	stp->printed = -1;
1399254562Scy	stp->nodes[0].parent = &stp->nodes[0];
1400254562Scy	stp->nodes[1].parent = &stp->nodes[1];
1401254562Scy	*pstp = stp->next;
1402254562Scy	free(stp);
1403254562Scy	nodecount--;
1404254562Scy	checktree(rnh);
1405254562Scy}
1406254562Scy
1407254562Scy
1408254562Scyvoid
1409254562Scyadd_addr(rnh, n, item)
1410254562Scy	ipf_rdx_head_t *rnh;
1411254562Scy	int n, item;
1412254562Scy{
1413254562Scy	ipf_rdx_node_t *rn;
1414254562Scy	myst_t *stp;
1415254562Scy
1416254562Scy	stp = calloc(1, sizeof(*stp));
1417254562Scy	rn = (ipf_rdx_node_t *)stp;
1418254562Scy	setaddr(&stp->dst, ttable[item].host);
1419254562Scy	stp->mask.adf_family = stp->dst.adf_family;
1420254562Scy	setmask(&stp->mask, ttable[item].mask);
1421254562Scy	stp->next = myst_top;
1422254562Scy	myst_top = stp;
1423254562Scy	(void) sprintf(rn[0].name, "_BORN.0");
1424254562Scy	(void) sprintf(rn[1].name, "_BORN.1");
1425254562Scy	rn = ipf_rx_addroute(rnh, &stp->dst, &stp->mask, stp->nodes);
1426254562Scy	(void) sprintf(rn[0].name, "%d_NODE.0", item);
1427254562Scy	(void) sprintf(rn[1].name, "%d_NODE.1", item);
1428254562Scy	printf("ADD %d/%d %s/%s\n", n, item, rn[0].name, rn[1].name);
1429254562Scy	nodecount++;
1430254562Scy	checktree(rnh);
1431254562Scy}
1432254562Scy
1433254562Scy
1434254562Scyvoid
1435254562Scychecktree(ipf_rdx_head_t *head)
1436254562Scy{
1437254562Scy	myst_t *s1;
1438254562Scy	ipf_rdx_node_t *rn;
1439254562Scy
1440254562Scy	if (nodecount <= 1)
1441254562Scy		return;
1442254562Scy
1443254562Scy	for (s1 = myst_top; s1 != NULL; s1 = s1->next) {
1444254562Scy		int fault = 0;
1445254562Scy		if (s1->printed == -1)
1446254562Scy			continue;
1447254562Scy		rn = &s1->nodes[1];
1448254562Scy		if (rn->right->parent != rn)
1449254562Scy			fault |= 1;
1450254562Scy		if (rn->left->parent != rn)
1451254562Scy			fault |= 2;
1452254562Scy		if (rn->parent->left != rn && rn->parent->right != rn)
1453254562Scy			fault |= 4;
1454254562Scy		if (fault != 0) {
1455254562Scy			printf("FAULT %#x %s\n", fault, rn->name);
1456254562Scy			dumptree(head);
1457254562Scy			ipf_rx_walktree(head, nodeprinter, NULL);
1458254562Scy			fflush(stdout);
1459254562Scy			fflush(stderr);
1460254562Scy			printf("--\n");
1461254562Scy			abort();
1462254562Scy		}
1463254562Scy	}
1464254562Scy}
1465254562Scy
1466254562Scy
1467254562Scyint *
1468254562Scyrandomize(int *pnitems)
1469254562Scy{
1470254562Scy	int *order;
1471254562Scy	int nitems;
1472254562Scy	int choice;
1473254562Scy	int j;
1474254562Scy	int i;
1475254562Scy
1476254562Scy	nitems = sizeof(ttable) / sizeof(ttable[0]);
1477254562Scy	*pnitems = nitems;
1478254562Scy	order = calloc(nitems, sizeof(*order));
1479254562Scy	srandom(getpid() * time(NULL));
1480254562Scy	memset(order, 0xff, nitems * sizeof(*order));
1481254562Scy	order[21] = 21;
1482254562Scy	for (i = 0; i < nitems - 1; i++) {
1483254562Scy		do {
1484254562Scy			choice = rand() % (nitems - 1);
1485254562Scy			for (j = 0; j < nitems; j++)
1486254562Scy				if (order[j] == choice)
1487254562Scy					break;
1488254562Scy		} while (j != nitems);
1489254562Scy		order[i] = choice;
1490254562Scy	}
1491254562Scy
1492254562Scy	return order;
1493254562Scy}
1494254562Scy
1495254562Scy
1496254562Scyvoid
1497254562Scyrandom_add(rnh)
1498254562Scy	ipf_rdx_head_t *rnh;
1499254562Scy{
1500254562Scy	int *order;
1501254562Scy	int nitems;
1502254562Scy	int i;
1503254562Scy
1504254562Scy	order = randomize(&nitems);
1505254562Scy
1506254562Scy	for (i = 0; i < nitems - 1; i++) {
1507254562Scy		add_addr(rnh, i, order[i]);
1508254562Scy		checktree(rnh);
1509254562Scy	}
1510254562Scy}
1511254562Scy
1512254562Scy
1513254562Scyvoid
1514254562Scyrandom_delete(rnh)
1515254562Scy	ipf_rdx_head_t *rnh;
1516254562Scy{
1517254562Scy	int *order;
1518254562Scy	int nitems;
1519254562Scy	int i;
1520254562Scy
1521254562Scy	order = randomize(&nitems);
1522254562Scy
1523254562Scy	for (i = 0; i < nitems - 1; i++) {
1524254562Scy		delete_addr(rnh, i);
1525254562Scy		checktree(rnh);
1526254562Scy	}
1527254562Scy}
1528254562Scy#endif /* RDX_DEBUG */
1529