Exemplo n.º 1
0
/*
 * Send out the NWK frame to the MAC layer for transmission. This function
 * does final assembly of the NWK header and generates the MAC request
 * based on the given information.
 */
static void nwk_tx(buffer_t *buf, nwk_hdr_t *hdr, bool indirect)
{
	mac_pib_t *pib = mac_pib_get();
	mac_data_req_t req;

	/* finish filling out the nwk hdr and generate it */
	hdr->nwk_frm_ctrl.protocol_ver          = ZIGBEE_PROTOCOL_VERSION;
	hdr->nwk_frm_ctrl.mcast_flag            = false;        // multicast not supported
	hdr->nwk_frm_ctrl.security              = false;
	hdr->nwk_frm_ctrl.src_rte               = false;
	hdr->nwk_frm_ctrl.dest_ieee_addr_flag   = false;
	hdr->nwk_frm_ctrl.src_ieee_addr_flag    = false;

	nwk_gen_header(buf, hdr);
	debug_dump_nwk_hdr(hdr);

	req.src_addr.mode                       = SHORT_ADDR;
	req.dest_addr.mode                      = SHORT_ADDR;
	req.src_addr.short_addr                 = hdr->mac_hdr->src_addr.short_addr;
	req.dest_addr.short_addr                = hdr->mac_hdr->dest_addr.short_addr;
	req.src_pan_id                          = pib->pan_id;
	req.dest_pan_id                         = pib->pan_id;
	req.msdu_handle                         = hdr->handle;
	req.buf                                 = buf;

	/*
	 * it its a broadcast, then no ack request.
	 * otherwise, ack requests on all other transfers.
	 */
	req.tx_options = (req.dest_addr.short_addr != 0xFFFF) ? MAC_ACK_REQUEST : 0x0;
	req.tx_options |= indirect ? MAC_INDIRECT_TRANS : 0x0;

	/* kick it to the curb! */
	mac_data_req(&req);
}
Exemplo n.º 2
0
/*
 * Check that the frame's dest addr is for us or a broadcast address. Otherwise
 * every frame sent by the simulator to us will trigger an interrupt. This
 * function will allow us to discard frames not meant for us.
 */
static bool drvr_check_addr(buffer_t *buf)
{
	buffer_t *tmp;
	mac_hdr_t hdr;
	U8 index;
	mac_pib_t *pib = mac_pib_get();

	BUF_ALLOC(tmp, TX);
	index = tmp->index;
	memcpy(tmp, buf, sizeof(buffer_t));
	tmp->index = index;
	mac_parse_hdr(tmp, &hdr);
	buf_free(tmp);


	if ((hdr.mac_frm_ctrl.frame_type == MAC_BEACON) ||
	    (hdr.mac_frm_ctrl.frame_type == MAC_ACK)) {
		return true;
	} else if (hdr.dest_addr.mode == SHORT_ADDR) {
		if ((hdr.dest_addr.short_addr == pib->short_addr) ||
		    (hdr.dest_addr.short_addr == MAC_BROADCAST_ADDR))
			return true;
	} else if (hdr.dest_addr.mode == LONG_ADDR) {
		if ((hdr.dest_addr.long_addr == pib->ext_addr))
			return true;
	}

	return false;
}
Exemplo n.º 3
0
/* Set the PHY channel to one of the 16 channels available for 802.15.4 */
void mac_set_channel(U8 channel)
{
	mac_pib_t *pib = mac_pib_get();

	if ((channel >= MAC_PHY_CHANNEL_OFFSET) &&
		(channel <= (MAC_PHY_CHANNEL_OFFSET + MAC_MAX_CHANNELS)))
		pib->curr_channel = channel;
}
Exemplo n.º 4
0
/*
 * This is the function that does the actual transmission of the
 * frame. It sends the data to the driver which will then send it
 * over the air. If the channel is busy, then it will back off for
 * a random delay and then retry the transfer. If it exceeds the
 * maximum backoffs, it will abort the transmission and send a data
 * confirm with a failure status. After transmission, if no ack is
 * needed, then a data confirm will immediately get issued to the
 * next higher layer that requested the transmission. If an ack is
 * required, the data confirm won't be sent until a proper ack is received.
 */
