BA
/
BaBoRo1
Embed:
(wiki syntax)
Show/hide line numbers
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 Tue Jul 12 2022 12:21:56 by
