Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nd_proxy.c Source File

nd_proxy.c

00001 /*
00002  * Copyright (c) 2015-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 
00018 #include "nsconfig.h"
00019 #ifdef HAVE_ND_PROXY
00020 #include "ns_types.h"
00021 #include "common_functions.h"
00022 #include "ns_trace.h"
00023 #include "string.h"
00024 #include "nsdynmemLIB.h"
00025 #include "ns_list.h"
00026 #include "Service_Libs/nd_proxy/nd_proxy.h"
00027 
00028 #define TRACE_GROUP "prox"
00029 
00030 /**
00031  * Downstream Interface list
00032  */
00033 typedef struct nd_proxy_downstream_list {
00034     int8_t id; /**< Proxy Interface Id*/
00035     bridge_state_update_cb *bridge_status_update; /**< Update bridge state */
00036     nd_proxy_req_cb *nd_proxy_validation; /**< Validate NS ND proxy response */
00037     ns_list_link_t link;
00038 } nd_proxy_downstream_list_s;
00039 
00040 /**
00041  * Upstream Interface list
00042  */
00043 typedef struct nd_proxy_upstream_list {
00044     int8_t id; /**< Upstream Interface Id*/
00045     nd_proxy_req_cb *route_on_link_validation; /**< Mesh Can validate OnLink Route */
00046     ns_list_link_t link;
00047 } nd_proxy_upstream_list_s;
00048 
00049 /**
00050  * Linked Downstream interface list to Upstream
00051  */
00052 typedef struct nd_proxy_downstream_interfaces_list {
00053     int8_t id; /**< Downstream Interface Id*/
00054     ns_list_link_t link;
00055 } nd_proxy_downstream_interfaces_list_s;
00056 
00057 typedef NS_LIST_HEAD (nd_proxy_upstream_list_s, link) upstream_interface_list_t;
00058 
00059 typedef NS_LIST_HEAD (nd_proxy_downstream_list_s, link) downstream_interface_list_t;
00060 
00061 typedef NS_LIST_HEAD (nd_proxy_downstream_interfaces_list_s, link) proxy_connected_downstream_list_t;
00062 
00063 /**
00064  * Linked Upstream and Downstream interface list
00065  */
00066 typedef struct nd_proxy_connected_list {
00067     int8_t id; /**< Upstream Interface Id*/
00068     proxy_connected_downstream_list_t connected_downstream_list; /**< Linked Downstream Interfaces to this interface*/
00069     ns_list_link_t link;
00070 } nd_proxy_connected_list_s;
00071 
00072 typedef NS_LIST_HEAD (nd_proxy_connected_list_s, link) proxy_connected_interface_list_t;
00073 
00074 /* List of registered Upstream interfaces */
00075 static upstream_interface_list_t upstream_interface_list;
00076 
00077 /* List of registered Downstream interfaces */
00078 static downstream_interface_list_t downstream_interface_list;
00079 
00080 /* List of connected Upstream interfaces */
00081 static proxy_connected_interface_list_t paired_interface_list;
00082 
00083 /**
00084  * Get or allocate new Downstream interface entry
00085  *
00086  */
00087 static nd_proxy_downstream_list_s * proxy_cache_downstream_interface_allocate(int8_t interface , downstream_interface_list_t *list)
00088 {
00089     ns_list_foreach(nd_proxy_downstream_list_s, e, list) {
00090         if (e->id == interface) {
00091             return e;
00092         }
00093     }
00094     nd_proxy_downstream_list_s *entry = ns_dyn_mem_alloc(sizeof(nd_proxy_downstream_list_s));
00095     if (entry) {
00096         entry->id = interface;
00097         ns_list_add_to_start(list, entry);
00098     }
00099 
00100     return entry;
00101 }
00102 
00103 /**
00104  * Get or allocate new Upstream interface entry
00105  *
00106  */
00107 static nd_proxy_upstream_list_s * proxy_cache_upstream_interface_allocate(int8_t interface , upstream_interface_list_t *list)
00108 {
00109     ns_list_foreach(nd_proxy_upstream_list_s, e, list) {
00110         if (e->id == interface) {
00111             return e;
00112         }
00113     }
00114     nd_proxy_upstream_list_s *entry = ns_dyn_mem_alloc(sizeof(nd_proxy_upstream_list_s));
00115     if (entry) {
00116         entry->id = interface;
00117         ns_list_add_to_start(list, entry);
00118     }
00119 
00120     return entry;
00121 }
00122 
00123 /**
00124  * Get registered Downstream interface entry
00125  *
00126  */
00127 static nd_proxy_downstream_list_s * proxy_cache_downstream_interface_get(int8_t interface , downstream_interface_list_t *list)
00128 {
00129     ns_list_foreach(nd_proxy_downstream_list_s, e, list) {
00130         if (e->id == interface) {
00131             return e;
00132         }
00133     }
00134     return NULL;
00135 }
00136 
00137 /**
00138  * Get registered Upstream interface entry
00139  *
00140  */
00141 static nd_proxy_upstream_list_s * proxy_cache_upstream_interface_get(int8_t interface , upstream_interface_list_t *list)
00142 {
00143     ns_list_foreach(nd_proxy_upstream_list_s, e, list) {
00144         if (e->id == interface) {
00145             return e;
00146         }
00147     }
00148     return NULL;
00149 }
00150 
00151 /**
00152  * Get linked proxy entry by Upstream interface id
00153  *
00154  */
00155 static nd_proxy_connected_list_s * proxy_upstream_conection_get(int8_t interface_id)
00156 {
00157     ns_list_foreach(nd_proxy_connected_list_s, e, &paired_interface_list) {
00158         if (e->id == interface_id) {
00159             return e;
00160         }
00161     }
00162     return NULL;
00163 }
00164 
00165 /**
00166  * Get or allocate new proxy entry by Upstream interface id
00167  *
00168  */
00169 static nd_proxy_connected_list_s * proxy_upstream_connection_allocate(int8_t interface_id)
00170 {
00171     ns_list_foreach(nd_proxy_connected_list_s, e, &paired_interface_list) {
00172         if (e->id == interface_id) {
00173             return e;
00174         }
00175     }
00176 
00177     nd_proxy_connected_list_s *entry = ns_dyn_mem_alloc(sizeof(nd_proxy_connected_list_s));
00178     if (entry) {
00179         entry->id = interface_id;
00180         ns_list_init(&entry->connected_downstream_list);
00181         ns_list_add_to_start(&paired_interface_list, entry);
00182     }
00183     return entry;
00184 }
00185 
00186 /**
00187  * Link Downstream interface to allocated proxy
00188  *
00189  */
00190 static bool proxy_downstream_conection_allocate(int8_t interface_id, proxy_connected_downstream_list_t *list)
00191 {
00192     ns_list_foreach(nd_proxy_downstream_interfaces_list_s, e, list) {
00193         if (e->id == interface_id) {
00194             return true;
00195         }
00196     }
00197 
00198     nd_proxy_downstream_interfaces_list_s *entry = ns_dyn_mem_alloc(sizeof(nd_proxy_downstream_interfaces_list_s));
00199     if (entry) {
00200         entry->id = interface_id;
00201         ns_list_add_to_start(list, entry);
00202         return true;
00203     }
00204     return false;
00205 }
00206 
00207 /**
00208  * Remove Downstream interface from linked Upstream list
00209  *
00210  */
00211 static bool proxy_cache_untie_connection_by_downstream(int8_t downstream_id)
00212 {
00213     bool ret_val = false;
00214     ns_list_foreach_safe(nd_proxy_connected_list_s, e, &paired_interface_list) {
00215 
00216         ns_list_foreach_safe(nd_proxy_downstream_interfaces_list_s, downstream, &e->connected_downstream_list) {
00217             if (downstream->id == downstream_id) {
00218                 //Remove from the list and free
00219                 ns_list_remove(&e->connected_downstream_list, downstream);
00220                 ns_dyn_mem_free(downstream);
00221                 ret_val = true;
00222             }
00223         }
00224 
00225         /* Free proxy connection if all mesh interfaces are disconnected */
00226         if (ns_list_is_empty(&e->connected_downstream_list)) {
00227             //Remove connection from list and free memory
00228             ns_list_remove(&paired_interface_list, e);
00229             ns_dyn_mem_free(e);
00230         }
00231 
00232     }
00233     return ret_val;
00234 }
00235 
00236 /**
00237  * Remove Upstream interface from connected list
00238  *
00239  * Function will tell to mesh interface by registered function pointer disabled proxy functionality
00240  *
00241  */
00242 static bool proxy_cache_untie_connection_by_upstream(int8_t upstream_id)
00243 {
00244     nd_proxy_downstream_list_s *downstream_interface;
00245 
00246     ns_list_foreach_safe(nd_proxy_connected_list_s, e, &paired_interface_list) {
00247 
00248         if (e->id != upstream_id) {
00249             continue;
00250         }
00251 
00252         ns_list_foreach_safe(nd_proxy_downstream_interfaces_list_s, downstream, &e->connected_downstream_list) {
00253             //Remove from the list and free
00254             downstream_interface = proxy_cache_downstream_interface_get(downstream->id, &downstream_interface_list);
00255             if (downstream_interface) {
00256                 //Indicate Downstream for missing Upstream
00257                 if (downstream_interface->bridge_status_update) {
00258                     downstream_interface->bridge_status_update(upstream_id, downstream->id, false);
00259                 }
00260             }
00261 
00262             ns_list_remove(&e->connected_downstream_list, downstream);
00263             ns_dyn_mem_free(downstream);
00264         }
00265 
00266         //Remove connection from list and free memory
00267         ns_list_remove(&paired_interface_list, e);
00268         ns_dyn_mem_free(e);
00269         return true;
00270 
00271     }
00272     return false;
00273 }
00274 
00275 /**
00276  * Generate Proxy between Upstream and Downstream interface
00277  *
00278  * Function will tell to Downstream interface by registered function pointer enabled proxy functionality
00279  *
00280  */
00281 static int proxy_cache_interface_enable_proxy(int8_t upstream_id, int8_t downstream_id)
00282 {
00283     //validate first current connection
00284     nd_proxy_connected_list_s *proxy = NULL;
00285     nd_proxy_downstream_list_s *downstream_interface = proxy_cache_downstream_interface_get(downstream_id, &downstream_interface_list);
00286     if (!downstream_interface) {
00287         tr_error("Unknown Downstream id");
00288         return -1;
00289     }
00290 
00291     if (!proxy_cache_upstream_interface_get(upstream_id , &upstream_interface_list)) {
00292         tr_error("Unknown Upstream id");
00293         return -1;
00294     }
00295 
00296     ns_list_foreach(nd_proxy_connected_list_s, e, &paired_interface_list) {
00297 
00298         if (e->id != upstream_id) {
00299             continue;
00300         }
00301 
00302         //Check Downstream
00303         ns_list_foreach_safe(nd_proxy_downstream_interfaces_list_s, mesh, &e->connected_downstream_list) {
00304             if (mesh->id == downstream_id) {
00305                 return 0;
00306             }
00307         }
00308     }
00309 
00310     //Allocate new Upstream and connection
00311     proxy = proxy_upstream_connection_allocate(upstream_id);
00312 
00313     if (!proxy) {
00314         tr_error("Proxy alloc fail");
00315         return -1;
00316     }
00317 
00318     if (!proxy_downstream_conection_allocate(downstream_id, &proxy->connected_downstream_list) )
00319     {
00320         tr_error("Up<->Down stream connect alloc fail");
00321         if (ns_list_is_empty(&proxy->connected_downstream_list)) {
00322             //Remove connection from list and free memory
00323             ns_list_remove(&paired_interface_list, proxy);
00324             ns_dyn_mem_free(proxy);
00325         }
00326         return -1;
00327     }
00328 
00329     if (downstream_interface->bridge_status_update) {
00330         downstream_interface->bridge_status_update(upstream_id, downstream_id, true);
00331     }
00332     return 0;
00333 }
00334 
00335 int nd_proxy_downstream_interface_register(int8_t interface_id, nd_proxy_req_cb *nd_proxy_req, bridge_state_update_cb * bridge_state_update)
00336 {
00337     if (interface_id < 0) {
00338         return -1;
00339     } else if (!nd_proxy_req) {
00340         return -1;
00341     }
00342     nd_proxy_downstream_list_s * entry = proxy_cache_downstream_interface_allocate(interface_id, &downstream_interface_list);
00343     if (!entry) {
00344         return -2;
00345     }
00346     //Set Function pointers
00347     entry->bridge_status_update = bridge_state_update;
00348     entry->nd_proxy_validation = nd_proxy_req;
00349 
00350     ns_list_foreach(nd_proxy_upstream_list_s, e, &upstream_interface_list) {
00351 
00352         if (proxy_cache_interface_enable_proxy(e->id,interface_id) == 0) {
00353             tr_debug("Proxy bridge enabled for interface %i to %i\n", e->id, interface_id);
00354         }
00355     }
00356 
00357     return 0;
00358 }
00359 
00360 int nd_proxy_downstream_interface_unregister(int8_t interface_id)
00361 {
00362     //Release from paired
00363     proxy_cache_untie_connection_by_downstream(interface_id);
00364 
00365     ns_list_foreach(nd_proxy_downstream_list_s, e, &downstream_interface_list) {
00366         if (e->id == interface_id) {
00367             ns_list_remove(&downstream_interface_list, e);
00368             ns_dyn_mem_free(e);
00369             return 0;
00370         }
00371     }
00372 
00373     return -1;
00374 }
00375 
00376 int nd_proxy_upstream_interface_register(int8_t interface_id, nd_proxy_req_cb *route_validation_req)
00377 {
00378     if (interface_id < 0) {
00379         return -1;
00380     } else if (!route_validation_req) {
00381         return -1;
00382     }
00383 
00384     nd_proxy_upstream_list_s * entry = proxy_cache_upstream_interface_allocate(interface_id, &upstream_interface_list);
00385     if (!entry) {
00386         return -1;
00387     }
00388     //Set Function pointers
00389     entry->route_on_link_validation = route_validation_req;
00390 
00391     //Link now all available interfaces which give proxy service
00392     ns_list_foreach(nd_proxy_downstream_list_s, e, &downstream_interface_list) {
00393 
00394         if (proxy_cache_interface_enable_proxy(interface_id, e->id) == 0) {
00395             tr_debug("Proxy bridge enabled for interface %i to %i \n", interface_id, e->id);
00396         }
00397     }
00398     return 0;
00399 }
00400 
00401 int nd_proxy_upstream_interface_unregister(int8_t interface_id)
00402 {
00403     proxy_cache_untie_connection_by_upstream(interface_id);
00404 
00405     ns_list_foreach(nd_proxy_upstream_list_s, e, &upstream_interface_list) {
00406         if (e->id == interface_id) {
00407             ns_list_remove(&upstream_interface_list, e);
00408             ns_dyn_mem_free(e);
00409             return 0;
00410         }
00411     }
00412 
00413     return -1;
00414 }
00415 
00416 bool nd_proxy_enabled_for_downstream(int8_t interface_id)
00417 {
00418     if (proxy_upstream_conection_get(interface_id) ) {
00419         return true;
00420     }
00421     return false;
00422 }
00423 
00424 bool nd_proxy_enabled_for_upstream(int8_t interface_id)
00425 {
00426     ns_list_foreach(nd_proxy_connected_list_s, e, &paired_interface_list) {
00427 
00428         ns_list_foreach(nd_proxy_downstream_interfaces_list_s, mesh, &e->connected_downstream_list) {
00429             if (mesh->id == interface_id) {
00430                 return true;
00431             }
00432         }
00433     }
00434     return false;
00435 }
00436 
00437 bool nd_proxy_target_address_validation(int8_t upstream_id, uint8_t *address, int8_t *downstream_id_ptr)
00438 {
00439     nd_proxy_downstream_list_s *downstream;
00440     nd_proxy_connected_list_s *upstream = proxy_upstream_conection_get(upstream_id);
00441     *downstream_id_ptr = -1;
00442     if (!upstream) {
00443         return false;
00444     }
00445 
00446     ns_list_foreach(nd_proxy_downstream_interfaces_list_s, downstream_entry, &upstream->connected_downstream_list) {
00447         downstream = proxy_cache_downstream_interface_get(downstream_entry->id, &downstream_interface_list);
00448         if (downstream) {
00449             if (downstream->nd_proxy_validation(downstream_entry->id, address) == 0) {
00450                 *downstream_id_ptr = downstream_entry->id;
00451                 return true;
00452             }
00453         }
00454     }
00455 
00456     return false;
00457 }
00458 
00459 bool nd_proxy_upstream_route_onlink(int8_t downstream_id, uint8_t *address)
00460 {
00461     ns_list_foreach(nd_proxy_connected_list_s, e, &paired_interface_list) {
00462 
00463         ns_list_foreach(nd_proxy_downstream_interfaces_list_s, downstream, &e->connected_downstream_list) {
00464             if (downstream->id == downstream_id) {
00465                 nd_proxy_upstream_list_s *upstream = proxy_cache_upstream_interface_get(e->id, &upstream_interface_list);
00466                 if (upstream) {
00467                     if (upstream->route_on_link_validation(e->id, address) == 0) {
00468                         return true;
00469                     }
00470                 }
00471             }
00472         }
00473     }
00474     return false;
00475 }
00476 #endif /* HAVE_ND_PROXY */
00477