Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ipv6.c Source File

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 */