Ejemplo n.º 1
0
U16 nwk_rte_tree_calc_cskip(U8 depth)
{
    U16 exp, temp;
    S16 num, den;
        U8 i;
    nwk_nib_t *nib = nwk_nib_get();

        exp = nib->max_depth - (depth + 1);

        if (nib->max_routers == 1)
        {
                return (U16)(1 + (nib->max_children * exp));
        }
        else
        {
        if (depth < nib->max_depth)
        {
            // Init the value of temp to 1. This is the lowest value it can have.
            // Then calculate the value of (max_routers^exp)
            temp = 1;
            for (i=0; i<exp; i++)
            {
                temp *= nib->max_routers;
            }

            // Need to be careful. There is a potential overflow if the value of max_children is large and temp is also large.
            num = (S16)((1 + nib->max_children - nib->max_routers) - (nib->max_children * temp));
            den = 1 - nib->max_routers;
            return (U16)(num/den);
        }
        }
    return 0;
}
Ejemplo n.º 2
0
U16 nwk_rte_tree_calc_next_hop(U16 dest)
{
        U16 cskip_parent;
    U16 dest_addr;
        bool route_down;
    nwk_nib_t *nib = nwk_nib_get();

    // if cskip is uninitialized, then calculate the value for this device
    // and save it in the nib.
    if (nib->cskip == 0xFFFF)
    {
        nib->cskip = nwk_rte_tree_calc_cskip(nib->depth);
    }

    // we need the depth one layer up to calculate the parent's cskip value.
    // if we're the coordinator, then we don't care because we will route down
    // no matter what. otherwise, we use the parent's cskip value to calc
    // whether to route up or down.
    cskip_parent = (nib->depth != 0) ? nwk_rte_tree_calc_cskip(nib->depth - 1) : 0;
        route_down = ((dest > nib->short_addr) && (dest < (nib->short_addr + cskip_parent)));

    // if we're the coordinator or we calculate that we need to route down, then
    // look for the child that will be our next hop. otherwise, just send it to
    // our parent.
    if ((nib->short_addr == 0) || route_down)
    {
        dest_addr = nwk_rte_tree_get_dwnstrm_rtr_addr(dest);
    }
    else
    {
        dest_addr = nwk_neighbor_tbl_get_parent();
    }
    return dest_addr;
}
Ejemplo n.º 3
0
static U16 nwk_rte_tree_get_dwnstrm_rtr_addr(U16 dest_addr)
{
    U8 i;
    U16 lower_addr, upper_addr;
    nwk_nib_t *nib = nwk_nib_get();
    address_t addr;

    addr.mode       = SHORT_ADDR;
    addr.short_addr = dest_addr;

    // can we get an exact match for the child device?
    if (nwk_neighbor_tbl_addr_exists(&addr))
    {
        return dest_addr;
    }

    // no child exists. find the downstream rtr to send the frame to.
    // to get the downstream router, we need to find a router whose
    // address allocation contains the dest_addr. That means that dest_addr must
    // lie between the upper and lower addresses in the rtr's addr allocation range.
    for (i=0; i<nib->max_routers; i++)
    {
        lower_addr = (U16)((nib->cskip * i) + 1);
        upper_addr = lower_addr + nib->cskip;

        if ((dest_addr > lower_addr) && (dest_addr < upper_addr))
        {
            return lower_addr;
        }
    }
    return INVALID_NWK_ADDR;
}
Ejemplo n.º 4
0
/*
 * Select the network to join. This function is called after a network discovery
 * and will select the network from the list of scan descriptors. If the
 * use_ext_pan_id flag is set in the APS Info Base, then it will search for that
 * pan ID and join that network.
 *
 * Otherwise, it looks for the following criteria in evaluating a network to join:
 * - The scan descriptor sender is a potential parent
 * - It has capacity
 * - It is permitting joining
 * - The protocol version matches this device's version
 * - The Zigbee stack profile matches this device's profile (ie: Zigbee vs Zigbee Pro)
 */
