Esempio n. 1
0
void fhss_beacon_decode_raw(fhss_synchronization_beacon_payload_s* dest, const uint8_t* buffer)
{
    dest->data_start_delimeter = *buffer++;

    dest->channel_index = *buffer++;
    dest->sender_unicast_channel = *buffer++;

    dest->current_superframe = common_read_16_bit(buffer);
    buffer += BEACON_FIELD_SIZE(current_superframe);

    dest->remaining_slots = common_read_16_bit(buffer);
    buffer += BEACON_FIELD_SIZE(remaining_slots);

    dest->channel_list_counter = common_read_16_bit(buffer);
    buffer += BEACON_FIELD_SIZE(channel_list_counter);

    dest->hop_count = *buffer++;
    dest->number_of_broadcast_channels = *buffer++;
    dest->number_of_tx_slots = *buffer++;

    dest->time_since_last_beacon = common_read_32_bit(buffer);
    buffer += BEACON_FIELD_SIZE(time_since_last_beacon);

    dest->processing_delay += common_read_16_bit(buffer);

    buffer += BEACON_FIELD_SIZE(processing_delay);

    dest->superframe_length = common_read_16_bit(buffer);
    buffer += BEACON_FIELD_SIZE(superframe_length);

    dest->number_of_superframes_per_channel = *buffer;
}
Esempio n. 2
0
static void thread_nd_coap_notification_callback(int8_t interface_id, const uint8_t ip_addr[16], uint16_t loc_addr, const uint8_t ml_eid[8])
{
    protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
    if (!cur) {
        return;
    }

    /* First check to see if we have an existing entry with different RLOC - we need to unicast error
     * notification to that old entry if so. */
    ipv6_neighbour_t *entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, ip_addr);
    if (entry && entry->ll_type == ADDR_802_15_4_SHORT) {
        uint16_t old_entry_rloc = common_read_16_bit(entry->ll_address + 2);
        if (old_entry_rloc != loc_addr) {
            uint8_t old_entry_ip[16];
            thread_addr_write_mesh_local_16(old_entry_ip, common_read_16_bit(entry->ll_address + 2), cur->thread_info);
            tr_warn("Proactive address change %s %04x->%04x", trace_ipv6(ip_addr), old_entry_rloc, loc_addr);
            thread_resolution_client_address_error(interface_id, old_entry_ip, ip_addr, ml_eid);
        }
    }

    /* Now treat as an unsolicited update (by address, because entry may be NULL) */
    uint8_t ll_addr[4];
    common_write_16_bit(cur->mac_parameters->pan_id, ll_addr + 0);
    common_write_16_bit(loc_addr, ll_addr + 2);
    ipv6_neighbour_update_unsolicited(&cur->ipv6_neighbour_cache, ip_addr, ADDR_802_15_4_SHORT, ll_addr);

    if (nd_proxy_enabled_for_upstream(cur->id)) {
        ipv6_route_add(ip_addr, 128, cur->id, NULL, ROUTE_THREAD_PROXIED_HOST, 3600, 0);
    }
}
Esempio n. 3
0
bool pana_header_parse(uint8_t *ptr, uint16_t data_length, pana_header_t *header)
{
    if (data_length < 16) {
        return false;
    }

    if (common_read_16_bit(ptr) != PANA_HEADER_START) {
        return false;
    }

    header->payload_len = common_read_16_bit(ptr + 2);
    ptr += 4;
    if (header->payload_len != data_length) {
        return false;
    }

    header->flags = common_read_16_bit(ptr);
    header->type = common_read_16_bit(ptr + 2);
    ptr += 4;
    header->session_id = common_read_32_bit(ptr);
    ptr += 4;
    header->seq = common_read_32_bit(ptr);

    return true;
}
Esempio n. 4
0
int mle_message_malformed_check(uint8_t *ptr, uint16_t data_len)
{
    uint8_t *dptr;
    uint16_t length;
    dptr = ptr;
    while (data_len) {
        if (data_len >= 2) {
            dptr += 1; //Skip TLV Type
            length = *dptr++;
            if (length == 0xff) {
                // Long length format
                data_len -= 2;
                if (data_len < 2) {
                    return -1;
                }
                length = common_read_16_bit(dptr);
                dptr += 2;
            }
            data_len -= 2;
            if (data_len >= length) {
                if (length) {
                    data_len -= length;
                    dptr += length;
                }
            } else {
                // buffer is overrun this is malformed.
                return -1;
            }
        } else {
            return -1;
        }
    }
    return 0;
}
Esempio n. 5
0
bool eapol_parse_pdu_header(uint8_t *ptr, uint16_t data_length, eapol_pdu_t *eapol_pdu)
{
    //Validate MIN length
    if (data_length < EAPOL_BASE_LENGTH) {
        return false;
    }
    //Validate Protocol version
    uint8_t protocol = *ptr++;
    if (protocol != EAPOL_PROTOCOL_VERSION) {
        return false;
    }
    eapol_pdu->packet_type = *ptr++;
    eapol_pdu->packet_length = common_read_16_bit(ptr);
    ptr += 2;
    //Validate Body Length
    if (eapol_pdu->packet_length > data_length - EAPOL_BASE_LENGTH) {
        return false;
    }
    eapol_pdu->packet_body = ptr;

    if (eapol_pdu->packet_type == EAPOL_EAP_TYPE) {
        return eapol_parse_eap_packet(eapol_pdu);
    } else if (eapol_pdu->packet_type == EAPOL_KEY_TYPE) {
        return eapol_parse_key_packet(eapol_pdu);
    } else {
        return false;
    }

}
Esempio n. 6
0
static bool eapol_parse_key_packet(eapol_pdu_t *eapol_pdu)
{
    if (eapol_pdu->packet_length < EAPOL_KEY_FRAME_BASE_SIZE) {
        return false;
    }
    uint8_t *ptr = eapol_pdu->packet_body;
    eapol_key_frame_t *key_frame = &eapol_pdu->msg.key;
    key_frame->key_description = *ptr++;
    if (key_frame->key_description != EAPOL_RSN_KEY_DESCRIPTION) {
        return false;
    }
    ptr = eapol_key_information_read(&key_frame->key_information, ptr);
    if (key_frame->key_information.description_version != KEY_DESCRIPTION_HMAC_SHA1_MIC_AES_ENC) {
        return false;
    }
    key_frame->key_length = common_read_16_bit(ptr);
    ptr += 2;

    key_frame->replay_counter = common_read_64_bit(ptr);
    ptr += 8;

    key_frame->key_nonce = ptr;
    ptr += 32;

    key_frame->key_iv = ptr;
    ptr += 16;

    key_frame->key_rsc = ptr;
    ptr += 16; //Skip 8 byte RSC + RESERVED 8

    key_frame->key_mic = ptr;
    ptr += 16;

    key_frame->key_data_length = common_read_16_bit(ptr);
    ptr += 2;
    key_frame->key_data = ptr;
    if (key_frame->key_data_length > (eapol_pdu->packet_length - EAPOL_KEY_FRAME_BASE_SIZE)) {
        return false;
    }

    return true;

}
Esempio n. 7
0
bool mle_tlv_read_16_bit_tlv(mle_tlv_type_t reqType, uint8_t *ptr, uint16_t data_len, uint16_t *buffer)
{
    mle_tlv_info_t tlv_info;
    if (mle_tlv_option_discover(ptr, data_len, reqType, &tlv_info) >= 2) {
        *buffer = common_read_16_bit(tlv_info.dataPtr);
        return true;
    }

    return false;
}
Esempio n. 8
0
uint8_t thread_meshcop_tlv_data_get_uint16(const uint8_t *ptr, uint16_t length, uint8_t type, uint16_t *data_ptr)
{
    uint8_t result_len;
    uint8_t *result_ptr;

    result_len = thread_meshcop_tlv_find(ptr, length, type, &result_ptr);
    if (result_len >= 2 && data_ptr) {
        *data_ptr = common_read_16_bit(result_ptr);
    }
    return result_len;
}
Esempio n. 9
0
uint16_t thread_meshcop_tlv_find(const uint8_t *ptr, uint16_t length, uint8_t type, uint8_t **result_ptr)
{
    const uint8_t *p;
    if (!ptr || length < 2) {
        return 0;
    }
    //tr_info("tlv_find length: %d, type: %d", length, type);

    p = ptr;
    while (p != NULL) {
        const uint8_t *tlv_data_ptr;
        uint16_t tlv_data_length;
        //tr_info("tlv_find first check");
        // check if we have enough length for normal length tlv
        if (p + 2 > ptr + length) {
            break;    //must have at least type and short length
        }

        if (p[1] == 0xff) {
            // Long length format
            if (p + 4 > ptr + length) {
                break;    // check if enough length for long length
            }

            tlv_data_length = common_read_16_bit(&p[2]);
            tlv_data_ptr = p + 4;
        } else {
            tlv_data_length = p[1];
            tlv_data_ptr = p + 2;
        }
        //tr_info("tlv_find check: %d, type: %d", tlv_data_length, *p);

        // check if length of tlv is correct
        if (tlv_data_ptr + tlv_data_length > ptr + length) {
            break;    //length goes past the data block
        }

        if (*p == type) {
            // Correct TLV found
            //tr_info("tlv_find Found: %d, type: %d", tlv_data_length, *p);
            if (result_ptr != NULL) {
                *result_ptr = (uint8_t *)tlv_data_ptr;
            }
            // return the correct tlv data
            return tlv_data_length;
        }

        p = tlv_data_ptr + tlv_data_length;
    }
    return 0;
}
Esempio n. 10
0
static buffer_t *udp_checksum_check(buffer_t *buf)
{
    uint8_t *ptr = buffer_data_pointer(buf) + 6;
    uint16_t check = common_read_16_bit(ptr);

    // We refuse checksum field 0000, as per IPv6 (RFC 2460). Would have
    // to accept this if handling IPv4.
    if (check == 0 || buffer_ipv6_fcf(buf, IPV6_NH_UDP)) {
        tr_err("CKSUM ERROR - src=%s", trace_ipv6(buf->src_sa.address));
        protocol_stats_update(STATS_IP_CKSUM_ERROR, 1);
        buf = buffer_free(buf);
    }
    return buf;
}
Esempio n. 11
0
int16_t thread_meshcop_tlv_length_required(const uint8_t *ptr, uint16_t length)
{
    if (length < 2) {
        return -1;
    }
    if (ptr[1] == 0xff) {
        // Long length format
        if (length < 4) {
            return -1;
        }
        return 4 + common_read_16_bit(&ptr[2]);
    }
	return 2 + ptr[1];
}
Esempio n. 12
0
static uint8_t *eapol_key_information_read(eapol_key_information_t *key_information, uint8_t *ptr)
{
    uint16_t key_info = common_read_16_bit(ptr);
    key_information->description_version = ((key_info & KEY_INFO_VERSION_BIT_MASK) >> KEY_INFO_VERSION_BIT_SHIFT);
    key_information->pairwise_key = ((key_info & KEY_INFO_KEY_TYPE_BIT_MASK) >> KEY_INFO_KEY_TYPE_BIT_SHIFT);
    key_information->install = ((key_info & KEY_INFO_INSTALL_BIT_MASK) >> KEY_INFO_INSTALL_BIT_SHIFT);
    key_information->key_ack = ((key_info & KEY_INFO_ACK_BIT_MASK) >> KEY_INFO_ACK_BIT_SHIFT);
    key_information->key_mic = ((key_info & KEY_INFO_MIC_MASK) >> KEY_INFO_MIC_SHIFT);
    key_information->secured_key_frame = ((key_info & KEY_INFO_SECURE_MASK) >> KEY_INFO_SECURE_SHIFT);
    key_information->error = ((key_info & KEY_INFO_ERROR_MASK) >> KEY_INFO_ERROR_SHIFT);
    key_information->request = ((key_info & KEY_INFO_REQUEST_MASK) >> KEY_INFO_REQUEST_SHIFT);
    key_information->encrypted_key_data = ((key_info & KEY_INFO_ENC_KEY_DATA_MASK) >> KEY_INFO_ENC_KEY_DATA_SHIFT);
    key_information->smk_handshake = ((key_info & KEY_INFO_SMK_MASK) >> KEY_INFO_SMK_SHIFT);
    return ptr + 2;
}
Esempio n. 13
0
static const uint8_t *thread_meshcop_next_tlv(const uint8_t *ptr, uint16_t length)
{
    // This fails if returned pointer would go past the length and it must have 2 bytes room
    if (length < 4) {
        return NULL;
    }
    if (ptr[1] == 0xff) {
        // Long length format
        if (length < 6) {
            return NULL;
        }
        return ptr + 4 + common_read_16_bit(&ptr[2]);
    }
	return ptr + 2 + ptr[1];
}
static void thread_parse_annoucement(protocol_interface_info_entry_t *cur, mle_message_t *mle_msg)
{
    uint64_t timestamp;
    uint16_t panid;
    uint8_t *ptr;
    uint8_t channel_page;
    uint16_t channel;
    link_configuration_s *linkConfiguration = thread_joiner_application_get_config(cur->id);


    tr_info("Recv Dataset Announce");
    if (8 > thread_tmfcop_tlv_data_get_uint64(mle_msg->data_ptr, mle_msg->data_length,MLE_TYPE_ACTIVE_TIMESTAMP,&timestamp)) {
        tr_error("Missing timestamp TLV");
        return;
    }
    if (2 > thread_tmfcop_tlv_data_get_uint16(mle_msg->data_ptr, mle_msg->data_length,MLE_TYPE_PANID,&panid)) {
        tr_error("Missing Panid TLV");
        return;
    }
    if (3 > thread_tmfcop_tlv_find(mle_msg->data_ptr, mle_msg->data_length,MLE_TYPE_CHANNEL,&ptr)) {
        tr_error("Missing Channel TLV");
        return;
    }
    channel_page = ptr[0];
    channel = common_read_16_bit(&ptr[1]);

    if (linkConfiguration->timestamp == timestamp) {
        // We received same timestamp
        tr_debug("Same timestamp");
        return;
    }

    if (cur->thread_info->announcement_info && cur->thread_info->announcement_info->timestamp == timestamp){
        // We received same timestamp again
        tr_debug("Processing announce with same timestamp");
        return;
    }


    if (linkConfiguration->timestamp > timestamp) {
        // We received older time stamp we just announce back to originator channel
        thread_bootstrap_announce_send(cur, linkConfiguration->channel_page, linkConfiguration->rfChannel, linkConfiguration->panId, linkConfiguration->timestamp, channel);
        return;
    }

    tr_debug("New configuration received");
    thread_bootstrap_temporary_attach(cur,channel_page, channel, panid, timestamp);
}
Esempio n. 15
0
bool thread_meshcop_tlv_exist(const uint8_t *ptr, const uint16_t length, const uint8_t type)
{
    const uint8_t *p;
    if (!ptr || length < 2) {
        return false;
    }

    p = ptr;
    while (p != NULL) {
        const uint8_t *tlv_data_ptr;
        uint16_t tlv_data_length;
        // check if we have enough length for normal length tlv
        if (p + 2 > ptr + length) {
            break;    //must have at least type and short length
        }

        if (p[1] == 0xff) {
            // Long length format
            if (p + 4 > ptr + length) {
                break;    // check if enough length for long length
            }

            tlv_data_length = common_read_16_bit(&p[2]);
            tlv_data_ptr = p + 4;
        } else {
            tlv_data_length = p[1];
            tlv_data_ptr = p + 2;
        }

        // check if length of tlv is correct
        if (tlv_data_ptr + tlv_data_length > ptr + length) {
            break;    //length goes past the data block
        }

        if (*p == type) {
            // Correct TLV found
            return true;
        }

        p = tlv_data_ptr + tlv_data_length;
    }
    return false;
}
Esempio n. 16
0
int mle_tlv_option_discover(uint8_t *ptr, uint16_t data_len, mle_tlv_type_t discovered_type, mle_tlv_info_t *option_info)
{
    uint8_t *dptr;
    uint16_t length;
    mle_tlv_type_t type;

    option_info->tlvLen = 0;
    option_info->tlvType = MLE_TYPE_UNASSIGNED;
    option_info->dataPtr = NULL;
    dptr = ptr;
    while (data_len) {
        type = (mle_tlv_type_t) * dptr++;
        length = *dptr++;
        if (length == 0xff) {
            // Long length format
            data_len -= 2;
            if (data_len < 2) {
                return -1;
            }
            length = common_read_16_bit(dptr);
            dptr += 2;
        }
        data_len -= 2;
        if (data_len >= length) {
            if (type == discovered_type) {
                option_info->tlvLen = length;
                option_info->tlvType = type;
                option_info->dataPtr = dptr;
                return length;
            } else {
                data_len -= length;
                dptr += length;
            }
        }
    }
    return -1;
}
Esempio n. 17
0
void mac_helper_coordinator_address_set(protocol_interface_info_entry_t *interface, addrtype_t adr_type, uint8_t *adr_ptr)
{
    mlme_set_t set_req;
    set_req.attr_index = 0;

    if (adr_type == ADDR_802_15_4_SHORT) {
        memcpy(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address, adr_ptr, 2);
        interface->mac_parameters->mac_cordinator_info.cord_adr_mode = MAC_ADDR_MODE_16_BIT;
        uint16_t short_addr = common_read_16_bit(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address);
        set_req.attr = macCoordShortAddress;
        set_req.value_pointer = &short_addr;
        set_req.value_size = 2;
    } else if (adr_type == ADDR_802_15_4_LONG) {
        memcpy(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address, adr_ptr, 8);
        interface->mac_parameters->mac_cordinator_info.cord_adr_mode = MAC_ADDR_MODE_64_BIT;
        set_req.attr = macCoordExtendedAddress;
        set_req.value_pointer = &interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address;
        set_req.value_size = 8;
    }

    if (interface->mac_api) {
        interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req);
    }
}
Esempio n. 18
0
buffer_t *pana_relay_parse(buffer_t *buf)
{
    uint8_t *ptr;
    buf->options.ll_security_bypass_tx = true;
    //tr_debug("Relay RX");
    ptr = buffer_data_pointer(buf);
    uint16_t length = buffer_data_length(buf);

    pana_avp_t pac_info;
    pac_info.code = AVP_PAC_INFO_CODE;

    if (!pana_avp_discover(ptr, length, &pac_info)  || pac_info.len != 18) {
        tr_debug("No Pac info");
        return buffer_free(buf);
    }

    pana_avp_t relay_msg;
    relay_msg.code = AVP_RELAY_MSG_CODE;

    if (!pana_avp_discover(ptr, length, &relay_msg)) {
        tr_debug("No Relay MSG");
        return buffer_free(buf);
    }
    //Set Message data to relay msg
    buffer_data_pointer_set(buf, relay_msg.avp_ptr);
    buffer_data_length_set(buf, relay_msg.len);
    //Set Destination to Pac Info
    ptr = pac_info.avp_ptr;
    memcpy(buf->dst_sa.address, ptr, 16);
    //buf->dst_sa.addr_type = ADDR_IPV6;
    ptr += 16;
    buf->dst_sa.port = common_read_16_bit(ptr);
    ptr += 2;
    //tr_debug("%s", trace_array(buf->dst_sa.address, 16) );
    return buf;
}
Esempio n. 19
0
buffer_t *udp_up(buffer_t *buf)
{
    //tr_debug("UDP UP");
    const uint8_t *ip_hdr;
    if ((buf->info & B_FROM_MASK) == B_FROM_IPV6_FWD) {
        // New paths leave IP header on for us to permit ICMP response;
        // note the pointer and strip now.
        ip_hdr = buffer_data_pointer(buf);
        buffer_data_strip_header(buf, buf->offset);
        buf->offset = 0;
    } else {
        // We came from cipv6_up (or...?) - we have no real IP headers
        ip_hdr = NULL;
    }

    uint16_t ip_len = buffer_data_length(buf);
    if (ip_len < 8) {
        return buffer_free(buf);
    }

    const uint8_t *udp_hdr = buffer_data_pointer(buf);

    buf->src_sa.port = common_read_16_bit(udp_hdr + 0);
    buf->dst_sa.port = common_read_16_bit(udp_hdr + 2);
    uint16_t udp_len = common_read_16_bit(udp_hdr + 4);

    buf = nwk_udp_rx_security_check(buf);
    if (!buf) {
        return NULL;
    }

    if (udp_len < 8 || udp_len > ip_len) {
        return buffer_free(buf);
    }

    // Set UDP length - may trim the buffer
    buffer_data_length_set(buf, udp_len);

    buf = udp_checksum_check(buf);
    if (!buf) {
        return buf;
    }

    // Remove UDP header
    buffer_data_pointer_set(buf, udp_hdr + 8);

    if (buf->dst_sa.port == 0) {
        tr_err("UDP port 0");
        protocol_stats_update(STATS_IP_RX_DROP, 1);
        return buffer_free(buf);
    }

    if (buf->dst_sa.port == UDP_PORT_ECHO && buf->src_sa.port != UDP_PORT_ECHO) {
        protocol_interface_info_entry_t *cur;
        tr_debug("UDP echo msg [%"PRIi16"]: %s%s",
                 buffer_data_length(buf),
                 trace_array(
                     buffer_data_pointer(buf),
                     (buffer_data_length(buf) > 64 ? 64 : buffer_data_length(buf))),
                 (buffer_data_length(buf) > 64 ? "..." : ""));

        cur = buf->interface;

        if (addr_is_ipv6_multicast(buf->dst_sa.address)) {
            const uint8_t *ipv6_ptr;
            ipv6_ptr = addr_select_source(cur, buf->dst_sa.address, 0);
            if (!ipv6_ptr) {
                tr_debug("UDP Echo:No address");
                return buffer_free(buf);
            }
            memcpy(buf->dst_sa.address, buf->src_sa.address, 16);
            memcpy(buf->src_sa.address, ipv6_ptr, 16);
        } else {
            memswap(buf->dst_sa.address, buf->src_sa.address, 16);
        }
        buf->dst_sa.port = buf->src_sa.port;
        buf->src_sa.port = UDP_PORT_ECHO;

        buf->info = (buffer_info_t)(B_FROM_UDP | B_TO_UDP | B_DIR_DOWN);
        buf->options.hop_limit = UNICAST_HOP_LIMIT_DEFAULT;
        buf->options.traffic_class = 0;
        buf->IPHC_NH = 0;
        return buffer_turnaround(buf);
    }

    if (ip_hdr) {
        /* New path generates port unreachable here, using the real IP headers
         * that we know the position of thanks to buf->offset.
         *
         * Old path has socket_up make port unreachable itself, creating a
         * fake IP header.
         */
        if (!buf->socket) {
            buffer_socket_set(buf, socket_lookup_ipv6(IPV6_NH_UDP, &buf->dst_sa, &buf->src_sa, true));
        }
        if (!buf->socket) {
            // Reconstruct original IP packet
            buffer_data_pointer_set(buf, udp_hdr);
            buffer_data_length_set(buf, ip_len);
            buffer_data_pointer_set(buf, ip_hdr);
            return icmpv6_error(buf, NULL, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_PORT_UNREACH, 0);
        }
    }

    buf->options.type = (uint8_t) SOCKET_FAMILY_IPV6;
    buf->options.code = IPV6_NH_UDP;
    buf->info = (buffer_info_t)(B_FROM_UDP | B_TO_APP | B_DIR_UP);
    return buf;
}
Esempio n. 20
0
uint8_t mac_indirect_data_req_handle(mac_pre_parsed_frame_t *buf, protocol_interface_rf_mac_setup_s *mac_ptr)
{

    if (!mac_ptr || !buf) {
        return 1;
    }

    if (buf->fcf_dsn.DstAddrMode == MAC_ADDR_MODE_NONE || buf->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE) {
        return 1;
    }

    uint8_t srcAddress[8];
    memset(&srcAddress, 0, 8);

    mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), srcAddress);

    //Call COMM status
    mac_api_t *mac_api = get_sw_mac_api(mac_ptr);
    if (mac_api) {
        mlme_comm_status_t comm_status;
        memset(&comm_status, 0, sizeof(mlme_comm_status_t));

        comm_status.status = MLME_DATA_POLL_NOTIFICATION;
        //Call com status
        comm_status.PANId = mac_header_get_dst_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf));
        comm_status.DstAddrMode = buf->fcf_dsn.DstAddrMode;;
        mac_header_get_dst_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), comm_status.DstAddr);
        comm_status.SrcAddrMode = buf->fcf_dsn.SrcAddrMode;
        mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), comm_status.SrcAddr);
        mac_header_security_components_read(buf, &comm_status.Key);
        if( mac_api->mlme_ind_cb ){
            mac_api->mlme_ind_cb(mac_api, MLME_COMM_STATUS, &comm_status);
        }
    }


    /* If the Ack we sent for the Data Request didn't have frame pending set, we shouldn't transmit - child may have slept */
    if (!buf->ack_pendinfg_status) {
        //tr_debug("Drop by pending");
        if (mac_ptr->indirect_pd_data_request_queue) {
            tr_error("Wrongly dropped");
        }
        //Free Buffer
        return 1;
    }

    uint8_t address_cmp_ok = 0;
    uint8_t len;
    mac_pre_build_frame_t *b_prev = NULL;

    if (buf->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_16_BIT) {
        len = 2;
    } else {
        len = 8;
    }

    mac_pre_build_frame_t *b = mac_ptr->indirect_pd_data_request_queue;
    while (b) {

        if (buf->neigh_info) {
            uint16_t compare_short;
            if (b->fcf_dsn.DstAddrMode == MAC_ADDR_MODE_16_BIT) {

                compare_short = common_read_16_bit(b->DstAddr);
                if (compare_short == buf->neigh_info->ShortAddress) {
                    address_cmp_ok = 1;
                }
            } else {
                if (memcmp(b->DstAddr, buf->neigh_info->ExtAddress, 8) == 0) {
                    address_cmp_ok = 1;
                }
            }
        } else {
            if (b->fcf_dsn.DstAddrMode == buf->fcf_dsn.SrcAddrMode) {
                if (memcmp(b->DstAddr, srcAddress, len) == 0) {
                    address_cmp_ok = 1;
                }
            }
        }

        if (address_cmp_ok) {
            if (b_prev) {
                b_prev->next = b->next;

            } else {
                mac_ptr->indirect_pd_data_request_queue = b->next;
            }
            b->next = NULL;
            b->priority = MAC_PD_DATA_MEDIUM_PRIORITY;
            mcps_sap_pd_req_queue_write(mac_ptr, b);
            return 1;
        } else {
            b_prev = b;
            b = b->next;
        }
    }
    return 0;
}
Esempio n. 21
0
/* We assume the packet is basically well-formed, as it will have either
 * cleared initial input parsing, or we formed it ourselves. hbh and srh
 * are set to point to the RPL Hop-by-Hop option and/or RPL Source Routing
 * Header, if present.
 */
