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.
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 #ifdef HAVE_MPL 01079 /* MPL does its own thing - we do not perform any "native" forwarding */ 01080 if (buf->options .ip_extflags & IPEXT_HBH_MPL) { 01081 goto no_forward; 01082 } 01083 #endif 01084 01085 #ifdef MULTICAST_FORWARDING 01086 uint_fast8_t group_scope = addr_ipv6_multicast_scope(buf->dst_sa .address ); 01087 uint_fast8_t src_scope = addr_ipv6_scope(buf->src_sa .address , cur); 01088 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 12:44:25 by