static bool zdo_nwk_select()
{
	aps_aib_t *aib = aps_aib_get();
	nwk_nib_t *nib = nwk_nib_get();
	zdo_pcb_t *pcb = zdo_pcb_get();
	nwk_join_req_t args;
	mem_ptr_t *mem_ptr;
	bool capacity           = false;
	bool permit_join        = false;
	bool prot_ver_match     = false;
	bool stack_prof_match   = false;

	/*
	 * currently, we will join the first network we find that
	 * fits our join criteria
	 */
	for (mem_ptr = pcb->descr_list; mem_ptr != NULL; mem_ptr = mem_ptr->next)
	{
		/*
		 * if we specify that we need to join a particular pan,
		 * then we need to find a node descr that matches the
		 * ext pan id. otherwise, if there's no such limitation,
		 * then just go on ahead.
		 */
		if ((!aib->use_ext_pan_id) || (aib->use_ext_pan_id == SCAN_ENTRY(mem_ptr)->ext_pan_id))
		{
			if ((aib->use_desig_parent &&
				(aib->desig_parent == SCAN_ENTRY(mem_ptr)->coord_addr.short_addr)) ||
			    !aib->use_desig_parent)
			{
				capacity = (nib->dev_type == NWK_ROUTER) ?
						(SCAN_ENTRY(mem_ptr)->rtr_cap >0) :
						(SCAN_ENTRY(mem_ptr)->end_dev_cap > 0);
				permit_join =
					(SCAN_ENTRY(mem_ptr)->superfrm_spec & MAC_ASSOC_PERMIT_MASK) >>
					       MAC_ASSOC_PERMIT_OFF;
				prot_ver_match =
					(SCAN_ENTRY(mem_ptr)->prot_ver == ZIGBEE_PROTOCOL_VERSION);
				stack_prof_match =
					(SCAN_ENTRY(mem_ptr)->stack_profile == ZIGBEE_STACK_PROFILE);

				if (SCAN_ENTRY(mem_ptr)->pot_parent &&
				    capacity && permit_join &&
				    prot_ver_match &&
				    stack_prof_match)
				{
					args.desc        = pcb->curr_descr = mem_ptr;
					args.ext_pan_id  = SCAN_ENTRY(mem_ptr)->ext_pan_id;
					args.join_as_rtr = (nib->dev_type == NWK_ROUTER);
					args.rejoin_nwk  = (aib->use_ext_pan_id == 0) ?
							   NWK_JOIN_NORMAL :
							   NWK_JOIN_REJOIN;
					nwk_join_req(&args);
					return true;
				}
			}
		}
	}
Ejemplo n.º 5
0
/*
 * Start a broadcast transmission. We need to check if one is
 * currently in progress. If not, then set the flags to indicate
 * that a broadcast is in progress, and setup the callback timer
 * to expire the broadcast after the spec'd time interval.
 */
U8 nwk_brc_start(buffer_t *buf, nwk_hdr_t *hdr)
{
	nwk_pcb_t *pcb = nwk_pcb_get();
	nwk_nib_t *nib = nwk_nib_get();
	buffer_t *brc_curr_buf;
	U8 index;

	/*
	 * if the brc is in the table, then drop it.
	 * otherwise, check for other error conditions
	 * as well that would cause us to drop the broadcast.
	 */
	if (!pcb->brc_accept_new	||
	    pcb->brc_active		||
	    (hdr->radius == 0)	||
	    !nwk_brc_check_dev_match(hdr->dest_addr))
	{
		buf_free(buf);
		return NWK_NOT_PERMITTED;
	}

	/* set up the brc fields to indicate the brc status */
	BUF_ALLOC(brc_curr_buf, TX);

	/*
	 * save off the original index of the alloc'd frame.
	 * we'll need to restore it after the memcpy.
	 */
	index = brc_curr_buf->index;
	memcpy(brc_curr_buf, buf, sizeof(buffer_t));
	brc_curr_buf->index = index;

	/*
	 * move the buf data pointer to the correct position
	 * in the buffer and add the len field
	 */
	brc_curr_buf->dptr = brc_curr_buf->buf + (buf->dptr - buf->buf);

	pcb->brc_accept_new  = false;
	pcb->brc_active      = true;
	pcb->brc_seq         = hdr->seq_num;
	pcb->brc_curr_frm    = brc_curr_buf;
	hdr->src_addr        = nib->short_addr;
	memcpy(&pcb->brc_nwk_hdr, hdr, sizeof(nwk_hdr_t));

	ctimer_set(&pcb->brc_tmr, NWK_PASSIVE_ACK_TIMEOUT, nwk_brc_expire, NULL);
	return NWK_SUCCESS;
}
Ejemplo n.º 6
0
void nwk_gen_beacon(buffer_t *buf)
{
    nwk_nib_t *nib = nwk_nib_get();
    bool ed_cap, rtr_cap;


    ed_cap  = nib->ed_cap > 0;
    rtr_cap = nib->rtr_cap > 0;

    //lint --e{826} Suppress Info 826: Suspicious pointer-to-pointer conversion (area too small)
    // ex: *(U16 *)buf->dptr = hdr->nwk_fcf
    // this removes the lint warning for this block only

    buf->len += NWK_BEACON_PAYLOAD_SIZE;
    buf->dptr -= NWK_BEACON_PAYLOAD_SIZE;
    *buf->dptr++ = ZIGBEE_PROTOCOL_ID;
    *buf->dptr++ = (ZIGBEE_PROTOCOL_VERSION << 4) | (nib->stack_profile & 0x0F);
    *buf->dptr++ = ((ed_cap << 7) | ((nib->depth & 0xF) << 3) | ((rtr_cap << 2))) & 0xFC;
    *(U64 *)buf->dptr   = nib->ext_pan_ID;
    buf->dptr += sizeof(U64);
    buf->dptr -= NWK_BEACON_PAYLOAD_SIZE;
}
Ejemplo n.º 7
0
/*
 * Generate a network layer beacon payload. A beacon frame contains information
 * from both the NWK and MAC layer. This function generates the NWK layer specific
 * information for the beacon. This function gets called by the MAC layer when
 * its generating a beacon frame in response to a beacon request.
 * The fields in the NWK portion of the beaon are as follows:
 * - Protocol ID
 * - Stack profile
 * - Protocol version
 * - Router capacity available
 * - Device depth
 * - End device capacity
 * - Extended PAN ID
 */
void nwk_gen_beacon(buffer_t *buf)
{
	nwk_nib_t *nib = nwk_nib_get();
	bool ed_cap, rtr_cap;


	ed_cap  = nib->ed_cap > 0;
	rtr_cap = nib->rtr_cap > 0;

	/*
	 * ex: *(U16 *)buf->dptr = hdr->nwk_fcf
	 * this removes the lint warning for this block only
	 */

	buf->len += NWK_BEACON_PAYLOAD_SIZE;
	buf->dptr -= NWK_BEACON_PAYLOAD_SIZE;
	*buf->dptr++ = ZIGBEE_PROTOCOL_ID;
	*buf->dptr++ = (ZIGBEE_PROTOCOL_VERSION << 4) | (nib->stack_profile & 0x0F);
	*buf->dptr++ = ((ed_cap << 7) | ((nib->depth & 0xF) << 3) | ((rtr_cap << 2))) & 0xFC;
	*(U64 *)buf->dptr   = nib->ext_pan_ID;
	buf->dptr += sizeof(U64);
	buf->dptr -= NWK_BEACON_PAYLOAD_SIZE;
}
Ejemplo n.º 8
0
/*
 * Check if the broadcast address matches the device type. Return true
 * if it matches. The reason we would need to check the device type is that
 * Zigbee divides broadcasts up into three types. If we don't match the
 * broadcast device type, we need to discard the frame.
 *
 * Here are the three device types:
 * - Broadcast to all devices
 * - Broadcast only to devices that have their receiver on when idle
 * - Broadcast only to routers and the coordinator
 */
bool nwk_brc_check_dev_match(U16 dest_addr)
{
	bool resp = false;
	nwk_nib_t *nib = nwk_nib_get();
	mac_pib_t *pib = mac_pib_get();

	switch (dest_addr)
	{
	case NWK_BROADCAST_ALL:
		resp = true;
		break;
	case NWK_BROADCAST_RXONIDLE:
		resp = (pib->rx_on_when_idle) ? true : false;
		break;
	case NWK_BROADCAST_ROUTERS_COORD:
		resp = ((nib->dev_type == NWK_COORDINATOR) ||
			(nib->dev_type == NWK_ROUTER)) ? true : false;
		break;
	default:
		break;
	}
	return resp;
}
Ejemplo n.º 9
0
void nwk_rte_tree_init()
{
    nwk_nib_t *nib = nwk_nib_get();
    nib->cskip = 0xFFFF;
}
Ejemplo n.º 10
0
U16 nwk_rte_tree_calc_ed_addr(U16 cskip, U8 num)
{
    nwk_nib_t *nib = nwk_nib_get();
    return (U16)(nib->short_addr + (cskip * nib->max_routers) + (num + 1));
}
Ejemplo n.º 11
0
U16 nwk_rte_tree_calc_rtr_addr(U16 cskip, U8 num)
{
    nwk_nib_t *nib = nwk_nib_get();
    return (U16)(nib->short_addr + (num * cskip) + 1);
}
Ejemplo n.º 12
0
void mac_cmd_handler(mac_cmd_t *cmd, mac_hdr_t *hdr)
{
    buffer_t *buf_out;
    mac_hdr_t hdr_out;
    nwk_nib_t *nib = nwk_nib_get();

    DBG_PRINT_SIMONLY("\n<INCOMING>");
    debug_dump_mac_cmd(cmd);
    switch (cmd->cmd_id)
    {
    case MAC_ASSOC_REQ:
        if (nib->joined)
        {
            DBG_PRINT_SIMONLY("MAC: MAC Association Request Command Received.\n");
            // check to make sure that association is permitted and the src address is the correct mode
            if ((pib.assoc_permit) && (hdr->src_addr.mode == LONG_ADDR))
            {
                mac_assoc_ind_t assoc_args;
                assoc_args.capability = cmd->assoc_req.cap_info;
                memcpy(&assoc_args.dev_addr, &hdr->src_addr, sizeof(address_t));
                mac_assoc_ind(&assoc_args);
            }
            else
            {
                mac_assoc_resp_t resp_args;
                memcpy(&resp_args.dev_addr, &hdr->src_addr, sizeof(address_t));
                resp_args.assoc_short_addr = 0xFFFF;
                resp_args.status = MAC_INVALID_PARAMETER;
                mac_assoc_resp(&resp_args);
            }
        }
        break;

    case MAC_ASSOC_RESP:
        if ((pcb.mac_state == MLME_DATA_REQ) || (pcb.mac_state == MLME_ASSOC_REQ))
        {
            pcb.mac_state = MLME_IDLE;
        }
        mac_assoc_conf(cmd->assoc_resp.short_addr, cmd->assoc_resp.assoc_status);
        break;

    case MAC_DATA_REQ:
        if (nib->joined)
        {
            DBG_PRINT("MAC: MAC Data Request Command Received.\n");
            mac_indir_data_req_handler(&hdr->src_addr);
        }
        break;

    case MAC_BEACON_REQ:
        if (nib->joined)
        {
            DBG_PRINT("MAC: MAC Beacon Request Command Received.\n");
            BUF_ALLOC(buf_out, TX);
            mac_gen_beacon_frm(buf_out, &hdr_out);
            mac_tx_handler(buf_out, &hdr_out.dest_addr, false, false, hdr_out.dsn, 0);
        }
        break;

    case MAC_ORPHAN_NOT:
        if (hdr->src_addr.mode == LONG_ADDR)
        {
            mac_orphan_ind(hdr->src_addr.long_addr);
        }
        break;

    case MAC_COORD_REALIGN:
        // check over the coord realign frame to make sure that the data is what we had previously
        if  ((cmd->coord_realign.pan_id == pib.pan_id) && (cmd->coord_realign.short_addr == pib.short_addr))
        {
            if ((pib.coord_addr.mode == SHORT_ADDR) && (cmd->coord_realign.coord_short_addr == pib.coord_addr.short_addr))
            {
                pcb.coor_realign_rcvd = true;
            }
            else if ((pib.coord_addr.mode == LONG_ADDR) && (hdr->src_addr.mode == LONG_ADDR) &&
                     (hdr->src_addr.long_addr == pib.coord_addr.long_addr))
            {
                pcb.coor_realign_rcvd = true;
            }
            else
            {
                return;
            }
        }
        else
        {
            return;
        }

        // stop the scan once we get a valid coord realignment command frame
        // the scan will end once the channel is beyond the channel range
        pcb.curr_scan_channel = MAC_PHY_CHANNEL_OFFSET + MAC_MAX_CHANNELS;
        ctimer_stop(&pcb.mlme_tmr);
        mac_scan(NULL);
        break;
    default:
        break;
    }
}