static void rpl_data_locate_info(buffer_t *buf, uint8_t **hbh, uint8_t **srh)
{
    uint8_t *ptr = buffer_data_pointer(buf);
    uint16_t len = buffer_data_length(buf);

    if (hbh) {
        *hbh = NULL;
    }
    if (srh) {
        *srh = NULL;
    }

    if (len < IPV6_HDRLEN) {
        return;
    }
    uint16_t ip_len = common_read_16_bit(ptr + IPV6_HDROFF_PAYLOAD_LENGTH);
    uint8_t nh = ptr[6];
    ptr += IPV6_HDRLEN;
    len -= IPV6_HDRLEN;
    if (ip_len > len) {
        return;
    }
    len = ip_len;
    while (len) {
        uint16_t hdrlen;
        switch (nh) {
            case IPV6_NH_HOP_BY_HOP:
            {
                if (len < 8) {
                    return;
                }
                nh = ptr[0];
                hdrlen = (ptr[1] + 1) * 8;
                /* Move on if they're not interested in HbH (looking for SRH) */
                if (!hbh) {
                    break;
                }
                if (hdrlen > len) {
                    return;
                }
                uint8_t *opt_ptr = ptr + 2;
                uint8_t *opt_end = ptr + hdrlen;
                while (opt_ptr < opt_end) {
                    switch (opt_ptr[0]) {
                        case IPV6_OPTION_PAD1:
                            opt_ptr++;
                            break;
                        case IPV6_OPTION_RPL:
                            *hbh = opt_ptr;
                            goto found_option;
                        default:
                            opt_ptr += 2 + opt_ptr[1];
                            break;
                    }
                }
            found_option:
                /* If they're not looking for SRH, finish now */
                if (!srh) {
                    return;
                }
                break;
            }
            case IPV6_NH_DEST_OPT:
                // Destination option permitted to appear before routing
                if (len < 8) {
                    return;
                }
                nh = ptr[0];
                hdrlen = (ptr[1] + 1) * 8;
                /* If they're not looking for SRH, finish now - past HbH */
                if (!srh) {
                    return;
                }
                break;
            case IPV6_NH_ROUTING:
                if (!srh) {
                    return;
                }
                if (ptr[2] == IPV6_ROUTING_TYPE_RPL) {
                    *srh = ptr;
                }
                // No need to examine past routing header
                return;
            default:
                // No other headers can appear before routing - last we care about
                return;
        }
        if (hdrlen > len) {
            return;
        }
        ptr += hdrlen;
        len -= hdrlen;
    }
    return;
}
Esempio n. 22
0
/*
 *   0                   1                   2                   3
 *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *                                  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *                                  |  Option Type  |  Opt Data Len |
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |O|R|F|0|0|0|0|0| RPLInstanceID |          SenderRank           |
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |                         (sub-TLVs)                            |
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 *                     Figure 1: RPL Option
 */
