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.
Dependents: cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more
ipv6.c
00001 /* 00002 * Copyright (c) 2013-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 #define _HAVE_IPV6 00020 00021 #ifdef _HAVE_IPV6 00022 00023 #include "ns_types.h" 00024 #include "string.h" 00025 #include "nsdynmemLIB.h" 00026 #include "Core/include/socket.h" 00027 #include "ns_trace.h" 00028 #include "NWK_INTERFACE/Include/protocol.h" 00029 #include "NWK_INTERFACE/Include/protocol_stats.h" 00030 #include "Common_Protocols/ipv6.h" 00031 #include "Common_Protocols/ipv6_fragmentation.h" 00032 #include "ipv6_stack/protocol_ipv6.h" 00033 #include "ipv6_stack/ipv6_routing_table.h" 00034 #include "Common_Protocols/ip.h" 00035 #include "Common_Protocols/icmpv6.h" 00036 #include "Common_Protocols/ipv6_resolution.h" 00037 #include "Common_Protocols/ipv6_flow.h" 00038 #include "RPL/rpl_data.h" 00039 #ifdef HAVE_MPL 00040 #include "MPL/mpl.h" 00041 #endif 00042 #include "Service_Libs/nd_proxy/nd_proxy.h" 00043 #include "common_functions.h" 00044 00045 #define TRACE_GROUP "ipv6" 00046 00047 static buffer_t *ipv6_consider_forwarding_multicast_packet(buffer_t *buf, protocol_interface_info_entry_t *cur, bool for_us); 00048 00049 static bool ipv6_packet_is_for_us(buffer_t *buf) 00050 { 00051 protocol_interface_info_entry_t *cur = buf->interface ; 00052 if (buf->dst_sa .addr_type != ADDR_IPV6 ) { 00053 return false; 00054 } 00055 00056 if (addr_is_ipv6_multicast(buf->dst_sa .address )) { 00057 return addr_am_group_member_on_interface(cur, buf->dst_sa .address ); 00058 } else if (addr_is_ipv6_loopback(buf->dst_sa .address )) { 00059 // We should have already dropped it if received externally 00060 return true; 00061 } else { 00062 return addr_interface_address_compare(cur, buf->dst_sa .address ) == 0; 00063 } 00064 } 00065 00066 static ipv6_exthdr_provider_fn_t *ipv6_exthdr_provider[ROUTE_MAX]; 00067 00068 /* On entry: 00069 * buf->route filled in with data from routing lookup, including source info 00070 * buf->dst = final destination 00071 * buf->src = source 00072 * Other metadata available (eg rpl info from parsing in up) 00073 * On exit: 00074 * buf->dst modified to next hop if source routing 00075 * Also possible to modify buf->route->next_hop_addr (eg RPL return to sender, 00076 * for forwarding-error, except where would you get the parent addr?) 00077 * 00078 * Return negative if failed (will usually end up treated as "no route" error). 00079 */ 00080 static buffer_t *ipv6_get_exthdrs(buffer_t *buf, ipv6_exthdr_stage_t stage, int16_t *result) 00081 { 00082 if (ipv6_exthdr_provider[buf->route->route_info.source]) { 00083 return ipv6_exthdr_provider[buf->route->route_info.source](buf, stage, result); 00084 } 00085 *result = 0; 00086 return buf; 00087 } 00088 00089 void ipv6_set_exthdr_provider(ipv6_route_src_t src, ipv6_exthdr_provider_fn_t *fn) 00090 { 00091 ipv6_exthdr_provider[src] = fn; 00092 } 00093 00094 00095 /* If next_if != NULL, this sends to next_hop on that interface */ 00096 buffer_routing_info_t *ipv6_buffer_route_to(buffer_t *buf, const uint8_t *next_hop, protocol_interface_info_entry_t *next_if) 00097 { 00098 buffer_routing_info_t *route; 00099 if (buf->route) { 00100 return buf->route; 00101 } 00102 00103 buf->route = route = ns_dyn_mem_temporary_alloc(sizeof(buffer_routing_info_t)); 00104 if (!route) { 00105 return NULL; 00106 } 00107 00108 route->ip_dest = NULL; 00109 route->ref_count = 1; 00110 00111 /* Realm-or-lower scope addresses must have interface specified */ 00112 bool interface_specific = addr_ipv6_scope(buf->dst_sa .address , buf->interface ) <= IPV6_SCOPE_REALM_LOCAL; 00113 protocol_interface_info_entry_t *cur = buf->interface ; 00114 if (cur == NULL && interface_specific) { 00115 goto no_route; 00116 } 00117 00118 ipv6_destination_t *dest_entry = ipv6_destination_lookup_or_create(buf->dst_sa .address , cur ? cur->id : -1); 00119 if (!dest_entry) { 00120 tr_err("ipv6_buffer_route no destination entry %s", trace_ipv6(buf->dst_sa .address )); 00121 goto no_route; 00122 } 00123 00124 #ifdef HAVE_IPV6_ND 00125 if (!next_hop && dest_entry->redirected) { 00126 next_hop = dest_entry->redirect_addr; 00127 next_if = protocol_stack_interface_info_get_by_id(dest_entry->interface_id); 00128 } 00129 #endif 00130 00131 if (next_hop && next_if) { 00132 if (interface_specific && next_if != buf->interface ) { 00133 tr_err("Next hop interface mismatch %s%%%d vs %s%%%d", trace_ipv6(buf->dst_sa .address ), buf->interface ->id, 00134 trace_ipv6(next_hop), next_if->id); 00135 } 00136 memcpy(route->route_info.next_hop_addr, next_hop, 16); 00137 route->route_info.interface_id = next_if->id; 00138 route->route_info.pmtu = 0xFFFF; 00139 route->route_info.source = ROUTE_REDIRECT; 00140 } else if (addr_is_ipv6_multicast(buf->dst_sa .address )) { 00141 /* 00142 * Multicast is handled specially - we always treat as on-link, so the 00143 * only thing used from the routing table is the interface selection. This 00144 * is what most network stacks do - basically means we direct on the 00145 * interface leading to the default router in most cases. We don't support 00146 * directing to a unicast next-hop, unless this was manually requested. 00147 */ 00148 if (!cur) { 00149 /* Choose interface (only) from routing table */ 00150 ipv6_route_t *ip_route = ipv6_route_choose_next_hop(buf->dst_sa .address , -1, NULL); 00151 if (!ip_route) { 00152 tr_debug("No route for multicast %s", trace_ipv6(buf->dst_sa .address )); 00153 goto no_route; 00154 } 00155 route->route_info.interface_id = ip_route->info.interface_id; 00156 } else { 00157 route->route_info.interface_id = cur->id; 00158 } 00159 memcpy(route->route_info.next_hop_addr, next_hop ? next_hop : buf->dst_sa .address , 16); 00160 route->route_info.pmtu = 0xFFFF; 00161 route->route_info.source = ROUTE_MULTICAST; 00162 } else /* unicast, normal */ { 00163 ipv6_route_predicate_fn_t *predicate = NULL; 00164 00165 #ifdef HAVE_RPL 00166 if (buf->rpl_instance_known) { 00167 if (!cur) { 00168 goto no_route; 00169 } 00170 /* Limit the route search so we don't match other RPL instances */ 00171 predicate = rpl_data_get_route_predicate(cur->rpl_domain, buf); 00172 } 00173 #endif 00174 00175 ipv6_route_t *ip_route = ipv6_route_choose_next_hop(buf->dst_sa .address , interface_specific ? cur->id : -1, predicate); 00176 if (!ip_route) { 00177 tr_debug("XXX ipv6_buffer_route no route to %s!", trace_ipv6(buf->dst_sa .address )); 00178 goto no_route; 00179 } 00180 00181 route->route_info = ip_route->info; 00182 /* Above line copies all the main route info, but for on-link routes, we 00183 * need to fill in next hop from the destination address. 00184 */ 00185 if (ip_route->on_link) { 00186 memcpy(route->route_info.next_hop_addr, buf->dst_sa .address , 16); 00187 } 00188 } 00189 00190 protocol_interface_info_entry_t *outgoing_if = protocol_stack_interface_info_get_by_id(route->route_info.interface_id); 00191 if (!outgoing_if) { 00192 goto no_route; // Shouldn't happen - internal error 00193 } 00194 00195 #ifdef HAVE_MPL 00196 if (outgoing_if->mpl_seed && buf->options .mpl_permitted && 00197 addr_is_ipv6_multicast(buf->dst_sa .address ) && 00198 addr_ipv6_multicast_scope(buf->dst_sa .address ) >= IPV6_SCOPE_REALM_LOCAL) { 00199 /* Special handling for MPL. Once we have decided we're sending to a 00200 * multicast next hop for a greater-than-realm-local destination, 00201 * if we're functioning as an MPL seed on that interface, we turn this 00202 * into an MPL route. If the destination matches a domain, MPL extension 00203 * header processing will add the necessary headers, else it will get 00204 * tunnelled to All-MPL-Forwarders (ff03::fc). 00205 */ 00206 route->route_info.source = ROUTE_MPL; 00207 } 00208 #endif 00209 00210 #ifndef NO_IPV6_PMTUD 00211 /* Update PMTU with first-hop link MTU (for initialisation, and may need to 00212 * reduce an existing entry if route has changed) */ 00213 if (dest_entry->pmtu > outgoing_if->ipv6_neighbour_cache.link_mtu) { 00214 dest_entry->pmtu = outgoing_if->ipv6_neighbour_cache.link_mtu; 00215 } 00216 /* Route can also limit PMTU */ 00217 if (dest_entry->pmtu > route->route_info.pmtu) { 00218 dest_entry->pmtu = route->route_info.pmtu; 00219 } 00220 /* Buffer then gets this PMTU (overwriting what we wrote from the route) */ 00221 route->route_info.pmtu = dest_entry->pmtu; 00222 #endif 00223 00224 dest_entry->interface_id = route->route_info.interface_id; 00225 if (!addr_is_ipv6_multicast(dest_entry->destination)) { 00226 dest_entry->last_neighbour = ipv6_neighbour_lookup_or_create(&outgoing_if->ipv6_neighbour_cache, route->route_info.next_hop_addr); 00227 } 00228 //tr_debug("%s->last_neighbour := %s", trace_ipv6(dest_entry->destination), trace_ipv6(route->route_info.next_hop_addr)); 00229 00230 if (!cur || route->route_info.interface_id != cur->id) { 00231 protocol_interface_info_entry_t *new_if = protocol_stack_interface_info_get_by_id(route->route_info.interface_id); 00232 if (!new_if) { 00233 goto no_route; 00234 } 00235 buf->interface = new_if; 00236 cur = new_if; 00237 } 00238 00239 if (buf->src_sa .addr_type == ADDR_NONE ) { 00240 const uint8_t *src = addr_select_source(cur, buf->dst_sa .address , 0); 00241 if (!src) { 00242 tr_debug("No source address"); 00243 goto no_route; 00244 } 00245 memcpy(buf->src_sa .address , src, 16); 00246 buf->src_sa .addr_type = ADDR_IPV6 ; 00247 } 00248 00249 return route; 00250 00251 no_route: 00252 ns_dyn_mem_free(buf->route); 00253 return buf->route = NULL; 00254 } 00255 00256 buffer_routing_info_t *ipv6_buffer_route(buffer_t *buf) 00257 { 00258 return ipv6_buffer_route_to(buf, NULL, NULL); 00259 } 00260 00261 /* Compute total IP header size requirements, before its construction 00262 * src and dst must be originator and final destination, and ipv6_buffer_route() 00263 * must have been called. This only counts the FIRST IP header and its extension headers - 00264 * RPL tunnelling takes more thought. 00265 * Doesn't account for fragmentation header. 00266 */ 00267 uint16_t ipv6_header_size_required(buffer_t *buf) 00268 { 00269 uint8_t hbh_options = 2; // dummy 2 for initial alignment 00270 uint16_t ip_size = IPV6_HDRLEN; 00271 00272 if (buf->options .ip_extflags & IPEXT_HBH_ROUTER_ALERT) { 00273 hbh_options += 4; 00274 } 00275 00276 #if 0 00277 /* If RPL source routing */ 00278 { 00279 ip_size += srh_size; 00280 } 00281 /* else If RPL up/down and NOT tunnelling, ie dest is RPL */ 00282 { 00283 hbh_options += 6; 00284 } 00285 00286 /* If MPL */ 00287 { 00288 hbh_options += mpl_option_size; // 4 or 6 00289 } 00290 #endif 00291 00292 if (hbh_options != 2) { 00293 ip_size += (hbh_options + 7) & ~ 7; 00294 } 00295 00296 return ip_size; 00297 } 00298 00299 uint16_t ipv6_max_unfragmented_payload(buffer_t *buf, uint16_t mtu_limit) 00300 { 00301 uint16_t ip_size = ipv6_header_size_required(buf); 00302 uint16_t pmtu = ipv6_mtu(buf); 00303 uint16_t frag_size; 00304 00305 if (pmtu < IPV6_MIN_LINK_MTU) { 00306 /* Small "PMTU" doesn't actually reduce our fragment size */ 00307 frag_size = IPV6_MIN_LINK_MTU; 00308 } else { 00309 frag_size = pmtu; 00310 } 00311 00312 if (mtu_limit && frag_size > mtu_limit) { 00313 frag_size = mtu_limit; 00314 } 00315 00316 /* If this is true, then we're exceeding a sub-minimum PMTU, so need to 00317 * include a fragment header, despite not actually fragmenting (RFC 2460, RFC 6415)*/ 00318 if (frag_size > pmtu) { 00319 ip_size += 8; 00320 } 00321 00322 return frag_size - ip_size; 00323 } 00324 00325 #ifdef NO_IP_FRAGMENT_TX 00326 #define ipv6_dontfrag(buf) true 00327 #else 00328 #define ipv6_dontfrag(buf) buf->options.ipv6_dontfrag 00329 #endif 00330 #ifdef NO_IPV6_PMTUD 00331 #define ipv6_use_min_mtu(buf) 1 00332 #else 00333 #define ipv6_use_min_mtu(buf) buf->options.ipv6_use_min_mtu 00334 #endif 00335 00336 /* Return the IPV6 MTU to use for a buffer to a specified final destination. 00337 * Gives result of Path MTU discovery, unless this is deactivated by 00338 * a socket option. 00339 * Note that the MTU returned may be less than the IPv6 minimum if there has 00340 * been such a "Packet Too Big" response (possibly due to IPv4<->IPv6 00341 * translation). In this case, it's up to the caller whether they want to 00342 * obey that MTU (presumably avoiding sub-IPv6 fragmentation at that link), 00343 * or use the IPv6 minimum (reducing work on other links, but presumably 00344 * necessitating sub-IPv6 fragmentation there). 00345 */ 00346 uint16_t ipv6_mtu(buffer_t *buf) 00347 { 00348 int8_t use_min_mtu = ipv6_use_min_mtu(buf); 00349 00350 if (use_min_mtu == -1) { 00351 use_min_mtu = addr_is_ipv6_multicast(buf->dst_sa .address ); 00352 } 00353 00354 if (use_min_mtu) { 00355 return IPV6_MIN_LINK_MTU; 00356 } 00357 00358 bool dontfrag = ipv6_dontfrag(buf); 00359 if (dontfrag) { 00360 return buf->interface ->ipv6_neighbour_cache.link_mtu; 00361 } else { 00362 return buf->route->route_info.pmtu; 00363 } 00364 } 00365 00366 static bool ipv6_fragmentation_needed(buffer_t *buf) 00367 { 00368 return buffer_data_length(buf) > ipv6_mtu(buf); 00369 } 00370 00371 /* Input: IP payload. dst/src as source and final destination, type=NH, tclass set. 00372 * Output: IP header added. With RPL HbH/SRH if necessary. 00373 * Buffer source/destination = IP source/destination (matching contents) 00374 */ 00375 buffer_t *ipv6_down(buffer_t *buf) 00376 { 00377 uint8_t *ptr; 00378 protocol_interface_info_entry_t *cur = 0; 00379 00380 buffer_routing_info_t *route = ipv6_buffer_route(buf); 00381 /* Note ipv6_buffer_route can change interface */ 00382 if (!route) { 00383 tr_warn("ipv6_down route fail"); 00384 drop: 00385 socket_tx_buffer_event_and_free(buf, SOCKET_NO_ROUTE); 00386 return NULL; 00387 } 00388 00389 cur = buf->interface ; 00390 if (cur == NULL) { 00391 tr_debug("ipv6_down Drop by Interface_PTR"); 00392 goto drop; 00393 } 00394 00395 if (buf->dst_sa .addr_type != ADDR_IPV6 ) { 00396 tr_debug("IP:Dest Not IPV6"); 00397 goto drop; 00398 } 00399 if (buf->src_sa .addr_type != ADDR_IPV6 ) { 00400 tr_debug("IP:SRC Not IPV6"); 00401 goto drop; 00402 } 00403 00404 /* Allow this to be decided at the last moment */ 00405 if (buf->options .hop_limit == 0) { 00406 buf->options .hop_limit = cur->cur_hop_limit; 00407 } 00408 00409 /* Choose a flow label if required (RFC 6437) */ 00410 if (buf->options .flow_label == IPV6_FLOW_UNSPECIFIED) { 00411 buf->options .flow_label = ipv6_flow_auto_label ? IPV6_FLOW_AUTOGENERATE : 0; 00412 } 00413 if (buf->options .flow_label < 0) { 00414 buf->options .flow_label = ipv6_flow_5tuple(buf->src_sa .address , buf->dst_sa .address , buf->options .type , buf->src_sa .port , buf->dst_sa .port ); 00415 } 00416 00417 /* Routing system can insert extension headers now */ 00418 /* If they want IP destination address changed (eg if inserting a routing 00419 * header), they can set buf->route.ip_dest. 00420 */ 00421 int16_t exthdr_result; 00422 buf = ipv6_get_exthdrs(buf, IPV6_EXTHDR_INSERT, &exthdr_result); 00423 if (!buf) { 00424 return NULL; 00425 } 00426 if (exthdr_result < 0) { 00427 goto drop; 00428 } 00429 00430 uint16_t payload_len = buffer_data_length(buf); 00431 00432 //tr_debug("IP Header Len: %02x", ip_header_len); 00433 uint16_t ip_hdr_len = ipv6_header_size_required(buf); 00434 00435 if ((buf = buffer_headroom(buf, ip_hdr_len)) == NULL) { 00436 return (buf); 00437 } 00438 ptr = buffer_data_reserve_header(buf, ip_hdr_len); 00439 ptr = common_write_32_bit((UINT32_C(6) << 28) | 00440 ((uint32_t)buf->options .traffic_class << 20) | 00441 (buf->options .flow_label & 0xfffff), ptr); 00442 ptr = common_write_16_bit((ip_hdr_len - IPV6_HDRLEN) + payload_len, ptr); 00443 /* Remember position of Next Header octet - we'll fill it later */ 00444 uint8_t *nh_ptr = ptr++; 00445 *ptr++ = buf->options .hop_limit ; 00446 00447 if (addr_is_ipv6_multicast(buf->src_sa .address )) { 00448 tr_err("Illegal source %s", tr_ipv6(ptr)); 00449 goto drop; 00450 } 00451 // Copy the source address (IPv6) 00452 memcpy(ptr, buf->src_sa .address , 16); 00453 ptr += 16; 00454 00455 // Copy the destination address (IPv6), either modified by routing, or 00456 // the original final destination. 00457 memcpy(ptr, buf->route->ip_dest ? buf->route->ip_dest : buf->dst_sa .address , 16); 00458 00459 // Last-minute enforcement of a couple of rules on destination from RFC 4291 00460 if (addr_is_ipv6_unspecified(ptr) || 00461 (addr_is_ipv6_multicast(ptr) && addr_ipv6_multicast_scope(ptr) == 0)) { 00462 tr_err("Illegal destination %s", tr_ipv6(ptr)); 00463 goto drop; 00464 } 00465 ptr += 16; 00466 00467 bool add_hbh = false; 00468 if (buf->options .ip_extflags & IPEXT_HBH_ROUTER_ALERT) { 00469 add_hbh = true; 00470 } 00471 00472 /* This HbH insertion would conflict with insertion from ipv6_get_exthdrs. */ 00473 /* Fortunately cases never overlap. */ 00474 if (add_hbh) { 00475 *nh_ptr = IPV6_NH_HOP_BY_HOP; 00476 nh_ptr = ptr; 00477 // Come back to fill these in later 00478 *ptr++ = IPV6_NH_NONE; 00479 *ptr++ = 0; 00480 00481 if (buf->options .ip_extflags & IPEXT_HBH_ROUTER_ALERT) { 00482 *ptr++ = IPV6_OPTION_ROUTER_ALERT; 00483 *ptr++ = 2; // Length 00484 ptr = common_write_16_bit(IPV6_ROUTER_ALERT_MLD, ptr); 00485 } 00486 #if 0 00487 if (multicast) { 00488 //tr_debug("TRIG Len; %02x", buf->trickle_data_len); 00489 *ptr++ = IPV6_OPTION_MPL; 00490 *ptr++ = buf->trickle_data_len; 00491 memcpy(ptr, buf->trickle_data_field, buf->trickle_data_len); 00492 ptr += buf->trickle_data_len; 00493 if (buf->trickle_data_len == 2) { 00494 *ptr++ = IPV6_OPTION_PADN; 00495 *ptr++ = 0; 00496 } 00497 } 00498 #endif 00499 uint8_t alignment = (ptr - nh_ptr) & 7; 00500 if (alignment) { 00501 uint8_t pad = 8 - alignment; 00502 if (pad == 1) { 00503 *ptr++ = IPV6_OPTION_PAD1; 00504 } else { 00505 *ptr++ = IPV6_OPTION_PADN; 00506 *ptr++ = (pad -= 2); 00507 while (pad) { 00508 *ptr = 0, pad--; 00509 } 00510 } 00511 } 00512 /* Go back and fill in the length byte */ 00513 nh_ptr[1] = ((ptr - nh_ptr) >> 3) - 1; 00514 } 00515 00516 #if 0 00517 if (src_route_len) { 00518 *nh_ptr = IPV6_NH_ROUTING; 00519 nh_ptr = ptr++; 00520 *ptr++ = src_route_len; 00521 ptr = gen_source_route_set(ptr); 00522 } 00523 #endif 00524 00525 // Fill in the previous Next Header field 00526 *nh_ptr = buf->options .type ; 00527 buf->options .type = 0; 00528 buf->options .code = 0; 00529 00530 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6 | B_TO_IPV6_FWD); 00531 00532 /* Divert to fragmentation if necessary */ 00533 if (ipv6_fragmentation_needed(buf)) { 00534 if (ipv6_dontfrag(buf)) { 00535 tr_debug("Packet too big"); 00536 goto drop; 00537 } else { 00538 return ipv6_frag_down(buf); 00539 } 00540 } 00541 00542 return buf; 00543 } 00544 00545 /* Input: IP packet, either locally-generated, or received and okay to forward 00546 * (XXX can currently distinguish with buf->ip_routed_up) 00547 * Buffer source/destination = IP source/destination (matching contents) 00548 * Output: Either go back for another IP header (tunnel entry) 00549 * or determine routing information, and pass to transmission. 00550 * Next hop IP address will be in buf->route->route_info.next_hop_addr. 00551 * (Or loop back up if it's for us). 00552 */ 00553 buffer_t *ipv6_forwarding_down(buffer_t *buf) 00554 { 00555 /* If it's for us, loop it back up. It goes back into forwarding up, as 00556 * we should process Destination headers etc... 00557 * (Note that we could theoretically go forwarding up/down a few times in 00558 * the event of a weird Routing Header) 00559 */ 00560 if (ipv6_packet_is_for_us(buf)) { 00561 if (addr_is_ipv6_multicast(buf->dst_sa .address )) { 00562 if (buf->options .multicast_loop ) { 00563 buffer_t *clone = buffer_clone(buf); 00564 if (clone) { 00565 clone->options .multicast_loop = true; // Flags that this is the loopback 00566 buffer_socket_set(clone, NULL); 00567 clone->info = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_FWD | B_TO_IPV6_FWD); 00568 protocol_push(clone); 00569 } 00570 buf->options .multicast_loop = false; // Clear flag, to ensure only 1 clone (eg if tunnelling) 00571 } 00572 } else { 00573 buffer_socket_set(buf, NULL); 00574 buf->info = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_FWD | B_TO_IPV6_FWD); 00575 return buf; 00576 } 00577 } 00578 00579 /* Note ipv6_buffer_route can change interface */ 00580 if (!ipv6_buffer_route(buf)) { 00581 protocol_stats_update(STATS_IP_NO_ROUTE, 1); 00582 tr_info("ipv6_forwarding route fail"); 00583 return icmpv6_error(buf, NULL, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_NO_ROUTE, 0); 00584 } 00585 00586 /* Allow routing code to update extension headers */ 00587 int16_t exthdr_result; 00588 buf = ipv6_get_exthdrs(buf, IPV6_EXTHDR_MODIFY, &exthdr_result); 00589 if (!buf) { 00590 return NULL; 00591 } 00592 if (exthdr_result < 0) { 00593 goto drop; 00594 } 00595 00596 if (!buf->ip_routed_up && addr_is_ipv6_multicast(buf->dst_sa .address )) { 00597 buf = ipv6_consider_forwarding_multicast_packet(buf, buf->interface , true); 00598 } 00599 00600 /* Routing code may say it needs to tunnel to add headers - loop back to IP layer if requested */ 00601 if (exthdr_result == IPV6_EXTHDR_MODIFY_TUNNEL) { 00602 /* Avoid an infinite loop in the event of routing code failure - never 00603 * let them ask for tunnelling more than once. 00604 */ 00605 if (buf->options .tunnelled ) { 00606 tr_error("Tunnel recursion"); 00607 goto drop; 00608 } 00609 buf->options .tunnelled = true; 00610 00611 buf->options .ip_extflags = 0; 00612 00613 /* Provide tunnel source, unless already set */ 00614 if (buf->src_sa .addr_type == ADDR_NONE ) { 00615 protocol_interface_info_entry_t *cur = buf->interface ; 00616 if (!cur) { 00617 goto drop; 00618 } 00619 if (addr_interface_select_source(cur, buf->src_sa .address , buf->dst_sa .address , 0) < 0) { 00620 tr_error("No tunnel source address"); 00621 goto drop; 00622 } 00623 buf->src_sa .addr_type = ADDR_IPV6 ; 00624 } 00625 /* Hop Limit copied from inner packet (maybe already decremented) */ 00626 /* ECN copied from inner packet (RFC 6040 normal mode) */ 00627 #ifdef RFC6040_COMPATIBILITY_MODE 00628 buf->options .traffic_class &=~ IP_TCLASS_ECN_MASK; 00629 #endif 00630 /* DSCP copied from inner packet */ 00631 buf->options .type = IPV6_NH_IPV6; 00632 if (ipv6_flow_auto_label) { 00633 /* Compute new flow label from inner src, dst, flow (RFC 6438) */ 00634 const uint8_t *iphdr = buffer_data_pointer(buf); 00635 uint_fast24_t flow = common_read_24_bit(iphdr + IPV6_HDROFF_FLOW_LABEL) & 0xFFFFF; 00636 buf->options .flow_label = ipv6_flow_2tuple_flow(iphdr + IPV6_HDROFF_SRC_ADDR, iphdr + IPV6_HDROFF_DST_ADDR, flow); 00637 } else { 00638 buf->options .flow_label = 0; 00639 } 00640 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6_FWD | B_TO_IPV6); 00641 return buf; 00642 } 00643 00644 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6 | B_TO_IPV6_TXRX); 00645 return buf; 00646 00647 drop: 00648 socket_tx_buffer_event_and_free(buf, SOCKET_NO_ROUTE); 00649 return NULL; 00650 } 00651 00652 #if defined HAVE_RPL || defined HAVE_MPL 00653 /* Tunnel exit is only needed (and allowed!) for RPL and MPL */ 00654 #define IP_ECN__DROP -1 00655 00656 /* 00657 * 4x4 array implementing the ECN combination rules from RFC 6040. 00658 * 00659 * Summary visualisation: Outer 00660 * N01C 00661 * +---- 00662 * N|NNN- 00663 * Inner 0|001C 00664 * 1|111C 00665 * C|CCCC 00666 * 00667 * Each of the 16 entries [outer][inner], with justification: 00668 */ 00669 static const int8_t exit_ecn_combination[4][4] = { 00670 // If the inner is Not-ECT, we mustn't propagate ECN markings onwards 00671 // So we strip off any capability flags 00672 [IP_ECN_NOT_ECT][IP_ECN_NOT_ECT] = IP_ECN_NOT_ECT, 00673 [IP_ECN_ECT_0 ][IP_ECN_NOT_ECT] = IP_ECN_NOT_ECT, 00674 [IP_ECN_ECT_1 ][IP_ECN_NOT_ECT] = IP_ECN_NOT_ECT, 00675 00676 // And if we see congestion experienced, we drop to indicate congestion 00677 [IP_ECN_CE ][IP_ECN_NOT_ECT] = IP_ECN__DROP, 00678 00679 // If inner supports ECN, we set outgoing to most severe (C>1>0>N) 00680 [IP_ECN_NOT_ECT][IP_ECN_ECT_0 ] = IP_ECN_ECT_0, 00681 [IP_ECN_ECT_0 ][IP_ECN_ECT_0 ] = IP_ECN_ECT_0, 00682 [IP_ECN_ECT_1 ][IP_ECN_ECT_0 ] = IP_ECN_ECT_1, 00683 [IP_ECN_CE ][IP_ECN_ECT_0 ] = IP_ECN_CE, 00684 00685 [IP_ECN_NOT_ECT][IP_ECN_ECT_1 ] = IP_ECN_ECT_1, 00686 [IP_ECN_ECT_0 ][IP_ECN_ECT_1 ] = IP_ECN_ECT_1, 00687 [IP_ECN_ECT_1 ][IP_ECN_ECT_1 ] = IP_ECN_ECT_1, 00688 [IP_ECN_CE ][IP_ECN_ECT_1 ] = IP_ECN_CE, 00689 00690 [IP_ECN_NOT_ECT][IP_ECN_CE ] = IP_ECN_CE, 00691 [IP_ECN_ECT_0 ][IP_ECN_CE ] = IP_ECN_CE, 00692 [IP_ECN_ECT_1 ][IP_ECN_CE ] = IP_ECN_CE, 00693 [IP_ECN_CE ][IP_ECN_CE ] = IP_ECN_CE, 00694 }; 00695 00696 /* On entry, buf is original IPv6 packet, payload points to outer packet's 00697 * protocol payload (ie the start of the inner IPv6 header.) 00698 */ 00699 static buffer_t *ipv6_tunnel_exit(buffer_t *buf, uint8_t *payload) 00700 { 00701 /* We're stripping the IP header - need the HBH header for future reference */ 00702 if ((buf->options .ip_extflags & IPEXT_HBH_RPL) && !rpl_data_remember_outer(buf)) { 00703 goto drop; 00704 } 00705 00706 buf->options .ip_extflags = 0; 00707 00708 buffer_data_pointer_set(buf, payload); 00709 00710 /* 00711 * First 8 bytes of the IP header that we need to patch: 00712 * . . . . . 00713 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00714 * |Version| DSCP |ECN| Flow Label | 00715 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00716 * | Payload Length | Next Header | Hop Limit | 00717 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00718 */ 00719 00720 if (buffer_data_length(buf) >= IPV6_HDRLEN) { 00721 /* RFC 6040 - combine ECN */ 00722 uint8_t inner_tclass = (payload[0] << 4) | (payload[1] >> 4); 00723 uint8_t outer_ecn = buf->options .traffic_class & IP_TCLASS_ECN_MASK; 00724 uint8_t inner_ecn = inner_tclass & IP_TCLASS_ECN_MASK; 00725 uint8_t inner_dscp = inner_tclass & IP_TCLASS_DSCP_MASK; 00726 int8_t outgoing_ecn = exit_ecn_combination[outer_ecn][inner_ecn]; 00727 if (outgoing_ecn == IP_ECN__DROP) { 00728 goto drop; 00729 } 00730 00731 /* RFC 2983 uniform model - copy DSCP from inner packet */ 00732 uint8_t outgoing_tclass = inner_dscp | outgoing_ecn; 00733 00734 /* Write the outgoing traffic-class field */ 00735 payload[0] = (payload[0] & 0xf0) | (outgoing_tclass >> 4); 00736 payload[1] = (outgoing_tclass << 4) | (payload[1] & 0x0f); 00737 00738 /* We would like RFC 3443-style "uniform model" Hop Limit handling. As 00739 * tunnel entry, we transfer the Hop Limit from the inner to the outer 00740 * packet. On exit we transfer from outer back to inner (and outer must 00741 * be lower than inner). Just in case another entry implementation didn't do 00742 * this and set a big outer, we take the minimum of inner and outer. 00743 */ 00744 if (payload[IPV6_HDROFF_HOP_LIMIT] > buf->options .hop_limit ) { 00745 payload[IPV6_HDROFF_HOP_LIMIT] = buf->options .hop_limit ; 00746 } 00747 } 00748 00749 00750 buf->info = (buffer_info_t)(B_DIR_UP | B_TO_IPV6_FWD | B_FROM_IPV6_FWD); 00751 return buf; 00752 00753 drop: 00754 protocol_stats_update(STATS_IP_RX_DROP, 1); 00755 return buffer_free(buf); 00756 } 00757 #endif /* HAVE_MPL || HAVE_RPL */ 00758 00759 static buffer_t *ipv6_handle_options(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *ptr, uint8_t nh, uint16_t payload_length, uint16_t *hdrlen_out, const sockaddr_t *ll_src, bool pre_fragment) 00760 { 00761 (void) nh; 00762 if (payload_length < 2) { 00763 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4); 00764 } 00765 00766 uint16_t hlen = (ptr[1] + 1) * 8; 00767 if (payload_length < hlen) { 00768 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, (ptr + 1) - buffer_data_pointer(buf)); 00769 } 00770 00771 if (pre_fragment) { 00772 *hdrlen_out = hlen; 00773 return buf; 00774 } 00775 00776 uint8_t *opt = ptr + 2; 00777 const uint8_t *const end = ptr + hlen; 00778 while (opt < end) { 00779 if (opt[0] == IPV6_OPTION_PAD1) { 00780 opt++; 00781 continue; 00782 } 00783 uint8_t opt_type = *opt++; 00784 if (opt >= end) { 00785 goto len_err; 00786 } 00787 uint8_t optlen = *opt++; 00788 if (opt + optlen > end) { 00789 goto len_err; 00790 } 00791 switch (opt_type) { 00792 #ifdef HAVE_RPL 00793 case IPV6_OPTION_RPL: 00794 if (!cur->rpl_domain) { 00795 goto drop; 00796 } 00797 if (optlen < 4) { 00798 goto len_err; 00799 } 00800 if (!rpl_data_process_hbh(buf, cur, opt, ll_src)) { 00801 goto drop; 00802 } 00803 break; 00804 #endif 00805 #ifdef HAVE_MPL 00806 case IPV6_OPTION_MPL: 00807 if (!mpl_hbh_len_check(opt, optlen)) { 00808 goto len_err; 00809 } 00810 if (!mpl_process_hbh(buf, cur, opt)) { 00811 goto drop; 00812 } 00813 break; 00814 #endif 00815 default: 00816 opt_type &= IPV6_OPTION_ACTION_MASK; 00817 if (opt_type == IPV6_OPTION_ACTION_SKIP) { 00818 break; 00819 } 00820 if (opt_type == IPV6_OPTION_ACTION_ERROR || 00821 (opt_type == IPV6_OPTION_ACTION_ERROR_UNICAST && !addr_is_ipv6_multicast(buf->dst_sa .address ))) { 00822 return icmpv6_error(buf, NULL, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_UNREC_IPV6_OPT, (opt - 2) - buffer_data_pointer(buf)); 00823 } 00824 /* falling to */ 00825 drop: 00826 protocol_stats_update(STATS_IP_RX_DROP, 1); 00827 return buffer_free(buf); 00828 00829 len_err: 00830 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, (opt - 1) - buffer_data_pointer(buf)); 00831 } 00832 opt += optlen; 00833 } 00834 00835 *hdrlen_out = hlen; 00836 00837 return buf; 00838 } 00839 00840 static buffer_t *ipv6_handle_routing_header(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *ptr, uint16_t payload_length, uint16_t *hdrlen_out, bool *forward_out, bool pre_fragment) 00841 { 00842 if (buf->options .ll_security_bypass_rx ) { 00843 tr_warn("Routing header: Security check fail"); 00844 protocol_stats_update(STATS_IP_RX_DROP, 1); 00845 return buffer_free(buf); 00846 } 00847 00848 if (payload_length < 4) { 00849 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4); 00850 } 00851 00852 uint16_t hlen = (ptr[1] + 1) * 8; 00853 if (payload_length < hlen) { 00854 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, (ptr + 1) - buffer_data_pointer(buf)); 00855 } 00856 00857 if (pre_fragment) { 00858 *hdrlen_out = hlen; 00859 return buf; 00860 } 00861 00862 uint8_t type = ptr[2]; 00863 uint8_t segs_left = ptr[3]; 00864 switch (type) { 00865 #ifdef HAVE_RPL 00866 case IPV6_ROUTING_TYPE_RPL: 00867 return rpl_data_process_routing_header(buf, cur, ptr, hdrlen_out, forward_out); 00868 #endif 00869 default: 00870 /* Unknown type: if segments left is 0, we ignore the header, else return an error */ 00871 if (segs_left == 0) { 00872 *hdrlen_out = hlen; 00873 } else { 00874 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, (ptr + 2) - buffer_data_pointer(buf)); 00875 } 00876 break; 00877 } 00878 00879 return buf; 00880 } 00881 00882 static buffer_t *ipv6_consider_forwarding_unicast_packet(buffer_t *buf, protocol_interface_info_entry_t *cur, const sockaddr_t *ll_src) 00883 { 00884 /* Security checks needed here before forwarding */ 00885 if (buf->options .ll_security_bypass_rx ) { 00886 tr_warn("IP Forward: Security check fail dst %s",trace_ipv6(buf->dst_sa .address )); 00887 protocol_stats_update(STATS_IP_RX_DROP, 1); 00888 return buffer_free(buf); 00889 } 00890 00891 if (cur->if_special_forwarding) { 00892 bool bounce = false; 00893 buf = cur->if_special_forwarding(cur, buf, ll_src, &bounce); 00894 if (!buf || bounce) { 00895 return buf; 00896 } 00897 } 00898 00899 if (!cur->ip_forwarding || 00900 addr_is_ipv6_loopback(buf->dst_sa .address ) || 00901 addr_is_ipv6_unspecified(buf->src_sa .address )) { 00902 protocol_stats_update(STATS_IP_RX_DROP, 1); 00903 return buffer_free(buf); 00904 } 00905 00906 /* Hop limit check and decrement */ 00907 if (buf->options .hop_limit <= 1) { 00908 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_TIME_EXCEEDED, ICMPV6_CODE_TME_EXCD_HOP_LIM_EXCD, 0); 00909 } 00910 00911 /* Routing rules may require us not to send back to our predecessor */ 00912 buffer_note_predecessor(buf, ll_src); 00913 00914 buf->ip_routed_up = true; 00915 buffer_data_pointer(buf)[IPV6_HDROFF_HOP_LIMIT] = --buf->options .hop_limit ; 00916 00917 /* Not for us, let's think about forwarding */ 00918 /* Note ipv6_buffer_route can change interface */ 00919 buffer_routing_info_t *routing = ipv6_buffer_route(buf); 00920 00921 if (!routing) { 00922 protocol_stats_update(STATS_IP_NO_ROUTE, 1); 00923 #ifdef HAVE_RPL 00924 if (rpl_data_forwarding_error(buf)) { 00925 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6_FWD | B_TO_IPV6_FWD); 00926 return buf; 00927 } 00928 #endif 00929 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_NO_ROUTE, 0); 00930 } 00931 00932 protocol_interface_info_entry_t *out_interface; 00933 out_interface = buf->interface ; 00934 00935 #ifdef HAVE_RPL 00936 /* We must not let RPL-bearing packets out of or into a RPL domain */ 00937 if (buf->options .ip_extflags & (IPEXT_HBH_RPL|IPEXT_SRH_RPL)) { 00938 if (out_interface->rpl_domain != cur->rpl_domain || !rpl_data_is_rpl_route(routing->route_info.source)) { 00939 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_ADM_PROHIB, 0); 00940 } 00941 } 00942 #endif 00943 /* If heading out a different interface, some extra scope checks for 00944 * crossing a zone boundary (see RFC 4007). 00945 */ 00946 if (out_interface->id != cur->id) { 00947 uint_fast8_t src_scope = addr_ipv6_scope(buf->src_sa .address , cur); 00948 /* Check source scope (standard RFC 4007 test) */ 00949 if (out_interface->zone_index[src_scope] != cur->zone_index[src_scope]) { 00950 buf->interface = cur; 00951 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_BEYOND_SCOPE, 0); 00952 } 00953 //#ifdef THREAD_SUPPORT 00954 /* Handle a Thread-specific wrinkle - Thread's "Realm-local" address 00955 * is really a ULA, so is global on other interfaces, and is treated 00956 * as such for routing purposes. There's nothing in the routing system 00957 * stopping a packet going into or out of Thread with a Realm-local 00958 * address. The generic code above has handled the case: 00959 * 00960 * Thread->External src=RL ("Beyond scope of source address") 00961 * 00962 * Here we block the other cases: 00963 * 00964 * External->Thread src=RL ("Source address failed ingress/egress policy") 00965 * Thread<->External dst=RL ("Communication with destination administratively prohibited") 00966 * 00967 * (NB if a real Realm-local address was defined, then we'd make routing 00968 * treat it like link-local, and we'd never find ourselves routing 00969 * to another interface, catching the first two cases, and the last 00970 * would have been caught by "Beyond scope of source address"). 00971 */ 00972 if (addr_ipv6_scope(buf->src_sa .address , out_interface) <= IPV6_SCOPE_REALM_LOCAL) { 00973 buf->interface = cur; 00974 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_SRC_FAILED_POLICY, 0); 00975 } 00976 if (addr_ipv6_scope(buf->dst_sa .address , out_interface) <= IPV6_SCOPE_REALM_LOCAL || 00977 addr_ipv6_scope(buf->dst_sa .address , cur) <= IPV6_SCOPE_REALM_LOCAL) { 00978 buf->interface = cur; 00979 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_ADM_PROHIB, 0); 00980 } 00981 //#endif 00982 } 00983 00984 /* route_info.pmtu will cover limits from both the interface and the 00985 * route. As a bonus, it will also cover any PMTUD we happen to have done 00986 * to that destination ourselves, as well as mop up any tunnelling issues. 00987 */ 00988 if (routing->route_info.pmtu < buffer_data_length(buf)) { 00989 buf->interface = cur; 00990 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PACKET_TOO_BIG, 0, routing->route_info.pmtu); 00991 } 00992 00993 /* Pass to "forwarding down" */ 00994 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6_FWD | B_TO_IPV6_FWD); 00995 return buf; 00996 } 00997 00998 void ipv6_transmit_multicast_on_interface(buffer_t *buf, protocol_interface_info_entry_t *cur) 00999 { 01000 /* Mess with routing to get this to go out the correct interface */ 01001 buf->interface = cur; 01002 if (!ipv6_buffer_route_to(buf, buf->dst_sa .address , cur)) { 01003 buffer_free(buf); 01004 return; 01005 } 01006 01007 /* Send straight to IP transmission? Or to forwarding down? */ 01008 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6_FWD | B_TO_IPV6_FWD); 01009 protocol_push(buf); 01010 } 01011 01012 #ifdef MULTICAST_FORWARDING 01013 static void ipv6_forward_multicast_onto_interface(buffer_t *buf, protocol_interface_info_entry_t *cur) 01014 { 01015 if (!buf) { 01016 return; 01017 } 01018 01019 if (buf->ip_routed_up) { 01020 buffer_data_pointer(buf)[IPV6_HDROFF_HOP_LIMIT] = --buf->options .hop_limit ; 01021 } 01022 buf->ip_routed_up = true; 01023 // Make sure we receive a copy if we are a member on this interface 01024 buf->options .multicast_loop = true; 01025 // Setting direction to DOWN indicates to special forwarding that hop limit is appropriate for outgoing interface 01026 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6_FWD | B_TO_IPV6_FWD); 01027 01028 if (cur->if_special_multicast_forwarding) { 01029 cur->if_special_multicast_forwarding(cur, buf); 01030 } 01031 01032 ipv6_transmit_multicast_on_interface(buf, cur); 01033 } 01034 #endif 01035 01036 /* Traditional multicast forwarding - from one interface to other(s). 01037 * Used for example for ff05::1 across the border router. This is limited to 01038 * scop values 4 and up, as we assume realms don't cross interfaces. 01039 * 01040 * This is distinct from MPL, which runs its own forwarding strategy. That is 01041 * used for scop 3 (realm). [It could run at higher scopes, except the MPL 01042 * code currently only transmits on 1 interface - rather than repeating on 01043 * multiple]. 01044 * 01045 * The two can be mixed, eg by encapsulating an ff05::1 packet in an MPL 01046 * packet to ff03::fc. That would be spread by the MPL forwarding logic, and 01047 * the border router would de-encapsulate and forward to Ethernet via this. 01048 */ 01049 01050 /* "For us" tells us that we need to return the buffer (or a copy) - if false, we don't */ 01051 /* This controls copying logic. */ 01052 static buffer_t *ipv6_consider_forwarding_multicast_packet(buffer_t *buf, protocol_interface_info_entry_t *cur, bool for_us) 01053 { 01054 /* Security checks needed here before forwarding */ 01055 if (buf->options .ll_security_bypass_rx ) { 01056 goto no_forward; 01057 } 01058 01059 /* Locally-sourced packets are forwarded on the way down. Don't do it again if we loop back for applications */ 01060 if ((buf->info & B_DIR_MASK) == B_DIR_UP && buf->options .multicast_loop ) { 01061 goto no_forward; 01062 } 01063 01064 /* Hop limit check */ 01065 if (buf->options .hop_limit <= 1) { 01066 goto no_forward; 01067 } 01068 01069 if (!cur->ip_multicast_forwarding || 01070 addr_is_ipv6_unspecified(buf->src_sa .address )) { 01071 goto no_forward; 01072 } 01073 01074 if (cur->if_special_multicast_forwarding) { 01075 cur->if_special_multicast_forwarding(cur, buf); 01076 } 01077 01078 uint_fast8_t group_scope = addr_ipv6_multicast_scope(buf->dst_sa .address ); 01079 uint_fast8_t src_scope = addr_ipv6_scope(buf->src_sa .address , cur); 01080 01081 #ifdef HAVE_MPL 01082 /* MPL does its own thing - we do not perform any "native" forwarding */ 01083 if (buf->options .ip_extflags & IPEXT_HBH_MPL) { 01084 goto no_forward; 01085 } 01086 #endif 01087 01088 #ifdef MULTICAST_FORWARDING 01089 /* Look at reverse path - check our route to the source address */ 01090 ipv6_route_t *route = ipv6_route_choose_next_hop(buf->src_sa .address , cur->id, NULL); 01091 01092 /* Only forward if it came from the interface leading to the source address */ 01093 if (!route || route->info.interface_id != cur->id) { 01094 goto no_forward; 01095 } 01096 01097 /* Mess around to minimise copies - initially no interface needs a packet */ 01098 protocol_interface_info_entry_t *fwd_interface = NULL; 01099 uint16_t ptb_mtu = 0xFFFF; 01100 01101 ns_list_foreach(protocol_interface_info_entry_t, interface, &protocol_interface_info_list) { 01102 if (interface != cur && 01103 interface->ip_multicast_forwarding && 01104 interface->zone_index[group_scope] == cur->zone_index[group_scope] && 01105 interface->zone_index[src_scope] == cur->zone_index[src_scope] && 01106 (group_scope >= interface->ip_mcast_fwd_for_scope || 01107 addr_multicast_fwd_check(interface, buf->dst_sa .address ))) { 01108 01109 /* This interface seems to want a packet. Couple more checks first */ 01110 if (buffer_data_length(buf) > interface->ipv6_neighbour_cache.link_mtu) { 01111 if (interface->ipv6_neighbour_cache.link_mtu < ptb_mtu) { 01112 ptb_mtu = interface->ipv6_neighbour_cache.link_mtu; 01113 } 01114 continue; 01115 } 01116 /* If we already have a previous interface to forward to, give them a clone now */ 01117 if (fwd_interface) { 01118 ipv6_forward_multicast_onto_interface(buffer_clone(buf), fwd_interface); 01119 } 01120 /* And remember this interface */ 01121 fwd_interface = interface; 01122 } 01123 } 01124 01125 /* We may need to report "packet too big" */ 01126 if (ptb_mtu != 0xFFFF && cur->icmp_tokens) { 01127 if (for_us || fwd_interface) { 01128 /* Someone else still needs a packet - clone for the error */ 01129 buffer_t *clone = buffer_clone(buf); 01130 if (clone) { 01131 protocol_push(icmpv6_error(clone, cur, ICMPV6_TYPE_ERROR_PACKET_TOO_BIG, 0, ptb_mtu)); 01132 } 01133 } else { 01134 /* Noone else needs a packet - consume for the error */ 01135 protocol_push(icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PACKET_TOO_BIG, 0, ptb_mtu)); 01136 return NULL; 01137 } 01138 } 01139 01140 if (fwd_interface) { 01141 /* We have 1 remaining interface to forward onto - clone or not depending on whether we need it */ 01142 if (for_us) { 01143 ipv6_forward_multicast_onto_interface(buffer_clone(buf), fwd_interface); 01144 return buf; 01145 } else { 01146 ipv6_forward_multicast_onto_interface(buf, fwd_interface); 01147 return NULL; 01148 } 01149 } 01150 #endif 01151 no_forward: 01152 /* Base functionality - if it's for us, return it, else bin it */ 01153 if (for_us) { 01154 return buf; 01155 } else { 01156 return buffer_free(buf); 01157 } 01158 } 01159 01160 01161 buffer_t *ipv6_forwarding_up(buffer_t *buf) 01162 { 01163 uint8_t *ptr = buffer_data_pointer(buf); 01164 uint16_t len = buffer_data_length(buf); 01165 uint8_t *nh_ptr; 01166 protocol_interface_info_entry_t *cur; 01167 bool intercept = false; 01168 01169 /* When processing a reassembled packet, we don't reprocess headers from before the fragment header */ 01170 uint16_t frag_offset; 01171 01172 cur = buf->interface ; 01173 01174 // Make sure that this is a v6 header (just in case...) 01175 if (!cur || len < IPV6_HDRLEN || (*ptr >> 4) != 6) { 01176 goto drop; 01177 } 01178 01179 if (buf->options .ip_extflags & IPEXT_FRAGMENT) { 01180 // Remember the flags for headers we parsed before the fragment header; 01181 // we won't re-parse them, and expect the metadata (from the first fragment) 01182 // to survive reassembly. 01183 frag_offset = buf->offset ; 01184 buf->options .ip_extflags &=~ IPEXT_FRAGMENT; 01185 tr_debug("Processing fragment from %d", frag_offset); 01186 } else { 01187 // Clear all info - extension header parsers will set 01188 frag_offset = 0; 01189 buf->options .ip_extflags = 0; 01190 } 01191 01192 buf->options .traffic_class = (ptr[0] << 4) | (ptr[1] >> 4); 01193 // Just skip Flow Label for now 01194 ptr += 4; 01195 01196 uint16_t payload_length = common_read_16_bit(ptr); 01197 ptr += 2; 01198 01199 // "Parameter problem" needs this pointer to Next Header field 01200 nh_ptr = ptr++; 01201 01202 // May as well note the outermost NH field now; will update later 01203 // if we go to an upper layer. 01204 buf->options .type = *nh_ptr; 01205 buf->options .code = 0; 01206 01207 // Read the Hop Limit 01208 buf->options .hop_limit = *ptr++; 01209 01210 // Remember the link-layer address for "special forwarding" check 01211 sockaddr_t ll_src = buf->src_sa ; 01212 sockaddr_t ll_dst = buf->dst_sa ; 01213 01214 // Get the Source Address 01215 memcpy(buf->src_sa .address , ptr, 16); 01216 buf->src_sa .addr_type = ADDR_IPV6 ; 01217 ptr += 16; 01218 01219 // Get the Destination Address 01220 memcpy(buf->dst_sa .address , ptr, 16); 01221 buf->dst_sa .addr_type = ADDR_IPV6 ; 01222 ptr += 16; 01223 01224 /* XXX I'm using ip_routed_up as a "received from outside this node" check 01225 * Not sure if that was original intent... We do want to accept it if it came 01226 * from inside this node. 01227 */ 01228 if (addr_is_ipv6_multicast(buf->src_sa .address ) || 01229 (buf->ip_routed_up && (addr_is_ipv6_loopback(buf->dst_sa .address ) || 01230 addr_is_ipv6_loopback(buf->src_sa .address ))) 01231 ) { 01232 goto drop; 01233 } 01234 01235 if (addr_is_ipv6_multicast(buf->dst_sa .address )) { 01236 /* RFC 4291 says we must drop multicast packets with scope 0 */ 01237 if (addr_ipv6_multicast_scope(buf->dst_sa .address ) == 0) { 01238 goto drop; 01239 } 01240 } else { 01241 /* RFC 1122 and 1812 say we SHOULD silently discard packets with unicast IP 01242 * address but link-layer multicast or broadcast. And we MUST NOT forward 01243 * them. So catch them here. 01244 */ 01245 if (buf->options .ll_multicast_rx || buf->options .ll_broadcast_rx ) { 01246 goto drop; 01247 } 01248 } 01249 01250 /* If security bypass is set, we only allow link-local traffic (unicast 01251 * or multicast with link-local scope), as per ZigBee IP 01252 */ 01253 if (buf->options .ll_security_bypass_rx ) { 01254 if (addr_ipv6_scope(buf->dst_sa .address , cur) != IPV6_SCOPE_LINK_LOCAL) { 01255 goto drop; 01256 } 01257 } 01258 01259 if (IPV6_HDRLEN + payload_length > buffer_data_length(buf)) { 01260 // Return "Parameter problem", pointing at Payload Length 01261 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4); 01262 } 01263 01264 /* Trim buffer if it's longer than payload length stated in IP header */ 01265 if (IPV6_HDRLEN + payload_length < buffer_data_length(buf)) { 01266 buffer_data_length_set(buf, IPV6_HDRLEN + payload_length); 01267 } 01268 01269 /* Handle any hop-by-hop options first, before checking destination */ 01270 if (*nh_ptr == IPV6_NH_HOP_BY_HOP) { 01271 uint16_t hdrlen = 0; 01272 if (payload_length == 0) { 01273 // RFC 2675 - return "Parameter problem", pointing at Payload Length 01274 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4); 01275 } 01276 buf = ipv6_handle_options(buf, cur, ptr, IPV6_NH_HOP_BY_HOP, payload_length, &hdrlen, &ll_src, ptr - buffer_data_pointer(buf) < frag_offset); 01277 if (hdrlen == 0) { 01278 /* Something went wrong - it will have freed buf or turned it into an ICMP error */ 01279 return buf; 01280 } 01281 nh_ptr = ptr; 01282 ptr += hdrlen; 01283 payload_length -= hdrlen; 01284 } 01285 01286 if (buf->options .ll_not_ours_rx ) { 01287 /* Wasn't addressed to us, but interface sent it up. It must now tell us 01288 * what to do with the packet. Options: 01289 * 1) Drop it (it frees) 01290 * 2) Bounce it (turns buffer into response, sets bounce true) 01291 * 3) Accept or forward as normal based on IP destination (returns buffer, clearing ll_not_ours_rx) 01292 * 4) Treat it as for us regardless of IP destination (returns buffer, leaving ll_not_ours_rx set) 01293 */ 01294 bool bounce = false; 01295 buf = cur->if_snoop(cur, buf, &ll_dst, &ll_src, &bounce); 01296 if (!buf || bounce) { 01297 return buf; 01298 } 01299 intercept = buf->options .ll_not_ours_rx ; 01300 } 01301 01302 if (*nh_ptr == IPV6_NH_ICMPV6 && payload_length >= 4 && ptr[0] == ICMPV6_TYPE_INFO_NS) { 01303 /* Treat as ours, let NS reply */ 01304 intercept = true; 01305 } 01306 01307 #ifdef HAVE_MPL 01308 /* We don't reprocess if this is a reassembly - each fragment is its own MPL 01309 * Data Message, and we already processed them. 01310 */ 01311 if ((buf->options .ip_extflags & IPEXT_HBH_MPL) && !frag_offset) { 01312 if (!mpl_forwarder_process_message(buf, NULL, false)) { 01313 /* False return means "duplicate" or other reason not to process */ 01314 return buffer_free(buf); 01315 } 01316 } 01317 #endif 01318 01319 bool for_us = intercept || ipv6_packet_is_for_us(buf); 01320 01321 if (addr_is_ipv6_multicast(buf->dst_sa .address )) { 01322 /* Multicast forwarding is told whether we're interested. It may 01323 * clone or take ownership of the buffer, depending on for_us. If not 01324 * forwarding or for us, it will bin. 01325 */ 01326 buf = ipv6_consider_forwarding_multicast_packet(buf, cur, for_us); 01327 if (!buf) { 01328 return NULL; 01329 } 01330 } else { /* unicast */ 01331 if (!for_us) { 01332 return ipv6_consider_forwarding_unicast_packet(buf, cur, &ll_src); 01333 } 01334 } 01335 01336 /* Its destination is us (or we're intercepting) - start munching headers */ 01337 /* Guess this should ultimately be the "CIPV6" up layer */ 01338 for (;;) { 01339 uint16_t hdrlen = 0; 01340 if (payload_length == 0 && *nh_ptr != IPV6_NH_NONE) { 01341 // RFC 2675 - return "Parameter problem", pointing at Payload Length 01342 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4); 01343 } 01344 switch (*nh_ptr) { 01345 case IPV6_NH_NONE: 01346 return buffer_free(buf); 01347 case IPV6_NH_DEST_OPT: 01348 buf = ipv6_handle_options(buf, cur, ptr, IPV6_NH_DEST_OPT, payload_length, &hdrlen, &ll_src, ptr - buffer_data_pointer(buf) < frag_offset); 01349 nh_ptr = ptr; 01350 break; 01351 #ifndef NO_IP_FRAGMENT_RX 01352 case IPV6_NH_FRAGMENT: 01353 return ipv6_frag_up(buf, ptr, nh_ptr, payload_length); 01354 #endif 01355 case IPV6_NH_ROUTING: { 01356 bool forward = false; 01357 buf = ipv6_handle_routing_header(buf, cur, ptr, payload_length, &hdrlen, &forward, ptr - buffer_data_pointer(buf) < frag_offset); 01358 if (forward) { 01359 /* Note that forwarding will cope with looping back if next address is 01360 * actually ours. We do want to always treat it as forwarding, as we do 01361 * want hop counts decremented, etc. 01362 */ 01363 return ipv6_consider_forwarding_unicast_packet(buf, cur, &ll_src); 01364 } 01365 nh_ptr = ptr; 01366 break; 01367 } 01368 case IPV6_NH_UDP: 01369 buf->info = (buffer_info_t)(B_DIR_UP | B_TO_UDP | B_FROM_IPV6_FWD); 01370 /* UDP may want to generate ICMP "port unreachable", so we leave the 01371 * IP headers unconsumed, setting offset to point to the UDP header 01372 */ 01373 buf->options .type = IPV6_NH_UDP; 01374 buf->offset = ptr - buffer_data_pointer(buf); 01375 return buf; 01376 #ifndef NO_TCP 01377 case IPV6_NH_TCP: 01378 buf->info = (buffer_info_t)(B_DIR_UP | B_TO_TCP | B_FROM_IPV6_FWD); 01379 goto upper_layer; 01380 #endif 01381 case IPV6_NH_ICMPV6: 01382 buf->info = (buffer_info_t)(B_DIR_UP | B_TO_ICMP | B_FROM_IPV6_FWD); 01383 goto upper_layer; 01384 #if defined HAVE_RPL || defined HAVE_MPL 01385 case IPV6_NH_IPV6: 01386 /* Tunnel support is only used for RPL or MPL. Only permit tunnel exit if there was 01387 * a RPL or MPL HbH option header, or RPL SRH header. Gives security, as 01388 * long as border router doesn't forward such packets into RPL/MPL domain. 01389 */ 01390 if (!(buf->options .ip_extflags & (IPEXT_HBH_RPL|IPEXT_SRH_RPL|IPEXT_HBH_MPL))) { 01391 goto bad_nh; 01392 } 01393 buffer_note_predecessor(buf, &ll_src); 01394 buf->options .type = *nh_ptr; 01395 return ipv6_tunnel_exit(buf, ptr); 01396 #endif 01397 default: { 01398 if (buf->options .ll_security_bypass_rx ) { 01399 goto bad_nh; 01400 } 01401 buffer_socket_set(buf, socket_lookup_ipv6(*nh_ptr, &buf->dst_sa , &buf->src_sa , true)); 01402 if (!buf->socket ) { 01403 goto bad_nh; 01404 } 01405 buf->info = (buffer_info_t)(B_DIR_UP | B_TO_APP | B_FROM_IPV6_FWD); 01406 goto upper_layer; 01407 } 01408 bad_nh: 01409 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_UNREC_NEXT_HDR, nh_ptr - buffer_data_pointer(buf)); 01410 } 01411 if (hdrlen == 0) { 01412 /* Something went wrong in an extension header - it will have freed buf or turned it into an ICMP error */ 01413 return buf; 01414 } 01415 ptr += hdrlen; 01416 payload_length -= hdrlen; 01417 } 01418 upper_layer: 01419 buf->options .type = *nh_ptr; 01420 buffer_data_pointer_set(buf, ptr); 01421 return buf; 01422 01423 drop: 01424 protocol_stats_update(STATS_IP_RX_DROP, 1); 01425 return buffer_free(buf); 01426 } 01427 01428 #endif /* _HAVE_IPV6 */
Generated on Tue Jul 12 2022 13:02:56 by
