Nicolas Borla / Mbed OS BBR_1Ebene
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ipv6.c Source File

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