/** * @file * @brief * This file implements the disassociation functionality. * * $Id: disassociate.c,v 1.44 2007/05/15 08:36:42 sschneid Exp $ */ /** * \author * Atmel Corporation: http://www.atmel.com * Support email: avr@atmel.com */ /* * Copyright (c) 2006, Atmel Corporation All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The name of ATMEL may not be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* === Includes ============================================================ */ #include #include "mac.h" #if APP_TYPE >= APP_L2 || defined(DOXYGEN) /* === Globals ============================================================= */ /* === Prototypes ========================================================== */ static void build_disassociate_command_frame(frame_buffer_t *fbuf, mlme_disassociate_req_t *dar, bool from_coord); /* === Implementation ====================================================== */ /** * @brief Implement an MLME-DISASSIOCIATE.request * * The MLME-DISASSOCIATE.request primitive is generated by the next * higher layer of an associated device and issued to its MLME to * request disassociation from the PAN. It is also generated by the * next higher layer of the coordinator and issued to its MLME to * instruct an associated device to leave the PAN. * * @param m Pointer to the message */ void mlme_disassociate_request(uint8_t *m) { mlme_disassociate_req_t *dar = (mlme_disassociate_req_t *)m; mlme_disassociate_conf_t dac; frame_buffer_t *fbuf; // Build the request from the coordinator perspective. if (mac_i_pan_coordinator) { #if DEVICE_TYPE == FD1 || DEVICE_TYPE == FD1_NOGTS // We are the coordinator, and if the DeviceAddress is not ours, // we need to send via indirect transmission. if (dar->DeviceAddress != mac_pib_macCoordExtendedAddress ) { fbuf = mac_buffer_request_indirect(); if (fbuf == NULL) { dac.size = sizeof(mlme_disassociate_conf_t) - sizeof(dac.size); dac.cmdcode = MLME_DISASSOCIATE_CONFIRM; dac.status = MAC_TRANSACTION_OVERFLOW; bios_pushback_event((uint8_t *)&dac); return; } if (mac_pib_macBeaconOrder == NON_BEACON_NETWORK && !mac_run_beacon_timer) { mac_run_beacon_timer = true; mac_start_beacon_timer(); } build_disassociate_command_frame(fbuf, dar, true); } else #endif /* DEVICE_TYPE == FD1 || DEVICE_TYPE == FD1_NOGTS */ { dac.size = sizeof(mlme_disassociate_conf_t) - sizeof(dac.size); dac.cmdcode = MLME_DISASSOCIATE_CONFIRM; dac.status = MAC_INVALID_PARAMETER; bios_pushback_event((uint8_t *)&dac); return; } } else // We are a device. { fbuf = mac_buffer_request(); if (fbuf == NULL) { dac.size = sizeof(mlme_disassociate_conf_t) - sizeof(dac.size); dac.cmdcode = MLME_DISASSOCIATE_CONFIRM; dac.status = MAC_TRANSACTION_OVERFLOW; bios_pushback_event((uint8_t *)&dac); return; } build_disassociate_command_frame(fbuf, dar, false); ASSERT(mac_message == NULL); mac_message = fbuf; // remember the original MAC state mac_original_state = mac_state; // do we need to wake up the radio first? if (mac_radio_sleep_state == RADIO_SLEEPING) { mac_state = MAC_WAKEUP_DISASSOC; // wake up radio first mac_phy_wakeup(); } else { mac_awake_disassociate(); } } } /** * @brief Continues handling of MLME-DISASSOCIATE.request once the radio is awake */ void mac_awake_disassociate(void) { // set the MAC to it's original state mac_state = mac_original_state; // Start CSMA-CA using backoff and retry (direct transmission) mac_csma_ca(true, true); // Once a device is disassociated from a coordinator, the // coordinator's address info. should be cleared. mac_pib_macCoordExtendedAddress = CLEAR_ADDR_64; mac_pib_macCoordShortAddress = BROADCAST; } /** * @brief Internal function to build the disassociation command frame. * * If "from_coord" is set, then the destination address of the frame * is taken from dar->DeviceAddress, otherwise our current * coordinator's long address is used as the destination address. * * The buffer passed as fbuf is filled with the respective data. It * is left up to the caller to initiate the data transmission (in the * direct transmission case only, i. e. on the device). * * @param out fbuf Frame buffer to fill in * @param in dar The disassociation request causing this command * @param in from_coord Whether this is going to be sent from a coordinator */ static void build_disassociate_command_frame(frame_buffer_t *fbuf, mlme_disassociate_req_t *dar, bool from_coord) { uint8_t index; uint16_t fcf; // Construct FCF first. // Note that 802.15.4-2006 would also set the intra_pan (resp. // panid_compression) bit but 802.15.4-2003 says we should include // both PANIds. fcf = FCF_SET_FRAMETYPE(FCF_FRAMETYPE_MAC_CMD) | FCF_SET_DEST_ADDR_MODE(FCF_LONG_ADDR) | FCF_SET_SOURCE_ADDR_MODE(FCF_LONG_ADDR) | FCF_ACK_REQUEST; index = 1; // Build the Frame Control Field fbuf->pd_data.data[index++] = fcf & 0xff; fbuf->pd_data.data[index++] = (fcf >> 8) & 0xff; // Populate the DSN. fbuf->pd_data.data[index++] = mac_pib_macDSN++; // Set destination pan id. fbuf->pd_data.data[index++] = mac_pib_macPANId; fbuf->pd_data.data[index++] = (mac_pib_macPANId>>8); // if a coord, then dest addr is 64 bit addr of the device. // if a dev, then the dest addr is "macCoordExtendedAddress". if (from_coord) { memcpy(&fbuf->pd_data.data[index], &dar->DeviceAddress, sizeof(uint64_t)); fbuf->transactiontime = mac_pib_macTransactionPersistenceTime; } else { memcpy(&fbuf->pd_data.data[index], &mac_pib_macCoordExtendedAddress, sizeof(uint64_t)); } index += sizeof(uint64_t); // Set the source pan id. fbuf->pd_data.data[index++] = mac_pib_macPANId; fbuf->pd_data.data[index++] = (mac_pib_macPANId>>8); // Set the source address, the source address of the device sending the command. memcpy(&fbuf->pd_data.data[index], &mac_ieee_address, sizeof(uint64_t)); index += sizeof(uint64_t); // Set up the command frame identifier. fbuf->pd_data.data[index++] = DISASSOCIATIONNOTIFICATION; // Set up the disassociation reason code. fbuf->pd_data.data[index++] = dar->DisassociateReason; /* begin MFR */ index += CRC_SIZE - sizeof(fbuf->pd_data.size); fbuf->pd_data.data[0] = fbuf->pd_data.psduLength = index; /* end MFR */ fbuf->msgtype = DISASSOCIATIONNOTIFICATION; fbuf->pd_data.size = sizeof(pd_data_req_t) - sizeof(fbuf->pd_data.size) + index; fbuf->pd_data.cmdcode = PD_DATA_REQUEST; } /** * @brief Process a disassociation notification command we received. * * Actual data are taken from the incoming frame in mac_parse_buffer. */ void mac_process_disassociate_notification(void) { mlme_disassociate_ind_t dai; // Set up the header portion of the mlme_disassociate_ind_t. dai.size = sizeof(mlme_disassociate_ind_t) - sizeof(dai.size); dai.cmdcode = MLME_DISASSOCIATE_INDICATION; // Build the indication parameters. // Set the DeviceAddress first. The device address is the address // of the device requesting the disassociaton which is always // contained in the source address. memcpy(&dai.DeviceAddress, &mac_parse_data.src_addr, sizeof(uint64_t)); dai.DisassociateReason = mac_parse_data.payload_data.disassoc_req_data.disassoc_reason; dai.SecurityUse = false; dai.ACLEntry = MAC_NOACLENTRYFOUND; bios_pushback_event((uint8_t *)&dai); // Once a device is disassociated from a coordinator, the // coordinator's address info. should be cleared. mac_pib_macCoordExtendedAddress = CLEAR_ADDR_64; mac_pib_macCoordShortAddress = BROADCAST; } #endif /* APP_TYPE >= APP_L2 || defined(DOXYGEN) */ /* EOF */