/** * @brief Resets the MAC helper variables and transition to idle state * * This function sets the MAC to idle state and resets * MAC helper variables */ void mac_idle_trans(void) { /* Wake up radio first */ mac_trx_wakeup(); { uint16_t default_shortaddress = macShortAddress_def; uint16_t default_panid = macPANId_def; #if (_DEBUG_ > 0) retval_t set_status = #endif set_tal_pib_internal(macShortAddress, (void *)&default_shortaddress); #if (_DEBUG_ > 0) Assert(MAC_SUCCESS == set_status); set_status = #endif set_tal_pib_internal(macPANId, (void *)&default_panid); #if (_DEBUG_ > 0) Assert(MAC_SUCCESS == set_status); set_status = set_status; #endif } mac_soft_reset(true); /* Set radio to sleep if allowed */ mac_sleep_trans(); }
/* * @brief Timer function after sync request to wake up radio at beacon time * * This function is a callback from the tracking beacon timer and implements * the RX timer service function during sync and enables the receiver before * the next beacon reception is expected. * * @param callback_parameter Callback parameter of the expired beacon * tracking timer */ void mac_t_tracking_beacons_cb(void *callback_parameter) { /* Wake up radio first */ mac_trx_wakeup(); /* Turn the radio on */ tal_rx_enable(PHY_RX_ON); callback_parameter = callback_parameter; /* Keep compiler happy. */ }
/* * @brief Continues handling of MLME-RX-ENABLE.request by * waking radio up and setting it into rx on state. * * @param rxe_buff_ptr Pointer to the MLME-RX-ENABLE buffer allocated by the * NHLE. */ static uint8_t mac_rx_enable() { uint8_t status; /* Wake up the radio first */ mac_trx_wakeup(); /* Turn the receiver on immediately. */ status = tal_rx_enable(PHY_RX_ON); /* Rx is enabled */ mac_rx_enabled = true; return (status); } /* mac_rx_enable() */
/** * @brief Wakes-up the radio and sets the corresponding TAL PIB attribute * * @param attribute PIB attribute to be set * @param attribute_value Attribute value to be set * * @return Status of the attempt to set the TAL PIB attribute */ retval_t set_tal_pib_internal(uint8_t attribute, pib_value_t *attribute_value) { retval_t status; if (RADIO_SLEEPING == mac_radio_sleep_state) { /* Wake up the radio */ mac_trx_wakeup(); status = tal_pib_set(attribute, attribute_value); /* Set radio to sleep if allowed */ mac_sleep_trans(); } else { status = tal_pib_set(attribute, attribute_value); } return status; }
/** * @brief Resets the MAC layer * * The MLME-RESET.request primitive allows the next higher layer to request * that the MLME performs a reset operation. * * @param m Pointer to the MLME_RESET.request given by the NHLE */ void mlme_reset_request(uint8_t *m) { mlme_reset_req_t *mrr = (mlme_reset_req_t *)BMM_BUFFER_POINTER((buffer_t *)m); /* Wakeup the radio */ mac_trx_wakeup(); /* Start MAC reset functionality */ uint8_t status = mac_reset(mrr->SetDefaultPIB); /* Set radio to sleep if allowed */ mac_sleep_trans(); /* * As this is a mlme_reset request, all the requests, data (whether * direct * or indirect), incoming frames are removed from the queues */ flush_queues(); send_reset_conf((buffer_t *)m, status); } /* mlme_reset_request() */
/* * @brief The MLME-GTS.request primitive makes a request for device to * request for GTS or on PANC to allocate or deallocate a GTS for itself * or other devices * * 802.15.4. Section 7.1.7.1. * * @param m The MLME-GTS.request message. */ void mlme_gts_request(uint8_t *m) { mlme_gts_req_t mgr; memcpy(&mgr, BMM_BUFFER_POINTER((buffer_t *)m), sizeof(mlme_gts_req_t)); if (MAC_NO_SHORT_ADDR_VALUE <= tal_pib.ShortAddress || (MAC_NO_SHORT_ADDR_VALUE <= mac_pib.mac_CoordShortAddress && MAC_PAN_COORD_STARTED != mac_state)) { mac_gen_mlme_gts_conf((buffer_t *)m, MAC_NO_SHORT_ADDRESS, mgr.GtsChar); return; } else if (true != mac_pib.mac_GTSPermit || (0 == mgr.GtsChar.GtsLength) || (MAC_ASSOCIATED == mac_state && (mgr.DeviceShortAddr != tal_pib.ShortAddress || MAC_SYNC_TRACKING_BEACON != mac_sync_state || (mgr.GtsChar.GtsCharType == GTS_DEALLOCATE && (!mac_dev_gts_table[mgr.GtsChar.GtsDirection]. GtsStartingSlot || mgr.GtsChar.GtsLength != mac_dev_gts_table[mgr.GtsChar.GtsDirection].GtsLength)) ) ) ) { mac_gen_mlme_gts_conf((buffer_t *)m, MAC_INVALID_PARAMETER, mgr.GtsChar); return; } #ifdef FFD else if (MAC_PAN_COORD_STARTED == mac_state) { if (GTS_ALLOCATE & mgr.GtsChar.GtsCharType) { if (mac_gts_allocate(mgr.GtsChar, mgr.DeviceShortAddr)) { mac_gen_mlme_gts_conf((buffer_t *)m, MAC_SUCCESS, mgr.GtsChar); return; } else { mac_gen_mlme_gts_conf((buffer_t *)m, MAC_NO_DATA, mgr.GtsChar); return; } } else { if (mac_gts_deallocate(mgr.GtsChar, mgr.DeviceShortAddr, true)) { mac_gen_mlme_gts_conf((buffer_t *)m, MAC_SUCCESS, mgr.GtsChar); return; } else { mac_gen_mlme_gts_conf((buffer_t *)m, MAC_NO_DATA, mgr.GtsChar); return; } } } #endif /* FFD */ else if (MAC_ASSOCIATED == mac_state) { frame_info_t *transmit_frame = (frame_info_t *)BMM_BUFFER_POINTER((buffer_t *)m); mac_trx_wakeup(); /* Build the GTS Request command frame. */ uint8_t tal_tx_status; uint8_t frame_len; uint8_t *frame_ptr; uint8_t *temp_frame_ptr; uint16_t fcf; /* * Use the mlme gts request buffer for transmitting * gts request frame. */ frame_info_t *gts_req_frame = (frame_info_t *)(BMM_BUFFER_POINTER((buffer_t *)m)); gts_req_frame->msg_type = GTSREQUEST; gts_req_frame->buffer_header = (buffer_t *)m; /* Get the payload pointer. */ frame_ptr = temp_frame_ptr = (uint8_t *)gts_req_frame + LARGE_BUFFER_SIZE - GTS_REQ_PAYLOAD_LEN - 2; /* Add *2 *octets *for *FCS. **/ /* Update the payload field. */ *frame_ptr++ = GTSREQUEST; /* Build the GTS characteristics info. */ *frame_ptr = *((uint8_t *)&mgr.GtsChar); /* Get the payload pointer again to add the MHR. */ frame_ptr = temp_frame_ptr; /* Update the length. */ frame_len = GTS_REQ_PAYLOAD_LEN + 2 + /* Add 2 octets for FCS */ 2 + /* 2 octets for Destination PAN-Id */ 2 + /* 2 octets for short Destination Address */ 2 + /* 2 octets for short Source Address */ 3; /* 3 octets DSN and FCF */ /* Source address */ frame_ptr -= 2; convert_16_bit_to_byte_array(tal_pib.ShortAddress, frame_ptr); frame_ptr -= 2; convert_16_bit_to_byte_array(mac_pib.mac_CoordShortAddress, frame_ptr); fcf = FCF_SET_FRAMETYPE(FCF_FRAMETYPE_MAC_CMD) | FCF_SET_DEST_ADDR_MODE(FCF_SHORT_ADDR) | FCF_SET_SOURCE_ADDR_MODE(FCF_SHORT_ADDR) | FCF_ACK_REQUEST | FCF_PAN_ID_COMPRESSION; /* Destination PAN-Id */ frame_ptr -= 2; convert_16_bit_to_byte_array(tal_pib.PANId, frame_ptr); /* Set DSN. */ frame_ptr--; *frame_ptr = mac_pib.mac_DSN++; /* Set the FCF. */ frame_ptr -= 2; convert_spec_16_bit_to_byte_array(fcf, frame_ptr); /* First element shall be length of PHY frame. */ frame_ptr--; *frame_ptr = frame_len; /* Finished building of frame. */ gts_req_frame->mpdu = frame_ptr; tal_tx_status = tal_tx_frame(transmit_frame, CSMA_SLOTTED, true); if (MAC_SUCCESS == tal_tx_status) { uint8_t update_index = mgr.GtsChar.GtsDirection; if (mgr.DeviceShortAddr == mac_pib.mac_CoordShortAddress) { update_index |= 0x02; } if (GTS_DEALLOCATE == mgr.GtsChar.GtsCharType) { mac_dev_gts_table[update_index].GtsLength = 0; mac_dev_gts_table[update_index].GtsStartingSlot = 0; mac_dev_gts_table[update_index].GtsState = GTS_STATE_IDLE; mac_gen_mlme_gts_conf((buffer_t *)m, MAC_SUCCESS, mgr.GtsChar); return; } else { mac_dev_gts_table[update_index].GtsReq_ptr = m; mac_dev_gts_table[update_index].GtsState = GTS_STATE_REQ_SENT; mac_dev_gts_table[update_index].GtsPersistCount = aGTSDescPersistenceTime; mac_dev_gts_table[update_index].GtsLength = mgr.GtsChar.GtsLength; MAKE_MAC_BUSY(); } } else { mac_gen_mlme_gts_conf((buffer_t *)m, tal_tx_status, mgr.GtsChar); } } else { mac_gen_mlme_gts_conf((buffer_t *)m, MAC_INVALID_PARAMETER, mgr.GtsChar); } return; }
/** * @brief The MLME-START.request primitive makes a request for the device to * start using a new superframe configuration * * @param m Pointer to MLME_START.request message issued by the NHLE */ void mlme_start_request(uint8_t *m) { mlme_start_req_t *msg = (mlme_start_req_t *)BMM_BUFFER_POINTER((buffer_t *)m); /* * The MLME_START.request parameters are copied into a global variable * structure, which is used by check_start_parameter() function. */ memcpy(&msr_params, msg, sizeof(msr_params)); if (BROADCAST == tal_pib.ShortAddress) { /* * The device is void of short address. This device cannot start a * network, hence a confirmation is given back. */ gen_mlme_start_conf((buffer_t *)m, MAC_NO_SHORT_ADDRESS); return; } #ifndef REDUCED_PARAM_CHECK if (!check_start_parameter(msg)) { /* * The MLME_START.request parameters are invalid, hence confirmation * is given to NHLE. */ gen_mlme_start_conf((buffer_t *)m, MAC_INVALID_PARAMETER); } else #endif /* REDUCED_PARAM_CHECK */ { /* * All the start parameters are valid, hence MLME_START.request can * proceed. */ set_tal_pib_internal(mac_i_pan_coordinator, (void *)&(msg->PANCoordinator)); if (msr_params.CoordRealignment) { /* First inform our devices of the configuration change */ if (!mac_tx_coord_realignment_command(COORDINATORREALIGNMENT, (buffer_t *)m, msr_params.PANId, msr_params.LogicalChannel, msr_params.ChannelPage)) { /* * The coordinator realignment command was unsuccessful, * hence the confiramtion is given to NHLE. */ gen_mlme_start_conf((buffer_t *)m, MAC_INVALID_PARAMETER); } } else { /* This is a normal MLME_START.request. */ retval_t channel_set_status, channel_page_set_status; /* The new PIBs are set at the TAL. */ set_tal_pib_internal(macBeaconOrder, (void *)&(msg->BeaconOrder)); /* If macBeaconOrder is equal to 15, set also macSuperframeOrder to 15. */ if (msg->BeaconOrder == NON_BEACON_NWK) { msg->SuperframeOrder = NON_BEACON_NWK; } set_tal_pib_internal(macSuperframeOrder, (void *)&(msg->SuperframeOrder)); #ifdef BEACON_SUPPORT /* * Symbol times are calculated according to the new BO and SO * values. */ if (tal_pib.BeaconOrder < NON_BEACON_NWK) { set_tal_pib_internal(macBattLifeExt, (void *)&(msr_params.BatteryLifeExtension)); } #endif /* BEACON_SUPPORT */ /* Wake up radio first */ mac_trx_wakeup(); /* MLME_START.request parameters other than BO and SO are set at TAL */ set_tal_pib_internal(macPANId, (void *)&(msr_params.PANId)); channel_page_set_status = set_tal_pib_internal(phyCurrentPage, (void *)&(msr_params.ChannelPage)); channel_set_status = set_tal_pib_internal(phyCurrentChannel, (void *)&(msr_params.LogicalChannel)); set_tal_pib_internal(mac_i_pan_coordinator, (void *)&(msr_params.PANCoordinator)); if ((MAC_SUCCESS == channel_page_set_status) && (MAC_SUCCESS == channel_set_status) && (PHY_RX_ON == tal_rx_enable(PHY_RX_ON)) ) { if (msr_params.PANCoordinator) { mac_state = MAC_PAN_COORD_STARTED; } else { mac_state = MAC_COORDINATOR; } gen_mlme_start_conf((buffer_t *)m, MAC_SUCCESS); #ifdef BEACON_SUPPORT /* * In case we have a beaconing network, the beacon timer needs * to be started now. */ if (tal_pib.BeaconOrder != NON_BEACON_NWK) { mac_start_beacon_timer(); } #endif /* BEACON_SUPPORT */ } else { /* Start of network failed. */ gen_mlme_start_conf((buffer_t *)m, MAC_INVALID_PARAMETER); } /* Set radio to sleep if allowed */ mac_sleep_trans(); } } }
/** * @brief Implements MLME-POLL.request * * This function handles an MLME-POLL.request primitive. * The MLME-POLL.request primitive is generated by the next * higher layer and issued to its MLME when data are to be * requested from a coordinator. * * @param m Pointer to the message */ void mlme_poll_request(uint8_t *m) { /* * Polling for data is only allowed, if the node * 1) is not a PAN coordinator, * 2) is not polling already, and * 3) is not scanning. */ if ( (MAC_POLL_IDLE == mac_poll_state) && #if (MAC_START_REQUEST_CONFIRM == 1) (MAC_PAN_COORD_STARTED != mac_state) && #endif /* MAC_START_REQUEST_CONFIRM == 1) */ (MAC_SCAN_IDLE == mac_scan_state) ) { bool status; address_field_t coord_addr; /* Wake up radio first */ mac_trx_wakeup(); /* * Extract the Coordinator address information from the Poll * request. * This is required later for building the proper destination * address * information in the data request frame. */ mlme_poll_req_t *msg = (mlme_poll_req_t *)BMM_BUFFER_POINTER((buffer_t *)m); { uint8_t data_req_addr_mode; if (msg->CoordAddrMode == FCF_SHORT_ADDR) { data_req_addr_mode = FCF_SHORT_ADDR; ADDR_COPY_DST_SRC_16(coord_addr.short_address, msg->CoordAddress); } else { data_req_addr_mode = FCF_LONG_ADDR; ADDR_COPY_DST_SRC_64(coord_addr.long_address, msg->CoordAddress); } /* Build and transmit data request frame due to explicit * poll request */ status = mac_build_and_tx_data_req(true, false, data_req_addr_mode, &coord_addr, msg->CoordPANId); } if (status) { /* Store the poll request buffer to give poll confirm */ mac_conf_buf_ptr = m; } else { gen_mlme_poll_conf((buffer_t *)m, MAC_CHANNEL_ACCESS_FAILURE); } } else { gen_mlme_poll_conf((buffer_t *)m, MAC_CHANNEL_ACCESS_FAILURE); } }
/** * @brief Implements the MLME-SYNC request. * * The MLME-SYNC.request primitive requests to synchronize with the * coordinator by acquiring and, if specified, tracking its beacons. * The MLME-SYNC.request primitive is generated by the next higher layer of a * device on a beacon-enabled PAN and issued to its MLME to synchronize with * the coordinator. * * Enable receiver and search for beacons for at most an interval of * [aBaseSuperframeDuration * ((2 ^ (n))+ 1)] symbols where n is the value of * macBeaconOrder. If a beacon frame containing the current PAN identifier of * the device is not received, the MLME shall repeat this search. Once the * number of missed beacons reaches aMaxLostBeacons, the MLME shall notify * the next higher layer by issuing the MLME-SYNC-LOSS.indication primitive * with a loss reason of BEACON_LOSS. * * @param m Pointer to the MLME sync request parameters. */ void mlme_sync_request(uint8_t *m) { #if (DEBUG > 0) retval_t set_status, set_status_2; #endif mlme_sync_req_t *msr = (mlme_sync_req_t *)BMM_BUFFER_POINTER((buffer_t *)m); /* * Sync is only allowed for nodes that are: * 1) Devices (also before association.) or coordinators * (no PAN coordinators), * 2) Currently NOT polling, and * 3) Currently NOT scanning. */ if ( #if (MAC_START_REQUEST_CONFIRM == 1) (MAC_PAN_COORD_STARTED == mac_state) || #endif /* (MAC_START_REQUEST_CONFIRM == 1) */ (MAC_POLL_IDLE != mac_poll_state) || (MAC_SCAN_IDLE != mac_scan_state) ) { /* Free the buffer allocated for MLME-SYNC-Request */ bmm_buffer_free((buffer_t *)m); mac_sync_loss(MAC_BEACON_LOSS); return; } /* Stop the beacon tracking period timer. */ pal_timer_stop(T_Beacon_Tracking_Period); #if (DEBUG > 0) if (pal_is_timer_running(T_Beacon_Tracking_Period)) { ASSERT("BCN tmr running" == 0); } #endif /* Set MAC Sync state properly. */ if (MAC_IDLE == mac_state) { /* * We try to sync before association. * This is a special sync state that checks beacon frames similar to * MAC_SYNC_TRACKING_BEACON while being associated. * * Before this state can be entered successfully a number of PIB * attributes have to be set properly: * 1) PAN-Id (macPANId) * 2) Coordinator Short or Long address (depending upon which type * of addressing the coordinator is using) * (macCoordShortAddress or mac macCoordExtendedAddress) * * Furthermore it is strongly recommended to set the Beacon order and * Superframe order (macBeaconOrder, macSuperframeOrder). * If these parameters are not set and the node tries to sync with a * network, where it never receives a beacon from, the missed beacon * timer (required for reporting a sync loss condition) will start * with a huge time value (based on a beacon order = 15). * If finally a beacon is received from the desired network, the timer * will be updated. * Nevertheless setting the PIB attributes before sync is safer. */ mac_sync_state = MAC_SYNC_BEFORE_ASSOC; } else { if (msr->TrackBeacon) { mac_sync_state = MAC_SYNC_TRACKING_BEACON; } else { mac_sync_state = MAC_SYNC_ONCE; } } /* Wake up radio first */ mac_trx_wakeup(); #if (DEBUG > 0) set_status = #endif set_tal_pib_internal(phyCurrentPage, (void *)&(msr->ChannelPage)); #if (DEBUG > 0) ASSERT(MAC_SUCCESS == set_status); #endif #if (DEBUG > 0) set_status_2 = #endif set_tal_pib_internal(phyCurrentChannel, (void *)&(msr->LogicalChannel)); #if (DEBUG > 0) ASSERT(MAC_SUCCESS == set_status_2); #endif mac_start_missed_beacon_timer(); /* Start synching by switching ON the receiver. */ tal_rx_enable(PHY_RX_ON); /* Free the buffer allocated by the higher layer */ bmm_buffer_free((buffer_t *)m); }
retval_t mlme_set(uint8_t attribute, pib_value_t *attribute_value, bool set_trx_to_sleep) #endif { /* * Variables indicates whether the transceiver has been woken up for * setting a TAL PIB attribute. */ static bool trx_pib_wakeup; retval_t status = MAC_SUCCESS; switch (attribute) { #if (MAC_ASSOCIATION_REQUEST_CONFIRM == 1) case macAssociatedPANCoord: mac_pib.mac_AssociatedPANCoord = attribute_value->pib_value_8bit; break; #endif /* (MAC_ASSOCIATION_REQUEST_CONFIRM == 1) */ #if ((MAC_INDIRECT_DATA_BASIC == 1) || defined(BEACON_SUPPORT)) case macMaxFrameTotalWaitTime: mac_pib.mac_MaxFrameTotalWaitTime = attribute_value->pib_value_16bit; break; #endif /* ((MAC_INDIRECT_DATA_BASIC == 1) || defined(BEACON_SUPPORT)) */ case macResponseWaitTime: mac_pib.mac_ResponseWaitTime = attribute_value->pib_value_16bit; break; case macAutoRequest: #if (MAC_BEACON_NOTIFY_INDICATION == 1) /* * If the beacon notification indications are not included * in the build, macAutoRequest can be changed as desired, since * beacon frames will be indicated to the higher * layer if required as defined by IEEE 802.15.4. */ mac_pib.mac_AutoRequest = attribute_value->pib_value_8bit; break; #else /* * If the beacon notification indications are not included * in the build, macAutoRequest must not be changed, since * beacon frames will never be indicated to the higher * layer, i.e. the higher would not be able to act on * received beacon frame information itself. */ status = MAC_INVALID_PARAMETER; break; #endif /* (MAC_BEACON_NOTIFY_INDICATION == 1) */ #ifdef GTS_SUPPORT case macGTSPermit: mac_pib.mac_GTSPermit = attribute_value->pib_value_8bit; break; #endif /* GTS_SUPPORT */ case macBattLifeExtPeriods: mac_pib.mac_BattLifeExtPeriods = attribute_value->pib_value_8bit; break; #if (MAC_ASSOCIATION_INDICATION_RESPONSE == 1) case macAssociationPermit: mac_pib.mac_AssociationPermit = attribute_value->pib_value_8bit; break; #endif /* (MAC_ASSOCIATION_INDICATION_RESPONSE == 1) */ #if (MAC_START_REQUEST_CONFIRM == 1) case macBeaconPayload: memcpy(mac_beacon_payload, attribute_value, mac_pib.mac_BeaconPayloadLength); break; case macBeaconPayloadLength: #ifndef REDUCED_PARAM_CHECK /* * If the application sits directly on top of the MAC, * this is also checked in mac_api.c. */ if (attribute_value->pib_value_8bit > aMaxBeaconPayloadLength) { status = MAC_INVALID_PARAMETER; break; } #endif /* REDUCED_PARAM_CHECK */ mac_pib.mac_BeaconPayloadLength = attribute_value->pib_value_8bit; break; case macBSN: mac_pib.mac_BSN = attribute_value->pib_value_8bit; break; #endif /* (MAC_START_REQUEST_CONFIRM == 1) */ #if (MAC_INDIRECT_DATA_FFD == 1) case macTransactionPersistenceTime: mac_pib.mac_TransactionPersistenceTime = attribute_value->pib_value_16bit; break; #endif /* (MAC_INDIRECT_DATA_FFD == 1) */ case macCoordExtendedAddress: mac_pib.mac_CoordExtendedAddress = attribute_value->pib_value_64bit; break; case macCoordShortAddress: mac_pib.mac_CoordShortAddress = attribute_value->pib_value_16bit; break; case macDSN: mac_pib.mac_DSN = attribute_value->pib_value_8bit; break; case macRxOnWhenIdle: mac_pib.mac_RxOnWhenIdle = attribute_value->pib_value_8bit; /* Check whether radio state needs to change now, */ if (mac_pib.mac_RxOnWhenIdle) { /* Check whether the radio needs to be woken up. */ mac_trx_wakeup(); /* Set transceiver in rx mode, otherwise it may stay in * TRX_OFF). */ tal_rx_enable(PHY_RX_ON); } else { /* Check whether the radio needs to be put to sleep. */ mac_sleep_trans(); } break; case macBattLifeExt: case macBeaconOrder: case macMaxCSMABackoffs: case macMaxBE: case macMaxFrameRetries: case macMinBE: case macPANId: #ifdef PROMISCUOUS_MODE case macPromiscuousMode: #endif /* PROMISCUOUS_MODE */ case macShortAddress: case macSuperframeOrder: case macIeeeAddress: case phyCurrentChannel: case phyCurrentPage: case phyTransmitPower: case phyCCAMode: #ifdef TEST_HARNESS case macPrivateCCAFailure: case macPrivateDisableACK: #endif /* TEST_HARNESS */ { /* Now only TAL PIB attributes are handled anymore. */ status = tal_pib_set(attribute, attribute_value); if (status == TAL_TRX_ASLEEP) { /* * Wake up the transceiver and repeat the * attempt * to set the TAL PIB attribute. */ tal_trx_wakeup(); status = tal_pib_set(attribute, attribute_value); if (status == MAC_SUCCESS) { /* * Set flag indicating that the trx has * been woken up * during PIB setting. */ trx_pib_wakeup = true; } } #if ((MAC_INDIRECT_DATA_BASIC == 1) || defined(BEACON_SUPPORT)) /* * In any case that the PIB setting was successful (no * matter * whether the trx had to be woken up or not), the PIB * attribute * recalculation needs to be done. */ if (status == MAC_SUCCESS) { /* * The value of the PIB attribute * macMaxFrameTotalWaitTime depends on the * values of the * following PIB attributes: * macMinBE * macMaxBE * macMaxCSMABackoffs * phyMaxFrameDuration * In order to save code space and since * changing of PIB * attributes is going to happen not too often, * this is done * always whenever a PIB attribute residing in * TAL is changed * (since all above mentioned PIB attributes are * in TAL). */ recalc_macMaxFrameTotalWaitTime(); } #endif /* ((MAC_INDIRECT_DATA_BASIC == 1) || defined(BEACON_SUPPORT)) */ } break; case macAckWaitDuration: default: status = MAC_UNSUPPORTED_ATTRIBUTE; break; #if ((defined MAC_SECURITY_ZIP) || (defined MAC_SECURITY_2006)) case macSecurityEnabled: mac_pib.mac_SecurityEnabled = attribute_value->pib_value_8bit; break; case macKeyTable: if (attribute_index >= mac_sec_pib.KeyTableEntries) { status = MAC_INVALID_INDEX; } else { memcpy(&mac_sec_pib.KeyTable[attribute_index], attribute_value, sizeof(mac_key_table_t)); } break; case macKeyTableEntries: if (attribute_value->pib_value_8bit > MAC_ZIP_MAX_KEY_TABLE_ENTRIES) { status = MAC_INVALID_PARAMETER; } else { mac_sec_pib.KeyTableEntries = attribute_value->pib_value_8bit; } break; case macDeviceTable: if (attribute_index >= mac_sec_pib.DeviceTableEntries) { status = MAC_INVALID_INDEX; } else { uint8_t *attribute_temp_ptr = (uint8_t *)attribute_value; /* * Since the members of the mac_dev_table_t structure do * contain padding bytes, * each member needs to be filled in separately. */ /* PAN-Id */ memcpy((uint8_t *)&mac_sec_pib.DeviceTable[ attribute_index].DeviceDescriptor[ 0].PANId, attribute_temp_ptr, sizeof(uint16_t)); /* * *ADDR_COPY_DST_SRC_16(mac_sec_pib.DeviceTable[attribute_index].DeviceDescriptor[0].PANId, *(uint16_t *)attribute_temp_ptr); */ attribute_temp_ptr += sizeof(uint16_t); /* Short Address */ memcpy((uint8_t *)&mac_sec_pib.DeviceTable[ attribute_index].DeviceDescriptor[ 0].ShortAddress, attribute_temp_ptr, sizeof(uint16_t)); /*ADDR_COPY_DST_SRC_16(mac_sec_pib.DeviceTable[attribute_index].DeviceDescriptor[0].ShortAddress, *(uint16_t *)attribute_temp_ptr);*/ attribute_temp_ptr += sizeof(uint16_t); /* Extended Address */ memcpy((uint8_t *)&mac_sec_pib.DeviceTable[ attribute_index].DeviceDescriptor[ 0].ExtAddress, attribute_temp_ptr, sizeof(uint64_t)); /*ADDR_COPY_DST_SRC_64(mac_sec_pib.DeviceTable[attribute_index].DeviceDescriptor[0].ExtAddress, *(uint64_t *)attribute_temp_ptr);*/ attribute_temp_ptr += sizeof(uint64_t); /* Extended Address */ memcpy( &mac_sec_pib.DeviceTable[attribute_index].DeviceDescriptor[ 0].FrameCounter, attribute_temp_ptr, sizeof(uint32_t)); attribute_temp_ptr += sizeof(uint32_t); /* Exempt */ mac_sec_pib.DeviceTable[attribute_index]. DeviceDescriptor[0].Exempt = *attribute_temp_ptr; } break; case macDeviceTableEntries: if (attribute_value->pib_value_16bit > MAC_ZIP_MAX_DEV_TABLE_ENTRIES) { status = MAC_INVALID_PARAMETER; } else { mac_sec_pib.DeviceTableEntries = attribute_value->pib_value_16bit; } break; case macSecurityLevelTable: if (attribute_index >= mac_sec_pib.SecurityLevelTableEntries) { status = MAC_INVALID_INDEX; } else { memcpy(&mac_sec_pib.SecurityLevelTable[attribute_index], attribute_value, sizeof(mac_sec_lvl_table_t)); } break; case macSecurityLevelTableEntries: if (attribute_value->pib_value_8bit > MAC_ZIP_MAX_SEC_LVL_TABLE_ENTRIES) { status = MAC_INVALID_PARAMETER; } else { mac_sec_pib.SecurityLevelTableEntries = attribute_value->pib_value_8bit; } break; case macFrameCounter: mac_sec_pib.FrameCounter = attribute_value->pib_value_32bit; break; case macDefaultKeySource: /* Key Source length is 8 octets. */ memcpy(mac_sec_pib.DefaultKeySource, attribute_value, 8); break; case macPANCoordExtendedAddress: memcpy(mac_sec_pib.PANCoordExtendedAddress, attribute_value, 8); break; case macPANCoordShortAddress: mac_sec_pib.PANCoordShortAddress = attribute_value->pib_value_16bit; break; #endif /* (MAC_SECURITY_ZIP || MAC_SECURITY_2006) */ #ifdef TEST_HARNESS case macPrivateIllegalFrameType: mac_pib.privateIllegalFrameType = attribute_value->pib_value_8bit; break; case macPrivateNoDataAfterAssocReq: mac_pib.privateNoDataAfterAssocReq = attribute_value->pib_value_8bit; break; case macPrivateVirtualPANs: mac_pib.privateVirtualPANs = attribute_value->pib_value_8bit; break; #endif /* TEST_HARNESS */ } /* * In case the transceiver shall be forced back to sleep and * has been woken up, it is put back to sleep again. */ if (set_trx_to_sleep && trx_pib_wakeup && !mac_pib.mac_RxOnWhenIdle) { #ifdef ENABLE_DEEP_SLEEP tal_trx_sleep(DEEP_SLEEP_MODE); #else tal_trx_sleep(SLEEP_MODE_1); #endif trx_pib_wakeup = false; } return status; }
/** * @brief Continues processing a data indication from the TAL for * non-polling and non-scanning states of the MAC * (mac_poll_state == MAC_POLL_IDLE, mac_scan_state == MAC_SCAN_IDLE). * * @param b_ptr Pointer to the buffer header. * @param f_ptr Pointer to the frame_info_t structure. * * @return bool True if frame has been processed, or false otherwise. */ static bool process_data_ind_not_transient(buffer_t *b_ptr, frame_info_t *f_ptr) { bool processed_in_not_transient = false; /* * We are in MAC_POLL_IDLE and MAC_SCAN_IDLE now, * so continue with the real MAC states. */ switch (mac_state) { #if (MAC_START_REQUEST_CONFIRM == 1) case MAC_PAN_COORD_STARTED: { switch (mac_parse_data.frame_type) { case FCF_FRAMETYPE_MAC_CMD: { switch (mac_parse_data.mac_command) { #if (MAC_ASSOCIATION_INDICATION_RESPONSE == 1) case ASSOCIATIONREQUEST: mac_process_associate_request(b_ptr); processed_in_not_transient = true; break; #endif /* (MAC_ASSOCIATION_INDICATION_RESPONSE == 1) */ #if (MAC_DISASSOCIATION_BASIC_SUPPORT == 1) case DISASSOCIATIONNOTIFICATION: mac_process_disassociate_notification(b_ptr); processed_in_not_transient = true; break; #endif /* (MAC_DISASSOCIATION_BASIC_SUPPORT == 1) */ #if (MAC_INDIRECT_DATA_FFD == 1) case DATAREQUEST: if (indirect_data_q.size > 0) { mac_process_data_request(b_ptr); processed_in_not_transient = true; } else { mac_handle_tx_null_data_frame(); } break; #endif /* (MAC_INDIRECT_DATA_FFD == 1) */ #if (MAC_ORPHAN_INDICATION_RESPONSE == 1) case ORPHANNOTIFICATION: mac_process_orphan_notification(b_ptr); processed_in_not_transient = true; break; #endif /* (MAC_ORPHAN_INDICATION_RESPONSE == 1) */ case BEACONREQUEST: mac_process_beacon_request(b_ptr); processed_in_not_transient = true; break; #if (MAC_PAN_ID_CONFLICT_AS_PC == 1) case PANIDCONFLICTNOTIFICAION: mac_sync_loss(MAC_PAN_ID_CONFLICT); break; #endif /* (MAC_PAN_ID_CONFLICT_AS_PC == 1) */ #ifdef GTS_SUPPORT case GTSREQUEST: mac_process_gts_request(b_ptr); processed_in_not_transient = true; #endif /* GTS_SUPPORT */ default: break; } } break; case FCF_FRAMETYPE_DATA: mac_process_data_frame(b_ptr); processed_in_not_transient = true; break; #if (MAC_PAN_ID_CONFLICT_AS_PC == 1) case FCF_FRAMETYPE_BEACON: /* PAN-Id conflict detection as PAN-Coordinator. */ /* Node is not scanning. */ check_for_pan_id_conflict_as_pc(false); break; #endif /* (MAC_PAN_ID_CONFLICT_AS_PC == 1) */ default: break; } } break; /* MAC_PAN_COORD_STARTED */ #endif /* (MAC_START_REQUEST_CONFIRM == 1) */ case MAC_IDLE: #if (MAC_ASSOCIATION_REQUEST_CONFIRM == 1) case MAC_ASSOCIATED: #endif /* (MAC_ASSOCIATION_REQUEST_CONFIRM == 1) */ #if (MAC_START_REQUEST_CONFIRM == 1) case MAC_COORDINATOR: #endif /* (MAC_START_REQUEST_CONFIRM == 1) */ { /* Is it a Beacon from our parent? */ switch (mac_parse_data.frame_type) { #if (MAC_SYNC_REQUEST == 1) case FCF_FRAMETYPE_BEACON: { uint32_t beacon_tx_time_symb; /* Check for PAN-Id conflict being NOT a PAN * Corodinator. */ #if (MAC_PAN_ID_CONFLICT_NON_PC == 1) if (mac_pib.mac_AssociatedPANCoord && (MAC_IDLE != mac_state)) { check_for_pan_id_conflict_non_pc(false); } #endif /* (MAC_PAN_ID_CONFLICT_NON_PC == 1) */ /* Check if the beacon is received from my * parent. */ if ((mac_parse_data.src_panid == tal_pib.PANId) && (((mac_parse_data.src_addr_mode == FCF_SHORT_ADDR) && (mac_parse_data.src_addr. short_address == mac_pib.mac_CoordShortAddress)) || ((mac_parse_data.src_addr_mode == FCF_LONG_ADDR) && (mac_parse_data.src_addr. long_address == mac_pib.mac_CoordExtendedAddress)))) { beacon_tx_time_symb = TAL_CONVERT_US_TO_SYMBOLS( f_ptr->time_stamp); #if (_DEBUG_ > 0) retval_t set_status = #endif set_tal_pib_internal(macBeaconTxTime, (void *)&beacon_tx_time_symb); #if (_DEBUG_ > 0) Assert(MAC_SUCCESS == set_status); #endif if ((MAC_SYNC_TRACKING_BEACON == mac_sync_state) || (MAC_SYNC_BEFORE_ASSOC == mac_sync_state) ) { uint32_t nxt_bcn_tm; uint32_t beacon_int_symb; /* Process a received beacon. */ mac_process_beacon_frame(b_ptr); /* Initialize beacon tracking * timer. */ { retval_t tmr_start_res = FAILURE; #ifdef BEACON_SUPPORT if (tal_pib.BeaconOrder < NON_BEACON_NWK) { beacon_int_symb = TAL_GET_BEACON_INTERVAL_TIME( tal_pib.BeaconOrder); } else #endif /* BEACON_SUPPORT */ { beacon_int_symb = TAL_GET_BEACON_INTERVAL_TIME( BO_USED_FOR_MAC_PERS_TIME); } pal_timer_stop( T_Beacon_Tracking_Period); #if (_DEBUG_ > 0) if (pal_is_timer_running( T_Beacon_Tracking_Period)) { Assert( "Bcn tmr running" == 0); } #endif do { /* * Calculate the * time for next * beacon * transmission */ beacon_tx_time_symb = tal_add_time_symbols( beacon_tx_time_symb, beacon_int_symb); /* * Take into * account the * time taken by * the radio to * wakeup from * sleep state */ nxt_bcn_tm = tal_sub_time_symbols( beacon_tx_time_symb, TAL_RADIO_WAKEUP_TIME_SYM << ( tal_pib . BeaconOrder + 2)); tmr_start_res = pal_timer_start( T_Beacon_Tracking_Period, TAL_CONVERT_SYMBOLS_TO_US( nxt_bcn_tm), TIMEOUT_ABSOLUTE, ( FUNC_PTR)mac_t_tracking_beacons_cb, NULL); } while (MAC_SUCCESS != tmr_start_res); #ifdef GTS_DEBUG port_pin_toggle_output_level( DEBUG_PIN1); port_pin_set_output_level( DEBUG_PIN2, 0); #endif } /* * Initialize superframe timer * if required only * for devices because * Superframe timer is already * running for * coordinator. */ /* TODO */ if (MAC_ASSOCIATED == mac_state) { mac_superframe_state = MAC_ACTIVE_CAP; /* Check whether the * radio needs to be * woken up. */ mac_trx_wakeup(); /* Set transceiver in rx * mode, otherwise it * may stay in * TRX_OFF). */ tal_rx_enable(PHY_RX_ON); if (tal_pib. SuperFrameOrder < tal_pib . BeaconOrder) { pal_timer_start( T_Superframe, TAL_CONVERT_SYMBOLS_TO_US( TAL_GET_SUPERFRAME_DURATION_TIME( tal_pib . SuperFrameOrder)), TIMEOUT_RELATIVE, ( FUNC_PTR)mac_t_start_inactive_device_cb, NULL); #ifdef GTS_DEBUG port_pin_set_output_level( DEBUG_PIN2, 1); #endif } #ifdef GTS_SUPPORT if (mac_final_cap_slot < FINAL_CAP_SLOT_DEFAULT) { uint32_t gts_tx_time = ( TAL_CONVERT_SYMBOLS_TO_US( TAL_GET_SUPERFRAME_DURATION_TIME( tal_pib . SuperFrameOrder)) >> 4) * ( mac_final_cap_slot + 1); pal_timer_start( T_CAP, gts_tx_time, TIMEOUT_RELATIVE, ( FUNC_PTR)mac_t_gts_cb, NULL); #ifdef GTS_DEBUG port_pin_set_output_level( DEBUG_PIN3, 1); #endif } #endif /* GTS_SUPPORT */ } /* Initialize missed beacon * timer. */ mac_start_missed_beacon_timer(); /* A device that is neither * scanning nor polling shall go * to sleep now. */ if ( (MAC_COORDINATOR != mac_state) && (MAC_SCAN_IDLE == mac_scan_state) && (MAC_POLL_IDLE == mac_poll_state) ) { /* * If the last received * beacon frame from our * parent * has indicated pending * broadbast data, we * need to * stay awake, until the * broadcast data has * been received. */ if (! mac_bc_data_indicated) { /* Set radio to * sleep if * allowed */ mac_sleep_trans(); } } } else if (MAC_SYNC_ONCE == mac_sync_state) { mac_process_beacon_frame(b_ptr); /* Do this after processing the * beacon. */ mac_sync_state = MAC_SYNC_NEVER; /* A device that is neither * scanning nor polling shall go * to sleep now. */ if ( (MAC_COORDINATOR != mac_state) && (MAC_SCAN_IDLE == mac_scan_state) && (MAC_POLL_IDLE == mac_poll_state) ) { /* * If the last received * beacon frame from our * parent * has indicated pending * broadbast data, we * need to * stay awake, until the * broadcast data has * been received. */ if (! mac_bc_data_indicated) { /* Set radio to * sleep if * allowed */ mac_sleep_trans(); } } } else { /* Process the beacon frame */ bmm_buffer_free(b_ptr); } processed_in_not_transient = true; } else {
/** * @brief The MLME-SCAN.request primitive makes a request for a node to * start a scan procedure. * * 802.15.4. Section 7.1.11.1. * * The MLME-SCAN.request primitive is used to initiate a channel scan over a * given list of channels. A device can use a channel scan to measure the * energy on the channel, search for the coordinator with which it associated, * or search for all coordinators transmitting beacon frames within the * POS of the scanning device. * * The MLME-SCAN.request primitive is generated by the next higher layer and * issued to its MLME to initiate a channel scan to search for activity within * the POS of the device. This primitive can be used to perform an ED scan to * determine channel usage, an active or passive scan to locate beacon frames * containing any PAN identifier, or an orphan scan to locate a PAN to which * the device is currently associated. * * ED or active scans can be performed before an FFD starts operation as a * PAN coordinator. Active or passive scans can be performed prior to selecting * a PAN for association. Orphan scans can be performed to attempt to locate a * specific coordinator with which communication has been lost. * * All devices shall be capable of performing passive scans and orphan scans; * ED scans and active scans are optional for an RFD. * * When the MLME receives the MLME-SCAN.request primitive, it initiates a scan * in all channels specified in the ScanChannels parameter. The MLME suspends * all beacon transmissions for the duration of the scan. During a scan, the * MAC sublayer only accepts frames received over the PHY data service that are * relevant to the scan being performed (see 7.5.2.1). * * An ED scan allows a device to obtain a measure of the peak energy in each * requested channel. The ED scan is performed on each channel by the MLMEs * repeatedly issuing the PLME-ED.request primitive to the PHY until * [aBaseSuperframeDuration * (2n + 1)] symbols, where n is the value of the * ScanDuration parameter, have elapsed. The MLME notes the maximum energy * measurement and moves on to the next channel in the channel list. A device * will be able to store between one and an implementation-specified maximum * number of channel ED measurements. The ED scan terminates when the number * of channel ED measurements stored equals this implementation-specified * maximum or when every channel specified in the channel list has been scanned. * * An active scan is used by an FFD to locate all coordinators transmitting * beacon frames within its POS. The active scan is performed on each channel * by the MLMEs first sending a beacon request command (see 7.3.2.4). The MLME * then enables the receiver and records the information contained in each * received beacon in a PAN descriptor structure (see Table 41 in 7.1.5.1.1). * A device will be able to store between one and an implementation-specified * maximum number of PAN descriptors. The active scan on a particular channel * terminates when the number of PAN descriptors stored equals this * implementation-specified maximum or when [aBaseSuperframeDuration*(2n + 1)] * symbols, where n is the value of the ScanDuration parameter, have elapsed. * If the latter condition has been satisfied, the channel is considered to * have been scanned. Where possible, the scan is repeated on each channel and * terminates when the number of PAN descriptors stored equals the * implementation-specified maximum or when every channel in the set of * available channels has been scanned. * * A passive scan, like an active scan, is used to locate all coordinators * transmitting beacon frames within the POS of the scanning device; the * difference is that the passive scan is a receive-only operation and does not * transmit the beacon request command. The passive scan is performed on each * channel by the MLMEs enabling its receiver and recording the information * contained in each received beacon in a PAN descriptor structure * (see Table 41 in 7.1.5.1.1). A device will be able to store between one and * an implementation-specified maximum number of PAN descriptors. The passive * scan on a particular channel terminates when the number of PAN descriptors * stored equals this implementation-specified maximum or when * [aBaseSuperframeDuration * (2n + 1)] symbols, where n is the value of the * ScanDuration parameter, have elapsed. If the latter condition has been * satisfied, the channel is considered to have been scanned. Where possible, * the scan is repeated on each channel and terminates when the number of PAN * descriptors stored equals the implementation-specified maximum or when * every channel in the set of available channels has been scanned. * * An orphan scan is used to locate the coordinator with which the scanning * device had previously associated. The orphan scan is performed on each * channel by the MLME first sending an orphan notification command * (see 7.3.2.3). The MLME then enables its receiver for at most * aResponseWaitTime symbols. If the device receives a coordinator realignment * command within this time, the MLME will disable its receiver. Otherwise, the * scan is repeated on the next channel in the channel list. The scan * terminates when the device receives a coordinator realignment command * (see 7.3.2.5) or when every channel in the set of available channels has * been scanned. * * The results of an ED scan are recorded in a list of ED values and reported * to the next higher layer through the MLME-SCAN.confirm primitive with a * status of MAC_SUCCESS. The results of an active or passive scan are recorded * in a set of PAN descriptor values and reported to the next higher layer * through the MLME-SCAN.confirm primitive. If no beacons were found, the * MLME-SCAN.confirm primitive will contain a null set of PAN descriptor * values and a status of NO_BEACON. Otherwise, the MLME-SCAN.confirm primitive * will contain the set of PANDescriptor values found, a list of unscanned * channels, and a status of MAC_SUCCESS. * * The results of an orphan scan are reported to the next higher layer through * the MLME-SCAN.confirm primitive. If successful, the MLME-SCAN.confirm * primitive will contain a status of MAC_SUCCESS. If the device did not receive * a * coordinator realignment command, MLME-SCAN.confirm primitive will contain * a status of NO_BEACON. In either case, the PANDescriptorList and * EnergyDetectList parameters of the MLMESCAN.confirm primitive are null. * * If any parameter in the MLME-SCAN.request primitive is not supported or is * out of range, the MAC sublayer will issue the MLME-SCAN.confirm primitive * with a status of MAC_INVALID_PARAMETER. * * @param m The MLME_SCAN.request message */ void mlme_scan_request(uint8_t *m) { mlme_scan_req_t *msr = (mlme_scan_req_t *)BMM_BUFFER_POINTER( (buffer_t *)m); mlme_scan_conf_t *msc; /* Save the original channel. */ mac_scan_orig_channel = tal_pib.CurrentChannel; /* Save the original channel page. */ mac_scan_orig_page = tal_pib.CurrentPage; /* Save the scan request parameters */ scan_duration = msr->ScanDuration; scan_type = msr->ScanType; scan_channels = msr->ScanChannels; scan_curr_page = msr->ChannelPage; msc = (mlme_scan_conf_t *)msr; /* * Store the scan request buffer reused to create the corresponding * scan confirmation */ mac_conf_buf_ptr = m; msc->cmdcode = MLME_SCAN_CONFIRM; msc->ScanType = scan_type; msc->UnscannedChannels = scan_channels; msc->ChannelPage = scan_curr_page; msc->ResultListSize = 0; msc->scan_result_list[0].ed_value[0] = 0; if ((MAC_POLL_IDLE != mac_poll_state) || (MAC_SCAN_IDLE != mac_scan_state) ) { /* Ignore scan request while being in a polling state or * scanning. */ msc->status = MAC_INVALID_PARAMETER; /* Append the scan confirmation message to the MAC-NHLE queue */ qmm_queue_append(&mac_nhle_q, (buffer_t *)m); return; /* no break here due to return */ } #ifndef REDUCED_PARAM_CHECK /* * Check for invalid channels to scan. * This can be either an emtpy scan mask, or a scan mask that contains * invalid channels for this band. */ /* * Checck also for a scan duration that is lower than * the max. beacon order. */ if ((0 == scan_channels) || ((scan_channels & INVERSE_CHANNEL_MASK) != 0) || (scan_duration > BEACON_NETWORK_MAX_BO) ) { msc->status = MAC_INVALID_PARAMETER; /* Append the scan confirm message to the MAC-NHLE queue */ qmm_queue_append(&mac_nhle_q, (buffer_t *)m); return; } #endif /* REDUCED_PARAM_CHECK */ #if (MAC_SCAN_ED_REQUEST_CONFIRM == 0) /* * If ED scan is not supported, the ED scan request * will be rejected before node will be woken up. */ if (MLME_SCAN_TYPE_ED == scan_type) { msc->status = MAC_INVALID_PARAMETER; /* Append the scan confirm message to the MAC-NHLE queue */ qmm_queue_append(&mac_nhle_q, (buffer_t *)m); return; } #endif /* (MAC_SCAN_ED_REQUEST_CONFIRM == 0) */ /* wake up radio first */ mac_trx_wakeup(); mac_awake_scan((buffer_t *)m); } /* mlme_scan_request() */