void mac_out(buffer_t *buf, bool ack_req, U8 dsn, U8 handle)
{
	U8 i;
	U16 csma_time;
	mac_pib_t *pib = mac_pib_get();
	mac_pcb_t *pcb = mac_pcb_get();

	for (i = 0; i < aMaxCsmaBackoffs; i++)
	{
		/* check if the channel is clear */
		if (drvr_get_cca())
		{
			/* send the frame if the CCA clears */
			drvr_tx(buf);

			/* collect a transmission stat here */
			pcb->total_xmit++;

			/*
			 * if there's no ack request,
			 * then we're finished. free the buf.
			 */
			if (!ack_req) {
				mac_data_conf(MAC_SUCCESS, handle);
				buf_free(buf);
			}
			return;
		} else {
			/*
			 * channel busy. do a busy wait and try again.
			 * Shift left of signed quantity (int) due to
			 * left shift of constant "1". its okay.
			 */
			csma_time = drvr_get_rand() % (U16)((1 << pib->min_be) - 1);
			busy_wait(csma_time);
		}
	}

	/*
	 * exceeded max csma backoffs. clean up and send a
	 * confirm with a fail message.
	 */
	if (ack_req)
	{
		/*
		 * if the ack request is set, then we need to
		 * check the retry queue and remove the entry.
		 */
		mac_retry_rem(dsn);

		/* collect a transmit fail stat here */
		pcb->total_fail++;
	} else
		buf_free(buf);

	mac_data_conf(MAC_CHANNEL_ACCESS_FAILURE, handle);
}
Exemplo n.º 5
0
void nwk_permit_join_req(U8 duration)
{
    mac_pib_t *pib = mac_pib_get();

    switch (duration)
    {
    case NWK_PERMIT_JOIN_DISABLE:
        pib->assoc_permit = false;
        break;

    case NWK_PERMIT_JOIN_ENABLE:
        pib->assoc_permit = true;
        break;

    default:
        pib->assoc_permit = true;
        ctimer_set(&permit_join_tmr, duration * CLOCK_SECOND, nwk_permit_join_disable, NULL);
        break;
    }
}
Exemplo n.º 6
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;
}
Exemplo n.º 7
0
void nwk_permit_join_disable()
{
    mac_pib_t *pib = mac_pib_get();

    pib->assoc_permit = false;
}
Exemplo n.º 8
0
void mac_set_short_addr(U16 addr)
{
	mac_pib_t *pib = mac_pib_get();
	pib->short_addr = addr;
}
Exemplo n.º 9
0
void mac_set_pan_id(U16 pan_id)
{
	mac_pib_t *pib = mac_pib_get();
	pib->pan_id = pan_id;
}
Exemplo n.º 10
0
/*
 * Handle the rx events from the mac process. If the driver
 * receives a valid frame, it will send an event to the mac
 * process. The mac process will then call the event handler
 * which retrieves the frame from the rx queue and parses it.
 * Once parsed, it will be handled according to the frame type.
 * If its a command frame, it gets sent to the command handler,
 * a data frame gets sent to the next higher layer, etc...
 */
