Esempio n. 1
0
/* Input: Final IP packet for transmission on link.
 *        Buffer destination = final destination
 *        Buffer source undefined.
 *        Route next hop address set.
 * Output: Buffer destination+source = link-layer addresses
 *         Sent to mesh, LowPAN fragmentation or MAC layers
 */
buffer_t *lowpan_down(buffer_t *buf)
{
    protocol_interface_info_entry_t *cur = buf->interface;

    buf->options.type = 0;

    if (!buf->route) {
        tr_debug("lowpan_down route");
        return buffer_free(buf);
    }

    const uint8_t *ip_src = buffer_data_pointer(buf) + 8;
    const uint8_t *next_hop = buf->route->route_info.next_hop_addr;
    bool link_local = addr_is_ipv6_link_local(next_hop);
    bool stable_only = false;

    /* We have IP next hop - figure out the MAC address */
    if (addr_is_ipv6_multicast(next_hop)) {
        buf->dst_sa.addr_type = ADDR_BROADCAST;
        common_write_16_bit(cur->mac_parameters->pan_id, buf->dst_sa.address);
        buf->dst_sa.address[2] = 0x80 | (next_hop[14] & 0x1f);
        buf->dst_sa.address[3] = next_hop[15];
        stable_only = true;
    } else { /* unicast */
        ipv6_neighbour_t *n = ipv6_interface_resolve_new(cur, buf);
        if (!n) {
            return NULL;
        }
        if (thread_info(cur)) {
            stable_only = thread_stable_context_check(cur, buf);
        }
    }

    if (!buf->link_specific.ieee802_15_4.useDefaultPanId) {
        /* Override dest PAN ID (from multicast map above, or neighbour cache) */
        common_write_16_bit(buf->link_specific.ieee802_15_4.dstPanId, buf->dst_sa.address);
    }

    /* Figure out which source MAC address to use. Usually try to match the
     * source, for best compression, and to ensure if the layer above uses LL64
     * (like MLE), it forces us to use our MAC64.
     */
    if (thread_info(cur) && !(link_local && thread_insist_that_mesh_isnt_a_link(cur)) && buf->dst_sa.addr_type == ADDR_802_15_4_SHORT) {
        /* For Thread, we want to always use short source address for unicast
         * to non-link-local 16-bit addresses, which is the case where we want
         * to use mesh headers.
         */
        buf->src_sa.addr_type = ADDR_802_15_4_SHORT;
    } else if (addr_iid_matches_eui64(ip_src + 8, cur->mac)) {
        buf->src_sa.addr_type = ADDR_802_15_4_LONG;
    } else if (cur->mac_parameters->mac_short_address < 0xfffe && addr_iid_matches_lowpan_short(ip_src + 8, cur->mac_parameters->mac_short_address)) {
        buf->src_sa.addr_type = ADDR_802_15_4_SHORT;
    } else {
        /* This lets mac_mlme_write_our_addr choose based on address mode */
        buf->src_sa.addr_type = ADDR_NONE;
    }

    if (!mac_helper_write_our_addr(cur, &buf->src_sa)) {
        return buffer_free(buf);
    }

    /* Clear Link Layer Re Transmission Counter */
    //buf->fhss_channel_retries_left = 1+ cur->mac_parameters->number_of_fhss_channel_retries;


    if (buf->dst_sa.addr_type != ADDR_802_15_4_LONG && buf->dst_sa.addr_type != ADDR_802_15_4_SHORT && buf->dst_sa.addr_type != ADDR_BROADCAST) {
        tr_debug("IP:Dest Pro. addr_type: %02x", buf->dst_sa.addr_type);
        return buffer_free(buf);
    }

    uint_fast8_t mesh_size;
    if (link_local && thread_insist_that_mesh_isnt_a_link(cur)) {
        mesh_size = 0;
    } else {
        /* Allow the link-layer destination addresses passed from upper layers
         * to be remapped - used to implement Thread anycast.
         *
         * Mapping function can change address and type - if it returns false,
         * packet is dropped.
         *
         * Note that this mapping has to be done before IPHC compression, which
         * is why it moved from mesh.c.
         */
        if (!mesh_address_map(cur, &buf->dst_sa.addr_type, buf->dst_sa.address)) {
            tr_debug("mesh_address_map fail");
            return buffer_free(buf);
        }

        /* After mapping, compute final mesh header size (which depends on
         * the final address).
         */
        mesh_size = mesh_header_size(buf);
    }

    if (mesh_size == 0) {
        if (buf->dst_sa.addr_type == ADDR_BROADCAST) {
            /* Thread says multicasts other than MLE are sent to our parent, if we're an end device */
            if (cur->ip_multicast_as_mac_unicast_to_parent && !buf->options.ll_broadcast_tx) {
                if (protocol_6lowpan_interface_get_mac_coordinator_address(cur, &buf->dst_sa) < 0) {
                    tr_warn("IP: No parent for multicast as unicast");
                    return buffer_free(buf);
                }
            } else {
                /*
                 * Not using a mesh header, so have to "purify" RFC 4944 multicast - we
                 * set a 100xxxxxxxxxxxxx RFC 4944 multicast address above, but
                 * IEEE 802.15.4 only supports broadcast in the real MAC header.
                 */
                common_write_16_bit(0xFFFF, buf->dst_sa.address + 2);
            }
        }
    }

    /* RFC 6282+4944 require that we limit compression to the first fragment.
     * This check is slightly conservative - always allow 4 for first-fragment header
     */
    uint_fast16_t overhead = mac_helper_frame_overhead(cur, buf);
    uint_fast16_t max_iphc_size = mac_helper_max_payload_size(cur, overhead) - mesh_size - 4;

    buf = iphc_compress(&cur->lowpan_contexts, buf, max_iphc_size, stable_only);
    if (!buf) {
        return NULL;
    }

    if (mesh_size != 0) {
        buf->info = (buffer_info_t)(B_FROM_IPV6_TXRX | B_TO_MESH_ROUTING | B_DIR_DOWN);
        return buf;
    }

    buf->info = (buffer_info_t)(B_FROM_IPV6_TXRX | B_TO_MAC | B_DIR_DOWN);

    return buf;
}
/* Public functions */
void thread_general_mle_receive_cb(int8_t interface_id, mle_message_t *mle_msg, mle_security_header_t *security_headers)
{
    /* TODO's:
     * - Any incoming link configuration or advertisement message, or an incoming update sent to a
     *   link-local address, whose IP Hop Limit is not 255, may have been forwarded by a Router
     *   and MUST be discarded.
     */

    protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);

    if (!cur) {
        return;
    }

    /* Check that message is from link-local scope */
    if(!addr_is_ipv6_link_local(mle_msg->packet_src_address)) {
        return;
    }

    uint8_t linkMargin = thread_compute_link_margin(mle_msg->dbm);

    // Always save lowpower queries
    thread_lowpower_process_request(mle_msg);

    switch (mle_msg->message_type) {
    case MLE_COMMAND_ACCEPT: {
        thread_parse_accept(cur, mle_msg, security_headers, linkMargin);
        break;
    }

    case MLE_COMMAND_METRIC_MANAGEMENT_REQUEST: {
        thread_lowpower_metrics_management_query_request_process(cur, mle_msg, security_headers, linkMargin);
        break;
    }

    case MLE_COMMAND_REJECT: {
        mle_neigh_table_entry_t *entry_temp;
        tr_warn("Reject Link");
        entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false);
        if (entry_temp) {
            mle_class_remove_entry(cur->id, entry_temp);
        }
        break;
    }

    case MLE_COMMAND_DATASET_ANNOUNCE: {
        thread_parse_annoucement(cur, mle_msg);
        break;
    }

    case MLE_COMMAND_ADVERTISEMENT: {
        thread_parse_advertisement(cur, mle_msg, security_headers, linkMargin);
        break;
    }

    case MLE_COMMAND_DATA_RESPONSE: {
        thread_parse_data_response(cur, mle_msg, linkMargin);
        break;
    }

    case MLE_COMMAND_CHILD_UPDATE_RESPONSE:
    {
        thread_parse_child_update_response(cur, mle_msg, security_headers, linkMargin);
        break;
    }

    case MLE_COMMAND_PARENT_RESPONSE: {
        tr_debug("MLE parent response received");
        thread_mle_parent_discover_receive_cb(interface_id, mle_msg, security_headers);
        break;
    }
    default:
        if ((thread_am_host(cur) || thread_am_reed(cur)) && mle_msg->message_type == MLE_COMMAND_CHILD_UPDATE_REQUEST){
            // Thread host and router in REED mode answer the message same way. Routers only process messages from child
            thread_host_child_update_request_process(cur, mle_msg, linkMargin);
        } else if (cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_ROUTER) {
            thread_router_bootstrap_mle_receive_cb(interface_id, mle_msg, security_headers);
        } else {
            tr_warn("Not supported MLE message for host %d", mle_msg->message_type);
        }
    }

}