Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of OmniWheels by
icmpv6_radv.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 /* 00018 * icmpv6_radv.c 00019 * 00020 * ICMPv6 Router Advertisement transmission 00021 * 00022 * This file handles all RS reception, and deals with the timing of all RAs. 00023 * The actual contents of the RAs are still handled separately by 00024 * nd_router_object.c for 6LoWPAN and protocol_ipv6.c for Ethernet. 00025 * 00026 * We handle multicast transmission - once initially scheduled, these will 00027 * automatically be repeated, and will be accelerated by RS reception if 00028 * rtr_adv_unicast_to_rs is false. 00029 * 00030 * If rtr_adv_unicast_to_rs is true, then each RS gets a unicast RA response, 00031 * without affecting any scheduled multicast transmissions. 00032 * 00033 * For 6LR operation, with RFC 6775 multihop distribution, we allow the system 00034 * to queue multiple transmissions to each destination - 1 per border router 00035 * (ABRO 6LBR). These are independently scheduled and rate limited; 1 RS 00036 * will lead to multiple independently randomised responses, 1 per ABRO, and 00037 * per-ABRO multicast transmissions will be independently randomly scheduled. 00038 */ 00039 00040 #include "nsconfig.h" 00041 #include "ns_types.h" 00042 #include "ns_list.h" 00043 #include "randLIB.h" 00044 #include <string.h> 00045 #include "nsdynmemLIB.h" 00046 #include "ns_trace.h" 00047 #include "NWK_INTERFACE/Include/protocol.h" 00048 #include "ipv6_stack/protocol_ipv6.h" 00049 #include "6LoWPAN/ND/nd_router_object.h" // for nd_ra_timing() 00050 #include "Common_Protocols/icmpv6.h" 00051 #include "Common_Protocols/icmpv6_radv.h" 00052 00053 #ifdef RADV_TX 00054 00055 #define TRACE_GROUP "RAdv" 00056 00057 typedef struct icmp_queued_ra { 00058 uint8_t addr[16]; /* destination address */ 00059 uint8_t abro[16]; /* RFC 6775 ABRO 6LBR address (or ADDR_UNSPECIFIED if no ABRO) */ 00060 bool rs_triggered; /* was queued by an RS */ 00061 uint16_t ticks; /* ticks until transmission (relative to last list entry) */ 00062 protocol_interface_info_entry_t *interface; 00063 ns_list_link_t link; 00064 } icmp_queued_ra_t; 00065 00066 static NS_LIST_DEFINE(icmp_ra_queue, icmp_queued_ra_t, link); 00067 00068 void icmpv6_radv_init(protocol_interface_info_entry_t *cur) 00069 { 00070 /* Initialise basic static config */ 00071 cur->adv_send_advertisements = false; 00072 cur->max_ra_delay_time = 5; 00073 cur->min_delay_between_ras = 30; 00074 cur->min_rtr_adv_interval = 2000; // 3 minutes 20 seconds (max/3) 00075 cur->max_rtr_adv_interval = 6000; // 10 minutes 00076 cur->max_initial_rtr_adv_interval = 160; // 16 seconds 00077 cur->max_initial_rtr_advertisements = 3; 00078 cur->adv_link_mtu = 0; 00079 cur->adv_cur_hop_limit = 0; 00080 cur->adv_reachable_time = 0; 00081 cur->adv_retrans_timer = 0; 00082 cur->rtr_adv_unicast_to_rs = false; 00083 cur->rtr_adv_flags = 0; 00084 cur->adv_copy_heard_flags = false; 00085 00086 /* Initialise timing info for local RAs */ 00087 cur->ra_timing.rtr_adv_last_send_time = protocol_core_monotonic_time - 0x10000; 00088 cur->ra_timing.initial_rtr_adv_count = 0; 00089 } 00090 00091 /* Locate the timing info for a given source - we currently have a split in that 00092 * specified ABROs get their timing info stored over in the associated nd_router_t, 00093 * and if there's no ABRO, it's in the interface structure. 00094 * 00095 * When/if the "advert contents" gets centralised, this info can be stored there 00096 * too. 00097 */ 00098 static ipv6_ra_timing_t *icmpv6_ra_timing_lookup(protocol_interface_info_entry_t *cur, const uint8_t abro[16]) 00099 { 00100 if (addr_is_ipv6_unspecified(abro)) { 00101 return &cur->ra_timing; 00102 } 00103 00104 return nd_ra_timing(abro); 00105 } 00106 00107 /* Queue an RA - on entry new_ra->ticks is ticks from now; we need to 00108 * insert it into the list which has relative ticks, so it gets decremented 00109 * by the ticks of all preceding queue members. */ 00110 void icmpv6_queue_ra(icmp_queued_ra_t *new_ra) 00111 { 00112 ns_list_foreach(icmp_queued_ra_t, ra, &icmp_ra_queue) { 00113 if (ra->ticks > new_ra->ticks) { 00114 ns_list_add_before(&icmp_ra_queue, ra, new_ra); 00115 ra->ticks -= new_ra->ticks; 00116 return; 00117 } 00118 new_ra->ticks -= ra->ticks; 00119 } 00120 00121 ns_list_add_to_end(&icmp_ra_queue, new_ra); 00122 } 00123 00124 void icmpv6_unqueue_ra(icmp_queued_ra_t *ra) 00125 { 00126 icmp_queued_ra_t *before = ns_list_get_next(&icmp_ra_queue, ra); 00127 00128 if (before) { 00129 before->ticks += ra->ticks; 00130 } 00131 00132 ns_list_remove(&icmp_ra_queue, ra); 00133 } 00134 00135 /* If there's an advert already queued to the specified destination for the specified ABRO, return it, and its scheduled time */ 00136 static icmp_queued_ra_t *icmpv6_queued_ra_lookup(const uint8_t *dest_addr, const uint8_t *abro, int8_t interface_id, uint16_t *abstime_out) 00137 { 00138 uint16_t abstime = 0; 00139 ns_list_foreach(icmp_queued_ra_t, ra, &icmp_ra_queue) { 00140 abstime += ra->ticks; 00141 if (interface_id == ra->interface->id && addr_ipv6_equal(dest_addr, ra->addr) && addr_ipv6_equal(abro, ra->abro)) { 00142 if (abstime_out) { 00143 *abstime_out = abstime; 00144 } 00145 return ra; 00146 } 00147 } 00148 00149 return NULL; 00150 } 00151 00152 /* Trigger a single RA from an RS - must be called multiple times if we have multiple ABROs */ 00153 void icmpv6_trigger_ra_from_rs(protocol_interface_info_entry_t *cur, const uint8_t dest[16], const uint8_t abro[16]) 00154 { 00155 uint16_t scheduled; 00156 00157 /* Check if we've already scheduled an RA to this destination for this ABRO */ 00158 icmp_queued_ra_t *ra = icmpv6_queued_ra_lookup(dest, abro, cur->id, &scheduled); 00159 00160 /* Delay "0" means next tick, ie somewhere between 0 and 100ms, so "(0, 4)" 00161 * gives us [0ms..500ms). 00162 */ 00163 uint16_t delay = randLIB_get_random_in_range(0, cur->max_ra_delay_time - 1); 00164 if (ra) { 00165 /* If we've already handled an RS for this destination, or we'd be 00166 * delaying an already-scheduled RA, ignore this RS. 00167 */ 00168 if (ra->rs_triggered || delay >= scheduled) { 00169 return; 00170 } 00171 /* Unqueue, and we'll requeue for an earlier time */ 00172 icmpv6_unqueue_ra(ra); 00173 } else { 00174 ra = ns_dyn_mem_alloc(sizeof(icmp_queued_ra_t)); 00175 if (!ra) { 00176 return; 00177 } 00178 memcpy(ra->addr, dest, 16); 00179 memcpy(ra->abro, abro, 16); 00180 ra->interface = cur; 00181 } 00182 00183 ra->rs_triggered = true; 00184 00185 /* Rate-limit multicasts - independently for each ABRO */ 00186 if (dest == ADDR_LINK_LOCAL_ALL_NODES) { 00187 ipv6_ra_timing_t *t = icmpv6_ra_timing_lookup(cur, abro); 00188 uint32_t time_since_last_ra; 00189 time_since_last_ra = protocol_core_monotonic_time - t->rtr_adv_last_send_time; 00190 00191 if (time_since_last_ra < cur->min_delay_between_ras) { 00192 delay += cur->min_delay_between_ras - time_since_last_ra; 00193 } 00194 } else { 00195 delay = 1; 00196 } 00197 ra->ticks = delay; 00198 00199 icmpv6_queue_ra(ra); 00200 } 00201 00202 buffer_t *icmpv6_rs_handler(buffer_t *buf, protocol_interface_info_entry_t *cur) 00203 { 00204 const uint8_t *sllao; 00205 00206 if (buf->options .hop_limit != 255 || buf->options .code != 0) { 00207 return buffer_free(buf); 00208 } 00209 00210 if (!icmpv6_options_well_formed_in_buffer(buf, 4)) { 00211 tr_debug("Malformed RS"); 00212 return buffer_free(buf); 00213 } 00214 00215 sllao = icmpv6_find_option_in_buffer(buf, 4, ICMPV6_OPT_SRC_LL_ADDR, 0); 00216 00217 if (addr_is_ipv6_unspecified(buf->src_sa .address ) && sllao) { 00218 return buffer_free(buf); 00219 } 00220 00221 if (!cur->adv_send_advertisements) { 00222 return buffer_free(buf); 00223 } 00224 00225 ipv6_neighbour_t *neighbour; 00226 00227 if (sllao && cur->if_llao_parse(cur, sllao, &buf->dst_sa )) { 00228 neighbour = ipv6_neighbour_update_unsolicited(&cur->ipv6_neighbour_cache, buf->src_sa .address , buf->dst_sa .addr_type , buf->dst_sa .address ); 00229 } else { 00230 neighbour = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, buf->src_sa .address ); 00231 } 00232 00233 if (neighbour && neighbour->is_router) { 00234 ipv6_router_gone(&cur->ipv6_neighbour_cache, neighbour); 00235 } 00236 00237 const uint8_t *dest; 00238 dest = cur->rtr_adv_unicast_to_rs ? buf->src_sa .address : ADDR_LINK_LOCAL_ALL_NODES; 00239 00240 /* Yuck - unify later */ 00241 if (cur->nwk_id == IF_6LoWPAN) { 00242 /* This triggers 1 RA per ABRO (nd_router_t) */ 00243 nd_trigger_ras_from_rs(dest, cur); 00244 } else { 00245 /* Just trigger 1 RA without ABRO */ 00246 icmpv6_trigger_ra_from_rs(cur, dest, ADDR_UNSPECIFIED); 00247 } 00248 00249 return buffer_free(buf); 00250 } 00251 00252 /* (Re)start multicast router advertisements for a given ABRO, or unspecified. adv_send_advertisements must be set */ 00253 void icmpv6_restart_router_advertisements(protocol_interface_info_entry_t *cur, const uint8_t abro[16]) 00254 { 00255 icmp_queued_ra_t *ra; 00256 00257 if (!cur->adv_send_advertisements) { 00258 return; 00259 } 00260 00261 ipv6_ra_timing_t *t = icmpv6_ra_timing_lookup(cur, abro); 00262 if (!t) { 00263 return; 00264 } 00265 00266 ra = icmpv6_queued_ra_lookup(ADDR_LINK_LOCAL_ALL_NODES, abro, cur->id, NULL); 00267 if (ra) { 00268 icmpv6_unqueue_ra(ra); 00269 } else { 00270 ra = ns_dyn_mem_alloc(sizeof(icmp_queued_ra_t)); 00271 if (!ra) { 00272 return; 00273 } 00274 00275 memcpy(ra->addr, ADDR_LINK_LOCAL_ALL_NODES, 16); 00276 memcpy(ra->abro, abro, 16); 00277 ra->rs_triggered = false; 00278 ra->interface = cur; 00279 /* For a new transmission, if this is 0, we don't send anything initially, 00280 * but we still want randomness; on the other hand there's no point 00281 * having a minimum delay. So let's do it like this - equal random range, 00282 * but starting immediately. 00283 */ 00284 if (cur->max_initial_rtr_advertisements == 0) { 00285 ra->ticks = randLIB_get_random_in_range(0, cur->max_rtr_adv_interval - cur->min_rtr_adv_interval); 00286 } 00287 } 00288 00289 /* If we are retriggering "initial" adverts, should allow some jitter in case 00290 * we're doing it in response to a multicast update. 00291 */ 00292 if (cur->max_initial_rtr_advertisements != 0) { 00293 ra->ticks = randLIB_get_random_in_range(0, cur->max_initial_rtr_adv_interval); 00294 } 00295 00296 t->initial_rtr_adv_count = cur->max_initial_rtr_advertisements; 00297 00298 /* And enforce the rate limiting, if somehow we cancelled and restarted this TX */ 00299 uint16_t time_since_last = protocol_core_monotonic_time - t->rtr_adv_last_send_time; 00300 if (time_since_last < cur->min_delay_between_ras) { 00301 ra->ticks += cur->min_delay_between_ras - time_since_last; 00302 } 00303 00304 icmpv6_queue_ra(ra); 00305 } 00306 00307 /* Cancel scheduled router advertisements, either for a given ABRO (real or ADDR_UNSPECIFIED), or any ABRO (NULL) */ 00308 void icmpv6_stop_router_advertisements(protocol_interface_info_entry_t *cur, const uint8_t *abro) 00309 { 00310 ns_list_foreach_safe(icmp_queued_ra_t, ra, &icmp_ra_queue) { 00311 if (ra->interface == cur) { 00312 /* Match ABRO if specified */ 00313 if (abro && !addr_ipv6_equal(abro, ra->abro)) { 00314 continue; 00315 } 00316 00317 icmpv6_unqueue_ra(ra); 00318 ns_dyn_mem_free(ra); 00319 } 00320 } 00321 } 00322 00323 /* Actually send an RA - have to refer to protocol_ipv6.c and nd_router_object.c 00324 * at the moment, as the information is stored differently. 00325 */ 00326 static void icmpv6_send_ra(protocol_interface_info_entry_t *cur, const uint8_t *dest, const uint8_t *abro) 00327 { 00328 if (cur->nwk_id == IF_6LoWPAN) { 00329 nd_ra_build_by_abro(abro, dest, cur); 00330 } else { 00331 ipv6_nd_ra_advert(cur, dest); 00332 } 00333 } 00334 00335 void icmpv6_radv_timer(uint16_t ticks) 00336 { 00337 /* This initialises to empty (on every call) */ 00338 NS_LIST_DEFINE(to_requeue, icmp_queued_ra_t, link); 00339 00340 /* Ticks are relative in this queue - break once all ticks are consumed */ 00341 ns_list_foreach_safe(icmp_queued_ra_t, ra, &icmp_ra_queue) { 00342 if (ra->ticks > ticks) { 00343 /* Next entry doesn't fire yet - just decrease its time and exit */ 00344 ra->ticks -= ticks; 00345 break; 00346 } 00347 00348 /* Have a firing entry - note that once ticks reaches 0, we can still 00349 * consume multiple simultaneous entries with ra->ticks == 0, so 00350 * we don't stop as soon as ticks hits 0. */ 00351 ticks -= ra->ticks; 00352 00353 /* Just remove, not "unqueue" here, as we're in the process of adjusting ticks */ 00354 ns_list_remove(&icmp_ra_queue, ra); 00355 00356 ipv6_ra_timing_t *t = icmpv6_ra_timing_lookup(ra->interface, ra->abro); 00357 if (!t) { 00358 ns_dyn_mem_free(ra); 00359 } else { 00360 /* Safety check - make sure we shut down okay if this gets flipped off */ 00361 if (ra->interface->adv_send_advertisements) { 00362 icmpv6_send_ra(ra->interface, ra->addr, ra->abro); 00363 t->rtr_adv_last_send_time = protocol_core_monotonic_time; 00364 } 00365 00366 /* Multicast adverts get automatically rescheduled */ 00367 if (addr_is_ipv6_multicast(ra->addr) && ra->interface->adv_send_advertisements) { 00368 /* reschedule - for safe list handling, stash and reinsert after the main loop */ 00369 ra->ticks = randLIB_get_random_in_range(ra->interface->min_rtr_adv_interval, ra->interface->max_rtr_adv_interval); 00370 if (t->initial_rtr_adv_count && --t->initial_rtr_adv_count) { 00371 uint16_t max = ra->interface->max_initial_rtr_adv_interval; 00372 if (ra->ticks > max) { 00373 ra->ticks = max; 00374 } 00375 } 00376 ra->rs_triggered = false; 00377 ns_list_add_to_end(&to_requeue, ra); 00378 } else { 00379 ns_dyn_mem_free(ra); 00380 } 00381 } 00382 } 00383 00384 ns_list_foreach_safe(icmp_queued_ra_t, ra, &to_requeue) { 00385 ns_list_remove(&to_requeue, ra); 00386 icmpv6_queue_ra(ra); 00387 } 00388 } 00389 00390 #endif /* RADV_TX */
Generated on Fri Jul 22 2022 04:53:50 by
1.7.2
