/* Check if a packet is for us */ static int is_packet_for_us(uint8_t *buf, int len, int do_send_ack) { frame802154_t frame; int result; uint8_t parsed = frame802154_parse(buf, len, &frame); if(parsed) { if(frame.fcf.dest_addr_mode) { int has_dest_panid; frame802154_has_panid(&frame.fcf, NULL, &has_dest_panid); if(has_dest_panid && frame802154_get_pan_id() != FRAME802154_BROADCASTPANDID && frame.dest_pid != frame802154_get_pan_id() && frame.dest_pid != FRAME802154_BROADCASTPANDID) { /* Packet to another PAN */ return 0; } if(!is_broadcast_addr(frame.fcf.dest_addr_mode, frame.dest_addr)) { result = linkaddr_cmp((linkaddr_t *)frame.dest_addr, &linkaddr_node_addr); if(autoack_enabled && result && do_send_ack) { /* this is a unicast frame and sending ACKs is enabled */ send_ack(&frame); } return result; } } return 1; } else { return 0; } }
/*---------------------------------------------------------------------------*/ static int parse(void) { frame802154_t frame; int hdr_len; hdr_len = frame802154_parse(packetbuf_dataptr(), packetbuf_datalen(), &frame); if(hdr_len && packetbuf_hdrreduce(hdr_len)) { packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, frame.fcf.frame_type); if(frame.fcf.dest_addr_mode) { if(frame.dest_pid != frame802154_get_pan_id() && frame.dest_pid != FRAME802154_BROADCASTPANDID) { /* Packet to another PAN */ PRINTF("15.4: for another pan %u\n", frame.dest_pid); return FRAMER_FAILED; } if(!frame802154_is_broadcast_addr(frame.fcf.dest_addr_mode, frame.dest_addr)) { packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, (linkaddr_t *)&frame.dest_addr); } } packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (linkaddr_t *)&frame.src_addr); packetbuf_set_attr(PACKETBUF_ATTR_PENDING, frame.fcf.frame_pending); if(frame.fcf.sequence_number_suppression == 0) { packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, frame.seq); } else { packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, 0xffff); } #if NETSTACK_CONF_WITH_RIME packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, frame.seq); #endif #if LLSEC802154_USES_AUX_HEADER if(frame.fcf.security_enabled) { packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, frame.aux_hdr.security_control.security_level); #if LLSEC802154_USES_FRAME_COUNTER packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1, frame.aux_hdr.frame_counter.u16[0]); packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3, frame.aux_hdr.frame_counter.u16[1]); #endif /* LLSEC802154_USES_FRAME_COUNTER */ #if LLSEC802154_USES_EXPLICIT_KEYS packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, frame.aux_hdr.security_control.key_id_mode); packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, frame.aux_hdr.key_index); packetbuf_set_attr(PACKETBUF_ATTR_KEY_SOURCE_BYTES_0_1, frame.aux_hdr.key_source.u16[0]); #endif /* LLSEC802154_USES_EXPLICIT_KEYS */ } #endif /* LLSEC802154_USES_AUX_HEADER */ PRINTF("15.4-IN: %2X", frame.fcf.frame_type); PRINTADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); PRINTADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); PRINTF("%d %u (%u)\n", hdr_len, packetbuf_datalen(), packetbuf_totlen()); return hdr_len; } return FRAMER_FAILED; }
/* Setup TSCH as a coordinator */ static void tsch_start_coordinator(void) { frame802154_set_pan_id(IEEE802154_PANID); /* Initialize hopping sequence as default */ memcpy(tsch_hopping_sequence, TSCH_DEFAULT_HOPPING_SEQUENCE, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)); ASN_DIVISOR_INIT(tsch_hopping_sequence_length, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)); #if TSCH_SCHEDULE_WITH_6TISCH_MINIMAL tsch_schedule_create_minimal(); #endif tsch_is_associated = 1; tsch_join_priority = 0; PRINTF("TSCH: starting as coordinator, PAN ID %x, asn-%x.%lx\n", frame802154_get_pan_id(), current_asn.ms1b, current_asn.ls4b); /* Start slot operation */ tsch_slot_operation_sync(RTIMER_NOW(), ¤t_asn); }
/*---------------------------------------------------------------------------*/ static int create_frame(int type, int do_create) { frame802154_t params; int hdr_len; if(frame802154_get_pan_id() == 0xffff) { return -1; } /* init to zeros */ memset(¶ms, 0, sizeof(params)); if(!initialized) { initialized = 1; mac_dsn = random_rand() & 0xff; } /* Build the FCF. */ params.fcf.frame_type = packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE); params.fcf.frame_pending = packetbuf_attr(PACKETBUF_ATTR_PENDING); if(packetbuf_holds_broadcast()) { params.fcf.ack_required = 0; } else { params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_MAC_ACK); } /* We do not compress PAN ID in outgoing frames, i.e. include one PAN ID (dest by default) * There is one exception, seemingly a typo in Table 2a: rows 2 and 3: when there is no * source nor destination address, we have dest PAN ID iff compression is *set*. */ params.fcf.panid_compression = 0; params.fcf.sequence_number_suppression = FRAME802154_SUPPR_SEQNO; /* Insert IEEE 802.15.4 version bits. */ params.fcf.frame_version = FRAME802154_VERSION; #if LLSEC802154_USES_AUX_HEADER if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL)) { params.fcf.security_enabled = 1; } /* Setting security-related attributes */ params.aux_hdr.security_control.security_level = packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL); #if LLSEC802154_USES_FRAME_COUNTER params.aux_hdr.frame_counter.u16[0] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1); params.aux_hdr.frame_counter.u16[1] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3); #else /* LLSEC802154_USES_FRAME_COUNTER */ params.aux_hdr.security_control.frame_counter_suppression = 1; params.aux_hdr.security_control.frame_counter_size = 1; #endif /* LLSEC802154_USES_FRAME_COUNTER */ #if LLSEC802154_USES_EXPLICIT_KEYS params.aux_hdr.security_control.key_id_mode = packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE); params.aux_hdr.key_index = packetbuf_attr(PACKETBUF_ATTR_KEY_INDEX); params.aux_hdr.key_source.u16[0] = packetbuf_attr(PACKETBUF_ATTR_KEY_SOURCE_BYTES_0_1); #endif /* LLSEC802154_USES_EXPLICIT_KEYS */ #endif /* LLSEC802154_USES_AUX_HEADER */ /* Increment and set the data sequence number. */ if(!do_create) { /* Only length calculation - no sequence number is needed and should not be consumed. */ } else if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)) { params.seq = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO); } else { /* Ensure that the sequence number 0 is not used as it would bypass the above check. */ if(mac_dsn == 0) { mac_dsn++; } params.seq = mac_dsn++; packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, params.seq); } /* Complete the addressing fields. */ /** \todo For phase 1 the addresses are all long. We'll need a mechanism in the rime attributes to tell the mac to use long or short for phase 2. */ if(LINKADDR_SIZE == 2) { /* Use short address mode if linkaddr size is short. */ params.fcf.src_addr_mode = FRAME802154_SHORTADDRMODE; } else { params.fcf.src_addr_mode = FRAME802154_LONGADDRMODE; } params.dest_pid = frame802154_get_pan_id(); if(packetbuf_holds_broadcast()) { /* Broadcast requires short address mode. */ params.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE; params.dest_addr[0] = 0xFF; params.dest_addr[1] = 0xFF; } else { linkaddr_copy((linkaddr_t *)¶ms.dest_addr, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); /* Use short address mode if linkaddr size is small */ if(LINKADDR_SIZE == 2) { params.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE; } else { params.fcf.dest_addr_mode = FRAME802154_LONGADDRMODE; } } /* Set the source PAN ID to the global variable. */ params.src_pid = frame802154_get_pan_id(); /* * Set up the source address using only the long address mode for * phase 1. */ linkaddr_copy((linkaddr_t *)¶ms.src_addr, &linkaddr_node_addr); params.payload = packetbuf_dataptr(); params.payload_len = packetbuf_datalen(); hdr_len = frame802154_hdrlen(¶ms); if(!do_create) { /* Only calculate header length */ return hdr_len; } else if(packetbuf_hdralloc(hdr_len)) { frame802154_create(¶ms, packetbuf_hdrptr()); PRINTF("15.4-OUT: %2X", params.fcf.frame_type); PRINTADDR(params.dest_addr); PRINTF("%d %u (%u)\n", hdr_len, packetbuf_datalen(), packetbuf_totlen()); return hdr_len; } else { PRINTF("15.4-OUT: too large header: %u\n", hdr_len); return FRAMER_FAILED; } }
/* Create an EB packet */ int tsch_packet_create_eb(uint8_t *buf, int buf_size, uint8_t seqno, uint8_t *hdr_len, uint8_t *tsch_sync_ie_offset) { int ret = 0; uint8_t curr_len = 0; uint8_t mlme_ie_offset; frame802154_t p; struct ieee802154_ies ies; if(buf_size < TSCH_PACKET_MAX_LEN) { return 0; } /* Create 802.15.4 header */ memset(&p, 0, sizeof(p)); p.fcf.frame_type = FRAME802154_BEACONFRAME; p.fcf.ie_list_present = 1; p.fcf.frame_version = FRAME802154_IEEE802154E_2012; p.fcf.src_addr_mode = LINKADDR_SIZE > 2 ? FRAME802154_LONGADDRMODE : FRAME802154_SHORTADDRMODE; p.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE; p.seq = seqno; p.fcf.sequence_number_suppression = FRAME802154_SUPPR_SEQNO; /* It is important not to compress PAN ID, as this would result in not including either * source nor destination PAN ID, leaving potential joining devices unaware of the PAN ID. */ p.fcf.panid_compression = 0; p.src_pid = frame802154_get_pan_id(); p.dest_pid = frame802154_get_pan_id(); linkaddr_copy((linkaddr_t *)&p.src_addr, &linkaddr_node_addr); p.dest_addr[0] = 0xff; p.dest_addr[1] = 0xff; #if LLSEC802154_ENABLED if(tsch_is_pan_secured) { p.fcf.security_enabled = packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) > 0; p.aux_hdr.security_control.security_level = packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL); p.aux_hdr.security_control.key_id_mode = packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE); p.aux_hdr.security_control.frame_counter_suppression = 1; p.aux_hdr.security_control.frame_counter_size = 1; p.aux_hdr.key_index = packetbuf_attr(PACKETBUF_ATTR_KEY_INDEX); } #endif /* LLSEC802154_ENABLED */ if((curr_len = frame802154_create(&p, buf)) == 0) { return 0; } /* Prepare Information Elements for inclusion in the EB */ memset(&ies, 0, sizeof(ies)); /* Add TSCH timeslot timing IE. */ #if TSCH_PACKET_EB_WITH_TIMESLOT_TIMING { int i; ies.ie_tsch_timeslot_id = 1; for(i = 0; i < tsch_ts_elements_count; i++) { ies.ie_tsch_timeslot[i] = RTIMERTICKS_TO_US(tsch_timing[i]); } } #endif /* TSCH_PACKET_EB_WITH_TIMESLOT_TIMING */ /* Add TSCH hopping sequence IE */ #if TSCH_PACKET_EB_WITH_HOPPING_SEQUENCE if(tsch_hopping_sequence_length.val <= sizeof(ies.ie_hopping_sequence_list)) { ies.ie_channel_hopping_sequence_id = 1; ies.ie_hopping_sequence_len = tsch_hopping_sequence_length.val; memcpy(ies.ie_hopping_sequence_list, tsch_hopping_sequence, ies.ie_hopping_sequence_len); } #endif /* TSCH_PACKET_EB_WITH_HOPPING_SEQUENCE */ /* Add Slotframe and Link IE */ #if TSCH_PACKET_EB_WITH_SLOTFRAME_AND_LINK { /* Send slotframe 0 with link at timeslot 0 */ struct tsch_slotframe *sf0 = tsch_schedule_get_slotframe_by_handle(0); struct tsch_link *link0 = tsch_schedule_get_link_by_timeslot(sf0, 0); if(sf0 && link0) { ies.ie_tsch_slotframe_and_link.num_slotframes = 1; ies.ie_tsch_slotframe_and_link.slotframe_handle = sf0->handle; ies.ie_tsch_slotframe_and_link.slotframe_size = sf0->size.val; ies.ie_tsch_slotframe_and_link.num_links = 1; ies.ie_tsch_slotframe_and_link.links[0].timeslot = link0->timeslot; ies.ie_tsch_slotframe_and_link.links[0].channel_offset = link0->channel_offset; ies.ie_tsch_slotframe_and_link.links[0].link_options = link0->link_options; } } #endif /* TSCH_PACKET_EB_WITH_SLOTFRAME_AND_LINK */ /* First add header-IE termination IE to stipulate that next come payload IEs */ if((ret = frame80215e_create_ie_header_list_termination_1(buf + curr_len, buf_size - curr_len, &ies)) == -1) { return -1; } curr_len += ret; /* We start payload IEs, save offset */ if(hdr_len != NULL) { *hdr_len = curr_len; } /* Save offset of the MLME IE descriptor, we need to know the total length * before writing it */ mlme_ie_offset = curr_len; curr_len += 2; /* Space needed for MLME descriptor */ /* Save the offset of the TSCH Synchronization IE, needed to update ASN and join priority before sending */ if(tsch_sync_ie_offset != NULL) { *tsch_sync_ie_offset = curr_len; } if((ret = frame80215e_create_ie_tsch_synchronization(buf + curr_len, buf_size - curr_len, &ies)) == -1) { return -1; } curr_len += ret; if((ret = frame80215e_create_ie_tsch_timeslot(buf + curr_len, buf_size - curr_len, &ies)) == -1) { return -1; } curr_len += ret; if((ret = frame80215e_create_ie_tsch_channel_hopping_sequence(buf + curr_len, buf_size - curr_len, &ies)) == -1) { return -1; } curr_len += ret; if((ret = frame80215e_create_ie_tsch_slotframe_and_link(buf + curr_len, buf_size - curr_len, &ies)) == -1) { return -1; } curr_len += ret; ies.ie_mlme_len = curr_len - mlme_ie_offset - 2; if((ret = frame80215e_create_ie_mlme(buf + mlme_ie_offset, buf_size - mlme_ie_offset, &ies)) == -1) { return -1; } /* Payload IE list termination: optional */ /* if((ret = frame80215e_create_ie_payload_list_termination(buf + curr_len, buf_size - curr_len, &ies)) == -1) { return -1; } curr_len += ret; */ return curr_len; }
/*---------------------------------------------------------------------------*/ static int init(void) { int put_index; tsExtAddr node_long_address; uint16_t node_short_address; tx_in_progress = 0; u32JPT_Init(); vMMAC_Enable(); /* Enable/disable interrupts */ if(poll_mode) { vMMAC_EnableInterrupts(NULL); vMMAC_ConfigureInterruptSources(0); } else { vMMAC_EnableInterrupts(&radio_interrupt_handler); } vMMAC_ConfigureRadio(); set_channel(MICROMAC_CONF_CHANNEL); set_txpower(MICROMAC_CONF_TX_POWER); vMMAC_GetMacAddress(&node_long_address); /* Short addresses are disabled by default */ node_short_address = (uint16_t)node_long_address.u32L; vMMAC_SetRxAddress(frame802154_get_pan_id(), node_short_address, &node_long_address); /* Disable hardware backoff */ vMMAC_SetTxParameters(1, 0, 0, 0); vMMAC_SetCutOffTimer(0, FALSE); /* Initialize ring buffer and first input packet pointer */ ringbufindex_init(&input_ringbuf, MIRCOMAC_CONF_BUF_NUM); /* get pointer to next input slot */ put_index = ringbufindex_peek_put(&input_ringbuf); if(put_index == -1) { rx_frame_buffer = NULL; printf("micromac_radio init:! no buffer available. Abort init.\n"); off(); return 0; } else { rx_frame_buffer = &input_array[put_index]; } input_frame_buffer = rx_frame_buffer; process_start(µmac_radio_process, NULL); #if RADIO_TEST_MODE == RADIO_TEST_MODE_HIGH_PWR /* Enable high power mode. * In this mode DIO2 goes high during RX * and DIO3 goes high during TX **/ vREG_SysWrite(REG_SYS_PWR_CTRL, u32REG_SysRead(REG_SYS_PWR_CTRL) | REG_SYSCTRL_PWRCTRL_RFRXEN_MASK | REG_SYSCTRL_PWRCTRL_RFTXEN_MASK); #elif RADIO_TEST_MODE == RADIO_TEST_MODE_ADVANCED /* output internal radio status on IO pins. * See Chris@NXP email */ vREG_SysWrite(REG_SYS_PWR_CTRL, u32REG_SysRead(REG_SYS_PWR_CTRL) | (1UL << 26UL)); #endif /* TEST_MODE */ return 1; }