Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers neighbor_cache.c Source File

neighbor_cache.c

00001 /*
00002  * Copyright (c) 2014-2017, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 #include "nsconfig.h"
00018 #include "ns_types.h"
00019 #include "common_functions.h"
00020 #include "ns_trace.h"
00021 #include "string.h"
00022 #include "nsdynmemLIB.h"
00023 #include "Service_Libs/Neighbor_cache/neighbor_table_definition.h"
00024 
00025 #ifdef HAVE_NEIGHBOR_CACHE
00026 
00027 static void entry_delete(neigh_cache_s *neigh_cache, neigh_cache_entry_s *entry);
00028 
00029 /**
00030  * \brief A function to initialize a neighbor cache before use
00031  *
00032  * \param neigh_cache pointer to neighbor cache.
00033  */
00034 void neighbor_cache_init(neigh_cache_s *neigh_cache)
00035 {
00036     ns_list_init(&neigh_cache->head);
00037 }
00038 
00039 /**
00040  * \brief A function to flush an entire neighbour cache
00041  *
00042  * \param neigh_cache pointer to neighbor cache.
00043  *
00044  * \return <n> The number of entries removed
00045  */
00046 int neighbor_cache_flush(neigh_cache_s *neigh_cache)
00047 {
00048     int count = 0;
00049 
00050     ns_list_foreach_safe(neigh_cache_entry_s, entry, &neigh_cache->head) {
00051         entry_delete(neigh_cache, entry);
00052         count++;
00053     }
00054 
00055     return count;
00056 }
00057 
00058 /**
00059  * \brief Extended internal implementation of neighbor_cache_entry_get
00060  *
00061  * \param neigh_cache pointer to neighbor cache.
00062  * \param address_type type for 16-bit or 64-bit address
00063  * \param address_ptr pointer to address of specified type
00064  * \param reorder true if permitted to reorder the list
00065  *
00066  * \return pointer to found entry
00067  * \return NULL if not found
00068  */
00069 static neigh_cache_entry_s *entry_get(neigh_cache_s *neigh_cache, neighbor_address_type_e address_type, const void *address_ptr, bool reorder)
00070 {
00071     uint16_t mac16 = 0;
00072     neigh_cache_entry_s *entry = NULL;
00073 
00074     if (address_type == NEIGH_16_BIT_ADDRESS) {
00075         mac16 = common_read_16_bit(address_ptr);
00076     }
00077 
00078     ns_list_foreach(neigh_cache_entry_s, e, &neigh_cache->head) {
00079         bool match = false;
00080         switch (address_type) {
00081             case NEIGH_64_BIT_ADDRESS:
00082                 match = memcmp(address_ptr, e->mac64, sizeof(entry->mac64)) == 0;
00083                 break;
00084             case NEIGH_16_BIT_ADDRESS:
00085                 match = e->mac16 == mac16;
00086                 break;
00087             case NEIGH__TIMED_OUT:
00088                 match = e->ttl == 0;
00089                 break;
00090         }
00091         if (match) {
00092             entry = e;
00093             break;
00094         }
00095     }
00096 
00097     if (!entry) {
00098         return NULL;
00099     }
00100 
00101     /*
00102      * If permitted, move this entry to head of list, so frequently-used entries
00103      * stay near the top.
00104      */
00105     if (entry != ns_list_get_first(&neigh_cache->head) && reorder) {
00106         ns_list_remove(&neigh_cache->head, entry);
00107         ns_list_add_to_start(&neigh_cache->head, entry);
00108     }
00109 
00110     return entry;
00111 }
00112 
00113 /**
00114  * \brief A function to locate a specific entry by address
00115  *
00116  * Note that this can re-order the cache, so could upset iteration using macros.
00117  *
00118  * \param neigh_cache pointer to neighbor cache.
00119  * \param address_type type for 16-bit or 64-bit address
00120  * \param address_ptr pointer to address of specified type
00121  *
00122  * \return pointer to cache entry
00123  * \return NULL if not found
00124  */
00125 neigh_cache_entry_s *neighbor_cache_entry_get(neigh_cache_s *neigh_cache, neighbor_address_type_e address_type, const void *address_ptr)
00126 {
00127     return entry_get(neigh_cache, address_type, address_ptr, true);
00128 }
00129 
00130 /**
00131  * \brief A function to create or return an existing neighbor cache entry.
00132  *
00133  * \param neigh_cache pointer to neighbor cache.
00134  * \param address_ptr pointer to EUI-64 address (64-bit)
00135  *
00136  * \return pointer to cache entry, possibly newly created.
00137  * \return NULL if entry not found an unable to allocate memory for new entry
00138  */
00139 neigh_cache_entry_s *neighbor_cache_entry_create(neigh_cache_s *neigh_cache, const uint8_t address_ptr[8])
00140 {
00141     neigh_cache_entry_s *entry;
00142 
00143     entry = neighbor_cache_entry_get(neigh_cache, NEIGH_64_BIT_ADDRESS, address_ptr);
00144     if (entry) {
00145         return entry;
00146     }
00147 
00148     entry = ns_dyn_mem_alloc(sizeof * entry);
00149     if (!entry) {
00150         return NULL;
00151     }
00152 
00153     memset(entry, 0, sizeof * entry);
00154     memcpy(entry->mac64, address_ptr, sizeof entry->mac64);
00155     entry->mac16 = 0xFFFF;
00156     entry->neighbor_keypair_info = NULL;
00157     ns_list_add_to_start(&neigh_cache->head, entry);
00158 
00159     return entry;
00160 }
00161 
00162 /**
00163  * \brief Delete an entry from the list, including housekeeping
00164  *
00165  * \param neigh_cache pointer to neighbor cache.
00166  * \param entry pointer to entry
00167  */
00168 static void entry_delete(neigh_cache_s *neigh_cache, neigh_cache_entry_s *entry)
00169 {
00170     ns_list_remove(&neigh_cache->head, entry);
00171     if (entry->neighbor_keypair_info) {
00172         ns_dyn_mem_free(entry->neighbor_keypair_info);
00173     }
00174     ns_dyn_mem_free(entry);
00175 }
00176 
00177 /**
00178  * \brief A function to delete an entry by address.
00179  *
00180  * \param neigh_cache pointer to neighbor cache.
00181  * \param address_type type for 16-bit or 64-bit address
00182  * \param address_ptr pointer to address of specified type
00183  *
00184  * \return 0 Removed OK
00185  * \return -1 Entry not found
00186  */
00187 int8_t neighbor_cache_entry_delete(neigh_cache_s *neigh_cache, neighbor_address_type_e address_type, const void *address_ptr)
00188 {
00189     neigh_cache_entry_s *entry;
00190 
00191     entry = entry_get(neigh_cache, address_type, address_ptr, false);
00192     if (!entry) {
00193         return -1;
00194     }
00195 
00196     entry_delete(neigh_cache, entry);
00197 
00198     return 0;
00199 }
00200 
00201 /**
00202  * \brief A function to delete an entry by entry pointer.
00203  *
00204  * \param neigh_cache pointer to neighbor cache.
00205  * \param entry pointer to entry
00206  *
00207  * \return pointer to the next entry, to allow deletion during iteration
00208  * \return NULL if no more entries
00209  * \return NEIGH_ENTRY_PTR_ERR if entry pointer not found (no longer checked)
00210  */
00211 neigh_cache_entry_s *neighbor_cache_entry_delete_by_entry_pointer(neigh_cache_s *neigh_cache, neigh_cache_entry_s *entry)
00212 {
00213     neigh_cache_entry_s *next = ns_list_get_next(&neigh_cache->head, entry);
00214 
00215     entry_delete(neigh_cache, entry);
00216 
00217     return next;
00218 }
00219 
00220 /**
00221  * \brief A function to update Neighbor cache Time-To-Live values.
00222  *
00223  * This decrements the TTL for all entries in the cache. TTL values are
00224  * are clamped to not wrap past zero. When an entry's TTL value becomes zero,
00225  * link_req_counter is set to NEIGH_LINK_REQUEST_COUNTER. (Note that
00226  * newly-created entries have ttl and link_req_counter both zero - they will
00227  * need initialising before use).
00228  *
00229  * \param neigh_cache pointer to neighbor cache.
00230  * \param tick amount to decrement TTL
00231  *
00232  * \return total number of entries in the cache whose TTL is 0 after the update
00233  */
00234 int neighbor_cache_ttl_update(neigh_cache_s *neigh_cache, uint16_t ticks)
00235 {
00236     int count = 0;
00237 
00238     ns_list_foreach(neigh_cache_entry_s, entry, &neigh_cache->head) {
00239         if (entry->ttl > ticks) {
00240             entry->ttl -= ticks;
00241         } else {
00242             if (entry->ttl > 0) {
00243                 entry->link_req_counter = NEIGH_LINK_REQUEST_COUNTER;
00244                 entry->ttl = 0;
00245             }
00246             count++;
00247         }
00248     }
00249 
00250     return count;
00251 }
00252 
00253 /**
00254  * \brief A function to get a timed-out neighbor entry.
00255  *
00256  * Returns an entry whose TTL field is set to zero.
00257  *
00258  * \param neigh_cache pointer to neighbor cache.
00259  *
00260  * \return pointer to a timed-out entry
00261  * \return NULL if no timed-out entries
00262  */
00263 neigh_cache_entry_s *neighbor_cache_entry_get_timed_out(neigh_cache_s *neigh_cache)
00264 {
00265     return neighbor_cache_entry_get(neigh_cache, NEIGH__TIMED_OUT, NULL);
00266 }
00267 
00268 #else // HAVE_NEIGHBOR_CACHE
00269 
00270 void neighbor_cache_init(neigh_cache_s *neigh_cache) {
00271     (void)neigh_cache;
00272 }
00273 int neighbor_cache_flush(neigh_cache_s *neigh_cache){
00274     (void)neigh_cache;
00275     return 0;
00276 }
00277 
00278 #endif // HAVE_NEIGHBOR_CACHE