/** Reaction on incoming UPDATE-DEVICE Issue UPDATE-DEVICE.indication */ void zb_aps_in_update_device(zb_uint8_t param) { /* get source address from the nwk header and convert it to long address */ zb_apsme_update_device_pkt_t *pkt = (zb_apsme_update_device_pkt_t *)ZB_BUF_BEGIN(ZB_BUF_FROM_REF(param)); zb_apsme_update_device_ind_t *ind = ZB_GET_BUF_PARAM(ZB_BUF_FROM_REF(param), zb_apsme_update_device_ind_t); TRACE_MSG(TRACE_SECUR3, ">>zb_aps_in_update_device %d", (FMT__H, param)); { zb_uint16_t src_short_addr = ZB_GET_BUF_PARAM(ZB_BUF_FROM_REF(param), zb_apsde_data_indication_t)->src_addr; zb_address_ieee_by_short(src_short_addr, ind->src_address); } ZB_IEEE_ADDR_COPY(ind->device_address, pkt->device_address); ZB_LETOH16(&ind->device_short_address, &pkt->device_short_address); /* We have short and long addresses of the device UPDATE-DEVICE is * about. Remember it. */ { zb_address_ieee_ref_t ref; (void)zb_address_update(ind->device_address, ind->device_short_address, ZB_FALSE, &ref); } ind->status = pkt->status; ZB_SCHEDULE_CALLBACK(zb_apsme_update_device_indication, param); TRACE_MSG(TRACE_SECUR3, "<<zb_aps_in_update_device", (FMT__0)); }
zb_ret_t zb_mlme_ed_scan() { zb_ret_t ret = RET_OK; zb_mac_scan_confirm_t *scan_confirm; /* mac spec 7.5.2.1.1 ED channel scan - discard all frames received over the PHY data service (UBEC stack accepts only beacon frames) - check one-by-one all logical channels, if it is specified in the requested channel mask, switch to this channel, set phyCurrentChannel = new_channel_number; phyCurrentPage = 0 alwayes for ZB - perform ED measurement for current channel during [(aBaseSuperframeDuration * (2^n + 1)) symbols] time. - save maximum ED value to confirmation buffer - perform scan confirm on procedure finish */ TRACE_MSG(TRACE_MAC1, ">> zb_mlme_ed_scan", (FMT__0)); { zb_mlme_scan_params_t *scan_params = ZB_GET_BUF_PARAM(MAC_CTX().pending_buf, zb_mlme_scan_params_t); MAC_CTX().unscanned_channels = scan_params->channels; /* timeout is calculated in beacon intervals */ MAC_CTX().rt_ctx.ed_scan.scan_timeout = (1l << scan_params->scan_duration) + 1; } ZB_BUF_REUSE(MAC_CTX().pending_buf); scan_confirm = ZB_GET_BUF_PARAM(MAC_CTX().pending_buf, zb_mac_scan_confirm_t); ZB_ASSERT(scan_confirm); ZB_BZERO(scan_confirm, sizeof(zb_mac_scan_confirm_t)); scan_confirm->unscanned_channels = MAC_CTX().unscanned_channels; #ifndef ZB_NS_BUILD MAC_CTX().rt_ctx.ed_scan.channel_number = ZB_MAC_START_CHANNEL_NUMBER; MAC_CTX().rt_ctx.ed_scan.save_channel = MAC_CTX().current_channel; MAC_CTX().rt_ctx.ed_scan.max_rssi_value = 0; ret = ZB_SCHEDULE_ALARM(zb_mlme_scan_step, 0, MAC_CTX().rt_ctx.ed_scan.scan_timeout); #else /* ZB_NS_BUILD */ ZB_BZERO(&scan_confirm->list.energy_detect[0], sizeof(scan_confirm->list.energy_detect)); scan_confirm->result_list_size = ZB_MAC_SUPPORTED_CHANNELS; ret = ZB_SCHEDULE_CALLBACK(zb_mlme_scan_confirm, ZB_REF_FROM_BUF(MAC_CTX().pending_buf)); #ifdef ZB_CHANNEL_ERROR_TEST /* channel interference test, show energy on current channel */ TRACE_MSG(TRACE_MAC3, "ch_err_test %hd, logical_channel %hd, ch index %hd", (FMT__H_H_H, ZB_MAC_GET_CHANNEL_ERROR_TEST(), ZB_MAC_GET_CURRENT_LOGICAL_CHANNEL(), ZB_MAC_GET_CURRENT_LOGICAL_CHANNEL() - ZB_MAC_START_CHANNEL_NUMBER)); if (ZB_MAC_GET_CHANNEL_ERROR_TEST()) { scan_confirm->list.energy_detect[ZB_MAC_GET_CURRENT_LOGICAL_CHANNEL() - ZB_MAC_START_CHANNEL_NUMBER] = ZB_CHANNEL_BUSY_ED_VALUE + 1; } #endif #endif /* ZB_NS_BUILD */ TRACE_MSG(TRACE_MAC1, "<< zb_mlme_ed_scan, ret %i", (FMT__D, ret)); return ret; }
/* TODO: fill partner_address for application key */ ZB_SCHEDULE_CALLBACK(zb_apsme_request_key_indication, param); TRACE_MSG(TRACE_SECUR2, "<<zb_aps_in_request_key", (FMT__0)); } #endif /* ZB_ROUTER_ROLE */ void zb_aps_in_switch_key(zb_uint8_t param) { /* get source address from the nwk header and convert it to long address */ zb_apsme_switch_key_pkt_t *pkt = (zb_apsme_switch_key_pkt_t *)ZB_BUF_BEGIN(ZB_BUF_FROM_REF(param)); zb_apsme_switch_key_ind_t *ind = ZB_GET_BUF_PARAM(ZB_BUF_FROM_REF(param), zb_apsme_switch_key_ind_t); { zb_uint16_t src_short_addr = ZB_GET_BUF_PARAM(ZB_BUF_FROM_REF(param), zb_apsde_data_indication_t)->src_addr; zb_address_ieee_by_short(src_short_addr, ind->src_address); } ind->key_seq_number = pkt->key_seq_number; ZB_SCHEDULE_CALLBACK(zb_apsme_switch_key_indication, param); TRACE_MSG(TRACE_SECUR3, "<<zb_aps_in_switch_key", (FMT__0)); }
void zb_handle_scan_request(zb_uint8_t param) { zb_ret_t ret; zb_uint8_t scan_type; TRACE_MSG(TRACE_MAC2, ">> zb_handle_scan_request", (FMT__0)); MAC_CTX().pending_buf = ZB_BUF_FROM_REF(param); scan_type = ZB_GET_BUF_PARAM(MAC_CTX().pending_buf, zb_mlme_scan_params_t)->scan_type; switch (scan_type) { case ACTIVE_SCAN: ret = zb_mlme_active_scan(); break; #ifndef ZB_LIMITED_FEATURES case ED_SCAN: ret = zb_mlme_ed_scan(); MAC_CTX().ed_scan_step_passed = 0; break; case ORPHAN_SCAN: ret = zb_mlme_orphan_scan(); break; #endif default: ret = RET_NOT_IMPLEMENTED; TRACE_MSG(TRACE_MAC3, "bad scan type %hd", (FMT__H, scan_type)); MAC_CTX().mac_status = MAC_INVALID_PARAMETER; break; } TRACE_MSG(TRACE_MAC2, "<< zb_handle_scan_request i", (FMT__D, ret)); }
zb_ret_t zb_mlme_orphan_scan() { zb_ret_t ret = RET_OK; zb_mlme_scan_params_t *scan_params; /* 7.5.2.1.4 - discard all frames except realignment command frames - switch to the channel - send an orphan notification command - enable receiver for at most macResponseWaitTime symbols and waits for coordinator realignment command - if realignment command received - end, otherwise set next channel */ TRACE_MSG(TRACE_MAC1, ">> mlme_orphan_scan", (FMT__0)); /* clear answer flag */ scan_params = ZB_GET_BUF_PARAM(MAC_CTX().pending_buf, zb_mlme_scan_params_t); MAC_CTX().unscanned_channels = scan_params->channels; MAC_CTX().rt_ctx.orphan_scan.got_realignment = 0; /* TODO: Configiure transiver to accept only realignment commands */ ret = ZB_SCHEDULE_ALARM(zb_mlme_scan_step, 0, ZB_MAC_PIB_RESPONSE_WAIT_TIME); TRACE_MSG(TRACE_MAC1, "<< mlme_orphan_scan %i", (FMT__D, ret)); return ret; }
void zb_aps_in_request_key(zb_uint8_t param) { /* get source address from the nwk header and convert it to long address */ zb_apsme_request_nwk_key_pkt_t *pkt = (zb_apsme_request_nwk_key_pkt_t *)ZB_BUF_BEGIN(ZB_BUF_FROM_REF(param)); zb_apsme_request_key_ind_t *ind = ZB_GET_BUF_PARAM(ZB_BUF_FROM_REF(param), zb_apsme_request_key_ind_t); TRACE_MSG(TRACE_SECUR2, ">>zb_aps_in_request_key", (FMT__0)); { zb_uint16_t src_short_addr = ZB_GET_BUF_PARAM(ZB_BUF_FROM_REF(param), zb_apsde_data_indication_t)->src_addr; zb_address_ieee_by_short(src_short_addr, ind->src_address); } ind->key_type = pkt->key_type; /* TODO: fill partner_address for application key */ ZB_SCHEDULE_CALLBACK(zb_apsme_request_key_indication, param); TRACE_MSG(TRACE_SECUR2, "<<zb_aps_in_request_key", (FMT__0)); }
void zb_aps_in_remove_device(zb_uint8_t param) { /* get source address from the nwk header and convert it to long address */ zb_apsme_remove_device_pkt_t *pkt = (zb_apsme_remove_device_pkt_t *)ZB_BUF_BEGIN(ZB_BUF_FROM_REF(param)); zb_apsme_remove_device_ind_t *ind = ZB_GET_BUF_PARAM(ZB_BUF_FROM_REF(param), zb_apsme_remove_device_ind_t); TRACE_MSG(TRACE_SECUR3, ">>zb_aps_in_remove_device %d", (FMT__H, param)); { zb_uint16_t src_short_addr = ZB_GET_BUF_PARAM(ZB_BUF_FROM_REF(param), zb_apsde_data_indication_t)->src_addr; zb_address_ieee_by_short(src_short_addr, ind->src_address); } ZB_IEEE_ADDR_COPY(ind->child_address, pkt->child_address); ZB_SCHEDULE_CALLBACK(zb_apsme_remove_device_indication, param); TRACE_MSG(TRACE_SECUR3, "<<zb_aps_in_remove_device", (FMT__0)); }
/* 7.1.11.1 MLME-SCAN.request */ void zb_mlme_scan_request(zb_uint8_t param) { zb_ret_t ret = RET_OK; zb_mlme_scan_params_t *params; zb_uint8_t scan_type; zb_uint8_t handle_scan_called = 0; TRACE_MSG(TRACE_MAC2, ">> zb_mlme_scan_request %hd", (FMT__H, param)); params = ZB_GET_BUF_PARAM((zb_buf_t *)ZB_BUF_FROM_REF(param), zb_mlme_scan_params_t); ZB_ASSERT(params); MAC_CTX().mac_status = MAC_SUCCESS; scan_type = params->scan_type; if (params->scan_duration > ZB_MAX_SCAN_DURATION_VALUE && scan_type != ORPHAN_SCAN) { ret = RET_ERROR; MAC_CTX().mac_status = MAC_INVALID_PARAMETER; } if ((ret == RET_OK)&&(!MAC_CTX().mlme_scan_in_progress)) { /* process request immediately*/ MAC_CTX().pending_buf = ZB_BUF_FROM_REF(param); ZB_SCHEDULE_CALLBACK(zb_handle_scan_request, param); handle_scan_called = 1; } if (!handle_scan_called) { zb_mac_scan_confirm_t *scan_confirm; scan_confirm = ZB_GET_BUF_PARAM(MAC_CTX().pending_buf, zb_mac_scan_confirm_t); scan_confirm->status = (ret == RET_OK) ? MAC_SUCCESS : MAC_CTX().mac_status != MAC_SUCCESS ? MAC_CTX().mac_status : MAC_INVALID_PARAMETER; scan_confirm->scan_type = scan_type; ZB_SCHEDULE_CALLBACK(zb_mlme_scan_confirm, ZB_REF_FROM_BUF(MAC_CTX().pending_buf)); } TRACE_MSG(TRACE_MAC2, "<< zb_mlme_scan_request", (FMT__0)); }
zb_ret_t zb_mlme_active_scan() { zb_ret_t ret = RET_OK; zb_mlme_scan_params_t *scan_params; zb_uint8_t channel_number; /* mac spec 7.5.2.1.2 Active channel scan - set macPANId to 0xffff in order to accept all incoming beacons - switch to next channel - send beacon request, mac spec 7.3.7 Beacon request command - enable receiver for [aBaseSuperframeDuration * (2^n + 1)] symbols == (2^n + 1)Beacon_Intervals, n == request.ScanDuration; accept only beacon frames - use mode macAutoRequest == FALSE: send each beacon to the higher layer using MLME-BEACON-NOTIFY indication. Beacon frame can contain payload - if frame_control.Security Enabled == 1, unsecure the beacon frame (mac spec 7.5.8.2.3) --- not supported now - if at least 1 beacon request was successfully sent but no beacons were found, set status NO_BEACON */ TRACE_MSG(TRACE_MAC1, ">> zb_mlme_active_scan", (FMT__0)); scan_params = ZB_GET_BUF_PARAM(MAC_CTX().pending_buf, zb_mlme_scan_params_t); ZB_ASSERT(scan_params); TRACE_MSG(TRACE_MAC1, "idle state, set beacon found == 0", (FMT__0)); MAC_CTX().rt_ctx.active_scan.beacon_found = 0; #ifdef ZB_MAC_TESTING_MODE MAC_CTX().rt_ctx.active_scan.pan_desc_buf_param = ZB_UNDEFINED_BUFFER; #endif channel_number = ZB_MAC_START_CHANNEL_NUMBER; TRACE_MSG(TRACE_MAC3, "set beacon mode ret %d, param channels 0x%x", (FMT__D_D, ret, scan_params->channels)); MAC_CTX().unscanned_channels = scan_params->channels; #ifdef ZB_MAC_TESTING_MODE if (MAC_CTX().rt_ctx.active_scan.stop_scan) { ZB_SCHEDULE_ALARM_CANCEL(zb_mac_scan_timeout, 0); ret = RET_OK; break; } #endif TRACE_MSG(TRACE_MAC2, "chan mask %x %x , chan %hd", (FMT__D_D_H, ((zb_uint16_t*)&scan_params->channels)[0], ((zb_uint16_t*)&scan_params->channels)[1], channel_number)); ZB_SCHEDULE_CALLBACK(zb_mlme_scan_step,0); TRACE_MSG(TRACE_MAC1, "<< zb_mlme_active_scan, ret %i", (FMT__D, ret)); return ret; }
void nwk_route_disc_failed(zb_uint8_t param) { zb_nlme_status_indication_t *status = ZB_GET_BUF_PARAM(ZB_BUF_FROM_REF(param), zb_nlme_status_indication_t); TRACE_MSG(TRACE_NWK1, ">> nwk_route_disc_failed", (FMT__0)); status->status = ZB_NWK_COMMAND_STATUS_NO_ROUTE_AVAILABLE; status->network_addr = ZG->nwk.handle.status_ind_addr; /* notify */ ZB_SCHEDULE_CALLBACK(zb_nlme_status_indication, param); ZB_SCHEDULE_ALARM_CANCEL(zb_nwk_mesh_expiry_route_disc, 0); ZB_SCHEDULE_ALARM(zb_nwk_mesh_expiry_route_disc, 0, ZB_NWK_EXPIRY_ROUTE_DISCOVERY); TRACE_MSG(TRACE_NWK1, ">> nwk_route_disc_failed", (FMT__0)); }
/* this is a universal routine for ed/active/orphan scans */ void zb_mlme_scan_step(zb_uint8_t param) { zb_uint8_t channel_number; zb_mlme_scan_params_t *scan_params; zb_ret_t ret = RET_OK; zb_uint16_t timeout; zb_uint32_t *unscanned_channels; TRACE_MSG(TRACE_MAC1, ">> zb_mlme_scan_step", (FMT__0)); ZVUNUSED(param); channel_number = ZB_MAC_START_CHANNEL_NUMBER; scan_params = ZB_GET_BUF_PARAM(MAC_CTX().pending_buf, zb_mlme_scan_params_t); /* Table 2.80 Fields of the Mgmt_NWK_Disc_req Command (the other scans requests are using the same parameters A value used to calculate the length of time to spend scanning each channel. The time spent scanning each channel is (aBaseSuperframeDuration * (2^n + 1)) symbols, where n is the value of the ScanDuration parameter. */ timeout = (1l << scan_params->scan_duration) + 1; MAC_CTX().mlme_scan_in_progress = 1; unscanned_channels = &MAC_CTX().unscanned_channels; for (;channel_number < ZB_MAC_START_CHANNEL_NUMBER + ZB_MAC_MAX_CHANNEL_NUMBER;channel_number++) { if (*unscanned_channels & 1l<<channel_number) { TRACE_MSG(TRACE_MAC2, "set channel %hd", (FMT__H, channel_number)); ZB_TRANSCEIVER_SET_CHANNEL(channel_number); *unscanned_channels &=~(1l<<channel_number); if (scan_params->scan_type == ACTIVE_SCAN) { ret = zb_beacon_request_command(); if (ret == RET_OK) { /* check beacon request TX status */ /* There's nothing to do during active scan, so, synchronous */ ret = zb_check_cmd_tx_status(); } } ZB_SCHEDULE_ALARM_CANCEL(zb_mlme_scan_step, 0); ret = ZB_SCHEDULE_ALARM(zb_mlme_scan_step, 0, timeout); break; } } if (channel_number == (ZB_MAC_START_CHANNEL_NUMBER + ZB_MAC_MAX_CHANNEL_NUMBER)) { zb_mac_scan_confirm_t *scan_confirm; /* There's no need to restore channel after active or orphan scan, because we will choose new channel, according to scan results. */ /* ZB_TRANSCEIVER_SET_CHANNEL(MAC_CTX().rt_ctx.ed_scan.save_channel);*/ scan_confirm = ZB_GET_BUF_PARAM(MAC_CTX().pending_buf, zb_mac_scan_confirm_t); TRACE_MSG(TRACE_MAC3, "beacon found %hd", (FMT__H, MAC_CTX().rt_ctx.active_scan.beacon_found)); if (scan_params->scan_type == ED_SCAN || MAC_CTX().rt_ctx.active_scan.beacon_found || MAC_CTX().rt_ctx.orphan_scan.got_realignment) { scan_confirm->status = MAC_SUCCESS; /* Q: do we really need to zero here? What about got_realignment? * * A: I think yes, because it is the only indication * for NO_BEACON status, that will not affect ED or ORPHAN scans. ED just * doesn't need any packets, and ORPHAN needs a realignment command that * is processed in appropriate function */ MAC_CTX().rt_ctx.active_scan.beacon_found = 0; } else { scan_confirm->status = MAC_NO_BEACON; } #ifdef ZB_MAC_TESTING_MODE { scan_confirm->result_list_size = desc_count; } #endif scan_confirm->scan_type = scan_params->scan_type; MAC_CTX().mlme_scan_in_progress = 0; ZB_SCHEDULE_CALLBACK(zb_mlme_scan_confirm, ZB_REF_FROM_BUF(MAC_CTX().pending_buf)); } TRACE_MSG(TRACE_MAC1, "<< zb_mlme_scan_step", (FMT__0)); }
/** Reaction on TRANSPORT-KEY APS command */ void zb_aps_in_transport_key(zb_uint8_t param) { zb_transport_key_nwk_key_dsc_pkt_t *dsc = (zb_transport_key_nwk_key_dsc_pkt_t *)ZB_BUF_BEGIN(ZB_BUF_FROM_REF(param)); TRACE_MSG(TRACE_SECUR3, ">>zb_aps_in_transport_key %d", (FMT__H, param)); /* See 4.4.3.3 Upon Receipt of a Transport-Key Command */ switch (dsc->key_type) { case ZB_STANDARD_NETWORK_KEY: if ( /* key is for me */ ZB_IEEE_ADDR_CMP(dsc->dest_address, ZB_PIB_EXTENDED_ADDRESS()) /* key is for all */ || ZB_IEEE_ADDR_IS_ZERO(dsc->dest_address)) { /* This key is for me. Issue APSME-TRANSPORT-KEY.indication. ZDO will * setup keys and remember TC address. */ zb_apsme_transport_key_indication_t *ind = ZB_GET_BUF_PARAM(ZB_BUF_FROM_REF(param), zb_apsme_transport_key_indication_t); TRACE_MSG(TRACE_SECUR3, "in std nwk key #%d for me", (FMT__D, dsc->seq_number)); ind->key_type = dsc->key_type; ZB_IEEE_ADDR_COPY(ind->src_address, dsc->source_address); ind->key.nwk.key_seq_number = dsc->seq_number; ZB_MEMCPY(ind->key.nwk.key, dsc->key, ZB_CCM_KEY_SIZE); ZB_SCHEDULE_CALLBACK(zb_apsme_transport_key_indication, param); /* #ifdef ZB_ROUTER_ROLE */ /* This feature should be processed at request */ #if 0 if (ZB_IEEE_ADDR_IS_ZERO(dsc->dest_address) /* && check for secured transfer at nwk level */ && ZB_IEEE_ADDR_CMP(dsc->source_address, ZB_AIB().trust_center_address)) { /* * Need to pass key to all rx-off-when-idle children. Need another * packet buffer for it. * Do the rest in the calback: this is blocked * buffer alloc. Not need to save current key: it will be aleady * assigned, so can send my own key. */ ZG->aps.tmp.neighbor_table_iterator = zb_nwk_neighbor_next_ze_children_rx_off_i(0); ZG->aps.tmp.key_seq_number = ind->key.nwk.key_seq_number; if (ZG->aps.tmp.neighbor_table_iterator != (zb_ushort_t)~0) { TRACE_MSG(TRACE_SECUR3, "send key #%hd to all ZE", (FMT__H, dsc->seq_number)); zb_get_out_buf_delayed(zb_aps_pass_nwk_key_to_children); } } #endif /* ZB_ROUTER_ROLE */ } #ifdef ZB_ROUTER_ROLE else { zb_address_ieee_ref_t addr_ref; zb_neighbor_tbl_ent_t *nbe; /* Search for child in the Neighbor table, mark child as Authenticated, * send key to it using unsecured NWK transfer */ if (zb_address_by_ieee(dsc->dest_address, ZB_FALSE, ZB_FALSE, &addr_ref) == RET_OK && zb_nwk_neighbor_get(addr_ref, ZB_FALSE, &nbe) == RET_OK && (nbe->relationship == ZB_NWK_RELATIONSHIP_UNAUTHENTICATED_CHILD || nbe->relationship == ZB_NWK_RELATIONSHIP_CHILD)) { zb_uint16_t addr; zb_address_short_by_ref(&addr, addr_ref); TRACE_MSG(TRACE_SECUR3, "send key #%hd to ZE %d, auth ok", (FMT__H_D, dsc->seq_number, addr)); zb_aps_send_command(param, addr, APS_CMD_TRANSPORT_KEY, (nbe->relationship != ZB_NWK_RELATIONSHIP_UNAUTHENTICATED_CHILD)); nbe->relationship = ZB_NWK_RELATIONSHIP_CHILD; } else { TRACE_MSG(TRACE_SECUR1, "child " TRACE_FORMAT_64 " not found", (FMT__A, TRACE_ARG_64(dsc->dest_address))); zb_free_buf(ZB_BUF_FROM_REF(param)); } } #endif /* ZB_ROUTER_ROLE */ break; default: break; } TRACE_MSG(TRACE_SECUR3, "<<zb_aps_in_transport_key", (FMT__0)); }
zb_ret_t zb_aps_unsecure_frame(zb_buf_t *buf) { zb_ret_t ret = RET_OK; zb_uint8_t *aps_hdr; zb_aps_nwk_aux_frame_hdr_t *aux; zb_ushort_t a_size; zb_uint8_t *key; zb_uint8_t *payload; zb_address_ieee_ref_t addr_ref; { zb_apsde_data_indication_t * ind = ZB_GET_BUF_PARAM(buf, zb_apsde_data_indication_t); ret = zb_address_by_short(ind->src_addr, ZB_FALSE, ZB_FALSE, &addr_ref); if (ret != RET_OK) { TRACE_MSG(TRACE_SECUR3, "can't get addr %d", (FMT__D, ind->src_addr)); } } if (ret == RET_OK) { aps_hdr = ZB_BUF_BEGIN(buf); aux = (zb_aps_nwk_aux_frame_hdr_t *)(aps_hdr + ZB_APS_HDR_SIZE(*aps_hdr)); a_size = ((zb_uint8_t *)aux - aps_hdr); if (ZB_SECUR_AUX_HDR_GET_KEY_TYPE(aux->secur_control) == ZB_SECUR_DATA_KEY) { aux->secur_control = ZB_APS_DATA_STD_SECUR_CONTROL; payload = (zb_uint8_t *)aux + sizeof(zb_aps_data_aux_frame_hdr_t); /* TODO: implement Data key */ /* obtain secure material. */ /* check frame counters */ key = 0; a_size += sizeof(zb_aps_data_aux_frame_hdr_t); } else { /* NWK key */ zb_neighbor_tbl_ent_t *nbe; /* Update security level which was zeroed before send */ aux->secur_control = ZB_APS_NWK_STD_SECUR_CONTROL; payload = (zb_uint8_t *)aux + sizeof(zb_aps_nwk_aux_frame_hdr_t); key = secur_nwk_key_by_seq(aux->key_seq_number); a_size += sizeof(zb_aps_nwk_aux_frame_hdr_t); /* Get neighbor table entry by source address. */ ret = zb_nwk_neighbor_get(addr_ref, ZB_TRUE, &nbe); if (ret == RET_OK) { if (key && nbe->key_seq_number != aux->key_seq_number) { /* Peer now use another nwk key */ nbe->incoming_frame_counter = 0; nbe->key_seq_number = aux->key_seq_number; TRACE_MSG(TRACE_SECUR3, "peer switched key", (FMT__0)); } { /* Check NWK FrameCounter */ zb_uint32_t frame_counter; ZB_LETOH32(&frame_counter, &aux->frame_counter); if (nbe->incoming_frame_counter > frame_counter || nbe->incoming_frame_counter == (zb_uint32_t)~0) { ret = RET_ERROR; TRACE_MSG(TRACE_SECUR3, "frm cnt %ld->%ld shift back", (FMT__L_L, nbe->incoming_frame_counter, frame_counter)); } else { nbe->incoming_frame_counter = frame_counter; } } } else { TRACE_MSG(TRACE_SECUR3, "can't get neighbor", (FMT__0)); } } } if (ret == RET_OK && !key) { /* set 'frame security failed' */ ret = RET_ERROR; TRACE_MSG(TRACE_SECUR3, "no key by seq %hd", (FMT__H, aux->key_seq_number)); } if (ret == RET_OK) { /* decrypt */ zb_secur_ccm_nonce_t nonce; zb_address_ieee_by_ref(nonce.source_address, addr_ref); nonce.frame_counter = aux->frame_counter; nonce.secur_control = aux->secur_control; ret = zb_ccm_decrypt_n_auth_stdsecur(key, (zb_uint8_t *)&nonce, buf, a_size, (ZB_BUF_BEGIN(buf) + ZB_BUF_LEN(buf)) - (aps_hdr + a_size)); if (ret == RET_OK) { /* Remove MIC */ TRACE_MSG(TRACE_SECUR3, "unsecured frm %p[%hd] ok", (FMT__P_H, buf, ZB_BUF_LEN(buf))); } else { TRACE_MSG(TRACE_SECUR3, "unsecure failed", (FMT__0)); } } return ret; }