static void mac_eventhandler(process_event_t event)
{
	buffer_t *buf, *buf_out;
	mac_hdr_t hdr;
	mac_cmd_t cmd;
	bool frm_pend;
	mac_pcb_t *pcb = mac_pcb_get();
	mac_pib_t *pib = mac_pib_get();

	if (event == event_mac_rx)
	{
		DBG_PRINT("MAC_EVENTHANDLER: Rx event occurred.\n");

		buf = mac_queue_buf_pop();
		if (buf) {
			DBG_PRINT_RAW("\n<INCOMING>");
			debug_dump_buf(buf->dptr, buf->len);

			/* decode the packet */
			mac_parse_hdr(buf, &hdr);
			debug_dump_mac_hdr(&hdr);

			/*
			 * check if an ack is needed. if so, then generate
			 * an ack and queue it for transmission. the frm
			 * pending bit will be set for any frame coming from
			 * an address that has an indirect frame for it. this
			 * is against the spec, but it will speed up the ack
			 * transmission.
			 * NOTE: the ack response section may change due to the
			 * tight ack timing requirements.
			 */
			if (hdr.mac_frm_ctrl.ack_req)
			{
				BUF_ALLOC(buf_out, TX);
				DBG_PRINT("MAC: ACK Required.\n");
				frm_pend = mac_indir_frm_pend(&hdr.src_addr);
				mac_gen_ack(buf_out, frm_pend, hdr.dsn);
				mac_out(buf_out, false, hdr.dsn, 0);
			}

			/*
			 * process accordingly. if a scan is in progress,
			 * all frames except for beacon frames will be
			 * discarded.
			 */
			switch(hdr.mac_frm_ctrl.frame_type)
			{
			case MAC_COMMAND:
				if (pcb->mac_state != MLME_SCAN)
				{
					/*
					 * need to handle the case that this is an indirect
					 * transfer, which means that we need to stop the
					 * poll timer and send a status to the poll confirm.
					 */
					if ((pcb->mac_state == MLME_DATA_REQ) &&
					(hdr.src_addr.mode == SHORT_ADDR) &&
					(hdr.src_addr.short_addr == pib->coord_addr.short_addr))
					{
						ctimer_stop(&pcb->mlme_tmr);
						mac_poll_conf(MAC_SUCCESS);
					}

					mac_parse_cmd(buf, &cmd);
					mac_cmd_handler(&cmd, &hdr);
				}
				buf_free(buf);
				break;
			case MAC_BEACON:
				/* discard the beacon if we're not doing a scan */
				if (pcb->mac_state == MLME_SCAN)
				{
					mac_parse_beacon(buf, &hdr);
					mac_beacon_notify_ind(buf, mac_scan_descr_find_addr(&hdr.src_addr));
				}
				buf_free(buf);
				break;
			case MAC_ACK:
				mac_retry_ack_handler(hdr.dsn);

				/*
				 * we need to do some special ops depending on the
				 * state we're in if we get an ACK.
				 */
				if (pcb->mac_state == MLME_ASSOC_REQ)
				{
					if (pcb->assoc_req_dsn == hdr.dsn)
						ctimer_set(&pcb->mlme_tmr,
							   pib->resp_wait_time,
							   mac_poll_req,
							   NULL);
				} else if (pcb->mac_state == MLME_DATA_REQ) {
					if (hdr.mac_frm_ctrl.frame_pending)
						ctimer_set(&pcb->mlme_tmr,
							   aMacMaxFrameTotalWaitTime,
							   mac_poll_timeout,
							   NULL);
				}
				buf_free(buf);
				break;
			case MAC_DATA:
				if (pcb->mac_state != MLME_SCAN)
				{
					/*
					 * need to handle the case that this is an indirect
					 * transfer, which means that we need to stop the poll
					 * timer and send a status to the poll confirm.
					 */
					if ((pcb->mac_state == MLME_DATA_REQ)  &&
						(hdr.src_addr.mode == SHORT_ADDR) &&
						(hdr.src_addr.short_addr == pib->coord_addr.short_addr))
					{
						ctimer_stop(&pcb->mlme_tmr);
						mac_poll_conf(MAC_SUCCESS);
					}

					mac_data_ind(buf, &hdr);
				} else
					buf_free(buf);
				break;
			default:
				/* TODO: Add a statistic here to capture an error'd rx */
			break;
			}
		}
		/*
		 * there's a possibility that more than one frame is in the
		 * buffer. if they came in before this function gets executed.
		 * So process until the queue is empty.
		 */
		if (!mac_queue_is_empty())
		{
			while (process_post(&mac_process, event_mac_rx, NULL) != PROCESS_ERR_OK)
			{
				;
			}
		}
	}
}
Exemplo n.º 11
0
//lint -e{715} Info 715: Symbol 'ptr' not referenced
//lint -e{818} Info 818: Pointer parameter ptr' could be declared as pointing to const
void mac_scan(void *ptr)
{
    mac_cmd_t cmd;
    mac_hdr_t hdr;
    buffer_t *buf;
    address_t src_addr, dest_addr;
    mac_scan_conf_t scan_conf;
    U32 duration;
    mac_pcb_t *pcb = mac_pcb_get();
    mac_pib_t *pib = mac_pib_get();

    // increment the current scan channel on entry into this function.
    pcb->curr_scan_channel++;

    // check if we are initializing the scan. if so, then start the init procedure.
    if (pcb->mac_state != MLME_SCAN)
    {
        // on a new scan, first save the original pan id
        pcb->original_pan_id = pib->pan_id;

        // then set the pan id to the broadcast pan id.
        // NOTE: the broadcast addr is same as broadcast pan id
        pib->pan_id = MAC_BROADCAST_ADDR;

        // init the curr scan channel to the first one
        pcb->curr_scan_channel  = MAC_PHY_CHANNEL_OFFSET;
        pcb->mac_state          = MLME_SCAN;
        pcb->nwk_cnt            = 0;
    }

    // search the channel mask to find the next allowable channel.
    // if the curr scan channel is not in the mask, then increment the channel and check again. keep doing
    // it until we either find an allowable channel or we exceed the max channels that are supported.
    for (;pcb->curr_scan_channel < (MAC_PHY_CHANNEL_OFFSET + MAC_MAX_CHANNELS); pcb->curr_scan_channel++)
    {
        //lint -e{701} Info 701: Shift left of signed quantity (int)
        // shift the bitmask and compare to the channel mask
        if (pcb->channel_mask & (1 << pcb->curr_scan_channel))
        {
            break;
        }
    }

    // we may get here if the curr scan channel exceeds the max channels. if thats the case, then we will
    // automatically end the active scan.
    if (pcb->curr_scan_channel < (MAC_PHY_CHANNEL_OFFSET + MAC_MAX_CHANNELS))
    {
        // set the channel on the radio
        mac_set_channel(pcb->curr_scan_channel);

        // generate and send the beacon request
        // get a free buffer, build the beacon request command, and then
        // send it using the mac_data_req service.
        BUF_ALLOC(buf, TX);

        dest_addr.mode          = SHORT_ADDR;
        dest_addr.short_addr    = MAC_BROADCAST_ADDR;

        if (pcb->scan_type == MAC_ACTIVE_SCAN)
        {
            cmd.cmd_id          = MAC_BEACON_REQ;
            src_addr.mode       = NO_PAN_ID_ADDR;
        }
        else if (pcb->scan_type == MAC_ORPHAN_SCAN)
        {
            cmd.cmd_id          = MAC_ORPHAN_NOT;
            src_addr.mode       = LONG_ADDR;
            src_addr.long_addr  = pib->ext_addr;
        }

        mac_gen_cmd(buf, &cmd);
        mac_gen_cmd_header(buf, &hdr, false, &src_addr, &dest_addr);
        mac_tx_handler(buf, &hdr.dest_addr, false, false, hdr.dsn, ZIGBEE_INVALID_HANDLE);

        // set the callback timer
        duration = (pcb->scan_type == MAC_ACTIVE_SCAN) ? MAC_SCAN_TIME(pcb->duration) : aMacResponseWaitTime;
        ctimer_set(&pcb->mlme_tmr, duration, mac_scan, NULL);
    }
    else
    {
        pcb->mac_state = MLME_IDLE;

        // Send the nwk scan confirm
        scan_conf.scan_type     = pcb->scan_type;
        scan_conf.energy_list   = NULL;

        if (pcb->scan_type == MAC_ACTIVE_SCAN)
        {
            scan_conf.status = MAC_SUCCESS;
        }
        else if (pcb->scan_type == MAC_ORPHAN_SCAN)
        {
            scan_conf.status = (pcb->coor_realign_rcvd) ? MAC_SUCCESS : MAC_NO_BEACON;
            pcb->coor_realign_rcvd = false;
        }

        // restore the original pan ID.
        pib->pan_id = pcb->original_pan_id;
        mac_scan_conf(&scan_conf);
    }
}