void mac_data_req(mac_data_req_t *req) { mac_hdr_t hdr; bool indirect; memset(&hdr, 0, sizeof(mac_hdr_t)); hdr.mac_frm_ctrl.frame_type = MAC_DATA; hdr.mac_frm_ctrl.ack_req = (bool)(req->tx_options & MAC_ACK_REQUEST); hdr.mac_frm_ctrl.frame_ver = MAC_802_15_4_2006; hdr.dsn = pib.dsn++; hdr.dest_pan_id = req->dest_pan_id; hdr.src_pan_id = req->src_pan_id; memcpy(&hdr.src_addr, &req->src_addr, sizeof(address_t)); memcpy(&hdr.dest_addr, &req->dest_addr, sizeof(address_t)); // generate the header mac_gen_header(req->buf, &hdr); DBG_PRINT_RAW("\n<OUTGOING>\n"); debug_dump_mac_hdr(&hdr); // send the frame to the tx handler for processing indirect = (req->tx_options & MAC_INDIRECT_TRANS); mac_tx_handler(req->buf, &hdr.dest_addr, indirect, hdr.mac_frm_ctrl.ack_req, hdr.dsn, req->msdu_handle); }
/* * 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) { ; } } } }