static buffer_t *rpl_data_exthdr_provider_hbh_2(buffer_t *buf, rpl_instance_t *instance, rpl_neighbour_t *neighbour, ipv6_exthdr_stage_t stage, int16_t *result)
{
    ipv6_route_info_t *route_info = &buf->route->route_info;

    /* This can be called both for routes which only use HbH headers (eg DIO)
     * as well as one-hop DAO_SR routes which would normally use source routing
     * headers, if there was more than one hop. For DAO_SR, neighbour will be
     * NULL.
     */

    rpl_dodag_t *dodag = rpl_instance_current_dodag(instance);
    if (!dodag) {
        *result = -1;
        return buf;
    }

    bool destination_in_instance = false;
    uint16_t ext_size = 0;
    if (addr_ipv6_equal(route_info->next_hop_addr, buf->dst_sa.address) ||
        addr_ipv6_equal(buf->dst_sa.address, dodag->id)) {
        destination_in_instance = true;

        if (buf->rpl_option) {
            /* Forwarding an existing option - preserve it */
            uint8_t opt_size = buf->rpl_option[0];
            ext_size = 2 + opt_size;
            ext_size = (ext_size + 7) &~ 7;
        } else {
            /* Generating our own option - fixed size, no TLVs */
            ext_size = 8;
        }
    }

    switch (stage) {
        case IPV6_EXTHDR_SIZE:
            *result = ext_size;
            return buf;

        case IPV6_EXTHDR_INSERT: {
            if (!destination_in_instance) {
                /* We don't add a header - we'll do it on the tunnel */
                *result = 0;
                return buf;
            }
            buf = buffer_headroom(buf, ext_size);
            if (!buf) {
                return NULL;
            }
            uint8_t *ext = buffer_data_reserve_header(buf, ext_size);
            ext[0] = buf->options.type;
            buf->options.type = IPV6_NH_HOP_BY_HOP;
            ext[1] = ext_size / 8 - 1;
            uint8_t *opt = ext + 2;
            opt[0] = IPV6_OPTION_RPL;
            if (buf->rpl_option) {
                /* Get back the RPL option we stripped off an outer IP header */
                memcpy(opt + 1, buf->rpl_option, 1 + buf->rpl_option[0]);
                ns_dyn_mem_free(buf->rpl_option);
                buf->rpl_option = NULL;
            } else {
                opt[1] = 4; // option length
                opt[2] = 0; // placeholder
                opt[3] = instance->id;
                /* For upwards routes we can deduce that DODAGID must be
                 * the destination, so set the D flag.
                 */
                if (rpl_instance_id_is_local(instance->id) && !rpl_data_is_rpl_downward_route(route_info->source)) {
                    opt[3] |= RPL_INSTANCE_DEST;
                }
                common_write_16_bit(RPL_RANK_INFINITE, opt + 4); // SenderRank (placeholder)
            }
            /* Pad HbH header if necessary. */
            uint8_t pad_len = ext + ext_size - (opt + 2 + opt[1]);
            if (pad_len == 1) {
                opt[0] = IPV6_OPTION_PAD1;
            } else if (pad_len > 1) {
                opt[0] = IPV6_OPTION_PADN;
                opt[1] = pad_len - 2;
                memset(opt + 2, 0, pad_len - 2);
            }
            // don't forget to set the "RPL option present" marker
            buf->options.ip_extflags |= IPEXT_HBH_RPL;
            *result = 0;
            return buf;
        }

        case IPV6_EXTHDR_MODIFY: {
            uint8_t *opt;
            uint16_t sender_rank;

            rpl_data_locate_info(buf, &opt, NULL);
            if (!opt) {
                *result = IPV6_EXTHDR_MODIFY_TUNNEL;
                // Tunnel to next hop in general case, but if going to DODAGID,
                // it can tunnel all the way (and it HAS to if it is a local
                // DODAG).
                if (!addr_ipv6_equal(buf->dst_sa.address, dodag->id)) {
                    memcpy(buf->dst_sa.address, route_info->next_hop_addr, 16);
                }
                buf->src_sa.addr_type = ADDR_NONE; // force auto-selection
                return buf;
            }

            if (buf->ip_routed_up) {
                /* Check for rank errors - RFC 6550 11.2.2.2. */
                /* Note that RPL spec does not say that packets from nodes of
                 * equal rank are errors, but we treat them as such to get
                 * reliable sibling loop detection - we require sender rank to be
                 * strictly less for Down packets and strictly greater for Up.
                 */
                sender_rank = common_read_16_bit(opt + 4);
                rpl_cmp_t cmp = rpl_rank_compare_dagrank_rank(dodag, sender_rank, instance->current_rank);
                rpl_cmp_t expected_cmp = (opt[2] & RPL_OPT_DOWN) ? RPL_CMP_LESS : RPL_CMP_GREATER;
                if (cmp != expected_cmp) {
                    /* Set the Rank-Error bit; if already set, drop */
                    if (opt[2] & RPL_OPT_RANK_ERROR) {
                        protocol_stats_update(STATS_RPL_ROUTELOOP, 1);
                        tr_info("Forwarding inconsistency R");
                        rpl_instance_inconsistency(instance);
                        *result = -1;
                        return buf;
                    } else {
                        opt[2] |= RPL_OPT_RANK_ERROR;
                    }
                }
            }

            if (buf->rpl_flag_error & RPL_OPT_FWD_ERROR) {
                opt[2] |= RPL_OPT_FWD_ERROR;
            } else if (rpl_data_is_rpl_downward_route(route_info->source)) {
                opt[2] |= RPL_OPT_DOWN;
            } else {
                opt[2] &= ~RPL_OPT_DOWN;
            }

            /* Set the D flag for local instances */
            if (rpl_instance_id_is_local(instance->id)) {
                if (addr_ipv6_equal(dodag->id, buf->dst_sa.address)) {
                    opt[3] |= RPL_INSTANCE_DEST;
                } else if (addr_ipv6_equal(dodag->id, buf->src_sa.address)) {
                    opt[3] &=~ RPL_INSTANCE_DEST;
                } else {
                    tr_error("Local instance invalid %s[%d]: %s -> %s", trace_ipv6(dodag->id), instance->id, trace_ipv6(buf->src_sa.address), trace_ipv6(buf->dst_sa.address));
                    *result = -1;
                    return buf;
                }
            }

            /* RPL 11.2.2.2. says we set SenderRank to infinite when forwarding
             * across a version discontinuity. (Must be up - we don't know versions
             * of downward routes).
             */
            if ((buf->rpl_flag_error & RPL_OPT_FWD_ERROR) || rpl_data_is_rpl_downward_route(route_info->source) || !neighbour || neighbour->dodag_version == instance->current_dodag_version) {
                sender_rank = nrpl_dag_rank(dodag, instance->current_rank);
            } else {
                sender_rank = RPL_RANK_INFINITE;
            }
            common_write_16_bit(sender_rank, opt + 4);
            *result = 0;
            return buf;
        }
        default:
            return buffer_free(buf);
    }
}
Esempio n. 23
0
buffer_t *lowpan_up(buffer_t *buf)
{
    protocol_interface_info_entry_t *cur = buf->interface;

    /* Reject:
     *    Packets without address
     *    Source broadcast PAN ID
     *    Short source addresses 0xfffe (illegal) and 0xffff (broadcast)
     */
    if (buf->dst_sa.addr_type == ADDR_NONE || buf->src_sa.addr_type == ADDR_NONE ||
            common_read_16_bit(buf->src_sa.address) == 0xffff ||
            (buf->dst_sa.addr_type == ADDR_802_15_4_SHORT && common_read_16_bit(buf->src_sa.address + 2) > 0xfffd)) {
        goto drop;
    }

    /* If our PAN ID is set to 0xffff (eg during beacon scan), the MAC will be
     * receiving all packets to all PANs. "Mute" 6LoWPAN reception in this state.
     */
    if (cur->mac_parameters->pan_id == 0xffff) {
        goto drop;
    }

    const uint8_t *ip_hc = buffer_data_pointer(buf);

    //tr_debug("IP-UP";

    if (buffer_data_length(buf) < 4 || addr_check_broadcast(buf->src_sa.address, buf->src_sa.addr_type) == 0) {
        tr_debug("cipv6_up() Too short or broadcast src");
        goto drop;
    } else if ((ip_hc[0] & LOWPAN_FRAG_MASK) == LOWPAN_FRAG) {
        /* 11 x00xxx: FRAG1/FRAGN (RFC 4944) */
        buf->info = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_FRAGMENTATION);
        return buf;
    } else if ((ip_hc[0] & LOWPAN_MESH_MASK) == LOWPAN_MESH) {
        /* 10 xxxxxx: MESH (RFC 4944) */
        buf->info = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_MESH_ROUTING);
        return buf;
    } else if (ip_hc[0] == LOWPAN_DISPATCH_IPV6) {
        /* Send this to new handler */
        buffer_data_strip_header(buf, 1);
        buf->ip_routed_up = true;
        buf->info = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_IPV6_FWD);
        return buf;
    } else if ((ip_hc[0] & LOWPAN_DISPATCH_IPHC_MASK) != LOWPAN_DISPATCH_IPHC) {
        /* Not handled: LOWPAN_HC1/LOWPAN_BC0/IPv6 (RFC 4944), or extension */
        tr_debug("LOWPAN: %02x %02x", ip_hc[0], ip_hc[1]);
        goto drop;
    }

    /* Divert to new routing system - in final system, MAC/Mesh/Frag should send to IPV6_TXRX layer */
    buf->ip_routed_up = true;
    buf = iphc_decompress(&cur->lowpan_contexts, buf);
    if (buf) {
        buf->info = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_IPV6_FWD);
    }
    return buf;

drop:
    protocol_stats_update(STATS_IP_RX_DROP, 1);
    return buffer_free(buf);
}