/* ****************************************************************************** * SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_route.c,v $ $Revision: 1.49.10.2 $ * $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_route.c,v $ * $Author: hchu0 $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Kenneth Jonsson ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* Route table functions, based on Patricia tree */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipcom_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include "ipcom_route.h" #include "ipcom_clib.h" #include "ipcom_err.h" #include "ipcom_set.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* *=========================================================================== * IPCOM_IS_BIT_SET *=========================================================================== * Description: Tests if a specifed bit in a buffer is set. * Parameters: [in] data - const void * pointer. * [in] bit - The bit to test, counted from left. * Returns: 0 if the bit is not set, !=0 if the bit the is set. * */ #define IPCOM_IS_BIT_SET(data, bit) \ (((Ip_u8 *) (data))[(bit) >> 3] & (0x80 >> ((bit) & 0x7))) /* Status of internal nodes during tree traversal */ #define IPCOM_ROUTE_STATUS_INIT 0 #define IPCOM_ROUTE_STATUS_OFF_SUBTREE 1 #define IPCOM_ROUTE_STATUS_ON_SUBTREE 2 #define IPCOM_ROUTE_STATUS_DONE 3 /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* *=========================================================================== * Ipcom_route_walk_subtree_cb *=========================================================================== * Description: Will be called for all leaf nodes when walking the tree. * Parameters: leaf - A leaf node (leaf->on == leaf->off == IP_NULL). * user - User defined data. * Returns: * */ typedef void (*Ipcom_route_walk_subtree_cb)(Ipcom_route_entry *leaf, void *user); /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_STATIC void ipcom_route_init_subtree_mask2(Ipcom_route_entry *rt, Ip_bool consecutive_mask); /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 LOCAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipcom_patricia_search *=========================================================================== * Description: Search a patricia tree for the the entry that best matches the * search criteria. * Parameters: top - The top of the patricia (sub)tree. * key - The key to search for, * mask - The mask to apply to the key before doing any test. * Returns: The best match entry. * */ IP_STATIC Ipcom_route_entry* ipcom_patricia_search(Ipcom_route_entry *top, const void *key, const void *mask) { Ipcom_route_entry *current = top; while (current->off != IP_NULL) { if ((mask == IP_NULL || IPCOM_IS_BIT_SET(mask, current->bit)) && IPCOM_IS_BIT_SET(key, current->bit)) current = current->on; else current = current->off; } ip_assert(current->on == IP_NULL); return current; } /* *=========================================================================== * ipcom_patricia_insert *=========================================================================== * Description: Insert route entry into the patricia route tree. * Parameters: domain - The address domain. * new_leaf - The new node to insert. The following fields must * have valid values: * flags must contain any user defined flags. * key must point to the search key * mask must point to the mask or be IP_NULL if the mask is all 1:s. * all other fields are initialized by this function. * Returns: 0 = success, <0 = error code * */ IP_STATIC Ip_err ipcom_patricia_insert(Ipcom_route *rtab, Ipcom_route_entry *new_leaf) { Ipcom_route_entry *new_internal_node; Ipcom_route_entry *current; #ifdef IP_ASSERT Ip_u16 max_bit; #endif Ip_u16 partition_bit; void *matched_key; current = ipcom_patricia_search(rtab->top, new_leaf->key, new_leaf->mask); if (ipcom_route_key_cmp(rtab->bit_count, current->key, new_leaf->key, new_leaf->mask) == IPCOM_ROUTE_KEY_CMP_PREFECT_MATCH) { /* Perfect match, replace this entry */ new_leaf->parent = current->parent; if (new_leaf->parent->on == current) new_leaf->parent->on = new_leaf; else { ip_assert(new_leaf->parent->off == current); new_leaf->parent->off = new_leaf; } if (IP_BIT_ISSET(current->flags, IPCOM_ROUTE_FLAG_END)) IP_BIT_SET(new_leaf->flags, IPCOM_ROUTE_FLAG_END); if (current->mask != IP_NULL) { /* current->mask pointer will become invalid, remove it */ Ipcom_route_entry *internal; for (internal = current->parent; internal != IP_NULL; internal = internal->parent) if (current->mask == internal->mask) internal->mask = IP_NULL; } ipcom_route_init_subtree_mask2(rtab->top, rtab->consecutive_mask); ipcom_route_init_subtree_mask2(new_leaf, rtab->consecutive_mask); current->parent = IP_NULL; ip_assert(rtab->notify_func != IP_NULL); if (IP_BIT_ISFALSE(current->flags, IPCOM_ROUTE_FLAG_INIT)) { rtab->notify_func(rtab, current, IPCOM_ROUTE_CODE_DUPLICATE); } return IPCOM_SUCCESS; } /* Find out where the entry should be inserted */ IP_ASSERTLINE(max_bit = (Ip_u16) (rtab->bit_count - 1)); matched_key = current->key; for (;;) { if (ipcom_route_key_cmp(current->parent->bit, new_leaf->key, matched_key, IP_NULL) != IPCOM_ROUTE_KEY_CMP_NO_MATCH) break; /* Need to compare fewer bits to make the addresses match */ current = current->parent; IP_ASSERTLINE(max_bit = (Ip_u16) (current->bit - 1)); } partition_bit = (Ip_u16) (current->parent->bit + 1); /* current->key and new_leaf->key differs in a bit between 'partition_bit' and 'max_bit' */ while (IPCOM_IS_BIT_SET(new_leaf->key, partition_bit) == IPCOM_IS_BIT_SET(matched_key, partition_bit)) { partition_bit++; } /* The key differ in bit 'partition_bit' */ ip_assert(max_bit >= partition_bit); /* Allocate memory for a new patricia tree internal node */ new_internal_node = ipcom_malloc(sizeof(Ipcom_route_entry)); if (new_internal_node == IP_NULL) return IPCOM_ERR_NO_MEMORY; ipcom_memset(new_internal_node, 0, sizeof(Ipcom_route_entry)); new_internal_node->bit = partition_bit; new_internal_node->flags = IPCOM_ROUTE_FLAG_INTERNAL; new_internal_node->key = IP_NULL; new_internal_node->mask = IP_NULL; /* Insert the new internal and leaf nodes */ new_internal_node->parent = current->parent; /* Add the new internal node as child of the 'current' parent */ if (current->parent->off == current) current->parent->off = new_internal_node; else current->parent->on = new_internal_node; current->parent = new_internal_node; new_leaf->parent = new_internal_node; /* Add the new leaf and the 'current' node as child to the new internal node */ if (IPCOM_IS_BIT_SET(new_leaf->key, partition_bit)) { new_internal_node->off = current; new_internal_node->on = new_leaf; } else { new_internal_node->on = current; new_internal_node->off = new_leaf; } ipcom_route_init_subtree_mask2(new_internal_node, rtab->consecutive_mask); return 0; } /* *=========================================================================== * ipcom_route_walk_subtree *=========================================================================== * Description: Visits all nodes rooted at 'subtree'. * Parameters: subtree - The root of the subtree to travers. * only_off_subtree - Visit only the nodes with the partition * bits cleared. * include_init_nodes - IP_TRUE if the user function should be * called even for initial nodes. * cb - The user function that will be called for leaf nodes. * user - User defined data passed to 'cb'. * Returns: * */ IP_STATIC void ipcom_route_walk_subtree(Ipcom_route_entry *subtree, Ip_bool only_off_subtree, Ip_bool include_init_nodes, Ipcom_route_walk_subtree_cb cb, void *user) { Ipcom_route_entry *rt = subtree; Ip_bool done = IP_FALSE; rt->status = IPCOM_ROUTE_STATUS_INIT; do { if (rt->off != IP_NULL && rt->status == IPCOM_ROUTE_STATUS_INIT) { /* Go down the sub-tree with partition bit cleared */ ip_assert(rt->on != IP_NULL); rt->status = IPCOM_ROUTE_STATUS_OFF_SUBTREE; rt = rt->off; rt->status = IPCOM_ROUTE_STATUS_INIT; } else if (!only_off_subtree && rt->on != IP_NULL && rt->status == IPCOM_ROUTE_STATUS_OFF_SUBTREE) { /* Go down the sub-tree with partition bit set */ ip_assert(rt->off != IP_NULL); rt->status = IPCOM_ROUTE_STATUS_ON_SUBTREE; rt = rt->on; rt->status = IPCOM_ROUTE_STATUS_INIT; } else { Ipcom_route_entry *leaf = rt; /* Must set status to DONE before calling the callback, since the callback might free the leaf node */ rt->status = IPCOM_ROUTE_STATUS_DONE; if (rt == subtree) /* Done with the whole subtree */ done = IP_TRUE; else rt = rt->parent; if (leaf->off == IP_NULL && (IP_BIT_ISFALSE(leaf->flags, IPCOM_ROUTE_FLAG_INIT) || include_init_nodes)) { ip_assert(leaf->on == IP_NULL); cb(leaf, user); } } } while (!done); } /* *=========================================================================== * ipcom_route_init_subtree_mask_cb *=========================================================================== * Description: Initialize the internal node mask references on a subtree. * Parameters: subtree - The head of the subtree. * consecutive_mask - Must be IP_FALSE if the masks can be * non-consecutive, this operation is much * expensive in this case. * Returns: * */ IP_STATIC void ipcom_route_init_subtree_mask_cb(Ipcom_route_entry *rt, void *unused) { /* Process the leaf node */ Ipcom_route_entry *current; (void) unused; ip_assert(rt->on == IP_NULL); if (rt->mask != IP_NULL) for (current = rt->parent; current != IP_NULL; current = current->parent) if (!IPCOM_IS_BIT_SET(rt->mask, current->bit)) current->mask = rt->mask; } /* *=========================================================================== * ipcom_route_init_subtree_mask2 *=========================================================================== * Description: Initialize the internal node mask references on a subtree. * Parameters: subtree - The head of the subtree. * consecutive_mask - Must be IP_FALSE if the masks can be * non-consecutive, this operation is much * expensive in this case. * Returns: * */ IP_STATIC void ipcom_route_init_subtree_mask2(Ipcom_route_entry *subtree, Ip_bool consecutive_mask) { ipcom_route_walk_subtree(subtree, consecutive_mask, IP_TRUE, ipcom_route_init_subtree_mask_cb, IP_NULL); } /* *=========================================================================== * ipcom_route_free_subtree_cb *=========================================================================== * Description: Frees the specified entry. * Parameters: rt - The entry to free. * Returns: * */ IP_STATIC void ipcom_route_free_subtree_cb(Ipcom_route_entry *rt, Ipcom_route *rtab) { if (IP_BIT_ISSET(rt->flags, IPCOM_ROUTE_FLAG_INTERNAL)) ipcom_free(rt); else rtab->notify_func(rtab, rt, IPCOM_ROUTE_CODE_REMOVE); } /* *=========================================================================== * ipcom_route_prev_entry *=========================================================================== * Description: Returns the previous leaf element in the route table. * Parameters: rt - The current route entry * Returns: The previous route entry or IP_NULL if the passed entry was * the first. * */ IP_INLINE Ipcom_route_entry * ipcom_route_prev_entry(Ipcom_route_entry *rt) { while (rt->parent->off == rt) { rt = rt->parent; if (rt->parent == IP_NULL) return IP_NULL; } rt = rt->parent->off; while (rt->on != IP_NULL) rt = rt->on; if (IP_BIT_ISSET(rt->flags, IPCOM_ROUTE_FLAG_INIT)) return IP_NULL; return rt; } /* *=========================================================================== * ipcom_route_last_entry *=========================================================================== * Description: Returns the last entry in the route table. * Parameters: rtab - The route table for which the last entry should be returned. * Returns: The last route entry or IP_NULL if the route table is empty. * */ IP_INLINE Ipcom_route_entry * ipcom_route_last_entry(Ipcom_route *rtab) { Ipcom_route_entry *rt; rt = rtab->top; while (rt->on != IP_NULL) rt = rt->on; if (IP_BIT_ISSET(rt->flags, IPCOM_ROUTE_FLAG_INIT)) rt = ipcom_route_prev_entry(rt); return rt; } /* **************************************************************************** * 9 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipcom_route_next_entry *=========================================================================== * Description: Returns the next leaf element in the route table. * Parameters: rt - The current route entry * Returns: The next route entry or IP_NULL if the passed entry was the last. * */ IP_GLOBAL Ipcom_route_entry * ipcom_route_next_entry(Ipcom_route_entry *rt) { while (rt->parent->on == rt) { rt = rt->parent; if (rt->parent == IP_NULL) return IP_NULL; } rt = rt->parent->on; while (rt->off != IP_NULL) rt = rt->off; if (IP_BIT_ISSET(rt->flags, IPCOM_ROUTE_FLAG_INIT)) return IP_NULL; return rt; } /* *=========================================================================== * ipcom_route_first_entry *=========================================================================== * Description: Returns the first entry in the route table. * Parameters: rtab - The route table for which the first entry should be returned. * Returns: The first route entry or IP_NULL if the route table is empty. * */ IP_GLOBAL Ipcom_route_entry * ipcom_route_first_entry(Ipcom_route *rtab) { Ipcom_route_entry *rt; rt = rtab->top; while (rt->off != IP_NULL) rt = rt->off; if (IP_BIT_ISSET(rt->flags, IPCOM_ROUTE_FLAG_INIT)) rt = ipcom_route_next_entry(rt); return rt; } /* **************************************************************************** * 10 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipcom_route_lookup *=========================================================================== * Description: Returns the matching entry in the route table. * Parameters: rtab - The route table to search in. * key - The key to use when searching. Must be at least * as long as specified in rtab->bit_size. * perfect_match - Will be set to IP_TRUE if the match was * perfect. Can be IP_NULL if this it not interesting. * Returns: The matching route entry (or IP_NULL if nothing matches). * */ IP_PUBLIC Ipcom_route_entry * ipcom_route_lookup(Ipcom_route *rtab, const void *key, Ip_bool *prefect_match) { Ipcom_route_entry *current; Ipcom_route_entry *found; Ipcom_set *start_nodes = IP_NULL; found = ipcom_patricia_search(rtab->top, key, IP_NULL); if (ipcom_route_key_cmp(rtab->bit_count, key, found->key, IP_NULL) == IPCOM_ROUTE_KEY_CMP_PREFECT_MATCH) { if (IP_BIT_ISSET(found->flags, IPCOM_ROUTE_FLAG_INIT)) /* This entry is one of the two entries added when the tree was created */ return IP_NULL; if (prefect_match != IP_NULL) *prefect_match = IP_TRUE; return found; } /* Start backtracking */ current = found; while (ipcom_route_key_cmp(rtab->bit_count, key, found->key, found->mask) == IPCOM_ROUTE_KEY_CMP_NO_MATCH) { if (rtab->consecutive_mask == IP_FALSE) { if (start_nodes == IP_NULL) { start_nodes = ipcom_set_new(sizeof(Ipcom_route_entry*)); if (start_nodes == IP_NULL) return IP_NULL; } if (current->mask != found->mask) { found = ipcom_patricia_search(current, key, found->mask); if (ipcom_route_key_cmp(rtab->bit_count, key, found->key, found->mask) != IPCOM_ROUTE_KEY_CMP_NO_MATCH) break; } current = found; } do { /* Go up to the next node with a netmask. */ current = current->parent; if (current == IP_NULL) { ipcom_set_delete(start_nodes); return IP_NULL; } } while (current->mask == IP_NULL || (start_nodes != IP_NULL && ipcom_set_contains(start_nodes, current))); /* Remember all internal nodes that we have used as a sub-root */ if (start_nodes != IP_NULL && ipcom_set_add(start_nodes, current) != IPCOM_SUCCESS) { ipcom_set_delete(start_nodes); return IP_NULL; } found = ipcom_patricia_search(current, key, current->mask); } ipcom_set_delete(start_nodes); if (IP_BIT_ISSET(found->flags, IPCOM_ROUTE_FLAG_INIT)) /* This entry is one of the two entries added when the tree was created */ return IP_NULL; if (prefect_match != IP_NULL) *prefect_match = IP_FALSE; return found; } /* *=========================================================================== * ipcom_route_new_table *=========================================================================== * Description: Create a empty routing table with 3 nodes. 1 internal node * and 2 leafs (all bits zero + all bits one). * Parameters: addr_bit_size - The bitsize of the addresses in the address * domain in which this routing table will be used. * Returns: Head of the route table. * */ IP_PUBLIC Ipcom_route * ipcom_route_new_table(Ip_u16 bit_count, Ipcom_route_notify_func notify_func) { Ip_u16 entry_size; Ip_u16 key_octet_count; Ipcom_route *rtab; Ipcom_route_entry *top; Ipcom_route_entry *off; Ipcom_route_entry *on; ip_assert(notify_func != IP_NULL); /* Round the bitsize up to the nearest size that can be divided by 4 */ key_octet_count = (Ip_u16) (((bit_count + 31) & ~31) / 8); /* Allocate memory for all 3 nodes */ entry_size = (Ip_u16) (sizeof(Ipcom_route_entry) + key_octet_count); rtab = ipcom_malloc((Ip_size_t)sizeof(Ipcom_route) + (Ip_size_t)sizeof(Ipcom_route_entry) + (Ip_size_t)entry_size * 2); if (rtab == IP_NULL) /* Not enough memory */ return IP_NULL; top = (Ipcom_route_entry *) (rtab + 1); off = top + 1; on = (Ipcom_route_entry *) ((Ip_u8 *) off + entry_size); /* Init the route table */ rtab->bit_count = bit_count; rtab->octet_count = key_octet_count; rtab->notify_func = notify_func; rtab->top = top; rtab->org_off = off; rtab->org_on = on; /* Init the internal node (head of table) */ top->parent = IP_NULL; top->off = off; top->on = on; top->bit = 0; top->flags = IPCOM_ROUTE_FLAG_INIT | IPCOM_ROUTE_FLAG_INTERNAL; top->key = IP_NULL; top->mask = IP_NULL; /* All zero end mark (default route) */ off->parent = top; off->on = IP_NULL; off->off = IP_NULL; off->bit = 0xffff; off->flags = IPCOM_ROUTE_FLAG_END | IPCOM_ROUTE_FLAG_INIT; off->key = (off + 1); ipcom_memset(off->key, 0, key_octet_count); off->mask = IP_NULL; /* All one end mark */ on->parent = top; on->on = IP_NULL; on->off = IP_NULL; on->bit = 0xffff; on->flags = IPCOM_ROUTE_FLAG_END | IPCOM_ROUTE_FLAG_INIT; on->key = (on + 1); ipcom_memset(on->key, -1, key_octet_count); on->mask = IP_NULL; rtab->consecutive_mask = IP_TRUE; return rtab; } /* *=========================================================================== * ipcom_route_free_table *=========================================================================== * Description: Frees all entries in the route table including the route * table head pointed to by 'rtab'. * Parameters: rtab - The route table to free. * Returns: * */ IP_PUBLIC void ipcom_route_free_table(Ipcom_route *rtab) { ip_assert(rtab != IP_NULL); ipcom_route_walk_subtree(rtab->top, IP_FALSE, IP_FALSE, (Ipcom_route_walk_subtree_cb) ipcom_route_free_subtree_cb, rtab); ipcom_free(rtab); } /* *=========================================================================== * iplite_add_route *=========================================================================== * Description: Adds a route entry to the specified routing tabel. * Parameters: rtab - The route tabel in which the element will be inserted. * elem_to_add - The new node to insert. The following fields must * have valid values: * flags must contain any user defined flags. * key must point to the search key * mask must point to the mask or be IP_NULL if the mask is all 1:s. * all other fields are initialized by this function. * Returns: IPCOM_SUCCESS or ipcom error code. * */ IP_PUBLIC Ip_err ipcom_route_add(Ipcom_route *rtab, Ipcom_route_entry *elem_to_add) { Ip_err err; ip_assert(elem_to_add->key != IP_NULL); elem_to_add->off = IP_NULL; elem_to_add->on = IP_NULL; elem_to_add->flags &= IPCOM_ROUTE_FLAG_MASK; ip_assert(rtab->notify_func != IP_NULL); err = ipcom_patricia_insert(rtab, elem_to_add); if (err == IPCOM_SUCCESS) rtab->notify_func(rtab, elem_to_add, IPCOM_ROUTE_CODE_ADD); return err; } /* *=========================================================================== * ipcom_route_remove *=========================================================================== * Description: Removes the specified entry from the route tabel. * NOTE: The entry is only removed, not freed. * Parameters: top - The top node in the route table. * elem_to_remove - The element to remove. * Returns: ipcom error code. * */ IP_PUBLIC Ip_err ipcom_route_remove(Ipcom_route *rtab, Ipcom_route_entry *elem_to_remove) { Ipcom_route_entry *del_internal; Ipcom_route_entry *internal; Ipcom_route_entry **pleaf = IP_NULL; Ip_bool fix_subtree_mask = IP_FALSE; /* The element to remove must be a leaf */ ip_assert(elem_to_remove->off == IP_NULL); ip_assert(elem_to_remove->on == IP_NULL); if (elem_to_remove->mask != IP_NULL) { /* There might be internal node that has a reference to this mask */ for (internal = elem_to_remove->parent; internal != IP_NULL; internal = internal->parent) { if (internal->mask == elem_to_remove->mask) { internal->mask = IP_NULL; fix_subtree_mask = IP_TRUE; } } } if (IP_BIT_ISSET(elem_to_remove->flags, IPCOM_ROUTE_FLAG_END)) { /* Put back the orginal end node */ internal = elem_to_remove->parent; if (elem_to_remove->parent->on == elem_to_remove) { elem_to_remove->parent->on = rtab->org_on; rtab->org_on->parent = internal; } else { elem_to_remove->parent->off = rtab->org_off; rtab->org_off->parent = internal; } } else { /* Remove the parent (internal node) of the remove entry also */ del_internal = elem_to_remove->parent; ip_assert(del_internal != IP_NULL); internal = del_internal->parent; ip_assert(internal != IP_NULL); if (internal->off == del_internal) pleaf = &internal->off; else pleaf = &internal->on; /* Link the other subtree/leaf to the parent of the removed internal node */ if (del_internal->on == elem_to_remove) *pleaf = del_internal->off; else *pleaf = del_internal->on; (*pleaf)->parent = internal; ipcom_free(del_internal); } if (fix_subtree_mask) /* The 'internal' variable now points to the nearest parent of deleted entry */ ipcom_route_init_subtree_mask2(internal, rtab->consecutive_mask); /* pass the node info to notify_func to update all next & narrow's parent pointer */ if(pleaf != IP_NULL) { ip_assert(*pleaf); if((*pleaf)->on == IP_NULL && IP_BIT_ISFALSE((*pleaf)->flags, IPCOM_ROUTE_FLAG_INIT)) { elem_to_remove->parent = *pleaf; } else { elem_to_remove->parent = IP_NULL; } } else { elem_to_remove->parent = IP_NULL; } if (IP_BIT_ISFALSE(elem_to_remove->flags, IPCOM_ROUTE_FLAG_INIT)) rtab->notify_func(rtab, elem_to_remove, IPCOM_ROUTE_CODE_REMOVE); rtab->restart_walk = IP_TRUE; return IPCOM_SUCCESS; } /* *=========================================================================== * ipcom_route_walk_tree *=========================================================================== * Description: Calls a callback function for each element in the route tree. * Parameters: rtab - The route tree to use * cb - Callback function to that will be called for each route entry. * data - User data that will be passed each time the callback * function is called. * Returns: * */ IP_PUBLIC void ipcom_route_walk_tree(Ipcom_route *rtab, Ipcom_route_walk_cb cb, void *data) { Ipcom_route_entry *current; Ipcom_route_entry *next; current = ipcom_route_first_entry(rtab); rtab->restart_walk = IP_FALSE; while (current != IP_NULL) { next = ipcom_route_next_entry(current); if (cb(current, data)) { /* The callback told us to remove this entry */ (void) ipcom_route_remove(rtab, current); rtab->restart_walk = IP_FALSE; } if (rtab->restart_walk) { rtab->restart_walk = IP_FALSE; next = ipcom_route_first_entry(rtab); } current = next; } rtab->restart_walk = IP_TRUE; } /* *=========================================================================== * ipcom_route_walk_tree_backwards *=========================================================================== * Description: Calls a callback function for each element in the route tree * in backwards order. * Parameters: rtab - The route tree to use * cb - Callback function to that will be called for each route entry. * data - User data that will be passed each time the callback * function is called. * Returns: * */ IP_PUBLIC void ipcom_route_walk_tree_backwards(Ipcom_route *rtab, Ipcom_route_walk_cb cb, void *data) { Ipcom_route_entry *current; Ipcom_route_entry *prev; current = ipcom_route_last_entry(rtab); rtab->restart_walk = IP_FALSE; while (current != IP_NULL) { prev = ipcom_route_prev_entry(current); if (cb(current, data)) { /* The callback told us to remove this entry */ (void) ipcom_route_remove(rtab, current); rtab->restart_walk = IP_FALSE; } if (rtab->restart_walk) { rtab->restart_walk = IP_FALSE; prev = ipcom_route_last_entry(rtab); } current = prev; } rtab->restart_walk = IP_TRUE; } /* *=========================================================================== * ipcom_route_key_cmp *=========================================================================== * Description: Compares 2 keys with or without a mask and returns * the result. * Parameters: key_bit_size - The size of the keys in bits. * key1 - A key. * key2 - Another key. * mask - The mask to use when comparing the keys, a 0 bit means * that this bit is alwasy a match. A value of IP_NULL is * interpreted as a mask of all 1. * Returns: IPCOM_ROUTE_KEY_CMP_PREFECT_MATCH, * IPCOM_ROUTE_KEY_CMP_MASK_MATCH, * IPCOM_ROUTE_KEY_CMP_NO_MATCH */ /*lint -efunc(413,ipcom_route_key_cmp) Likely use of null pointer */ IP_PUBLIC int ipcom_route_key_cmp(Ip_u32 key_bit_size, const void *key1, const void *key2, const void *mask) { int i = 0; /* Check if the key bit size is dividable with 16 */ if ((key_bit_size & 0xf) == 0) { int key_byte_size; int key_short_size = (int)(key_bit_size >> 4); /* Check for perfect match first */ for (; i < key_short_size; i++) { if (((Ip_u16 *) key1)[i] != ((Ip_u16 *) key2)[i]) break; } if (i == key_short_size) return IPCOM_ROUTE_KEY_CMP_PREFECT_MATCH; /* No perfect match, check for mask match */ key_byte_size = key_short_size << 1; for (i <<= 1; i < key_byte_size; i++) { if (mask && ((Ip_u8 *) mask)[i] != 0xff) break; if (((Ip_u8 *) key1)[i] != ((Ip_u8 *) key2)[i]) return IPCOM_ROUTE_KEY_CMP_NO_MATCH; } ip_assert(mask != IP_NULL); while (i < key_byte_size && ((Ip_u8 *) mask)[i] == 0) i++; } for (i <<= 3; i < (int)key_bit_size; i++) if (mask == IP_NULL || IPCOM_IS_BIT_SET(mask, i)) if (IPCOM_IS_BIT_SET(key1, i) != IPCOM_IS_BIT_SET(key2, i)) return IPCOM_ROUTE_KEY_CMP_NO_MATCH; return IPCOM_ROUTE_KEY_CMP_MASK_MATCH; } /* *=========================================================================== * ipcom_route_init_subtree_mask *=========================================================================== * Description: Initialize the internal node mask references on a subtree. * Parameters: rt - The head of the subtree. * Returns: * */ IP_PUBLIC void ipcom_route_init_subtree_mask(Ipcom_route_entry *rt) { ipcom_route_init_subtree_mask2(rt, IP_FALSE); } /* **************************************************************************** * END OF FILE **************************************************************************** */