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: TYBLE16_simple_data_logger TYBLE16_MP3_Air
ipv6.c
00001 /* 00002 * Copyright (c) 2013-2019, 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/ns_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 /* Consider multicast forwarding /before/ calling routing code to modify 00587 * extension headers - if that actually decides to tunnel it will 00588 * overwrite the buffer's src_sa and dst_sa, when we want to consider 00589 * forwarding the inner packet. This ordering works out for our only 00590 * header-modifying multicast case of MPL: 00591 * 1) We never want to forward packets with MPL headers, which means the 00592 * outer packet in a tunnel gets ignored anyway. 00593 * 2) This also means we don't have to worry that we're forwarding packets 00594 * with the extension header not filled in yet. 00595 * If we ever do have a multicast system where we are working with 00596 * extension headers and forwarding those across interfaces, ipv6_get_exthdrs 00597 * system will need a rework - probably split the "try MODIFY" call from the 00598 * subsequent "give me tunnel parameters" part. 00599 */ 00600 if (!buf->ip_routed_up && addr_is_ipv6_multicast(buf->dst_sa .address )) { 00601 buf = ipv6_consider_forwarding_multicast_packet(buf, buf->interface , true); 00602 } 00603 00604 /* Allow routing code to update extension headers */ 00605 int16_t exthdr_result; 00606 buf = ipv6_get_exthdrs(buf, IPV6_EXTHDR_MODIFY, &exthdr_result); 00607 if (!buf) { 00608 return NULL; 00609 } 00610 if (exthdr_result < 0) { 00611 goto drop; 00612 } 00613 00614 /* Routing code may say it needs to tunnel to add headers - loop back to IP layer if requested */ 00615 if (exthdr_result == IPV6_EXTHDR_MODIFY_TUNNEL) { 00616 /* Avoid an infinite loop in the event of routing code failure - never 00617 * let them ask for tunnelling more than once. 00618 */ 00619 if (buf->options .tunnelled ) { 00620 tr_error("Tunnel recursion"); 00621 goto drop; 00622 } 00623 buf->options .tunnelled = true; 00624 00625 buf->options .ip_extflags = 0; 00626 00627 /* Provide tunnel source, unless already set */ 00628 if (buf->src_sa .addr_type == ADDR_NONE ) { 00629 protocol_interface_info_entry_t *cur = buf->interface ; 00630 if (!cur) { 00631 goto drop; 00632 } 00633 if (addr_interface_select_source(cur, buf->src_sa .address , buf->dst_sa .address , 0) < 0) { 00634 tr_error("No tunnel source address"); 00635 goto drop; 00636 } 00637 buf->src_sa .addr_type = ADDR_IPV6 ; 00638 } 00639 /* Hop Limit copied from inner packet (maybe already decremented) */ 00640 /* ECN copied from inner packet (RFC 6040 normal mode) */ 00641 #ifdef RFC6040_COMPATIBILITY_MODE 00642 buf->options .traffic_class &= ~ IP_TCLASS_ECN_MASK; 00643 #endif 00644 /* DSCP copied from inner packet */ 00645 buf->options .type = IPV6_NH_IPV6; 00646 if (ipv6_flow_auto_label) { 00647 /* Compute new flow label from inner src, dst, flow (RFC 6438) */ 00648 const uint8_t *iphdr = buffer_data_pointer(buf); 00649 uint_fast24_t flow = common_read_24_bit(iphdr + IPV6_HDROFF_FLOW_LABEL) & 0xFFFFF; 00650 buf->options .flow_label = ipv6_flow_2tuple_flow(iphdr + IPV6_HDROFF_SRC_ADDR, iphdr + IPV6_HDROFF_DST_ADDR, flow); 00651 } else { 00652 buf->options .flow_label = 0; 00653 } 00654 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6_FWD | B_TO_IPV6); 00655 return buf; 00656 } 00657 00658 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6 | B_TO_IPV6_TXRX); 00659 return buf; 00660 00661 drop: 00662 socket_tx_buffer_event_and_free(buf, SOCKET_NO_ROUTE); 00663 return NULL; 00664 } 00665 00666 #if defined HAVE_RPL || defined HAVE_MPL 00667 /* Tunnel exit is only needed (and allowed!) for RPL and MPL */ 00668 #define IP_ECN__DROP -1 00669 00670 /* 00671 * 4x4 array implementing the ECN combination rules from RFC 6040. 00672 * 00673 * Summary visualisation: Outer 00674 * N01C 00675 * +---- 00676 * N|NNN- 00677 * Inner 0|001C 00678 * 1|111C 00679 * C|CCCC 00680 * 00681 * Each of the 16 entries [outer][inner], with justification: 00682 */ 00683 static const int8_t exit_ecn_combination[4][4] = { 00684 // If the inner is Not-ECT, we mustn't propagate ECN markings onwards 00685 // So we strip off any capability flags 00686 [IP_ECN_NOT_ECT][IP_ECN_NOT_ECT] = IP_ECN_NOT_ECT, 00687 [IP_ECN_ECT_0 ][IP_ECN_NOT_ECT] = IP_ECN_NOT_ECT, 00688 [IP_ECN_ECT_1 ][IP_ECN_NOT_ECT] = IP_ECN_NOT_ECT, 00689 00690 // And if we see congestion experienced, we drop to indicate congestion 00691 [IP_ECN_CE ][IP_ECN_NOT_ECT] = IP_ECN__DROP, 00692 00693 // If inner supports ECN, we set outgoing to most severe (C>1>0>N) 00694 [IP_ECN_NOT_ECT][IP_ECN_ECT_0 ] = IP_ECN_ECT_0, 00695 [IP_ECN_ECT_0 ][IP_ECN_ECT_0 ] = IP_ECN_ECT_0, 00696 [IP_ECN_ECT_1 ][IP_ECN_ECT_0 ] = IP_ECN_ECT_1, 00697 [IP_ECN_CE ][IP_ECN_ECT_0 ] = IP_ECN_CE, 00698 00699 [IP_ECN_NOT_ECT][IP_ECN_ECT_1 ] = IP_ECN_ECT_1, 00700 [IP_ECN_ECT_0 ][IP_ECN_ECT_1 ] = IP_ECN_ECT_1, 00701 [IP_ECN_ECT_1 ][IP_ECN_ECT_1 ] = IP_ECN_ECT_1, 00702 [IP_ECN_CE ][IP_ECN_ECT_1 ] = IP_ECN_CE, 00703 00704 [IP_ECN_NOT_ECT][IP_ECN_CE ] = IP_ECN_CE, 00705 [IP_ECN_ECT_0 ][IP_ECN_CE ] = IP_ECN_CE, 00706 [IP_ECN_ECT_1 ][IP_ECN_CE ] = IP_ECN_CE, 00707 [IP_ECN_CE ][IP_ECN_CE ] = IP_ECN_CE, 00708 }; 00709 00710 /* On entry, buf is original IPv6 packet, payload points to outer packet's 00711 * protocol payload (ie the start of the inner IPv6 header.) 00712 */ 00713 static buffer_t *ipv6_tunnel_exit(buffer_t *buf, uint8_t *payload) 00714 { 00715 /* We're stripping the IP header - need the HBH header for future reference */ 00716 if ((buf->options .ip_extflags & IPEXT_HBH_RPL) && !rpl_data_remember_outer(buf)) { 00717 goto drop; 00718 } 00719 00720 buf->options .ip_extflags = 0; 00721 00722 buffer_data_pointer_set(buf, payload); 00723 00724 /* 00725 * First 8 bytes of the IP header that we need to patch: 00726 * . . . . . 00727 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00728 * |Version| DSCP |ECN| Flow Label | 00729 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00730 * | Payload Length | Next Header | Hop Limit | 00731 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00732 */ 00733 00734 if (buffer_data_length(buf) >= IPV6_HDRLEN) { 00735 /* RFC 6040 - combine ECN */ 00736 uint8_t inner_tclass = (payload[0] << 4) | (payload[1] >> 4); 00737 uint8_t outer_ecn = buf->options .traffic_class & IP_TCLASS_ECN_MASK; 00738 uint8_t inner_ecn = inner_tclass & IP_TCLASS_ECN_MASK; 00739 uint8_t inner_dscp = inner_tclass & IP_TCLASS_DSCP_MASK; 00740 int8_t outgoing_ecn = exit_ecn_combination[outer_ecn][inner_ecn]; 00741 if (outgoing_ecn == IP_ECN__DROP) { 00742 goto drop; 00743 } 00744 00745 /* RFC 2983 uniform model - copy DSCP from inner packet */ 00746 uint8_t outgoing_tclass = inner_dscp | outgoing_ecn; 00747 00748 /* Write the outgoing traffic-class field */ 00749 payload[0] = (payload[0] & 0xf0) | (outgoing_tclass >> 4); 00750 payload[1] = (outgoing_tclass << 4) | (payload[1] & 0x0f); 00751 00752 /* We would like RFC 3443-style "uniform model" Hop Limit handling. As 00753 * tunnel entry, we transfer the Hop Limit from the inner to the outer 00754 * packet. On exit we transfer from outer back to inner (and outer must 00755 * be lower than inner). Just in case another entry implementation didn't do 00756 * this and set a big outer, we take the minimum of inner and outer. 00757 */ 00758 if (payload[IPV6_HDROFF_HOP_LIMIT] > buf->options .hop_limit ) { 00759 payload[IPV6_HDROFF_HOP_LIMIT] = buf->options .hop_limit ; 00760 } 00761 } 00762 00763 00764 buf->info = (buffer_info_t)(B_DIR_UP | B_TO_IPV6_FWD | B_FROM_IPV6_FWD); 00765 return buf; 00766 00767 drop: 00768 protocol_stats_update(STATS_IP_RX_DROP, 1); 00769 return buffer_free(buf); 00770 } 00771 #endif /* HAVE_MPL || HAVE_RPL */ 00772 00773 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) 00774 { 00775 (void) nh; 00776 if (payload_length < 2) { 00777 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4); 00778 } 00779 00780 uint16_t hlen = (ptr[1] + 1) * 8; 00781 if (payload_length < hlen) { 00782 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, (ptr + 1) - buffer_data_pointer(buf)); 00783 } 00784 00785 if (pre_fragment) { 00786 *hdrlen_out = hlen; 00787 return buf; 00788 } 00789 00790 uint8_t *opt = ptr + 2; 00791 const uint8_t *const end = ptr + hlen; 00792 while (opt < end) { 00793 if (opt[0] == IPV6_OPTION_PAD1) { 00794 opt++; 00795 continue; 00796 } 00797 uint8_t opt_type = *opt++; 00798 if (opt >= end) { 00799 goto len_err; 00800 } 00801 uint8_t optlen = *opt++; 00802 if (opt + optlen > end) { 00803 goto len_err; 00804 } 00805 switch (opt_type) { 00806 #ifdef HAVE_RPL 00807 case IPV6_OPTION_RPL: 00808 if (!cur->rpl_domain) { 00809 goto drop; 00810 } 00811 if (optlen < 4) { 00812 goto len_err; 00813 } 00814 if (!rpl_data_process_hbh(buf, cur, opt, ll_src)) { 00815 goto drop; 00816 } 00817 break; 00818 #endif 00819 #ifdef HAVE_MPL 00820 case IPV6_OPTION_MPL: 00821 if (!mpl_hbh_len_check(opt, optlen)) { 00822 goto len_err; 00823 } 00824 if (!mpl_process_hbh(buf, cur, opt)) { 00825 goto drop; 00826 } 00827 break; 00828 #endif 00829 default: 00830 opt_type &= IPV6_OPTION_ACTION_MASK; 00831 if (opt_type == IPV6_OPTION_ACTION_SKIP) { 00832 break; 00833 } 00834 if (opt_type == IPV6_OPTION_ACTION_ERROR || 00835 (opt_type == IPV6_OPTION_ACTION_ERROR_UNICAST && !addr_is_ipv6_multicast(buf->dst_sa .address ))) { 00836 return icmpv6_error(buf, NULL, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_UNREC_IPV6_OPT, (opt - 2) - buffer_data_pointer(buf)); 00837 } 00838 /* falling to */ 00839 drop: 00840 protocol_stats_update(STATS_IP_RX_DROP, 1); 00841 return buffer_free(buf); 00842 00843 len_err: 00844 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, (opt - 1) - buffer_data_pointer(buf)); 00845 } 00846 opt += optlen; 00847 } 00848 00849 *hdrlen_out = hlen; 00850 00851 return buf; 00852 } 00853 00854 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) 00855 { 00856 if (buf->options .ll_security_bypass_rx ) { 00857 tr_warn("Routing header: Security check fail"); 00858 protocol_stats_update(STATS_IP_RX_DROP, 1); 00859 return buffer_free(buf); 00860 } 00861 00862 if (payload_length < 4) { 00863 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4); 00864 } 00865 00866 uint16_t hlen = (ptr[1] + 1) * 8; 00867 if (payload_length < hlen) { 00868 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, (ptr + 1) - buffer_data_pointer(buf)); 00869 } 00870 00871 if (pre_fragment) { 00872 *hdrlen_out = hlen; 00873 return buf; 00874 } 00875 00876 uint8_t type = ptr[2]; 00877 uint8_t segs_left = ptr[3]; 00878 switch (type) { 00879 #ifdef HAVE_RPL 00880 case IPV6_ROUTING_TYPE_RPL: 00881 return rpl_data_process_routing_header(buf, cur, ptr, hdrlen_out, forward_out); 00882 #endif 00883 default: 00884 /* Unknown type: if segments left is 0, we ignore the header, else return an error */ 00885 if (segs_left == 0) { 00886 *hdrlen_out = hlen; 00887 } else { 00888 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, (ptr + 2) - buffer_data_pointer(buf)); 00889 } 00890 break; 00891 } 00892 00893 return buf; 00894 } 00895 00896 static buffer_t *ipv6_consider_forwarding_unicast_packet(buffer_t *buf, protocol_interface_info_entry_t *cur, const sockaddr_t *ll_src) 00897 { 00898 /* Security checks needed here before forwarding */ 00899 if (buf->options .ll_security_bypass_rx ) { 00900 tr_warn("IP Forward: Security check fail dst %s", trace_ipv6(buf->dst_sa .address )); 00901 protocol_stats_update(STATS_IP_RX_DROP, 1); 00902 return buffer_free(buf); 00903 } 00904 00905 if (cur->if_special_forwarding) { 00906 bool bounce = false; 00907 buf = cur->if_special_forwarding(cur, buf, ll_src, &bounce); 00908 if (!buf || bounce) { 00909 return buf; 00910 } 00911 } 00912 00913 if (!cur->ip_forwarding || 00914 addr_is_ipv6_loopback(buf->dst_sa .address ) || 00915 addr_is_ipv6_unspecified(buf->src_sa .address )) { 00916 protocol_stats_update(STATS_IP_RX_DROP, 1); 00917 return buffer_free(buf); 00918 } 00919 00920 /* Hop limit check and decrement */ 00921 if (buf->options .hop_limit <= 1) { 00922 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_TIME_EXCEEDED, ICMPV6_CODE_TME_EXCD_HOP_LIM_EXCD, 0); 00923 } 00924 00925 /* Routing rules may require us not to send back to our predecessor */ 00926 buffer_note_predecessor(buf, ll_src); 00927 00928 buf->ip_routed_up = true; 00929 buffer_data_pointer(buf)[IPV6_HDROFF_HOP_LIMIT] = --buf->options .hop_limit ; 00930 00931 /* Not for us, let's think about forwarding */ 00932 /* Note ipv6_buffer_route can change interface */ 00933 buffer_routing_info_t *routing = ipv6_buffer_route(buf); 00934 00935 if (!routing) { 00936 protocol_stats_update(STATS_IP_NO_ROUTE, 1); 00937 #ifdef HAVE_RPL 00938 if (rpl_data_forwarding_error(buf)) { 00939 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6_FWD | B_TO_IPV6_FWD); 00940 return buf; 00941 } 00942 #endif 00943 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_NO_ROUTE, 0); 00944 } 00945 00946 protocol_interface_info_entry_t *out_interface; 00947 out_interface = buf->interface ; 00948 00949 #ifdef HAVE_RPL 00950 /* We must not let RPL-bearing packets out of or into a RPL domain */ 00951 if (buf->options .ip_extflags & (IPEXT_HBH_RPL | IPEXT_SRH_RPL)) { 00952 if (out_interface->rpl_domain != cur->rpl_domain || !rpl_data_is_rpl_route(routing->route_info.source)) { 00953 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_ADM_PROHIB, 0); 00954 } 00955 } 00956 #endif 00957 /* If heading out a different interface, some extra scope checks for 00958 * crossing a zone boundary (see RFC 4007). 00959 */ 00960 if (out_interface->id != cur->id) { 00961 uint_fast8_t src_scope = addr_ipv6_scope(buf->src_sa .address , cur); 00962 /* Check source scope (standard RFC 4007 test) */ 00963 if (out_interface->zone_index[src_scope] != cur->zone_index[src_scope]) { 00964 buf->interface = cur; 00965 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_BEYOND_SCOPE, 0); 00966 } 00967 //#ifdef THREAD_SUPPORT 00968 /* Handle a Thread-specific wrinkle - Thread's "Realm-local" address 00969 * is really a ULA, so is global on other interfaces, and is treated 00970 * as such for routing purposes. There's nothing in the routing system 00971 * stopping a packet going into or out of Thread with a Realm-local 00972 * address. The generic code above has handled the case: 00973 * 00974 * Thread->External src=RL ("Beyond scope of source address") 00975 * 00976 * Here we block the other cases: 00977 * 00978 * External->Thread src=RL ("Source address failed ingress/egress policy") 00979 * Thread<->External dst=RL ("Communication with destination administratively prohibited") 00980 * 00981 * (NB if a real Realm-local address was defined, then we'd make routing 00982 * treat it like link-local, and we'd never find ourselves routing 00983 * to another interface, catching the first two cases, and the last 00984 * would have been caught by "Beyond scope of source address"). 00985 */ 00986 if (addr_ipv6_scope(buf->src_sa .address , out_interface) <= IPV6_SCOPE_REALM_LOCAL) { 00987 buf->interface = cur; 00988 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_SRC_FAILED_POLICY, 0); 00989 } 00990 if (addr_ipv6_scope(buf->dst_sa .address , out_interface) <= IPV6_SCOPE_REALM_LOCAL || 00991 addr_ipv6_scope(buf->dst_sa .address , cur) <= IPV6_SCOPE_REALM_LOCAL) { 00992 buf->interface = cur; 00993 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_ADM_PROHIB, 0); 00994 } 00995 //#endif 00996 } 00997 00998 /* route_info.pmtu will cover limits from both the interface and the 00999 * route. As a bonus, it will also cover any PMTUD we happen to have done 01000 * to that destination ourselves, as well as mop up any tunnelling issues. 01001 */ 01002 if (routing->route_info.pmtu < buffer_data_length(buf)) { 01003 buf->interface = cur; 01004 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PACKET_TOO_BIG, 0, routing->route_info.pmtu); 01005 } 01006 01007 /* Pass to "forwarding down" */ 01008 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6_FWD | B_TO_IPV6_FWD); 01009 return buf; 01010 } 01011 01012 void ipv6_transmit_multicast_on_interface(buffer_t *buf, protocol_interface_info_entry_t *cur) 01013 { 01014 /* Mess with routing to get this to go out the correct interface */ 01015 buf->interface = cur; 01016 if (!ipv6_buffer_route_to(buf, buf->dst_sa .address , cur)) { 01017 buffer_free(buf); 01018 return; 01019 } 01020 01021 /* Send straight to IP transmission? Or to forwarding down? */ 01022 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6_FWD | B_TO_IPV6_FWD); 01023 protocol_push(buf); 01024 } 01025 01026 #ifdef MULTICAST_FORWARDING 01027 static void ipv6_forward_multicast_onto_interface(buffer_t *buf, protocol_interface_info_entry_t *cur) 01028 { 01029 if (!buf) { 01030 return; 01031 } 01032 01033 if (buf->ip_routed_up) { 01034 buffer_data_pointer(buf)[IPV6_HDROFF_HOP_LIMIT] = --buf->options .hop_limit ; 01035 } 01036 buf->ip_routed_up = true; 01037 // Make sure we receive a copy if we are a member on this interface 01038 buf->options .multicast_loop = true; 01039 // Setting direction to DOWN indicates to special forwarding that hop limit is appropriate for outgoing interface 01040 buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_IPV6_FWD | B_TO_IPV6_FWD); 01041 01042 if (cur->if_special_multicast_forwarding) { 01043 cur->if_special_multicast_forwarding(cur, buf); 01044 } 01045 01046 ipv6_transmit_multicast_on_interface(buf, cur); 01047 } 01048 #endif 01049 01050 /* Traditional multicast forwarding - from one interface to other(s). 01051 * Used for example for ff05::1 across the border router. This is limited to 01052 * scop values 4 and up, as we assume realms don't cross interfaces. 01053 * 01054 * This is distinct from MPL, which runs its own forwarding strategy. That is 01055 * used for scop 3 (realm). [It could run at higher scopes, except the MPL 01056 * code currently only transmits on 1 interface - rather than repeating on 01057 * multiple]. 01058 * 01059 * The two can be mixed, eg by encapsulating an ff05::1 packet in an MPL 01060 * packet to ff03::fc. That would be spread by the MPL forwarding logic, and 01061 * the border router would de-encapsulate and forward to Ethernet via this. 01062 */ 01063 01064 /* "For us" tells us that we need to return the buffer (or a copy) - if false, we don't */ 01065 /* This controls copying logic. */ 01066 static buffer_t *ipv6_consider_forwarding_multicast_packet(buffer_t *buf, protocol_interface_info_entry_t *cur, bool for_us) 01067 { 01068 /* Security checks needed here before forwarding */ 01069 if (buf->options .ll_security_bypass_rx ) { 01070 goto no_forward; 01071 } 01072 01073 /* Locally-sourced packets are forwarded on the way down. Don't do it again if we loop back for applications */ 01074 if ((buf->info & B_DIR_MASK) == B_DIR_UP && buf->options .multicast_loop ) { 01075 goto no_forward; 01076 } 01077 01078 /* Hop limit check */ 01079 if (buf->options .hop_limit <= 1) { 01080 goto no_forward; 01081 } 01082 01083 if (!cur->ip_multicast_forwarding || 01084 addr_is_ipv6_unspecified(buf->src_sa .address )) { 01085 goto no_forward; 01086 } 01087 01088 if (cur->if_special_multicast_forwarding) { 01089 cur->if_special_multicast_forwarding(cur, buf); 01090 } 01091 01092 #ifdef HAVE_MPL 01093 /* MPL does its own thing - we do not perform any "native" forwarding */ 01094 if (buf->options .ip_extflags & IPEXT_HBH_MPL) { 01095 goto no_forward; 01096 } 01097 #endif 01098 01099 #ifdef MULTICAST_FORWARDING 01100 uint_fast8_t group_scope = addr_ipv6_multicast_scope(buf->dst_sa .address ); 01101 uint_fast8_t src_scope = addr_ipv6_scope(buf->src_sa .address , cur); 01102 01103 /* Look at reverse path - check our route to the source address */ 01104 ipv6_route_t *route = ipv6_route_choose_next_hop(buf->src_sa .address , cur->id, NULL); 01105 01106 /* Only forward if it came from the interface leading to the source address */ 01107 if (!route || route->info.interface_id != cur->id) { 01108 goto no_forward; 01109 } 01110 01111 /* Mess around to minimise copies - initially no interface needs a packet */ 01112 protocol_interface_info_entry_t *fwd_interface = NULL; 01113 uint16_t ptb_mtu = 0xFFFF; 01114 01115 ns_list_foreach(protocol_interface_info_entry_t, interface, &protocol_interface_info_list) { 01116 if (interface != cur && 01117 interface->ip_multicast_forwarding && 01118 interface->zone_index[group_scope] == cur->zone_index[group_scope] && 01119 interface->zone_index[src_scope] == cur->zone_index[src_scope] && 01120 (group_scope >= interface->ip_mcast_fwd_for_scope || 01121 addr_multicast_fwd_check(interface, buf->dst_sa .address ))) { 01122 01123 /* This interface seems to want a packet. Couple more checks first */ 01124 if (buffer_data_length(buf) > interface->ipv6_neighbour_cache.link_mtu) { 01125 if (interface->ipv6_neighbour_cache.link_mtu < ptb_mtu) { 01126 ptb_mtu = interface->ipv6_neighbour_cache.link_mtu; 01127 } 01128 continue; 01129 } 01130 /* If we already have a previous interface to forward to, give them a clone now */ 01131 if (fwd_interface) { 01132 ipv6_forward_multicast_onto_interface(buffer_clone(buf), fwd_interface); 01133 } 01134 /* And remember this interface */ 01135 fwd_interface = interface; 01136 } 01137 } 01138 01139 /* We may need to report "packet too big" */ 01140 if (ptb_mtu != 0xFFFF && cur->icmp_tokens) { 01141 if (for_us || fwd_interface) { 01142 /* Someone else still needs a packet - clone for the error */ 01143 buffer_t *clone = buffer_clone(buf); 01144 if (clone) { 01145 protocol_push(icmpv6_error(clone, cur, ICMPV6_TYPE_ERROR_PACKET_TOO_BIG, 0, ptb_mtu)); 01146 } 01147 } else { 01148 /* Noone else needs a packet - consume for the error */ 01149 protocol_push(icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PACKET_TOO_BIG, 0, ptb_mtu)); 01150 return NULL; 01151 } 01152 } 01153 01154 if (fwd_interface) { 01155 /* We have 1 remaining interface to forward onto - clone or not depending on whether we need it */ 01156 if (for_us) { 01157 ipv6_forward_multicast_onto_interface(buffer_clone(buf), fwd_interface); 01158 return buf; 01159 } else { 01160 ipv6_forward_multicast_onto_interface(buf, fwd_interface); 01161 return NULL; 01162 } 01163 } 01164 #endif 01165 no_forward: 01166 /* Base functionality - if it's for us, return it, else bin it */ 01167 if (for_us) { 01168 return buf; 01169 } else { 01170 return buffer_free(buf); 01171 } 01172 } 01173 01174 01175 buffer_t *ipv6_forwarding_up(buffer_t *buf) 01176 { 01177 uint8_t *ptr = buffer_data_pointer(buf); 01178 uint16_t len = buffer_data_length(buf); 01179 uint8_t *nh_ptr; 01180 protocol_interface_info_entry_t *cur; 01181 bool intercept = false; 01182 01183 /* When processing a reassembled packet, we don't reprocess headers from before the fragment header */ 01184 uint16_t frag_offset; 01185 01186 cur = buf->interface ; 01187 01188 // Make sure that this is a v6 header (just in case...) 01189 if (!cur || len < IPV6_HDRLEN || (*ptr >> 4) != 6) { 01190 goto drop; 01191 } 01192 01193 if (buf->options .ip_extflags & IPEXT_FRAGMENT) { 01194 // Remember the flags for headers we parsed before the fragment header; 01195 // we won't re-parse them, and expect the metadata (from the first fragment) 01196 // to survive reassembly. 01197 frag_offset = buf->offset ; 01198 buf->options .ip_extflags &= ~ IPEXT_FRAGMENT; 01199 tr_debug("Processing fragment from %d", frag_offset); 01200 } else { 01201 // Clear all info - extension header parsers will set 01202 frag_offset = 0; 01203 buf->options .ip_extflags = 0; 01204 } 01205 01206 buf->options .traffic_class = (ptr[0] << 4) | (ptr[1] >> 4); 01207 // Just skip Flow Label for now 01208 ptr += 4; 01209 01210 uint16_t payload_length = common_read_16_bit(ptr); 01211 ptr += 2; 01212 01213 // "Parameter problem" needs this pointer to Next Header field 01214 nh_ptr = ptr++; 01215 01216 // May as well note the outermost NH field now; will update later 01217 // if we go to an upper layer. 01218 buf->options .type = *nh_ptr; 01219 buf->options .code = 0; 01220 01221 // Read the Hop Limit 01222 buf->options .hop_limit = *ptr++; 01223 01224 // Remember the link-layer address for "special forwarding" check 01225 sockaddr_t ll_src = buf->src_sa ; 01226 sockaddr_t ll_dst = buf->dst_sa ; 01227 01228 // Get the Source Address 01229 memcpy(buf->src_sa .address , ptr, 16); 01230 buf->src_sa .addr_type = ADDR_IPV6 ; 01231 ptr += 16; 01232 01233 // Get the Destination Address 01234 memcpy(buf->dst_sa .address , ptr, 16); 01235 buf->dst_sa .addr_type = ADDR_IPV6 ; 01236 ptr += 16; 01237 01238 /* XXX I'm using ip_routed_up as a "received from outside this node" check 01239 * Not sure if that was original intent... We do want to accept it if it came 01240 * from inside this node. 01241 */ 01242 if (addr_is_ipv6_multicast(buf->src_sa .address ) || 01243 (buf->ip_routed_up && (addr_is_ipv6_loopback(buf->dst_sa .address ) || 01244 addr_is_ipv6_loopback(buf->src_sa .address ))) 01245 ) { 01246 goto drop; 01247 } 01248 01249 if (addr_is_ipv6_multicast(buf->dst_sa .address )) { 01250 /* RFC 4291 says we must drop multicast packets with scope 0 */ 01251 if (addr_ipv6_multicast_scope(buf->dst_sa .address ) == 0) { 01252 goto drop; 01253 } 01254 } else { 01255 /* RFC 1122 and 1812 say we SHOULD silently discard packets with unicast IP 01256 * address but link-layer multicast or broadcast. And we MUST NOT forward 01257 * them. So catch them here. 01258 */ 01259 if (buf->options .ll_multicast_rx || buf->options .ll_broadcast_rx ) { 01260 goto drop; 01261 } 01262 } 01263 01264 /* If security bypass is set, we only allow link-local traffic (unicast 01265 * or multicast with link-local scope), as per ZigBee IP 01266 */ 01267 if (buf->options .ll_security_bypass_rx ) { 01268 if (addr_ipv6_scope(buf->dst_sa .address , cur) != IPV6_SCOPE_LINK_LOCAL) { 01269 goto drop; 01270 } 01271 } 01272 01273 if (IPV6_HDRLEN + payload_length > buffer_data_length(buf)) { 01274 // Return "Parameter problem", pointing at Payload Length 01275 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4); 01276 } 01277 01278 /* Trim buffer if it's longer than payload length stated in IP header */ 01279 if (IPV6_HDRLEN + payload_length < buffer_data_length(buf)) { 01280 buffer_data_length_set(buf, IPV6_HDRLEN + payload_length); 01281 } 01282 01283 /* Handle any hop-by-hop options first, before checking destination */ 01284 if (*nh_ptr == IPV6_NH_HOP_BY_HOP) { 01285 uint16_t hdrlen = 0; 01286 if (payload_length == 0) { 01287 // RFC 2675 - return "Parameter problem", pointing at Payload Length 01288 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4); 01289 } 01290 buf = ipv6_handle_options(buf, cur, ptr, IPV6_NH_HOP_BY_HOP, payload_length, &hdrlen, &ll_src, ptr - buffer_data_pointer(buf) < frag_offset); 01291 if (hdrlen == 0) { 01292 /* Something went wrong - it will have freed buf or turned it into an ICMP error */ 01293 return buf; 01294 } 01295 nh_ptr = ptr; 01296 ptr += hdrlen; 01297 payload_length -= hdrlen; 01298 } 01299 01300 if (buf->options .ll_not_ours_rx ) { 01301 /* Wasn't addressed to us, but interface sent it up. It must now tell us 01302 * what to do with the packet. Options: 01303 * 1) Drop it (it frees) 01304 * 2) Bounce it (turns buffer into response, sets bounce true) 01305 * 3) Accept or forward as normal based on IP destination (returns buffer, clearing ll_not_ours_rx) 01306 * 4) Treat it as for us regardless of IP destination (returns buffer, leaving ll_not_ours_rx set) 01307 */ 01308 bool bounce = false; 01309 buf = cur->if_snoop(cur, buf, &ll_dst, &ll_src, &bounce); 01310 if (!buf || bounce) { 01311 return buf; 01312 } 01313 intercept = buf->options .ll_not_ours_rx ; 01314 } 01315 01316 if (*nh_ptr == IPV6_NH_ICMPV6 && payload_length >= 4 && ptr[0] == ICMPV6_TYPE_INFO_NS) { 01317 /* Treat as ours, let NS reply */ 01318 intercept = true; 01319 } 01320 01321 #ifdef HAVE_MPL 01322 /* We don't reprocess if this is a reassembly - each fragment is its own MPL 01323 * Data Message, and we already processed them. 01324 */ 01325 if ((buf->options .ip_extflags & IPEXT_HBH_MPL) && !frag_offset) { 01326 if (!mpl_forwarder_process_message(buf, NULL, false)) { 01327 /* False return means "duplicate" or other reason not to process */ 01328 return buffer_free(buf); 01329 } 01330 } 01331 #endif 01332 01333 bool for_us = intercept || ipv6_packet_is_for_us(buf); 01334 01335 if (addr_is_ipv6_multicast(buf->dst_sa .address )) { 01336 /* Multicast forwarding is told whether we're interested. It may 01337 * clone or take ownership of the buffer, depending on for_us. If not 01338 * forwarding or for us, it will bin. 01339 */ 01340 buf = ipv6_consider_forwarding_multicast_packet(buf, cur, for_us); 01341 if (!buf) { 01342 return NULL; 01343 } 01344 } else { /* unicast */ 01345 if (!for_us) { 01346 return ipv6_consider_forwarding_unicast_packet(buf, cur, &ll_src); 01347 } 01348 } 01349 01350 /* Its destination is us (or we're intercepting) - start munching headers */ 01351 /* Guess this should ultimately be the "CIPV6" up layer */ 01352 for (;;) { 01353 uint16_t hdrlen = 0; 01354 if (payload_length == 0 && *nh_ptr != IPV6_NH_NONE) { 01355 // RFC 2675 - return "Parameter problem", pointing at Payload Length 01356 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4); 01357 } 01358 switch (*nh_ptr) { 01359 case IPV6_NH_NONE: 01360 return buffer_free(buf); 01361 case IPV6_NH_DEST_OPT: 01362 buf = ipv6_handle_options(buf, cur, ptr, IPV6_NH_DEST_OPT, payload_length, &hdrlen, &ll_src, ptr - buffer_data_pointer(buf) < frag_offset); 01363 nh_ptr = ptr; 01364 break; 01365 #ifndef NO_IP_FRAGMENT_RX 01366 case IPV6_NH_FRAGMENT: 01367 return ipv6_frag_up(buf, ptr, nh_ptr, payload_length); 01368 #endif 01369 case IPV6_NH_ROUTING: { 01370 bool forward = false; 01371 buf = ipv6_handle_routing_header(buf, cur, ptr, payload_length, &hdrlen, &forward, ptr - buffer_data_pointer(buf) < frag_offset); 01372 if (forward) { 01373 /* Note that forwarding will cope with looping back if next address is 01374 * actually ours. We do want to always treat it as forwarding, as we do 01375 * want hop counts decremented, etc. 01376 */ 01377 return ipv6_consider_forwarding_unicast_packet(buf, cur, &ll_src); 01378 } 01379 nh_ptr = ptr; 01380 break; 01381 } 01382 case IPV6_NH_UDP: 01383 buf->info = (buffer_info_t)(B_DIR_UP | B_TO_UDP | B_FROM_IPV6_FWD); 01384 /* UDP may want to generate ICMP "port unreachable", so we leave the 01385 * IP headers unconsumed, setting offset to point to the UDP header 01386 */ 01387 buf->options .type = IPV6_NH_UDP; 01388 buf->offset = ptr - buffer_data_pointer(buf); 01389 return buf; 01390 #ifndef NO_TCP 01391 case IPV6_NH_TCP: 01392 buf->info = (buffer_info_t)(B_DIR_UP | B_TO_TCP | B_FROM_IPV6_FWD); 01393 goto upper_layer; 01394 #endif 01395 case IPV6_NH_ICMPV6: 01396 buf->info = (buffer_info_t)(B_DIR_UP | B_TO_ICMP | B_FROM_IPV6_FWD); 01397 goto upper_layer; 01398 #if defined HAVE_RPL || defined HAVE_MPL 01399 case IPV6_NH_IPV6: 01400 /* Tunnel support is only used for RPL or MPL. Only permit tunnel exit if there was 01401 * a RPL or MPL HbH option header, or RPL SRH header. Gives security, as 01402 * long as border router doesn't forward such packets into RPL/MPL domain. 01403 */ 01404 if (!(buf->options .ip_extflags & (IPEXT_HBH_RPL | IPEXT_SRH_RPL | IPEXT_HBH_MPL))) { 01405 goto bad_nh; 01406 } 01407 buffer_note_predecessor(buf, &ll_src); 01408 buf->options .type = *nh_ptr; 01409 return ipv6_tunnel_exit(buf, ptr); 01410 #endif 01411 default: { 01412 if (buf->options .ll_security_bypass_rx ) { 01413 goto bad_nh; 01414 } 01415 buffer_socket_set(buf, socket_lookup_ipv6(*nh_ptr, &buf->dst_sa , &buf->src_sa , true)); 01416 if (!buf->socket ) { 01417 goto bad_nh; 01418 } 01419 buf->info = (buffer_info_t)(B_DIR_UP | B_TO_APP | B_FROM_IPV6_FWD); 01420 goto upper_layer; 01421 } 01422 bad_nh: 01423 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_UNREC_NEXT_HDR, nh_ptr - buffer_data_pointer(buf)); 01424 } 01425 if (hdrlen == 0) { 01426 /* Something went wrong in an extension header - it will have freed buf or turned it into an ICMP error */ 01427 return buf; 01428 } 01429 ptr += hdrlen; 01430 payload_length -= hdrlen; 01431 } 01432 upper_layer: 01433 buf->options .type = *nh_ptr; 01434 buffer_data_pointer_set(buf, ptr); 01435 return buf; 01436 01437 drop: 01438 protocol_stats_update(STATS_IP_RX_DROP, 1); 01439 return buffer_free(buf); 01440 } 01441 01442 #endif /* _HAVE_IPV6 */
Generated on Tue Jul 12 2022 13:54:25 by
