/*---------------------------------------------------------------------------*/ int anti_replay_was_replayed(struct anti_replay_info *info) { uint32_t received_counter; received_counter = anti_replay_get_counter(); if(packetbuf_holds_broadcast()) { /* broadcast */ if(received_counter <= info->last_broadcast_counter) { return 1; } else { info->last_broadcast_counter = received_counter; return 0; } } else { /* unicast */ if(received_counter <= info->last_unicast_counter) { return 1; } else { info->last_unicast_counter = received_counter; return 0; } } }
/*---------------------------------------------------------------------------*/ void anti_replay_restore_counter(struct anti_replay_info *info) { uint8_t seqno; frame802154_frame_counter_t copied_counter; seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO); copied_counter.u32 = packetbuf_holds_broadcast() ? info->his_broadcast_counter.u32 : info->his_unicast_counter.u32; if(seqno < copied_counter.u8[0]) { copied_counter.u8[1]++; if(!copied_counter.u8[1]) { copied_counter.u8[2]++; if(!copied_counter.u8[2]) { copied_counter.u8[3]++; } } } copied_counter.u8[0] = seqno; packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1, copied_counter.u16[0]); packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3, copied_counter.u16[1]); }
/*---------------------------------------------------------------------------*/ int anti_replay_was_replayed(struct anti_replay_info *info) { uint32_t received_counter; received_counter = anti_replay_get_counter(); if(packetbuf_holds_broadcast()) { #if DEBUG if(received_counter < info->his_broadcast_counter.u32) { PRINTF("anti-replay: Broadcast out of order\n"); } #endif /* DEBUG */ if(received_counter <= info->his_broadcast_counter.u32) { return 1; } else { info->his_broadcast_counter.u32 = received_counter; return 0; } } else { #if DEBUG if(received_counter < info->his_unicast_counter.u32) { PRINTF("anti-replay: Unicast out of order\n"); } #endif /* DEBUG */ if(received_counter <= info->his_unicast_counter.u32) { return 1; } else { info->his_unicast_counter.u32 = received_counter; return 0; } } }
/*---------------------------------------------------------------------------*/ static void packet_input(void) { if(packetbuf_datalen() == ACK_LEN){ /* Ignore ack packets */ PRINTF("nullrdc: ignored ack\n"); }else if(NETSTACK_FRAMER.parse() < 0){ PRINTF("nullrdc: failed to parse %u\n", packetbuf_datalen()); #if NULLRDC_ADDRESS_FILTER }else if(!linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_node_addr) && !packetbuf_holds_broadcast()){ PRINTF("nullrdc: not for us\n"); #endif /* NULLRDC_ADDRESS_FILTER */ }else{ int duplicate = 0; /* Check for duplicate packet. */ duplicate = mac_sequence_is_duplicate(); if(duplicate){ /* Drop the packet. */ PRINTF("nullrdc: drop duplicate link layer packet %u\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)); }else{ mac_sequence_register_seqno(); } if(!duplicate) { NETSTACK_MAC.input(); } } }
/*---------------------------------------------------------------------------*/ uint8_t adaptivesec_get_sec_lvl(void) { switch(packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE)) { case FRAME802154_CMDFRAME: switch(adaptivesec_get_cmd_id()) { case AKES_HELLO_IDENTIFIER: return ADAPTIVESEC_BROADCAST_SEC_LVL & 3; case AKES_HELLOACK_IDENTIFIER: case AKES_HELLOACK_P_IDENTIFIER: case AKES_ACK_IDENTIFIER: return AKES_ACKS_SEC_LVL; case AKES_UPDATE_IDENTIFIER: case AKES_UPDATEACK_IDENTIFIER: return AKES_UPDATES_SEC_LVL; } break; case FRAME802154_DATAFRAME: return packetbuf_holds_broadcast() ? ADAPTIVESEC_BROADCAST_SEC_LVL : ADAPTIVESEC_UNICAST_SEC_LVL; break; } return 0; }
/*---------------------------------------------------------------------------*/ static int on_frame_created(void) { uint8_t sec_lvl; enum akes_nbr_status status; struct akes_nbr_entry *entry; uint8_t *dataptr; uint8_t datalen; sec_lvl = adaptivesec_get_sec_lvl(); if(sec_lvl && !packetbuf_holds_broadcast()) { status = akes_get_receiver_status(); entry = akes_nbr_get_receiver_entry(); if(!entry || !entry->refs[status]) { return 0; } dataptr = packetbuf_dataptr(); datalen = packetbuf_datalen(); adaptivesec_aead(entry->refs[status]->pairwise_key, sec_lvl & (1 << 2), dataptr + datalen, 1); packetbuf_set_datalen(datalen + ADAPTIVESEC_UNICAST_MIC_LEN); } return 1; }
/*---------------------------------------------------------------------------*/ static enum adaptivesec_verify verify(struct akes_nbr *sender) { if(packetbuf_holds_broadcast()) { if(verify_broadcast(sender)) { PRINTF("coresec-strategy: Inauthentic broadcast\n"); return 0; } } else { #if ANTI_REPLAY_WITH_SUPPRESSION packetbuf_set_attr(PACKETBUF_ATTR_NEIGHBOR_INDEX, sender->foreign_index); #endif /* ANTI_REPLAY_WITH_SUPPRESSION */ if(adaptivesec_verify(sender->pairwise_key)) { PRINTF("coresec-strategy: Inauthentic unicast\n"); return ADAPTIVESEC_VERIFY_INAUTHENTIC; } } #if !POTR_ENABLED if(anti_replay_was_replayed(&sender->anti_replay_info)) { PRINTF("coresec-strategy: Replayed\n"); return ADAPTIVESEC_VERIFY_REPLAYED; } #endif /* !POTR_ENABLED */ return ADAPTIVESEC_VERIFY_SUCCESS; }
/*---------------------------------------------------------------------------*/ static void send(mac_callback_t sent, void *ptr) { struct akes_nbr_entry *entry; packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); if(packetbuf_holds_broadcast()) { if(!akes_nbr_count(AKES_NBR_PERMANENT)) { mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 0); return; } adaptivesec_add_security_header(NULL); } else { entry = akes_nbr_get_receiver_entry(); if(!entry || !entry->permanent) { mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 0); return; } adaptivesec_add_security_header(&entry->permanent->anti_replay_info); #if ANTI_REPLAY_WITH_SUPPRESSION packetbuf_set_attr(PACKETBUF_ATTR_NEIGHBOR_INDEX, entry->local_index); #endif /* ANTI_REPLAY_WITH_SUPPRESSION */ } #if !ANTI_REPLAY_WITH_SUPPRESSION && !POTR_ENABLED framer_802154_set_seqno(); #endif /* ANTI_REPLAY_WITH_SUPPRESSION && !POTR_ENABLED */ ADAPTIVESEC_STRATEGY.send(sent, ptr); }
/*---------------------------------------------------------------------------*/ static int decrypt_verify(struct neighbor *sender) { if(packetbuf_holds_broadcast()) { if(!decrypt_verify_broadcast(sender)) { PRINTF("coresec-strategy: Unauthentic broadcast\n"); return 0; } } else { #if ANTI_REPLAY_WITH_SUPPRESSION packetbuf_set_attr(PACKETBUF_ATTR_NEIGHBOR_INDEX, sender->foreign_index); #endif /* ANTI_REPLAY_WITH_SUPPRESSION */ if(!adaptivesec_decrypt_verify(sender->pairwise_key)) { PRINTF("coresec-strategy: Unauthentic unicast\n"); return 0; } } if(anti_replay_was_replayed(&sender->anti_replay_info)) { PRINTF("coresec-strategy: Replayed\n"); return 0; } return 1; }
/*---------------------------------------------------------------------------*/ static void send(mac_callback_t sent, void *ptr) { if(packetbuf_holds_broadcast()) { send_broadcast(sent, ptr); } else { NETSTACK_MAC.send(sent, ptr); } }
/*---------------------------------------------------------------------------*/ int anti_replay_set_counter(struct anti_replay_info *receiver_info) { #if ANTI_REPLAY_WITH_SUPPRESSION if(packetbuf_holds_broadcast()) { order_and_set_counter(++anti_replay_my_broadcast_counter); } else { if(++my_unicast_counter == 0xFFFFFFFF) { return 0; } order_and_set_counter(++receiver_info->my_unicast_counter.u32); } #else /* ANTI_REPLAY_WITH_SUPPRESSION */ order_and_set_counter(++my_counter); #endif /* ANTI_REPLAY_WITH_SUPPRESSION */ return (anti_replay_get_counter() != 0xFFFFFFFF); }
static uint8_t send_packet(struct net_buf *buf, mac_callback_t sent_callback, void *ptr) { bool is_broadcast, ack_required; uint8_t attempts; uint8_t retries; int ret; #ifdef SIMPLERDC_802154_ACK_REQ packetbuf_set_attr(buf, PACKETBUF_ATTR_MAC_ACK, 1); #endif retries = prepare_packet(buf); if (!retries) { return MAC_TX_ERR_FATAL; } ack_required = prepare_for_ack(buf); is_broadcast = !!packetbuf_holds_broadcast(buf); attempts = 0; while (retries) { attempts++; retries--; ret = NETSTACK_RADIO.transmit(buf, packetbuf_totlen(buf)); if (ret == RADIO_TX_COLLISION) { continue; } ret = wait_for_ack(is_broadcast, ack_required); if (ret == MAC_TX_OK) { break; } } mac_call_sent_callback(buf, sent_callback, ptr, ret, attempts); if (ret == MAC_TX_OK) { return 1; } return 0; }
/** * \brief Take a packet received over the 802.15.4 link, and send it * out over ethernet, performing any translations needed. */ void mac_LowpanToEthernet(void) { /* parsed_frame = sicslowmac_get_frame(); */ //Setup generic ethernet stuff ETHBUF(uip_buf)->type = htons(UIP_ETHTYPE_IPV6); //Check for broadcast message if(packetbuf_holds_broadcast()) { /* if( ( parsed_frame->fcf->destAddrMode == SHORTADDRMODE) && */ /* ( parsed_frame->dest_addr->addr16 == 0xffff) ) { */ ETHBUF(uip_buf)->dest.addr[0] = 0x33; ETHBUF(uip_buf)->dest.addr[1] = 0x33; ETHBUF(uip_buf)->dest.addr[2] = UIP_IP_BUF->destipaddr.u8[12]; ETHBUF(uip_buf)->dest.addr[3] = UIP_IP_BUF->destipaddr.u8[13]; ETHBUF(uip_buf)->dest.addr[4] = UIP_IP_BUF->destipaddr.u8[14]; ETHBUF(uip_buf)->dest.addr[5] = UIP_IP_BUF->destipaddr.u8[15]; } else { //Otherwise we have a real address mac_createEthernetAddr((uint8_t *) &(ETHBUF(uip_buf)->dest.addr[0]), (uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); } mac_createEthernetAddr((uint8_t *) &(ETHBUF(uip_buf)->src.addr[0]), (uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER)); //We only do address translation in network mode! if (usbstick_mode.translate) { //Some IP packets have link layer in them, need to change them around! mac_translateIPLinkLayer(ll_8023_type); } PRINTF("Low2Eth: Sending packet to ethernet\n"); uip_len += UIP_LLH_LEN; /* rndis_send(uip_buf, uip_len, 1); */ /* rndis_stat.rxok++; */ /* uip_len = 0; */ }
/*---------------------------------------------------------------------------*/ static void input(void) { struct akes_nbr_entry *entry; #if LLSEC802154_USES_AUX_HEADER && POTR_ENABLED packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, adaptivesec_get_sec_lvl()); #endif /* LLSEC802154_USES_AUX_HEADER && POTR_ENABLED */ switch(packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE)) { case FRAME802154_CMDFRAME: cmd_broker_publish(); break; case FRAME802154_DATAFRAME: entry = akes_nbr_get_sender_entry(); if(!entry || !entry->permanent) { PRINTF("adaptivesec: Ignored incoming frame\n"); return; } #if SECRDC_WITH_SECURE_PHASE_LOCK if(packetbuf_holds_broadcast() && ADAPTIVESEC_STRATEGY.verify(entry->permanent)) { return; } #else /* SECRDC_WITH_SECURE_PHASE_LOCK */ #if ANTI_REPLAY_WITH_SUPPRESSION && !POTR_ENABLED anti_replay_restore_counter(&entry->permanent->anti_replay_info); #endif /* ANTI_REPLAY_WITH_SUPPRESSION && !POTR_ENABLED */ if(ADAPTIVESEC_STRATEGY.verify(entry->permanent) != ADAPTIVESEC_VERIFY_SUCCESS) { return; } #endif /* SECRDC_WITH_SECURE_PHASE_LOCK */ akes_nbr_prolong(entry->permanent); NETSTACK_NETWORK.input(); break; } }
/*---------------------------------------------------------------------------*/ static int send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_list *buf_list, int is_receiver_awake) { rtimer_clock_t t0; rtimer_clock_t encounter_time = 0; int strobes; uint8_t got_strobe_ack = 0; int len; uint8_t is_broadcast = 0; uint8_t is_reliable = 0; uint8_t is_known_receiver = 0; uint8_t collisions; int transmit_len; int ret; uint8_t contikimac_was_on; uint8_t seqno; /* Exit if RDC and radio were explicitly turned off */ if(!contikimac_is_on && !contikimac_keep_radio_on) { PRINTF("contikimac: radio is turned off\n"); return MAC_TX_ERR_FATAL; } if(packetbuf_totlen() == 0) { PRINTF("contikimac: send_packet data len 0\n"); return MAC_TX_ERR_FATAL; } #if !NETSTACK_CONF_BRIDGE_MODE /* If NETSTACK_CONF_BRIDGE_MODE is set, assume PACKETBUF_ADDR_SENDER is already set. */ packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); #endif if(packetbuf_holds_broadcast()) { is_broadcast = 1; PRINTDEBUG("contikimac: send broadcast\n"); if(broadcast_rate_drop()) { return MAC_TX_COLLISION; } } else { #if NETSTACK_CONF_WITH_IPV6 PRINTDEBUG("contikimac: send unicast to %02x%02x:%02x%02x:%02x%02x:%02x%02x\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[2], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[3], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[4], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[5], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[6], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[7]); #else /* NETSTACK_CONF_WITH_IPV6 */ PRINTDEBUG("contikimac: send unicast to %u.%u\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]); #endif /* NETSTACK_CONF_WITH_IPV6 */ } is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) #if NETSTACK_CONF_WITH_RIME || packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) #endif /* NETSTACK_CONF_WITH_RIME */ ; if(!packetbuf_attr(PACKETBUF_ATTR_IS_CREATED_AND_SECURED)) { packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); if(NETSTACK_FRAMER.create_and_secure() < 0) { PRINTF("contikimac: framer failed\n"); return MAC_TX_ERR_FATAL; } } transmit_len = packetbuf_totlen(); NETSTACK_RADIO.prepare(packetbuf_hdrptr(), transmit_len); if(!is_broadcast && !is_receiver_awake) { #if WITH_PHASE_OPTIMIZATION ret = phase_wait(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), CYCLE_TIME, GUARD_TIME, mac_callback, mac_callback_ptr, buf_list); if(ret == PHASE_DEFERRED) { return MAC_TX_DEFERRED; } if(ret != PHASE_UNKNOWN) { is_known_receiver = 1; } #endif /* WITH_PHASE_OPTIMIZATION */ } /* By setting we_are_sending to one, we ensure that the rtimer powercycle interrupt do not interfere with us sending the packet. */ we_are_sending = 1; /* If we have a pending packet in the radio, we should not send now, because we will trash the received packet. Instead, we signal that we have a collision, which lets the packet be received. This packet will be retransmitted later by the MAC protocol instread. */ if(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet()) { we_are_sending = 0; PRINTF("contikimac: collision receiving %d, pending %d\n", NETSTACK_RADIO.receiving_packet(), NETSTACK_RADIO.pending_packet()); return MAC_TX_COLLISION; } /* Switch off the radio to ensure that we didn't start sending while the radio was doing a channel check. */ off(); strobes = 0; /* Send a train of strobes until the receiver answers with an ACK. */ collisions = 0; got_strobe_ack = 0; /* Set contikimac_is_on to one to allow the on() and off() functions to control the radio. We restore the old value of contikimac_is_on when we are done. */ contikimac_was_on = contikimac_is_on; contikimac_is_on = 1; #if !RDC_CONF_HARDWARE_CSMA /* Check if there are any transmissions by others. */ /* TODO: why does this give collisions before sending with the mc1322x? */ if(is_receiver_awake == 0) { int i; for(i = 0; i < CCA_COUNT_MAX_TX; ++i) { t0 = RTIMER_NOW(); on(); #if CCA_CHECK_TIME > 0 while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + CCA_CHECK_TIME)) { } #endif if(NETSTACK_RADIO.channel_clear() == 0) { collisions++; off(); break; } off(); t0 = RTIMER_NOW(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + CCA_SLEEP_TIME)) { } } } if(collisions > 0) { we_are_sending = 0; off(); PRINTF("contikimac: collisions before sending\n"); contikimac_is_on = contikimac_was_on; return MAC_TX_COLLISION; } #endif /* RDC_CONF_HARDWARE_CSMA */ #if !RDC_CONF_HARDWARE_ACK if(!is_broadcast) { /* Turn radio on to receive expected unicast ack. Not necessary with hardware ack detection, and may trigger an unnecessary cca or rx cycle */ on(); } #endif watchdog_periodic(); t0 = RTIMER_NOW(); seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO); for(strobes = 0, collisions = 0; got_strobe_ack == 0 && collisions == 0 && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + STROBE_TIME); strobes++) { watchdog_periodic(); if(!is_broadcast && (is_receiver_awake || is_known_receiver) && !RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + MAX_PHASE_STROBE_TIME)) { PRINTF("miss to %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0]); break; } len = 0; { rtimer_clock_t wt; rtimer_clock_t txtime; int ret; txtime = RTIMER_NOW(); ret = NETSTACK_RADIO.transmit(transmit_len); #if RDC_CONF_HARDWARE_ACK /* For radios that block in the transmit routine and detect the ACK in hardware */ if(ret == RADIO_TX_OK) { if(!is_broadcast) { got_strobe_ack = 1; encounter_time = txtime; break; } } else if (ret == RADIO_TX_NOACK) { } else if (ret == RADIO_TX_COLLISION) { PRINTF("contikimac: collisions while sending\n"); collisions++; } wt = RTIMER_NOW(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + INTER_PACKET_INTERVAL)) { } #else /* RDC_CONF_HARDWARE_ACK */ /* Wait for the ACK packet */ wt = RTIMER_NOW(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + INTER_PACKET_INTERVAL)) { } if(!is_broadcast && (NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet() || NETSTACK_RADIO.channel_clear() == 0)) { uint8_t ackbuf[ACK_LEN]; wt = RTIMER_NOW(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { } len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); if(len == ACK_LEN && seqno == ackbuf[ACK_LEN - 1]) { got_strobe_ack = 1; encounter_time = txtime; break; } else { PRINTF("contikimac: collisions while sending\n"); collisions++; } } #endif /* RDC_CONF_HARDWARE_ACK */ } } off(); PRINTF("contikimac: send (strobes=%u, len=%u, %s, %s), done\n", strobes, packetbuf_totlen(), got_strobe_ack ? "ack" : "no ack", collisions ? "collision" : "no collision"); #if CONTIKIMAC_CONF_COMPOWER /* Accumulate the power consumption for the packet transmission. */ compower_accumulate(¤t_packet); /* Convert the accumulated power consumption for the transmitted packet to packet attributes so that the higher levels can keep track of the amount of energy spent on transmitting the packet. */ compower_attrconv(¤t_packet); /* Clear the accumulated power consumption so that it is ready for the next packet. */ compower_clear(¤t_packet); #endif /* CONTIKIMAC_CONF_COMPOWER */ contikimac_is_on = contikimac_was_on; we_are_sending = 0; /* Determine the return value that we will return from the function. We must pass this value to the phase module before we return from the function. */ if(collisions > 0) { ret = MAC_TX_COLLISION; } else if(!is_broadcast && !got_strobe_ack) { ret = MAC_TX_NOACK; } else { ret = MAC_TX_OK; } #if WITH_PHASE_OPTIMIZATION if(is_known_receiver && got_strobe_ack) { PRINTF("no miss %d wake-ups %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], strobes); } if(!is_broadcast) { if(collisions == 0 && is_receiver_awake == 0) { phase_update(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time, ret); } } #endif /* WITH_PHASE_OPTIMIZATION */ return ret; }
/*---------------------------------------------------------------------------*/ static void input_packet(void) { static struct ctimer ct; int duplicate = 0; #if CONTIKIMAC_SEND_SW_ACK int original_datalen; uint8_t *original_dataptr; original_datalen = packetbuf_datalen(); original_dataptr = packetbuf_dataptr(); #endif if(!we_are_receiving_burst) { off(); } if(packetbuf_datalen() == ACK_LEN) { /* Ignore ack packets */ PRINTF("ContikiMAC: ignored ack\n"); return; } /* printf("cycle_start 0x%02x 0x%02x\n", cycle_start, cycle_start % CYCLE_TIME);*/ if(packetbuf_totlen() > 0 && NETSTACK_FRAMER.parse() >= 0) { if(packetbuf_datalen() > 0 && packetbuf_totlen() > 0 && (linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_node_addr) || packetbuf_holds_broadcast())) { /* This is a regular packet that is destined to us or to the broadcast address. */ /* If FRAME_PENDING is set, we are receiving a packets in a burst */ we_are_receiving_burst = packetbuf_attr(PACKETBUF_ATTR_PENDING); if(we_are_receiving_burst) { on(); /* Set a timer to turn the radio off in case we do not receive a next packet */ ctimer_set(&ct, INTER_PACKET_DEADLINE, recv_burst_off, NULL); } else { off(); ctimer_stop(&ct); } #if RDC_WITH_DUPLICATE_DETECTION /* Check for duplicate packet. */ duplicate = mac_sequence_is_duplicate(); if(duplicate) { /* Drop the packet. */ PRINTF("contikimac: Drop duplicate\n"); } else { mac_sequence_register_seqno(); } #endif /* RDC_WITH_DUPLICATE_DETECTION */ #if CONTIKIMAC_CONF_COMPOWER /* Accumulate the power consumption for the packet reception. */ compower_accumulate(¤t_packet); /* Convert the accumulated power consumption for the received packet to packet attributes so that the higher levels can keep track of the amount of energy spent on receiving the packet. */ compower_attrconv(¤t_packet); /* Clear the accumulated power consumption so that it is ready for the next packet. */ compower_clear(¤t_packet); #endif /* CONTIKIMAC_CONF_COMPOWER */ PRINTDEBUG("contikimac: data (%u)\n", packetbuf_datalen()); #if CONTIKIMAC_SEND_SW_ACK { frame802154_t info154; frame802154_parse(original_dataptr, original_datalen, &info154); if(info154.fcf.frame_type == FRAME802154_DATAFRAME && info154.fcf.ack_required != 0 && linkaddr_cmp((linkaddr_t *)&info154.dest_addr, &linkaddr_node_addr)) { uint8_t ackdata[ACK_LEN] = {0, 0, 0}; we_are_sending = 1; ackdata[0] = FRAME802154_ACKFRAME; ackdata[1] = 0; ackdata[2] = info154.seq; NETSTACK_RADIO.send(ackdata, ACK_LEN); we_are_sending = 0; } } #endif /* CONTIKIMAC_SEND_SW_ACK */ if(!duplicate) { NETSTACK_MAC.input(); } return; } else { PRINTDEBUG("contikimac: data not for us\n"); } } else { PRINTF("contikimac: failed to parse (%u)\n", packetbuf_totlen()); } }
/*---------------------------------------------------------------------------*/ static uint8_t packet_input(struct net_buf *buf) { #if NULLRDC_SEND_802154_ACK int original_datalen; uint8_t *original_dataptr; original_datalen = packetbuf_datalen(buf); original_dataptr = packetbuf_dataptr(buf); #endif #if NULLRDC_802154_AUTOACK if(packetbuf_datalen(buf) == ACK_LEN) { /* Ignore ack packets */ PRINTF("nullrdc: ignored ack\n"); } else #endif /* NULLRDC_802154_AUTOACK */ if(NETSTACK_FRAMER.parse(buf) < 0) { PRINTF("nullrdc: failed to parse msg len %u\n", packetbuf_datalen(buf)); #if NULLRDC_ADDRESS_FILTER } else if(!linkaddr_cmp(packetbuf_addr(buf, PACKETBUF_ADDR_RECEIVER), &linkaddr_node_addr) && !packetbuf_holds_broadcast(buf)) { PRINTF("nullrdc: not for us\n"); #endif /* NULLRDC_ADDRESS_FILTER */ } else { int duplicate = 0; #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW /* If llsec is not doing anti replay checks this needs to be done */ if(anti_replay_is_anti_replay_checked(buf) == 0) { /* Check for duplicate packet. */ duplicate = mac_sequence_is_duplicate(buf); if(duplicate) { /* Drop the packet. */ PRINTF("nullrdc: drop duplicate link layer packet %u\n", packetbuf_attr(buf, PACKETBUF_ATTR_MAC_SEQNO)); } else { mac_sequence_register_seqno(buf); } } #endif /* NULLRDC_802154_AUTOACK */ /* TODO We may want to acknowledge only authentic frames */ #if NULLRDC_SEND_802154_ACK { frame802154_t info154; frame802154_parse(original_dataptr, original_datalen, &info154); if(info154.fcf.frame_type == FRAME802154_DATAFRAME && info154.fcf.ack_required != 0 && linkaddr_cmp((linkaddr_t *)&info154.dest_addr, &linkaddr_node_addr)) { uint8_t ackdata[ACK_LEN] = {0, 0, 0}; ackdata[0] = FRAME802154_ACKFRAME; ackdata[1] = 0; ackdata[2] = info154.seq; return NETSTACK_RADIO.send(ackdata, ACK_LEN); } } #endif /* NULLRDC_SEND_ACK */ if(!duplicate) { return NETSTACK_MAC.input(buf); } } return 0; }
/*---------------------------------------------------------------------------*/ static int send_one_packet(struct net_buf *buf, mac_callback_t sent, void *ptr) { int ret; int last_sent_ok = 0; #if NULLRDC_ENABLE_RETRANSMISSIONS rtimer_clock_t target_time; uint8_t tx_attempts = 0; uint8_t max_tx_attempts; if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) > 0) { max_tx_attempts = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS); } else { max_tx_attempts = NULLRDC_MAX_RETRANSMISSIONS + 1; } #endif /* NULLRDC_ENABLE_RETRANSMISSIONS */ packetbuf_set_addr(buf, PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW packetbuf_set_attr(buf, PACKETBUF_ATTR_MAC_ACK, 1); #endif /* NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW */ if(NETSTACK_FRAMER.create_and_secure(buf) < 0) { /* Failed to allocate space for headers */ PRINTF("nullrdc: send failed, too large header\n"); ret = MAC_TX_ERR_FATAL; } else { #if NULLRDC_802154_AUTOACK int is_broadcast; uint8_t dsn; dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff; NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen()); is_broadcast = packetbuf_holds_broadcast(); if(NETSTACK_RADIO.receiving_packet() || (!is_broadcast && NETSTACK_RADIO.pending_packet())) { /* Currently receiving a packet over air or the radio has already received a packet that needs to be read before sending with auto ack. */ ret = MAC_TX_COLLISION; } else { if(!is_broadcast) { RIMESTATS_ADD(reliabletx); } #if NULLRDC_ENABLE_RETRANSMISSIONS while(1) { /* Transmit packet and check status */ tx_attempts++; #endif /* NULLRDC_ENABLE_RETRANSMISSIONS */ switch(NETSTACK_RADIO.transmit(packetbuf_totlen(buf))) { case RADIO_TX_OK: if(is_broadcast) { ret = MAC_TX_OK; } else { rtimer_clock_t wt; /* Check for ack */ wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)) { #if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); #endif /* CONTIKI_TARGET_COOJA */ } ret = MAC_TX_NOACK; if(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet() || NETSTACK_RADIO.channel_clear() == 0) { int len; uint8_t ackbuf[ACK_LEN]; if(AFTER_ACK_DETECTED_WAIT_TIME > 0) { wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTED_WAIT_TIME)) { #if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); #endif /* CONTIKI_TARGET_COOJA */ } } if(NETSTACK_RADIO.pending_packet()) { len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); if(len == ACK_LEN && ackbuf[2] == dsn) { /* Ack received */ RIMESTATS_ADD(ackrx); ret = MAC_TX_OK; } else { /* Not an ack or ack not for us: collision */ ret = MAC_TX_COLLISION; } } } else { PRINTF("nullrdc tx noack\n"); } } break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; default: ret = MAC_TX_ERR; break; } #if NULLRDC_ENABLE_RETRANSMISSIONS if(is_broadcast) { #if !NULLRDC_ENABLE_RETRANSMISSIONS_BCAST break; #else /* NULLRDC_ENABLE_RETRANSMISSIONS_BCAST */ if(ret != MAC_TX_COLLISION) { /* Retry broadcast frame only upon collision */ break; } #endif /* NULLRDC_ENABLE_RETRANSMISSIONS_BCAST */ } else { /* Frame is unicast. Do not retry unless NO_ACK or COLLISION */ if((ret != MAC_TX_NOACK) && (ret != MAC_TX_COLLISION)) { break; } } /* Do not retry if max attempts reached. */ if(tx_attempts >= max_tx_attempts) { PRINTF("nullrdc: max tx attempts reached\n"); break; } /* Block-wait before retrying the frame. */ target_time = RTIMER_NOW() + (RTIMER_SECOND * NULLRDC_TX_RETRY_DELAY_MS / 1000); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), target_time)) { /* Wait */ } /* Attempt a new frame (re)transmission */ } #endif /* NULLRDC_ENABLE_RETRANSMISSIONS */ } #else /* ! NULLRDC_802154_AUTOACK */ switch(NETSTACK_RADIO.send(buf, packetbuf_hdrptr(buf), packetbuf_totlen(buf))) { case RADIO_TX_OK: ret = MAC_TX_OK; break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; case RADIO_TX_NOACK: ret = MAC_TX_NOACK; break; default: ret = MAC_TX_ERR; break; } #endif /* ! NULLRDC_802154_AUTOACK */ } if(ret == MAC_TX_OK) { last_sent_ok = 1; } #if ! NULLRDC_ENABLE_RETRANSMISSIONS mac_call_sent_callback(buf, sent, ptr, ret, 1); #else mac_call_sent_callback(buf, sent, ptr, ret, tx_attempts); #endif /* !NULLRDC_ENABLE_RETRANSMISSIONS */ return last_sent_ok; }
/*---------------------------------------------------------------------------*/ static uint8_t get_overhead(void) { return packetbuf_holds_broadcast() ? 0 : ADAPTIVESEC_UNICAST_MIC_LEN; }
/*---------------------------------------------------------------------------*/ uint8_t adaptivesec_mic_len(void) { return packetbuf_holds_broadcast() ? ADAPTIVESEC_BROADCAST_MIC_LEN : ADAPTIVESEC_UNICAST_MIC_LEN; }
/*---------------------------------------------------------------------------*/ static int send_packet(void) { rtimer_clock_t t0; rtimer_clock_t t; rtimer_clock_t encounter_time = 0; int strobes; struct cxmac_hdr *hdr; int got_strobe_ack = 0; uint8_t strobe[MAX_STROBE_SIZE]; int strobe_len, len; int is_broadcast = 0; int is_dispatch, is_strobe_ack; /*int is_reliable;*/ struct encounter *e; struct queuebuf *packet; int is_already_streaming = 0; uint8_t collisions; /* Create the X-MAC header for the data packet. */ #if !NETSTACK_CONF_BRIDGE_MODE /* If NETSTACK_CONF_BRIDGE_MODE is set, assume PACKETBUF_ADDR_SENDER is already set. */ packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); #endif if(packetbuf_holds_broadcast()) { is_broadcast = 1; PRINTDEBUG("cxmac: send broadcast\n"); } else { #if NETSTACK_CONF_WITH_IPV6 PRINTDEBUG("cxmac: send unicast to %02x%02x:%02x%02x:%02x%02x:%02x%02x\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[2], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[3], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[4], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[5], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[6], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[7]); #else PRINTDEBUG("cxmac: send unicast to %u.%u\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]); #endif /* NETSTACK_CONF_WITH_IPV6 */ } /* is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) || packetbuf_attr(PACKETBUF_ATTR_ERELIABLE);*/ len = NETSTACK_FRAMER.create(); strobe_len = len + sizeof(struct cxmac_hdr); if(len < 0 || strobe_len > (int)sizeof(strobe)) { /* Failed to send */ PRINTF("cxmac: send failed, too large header\n"); return MAC_TX_ERR_FATAL; } memcpy(strobe, packetbuf_hdrptr(), len); strobe[len] = DISPATCH; /* dispatch */ strobe[len + 1] = TYPE_STROBE; /* type */ packetbuf_compact(); packet = queuebuf_new_from_packetbuf(); if(packet == NULL) { /* No buffer available */ PRINTF("cxmac: send failed, no queue buffer available (of %u)\n", QUEUEBUF_CONF_NUM); return MAC_TX_ERR; } #if WITH_STREAMING if(is_streaming == 1 && (linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &is_streaming_to) || linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &is_streaming_to_too))) { is_already_streaming = 1; } if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_STREAM) { is_streaming = 1; if(linkaddr_cmp(&is_streaming_to, &linkaddr_null)) { linkaddr_copy(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); } else if(!linkaddr_cmp(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) { linkaddr_copy(&is_streaming_to_too, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); } stream_until = RTIMER_NOW() + DEFAULT_STREAM_TIME; } #endif /* WITH_STREAMING */ off(); #if WITH_ENCOUNTER_OPTIMIZATION /* We go through the list of encounters to find if we have recorded an encounter with this particular neighbor. If so, we can compute the time for the next expected encounter and setup a ctimer to switch on the radio just before the encounter. */ for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) { const linkaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); if(linkaddr_cmp(neighbor, &e->neighbor)) { rtimer_clock_t wait, now, expected; /* We expect encounters to happen every DEFAULT_PERIOD time units. The next expected encounter is at time e->time + DEFAULT_PERIOD. To compute a relative offset, we subtract with clock_time(). Because we are only interested in turning on the radio within the DEFAULT_PERIOD period, we compute the waiting time with modulo DEFAULT_PERIOD. */ now = RTIMER_NOW(); wait = ((rtimer_clock_t)(e->time - now)) % (DEFAULT_PERIOD); expected = now + wait - 2 * DEFAULT_ON_TIME; #if WITH_ACK_OPTIMIZATION /* Wait until the receiver is expected to be awake */ if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) != PACKETBUF_ATTR_PACKET_TYPE_ACK && is_streaming == 0) { /* Do not wait if we are sending an ACK, because then the receiver will already be awake. */ while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected)); } #else /* WITH_ACK_OPTIMIZATION */ /* Wait until the receiver is expected to be awake */ while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected)); #endif /* WITH_ACK_OPTIMIZATION */ } } #endif /* WITH_ENCOUNTER_OPTIMIZATION */ /* By setting we_are_sending to one, we ensure that the rtimer powercycle interrupt do not interfere with us sending the packet. */ we_are_sending = 1; t0 = RTIMER_NOW(); strobes = 0; LEDS_ON(LEDS_BLUE); /* Send a train of strobes until the receiver answers with an ACK. */ /* Turn on the radio to listen for the strobe ACK. */ on(); collisions = 0; if(!is_already_streaming) { watchdog_stop(); got_strobe_ack = 0; t = RTIMER_NOW(); for(strobes = 0, collisions = 0; got_strobe_ack == 0 && collisions == 0 && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + cxmac_config.strobe_time); strobes++) { while(got_strobe_ack == 0 && RTIMER_CLOCK_LT(RTIMER_NOW(), t + cxmac_config.strobe_wait_time)) { rtimer_clock_t now = RTIMER_NOW(); /* See if we got an ACK */ packetbuf_clear(); len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); if(len > 0) { packetbuf_set_datalen(len); if(NETSTACK_FRAMER.parse() >= 0) { hdr = packetbuf_dataptr(); is_dispatch = hdr->dispatch == DISPATCH; is_strobe_ack = hdr->type == TYPE_STROBE_ACK; if(is_dispatch && is_strobe_ack) { if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_node_addr)) { /* We got an ACK from the receiver, so we can immediately send the packet. */ got_strobe_ack = 1; encounter_time = now; } else { PRINTDEBUG("cxmac: strobe ack for someone else\n"); } } else /*if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE)*/ { PRINTDEBUG("cxmac: strobe from someone else\n"); collisions++; } } else { PRINTF("cxmac: send failed to parse %u\n", len); } } } t = RTIMER_NOW(); /* Send the strobe packet. */ if(got_strobe_ack == 0 && collisions == 0) { if(is_broadcast) { #if WITH_STROBE_BROADCAST NETSTACK_RADIO.send(strobe, strobe_len); #else /* restore the packet to send */ queuebuf_to_packetbuf(packet); NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); #endif off(); } else { NETSTACK_RADIO.send(strobe, strobe_len); #if 0 /* Turn off the radio for a while to let the other side respond. We don't need to keep our radio on when we know that the other side needs some time to produce a reply. */ off(); rtimer_clock_t wt = RTIMER_NOW(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + WAIT_TIME_BEFORE_STROBE_ACK)); #endif /* 0 */ on(); } } } } #if WITH_ACK_OPTIMIZATION /* If we have received the strobe ACK, and we are sending a packet that will need an upper layer ACK (as signified by the PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */ if(got_strobe_ack && (packetbuf_attr(PACKETBUF_ATTR_RELIABLE) || #if NETSTACK_CONF_WITH_RIME packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) || #endif /* NETSTACK_CONF_WITH_RIME */ packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_STREAM)) { on(); /* Wait for ACK packet */ waiting_for_packet = 1; } else { off(); } #else /* WITH_ACK_OPTIMIZATION */ off(); #endif /* WITH_ACK_OPTIMIZATION */ /* restore the packet to send */ queuebuf_to_packetbuf(packet); queuebuf_free(packet); /* Send the data packet. */ if((is_broadcast || got_strobe_ack || is_streaming) && collisions == 0) { NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); } #if WITH_ENCOUNTER_OPTIMIZATION if(got_strobe_ack && !is_streaming) { register_encounter(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time); } #endif /* WITH_ENCOUNTER_OPTIMIZATION */ watchdog_start(); PRINTF("cxmac: send (strobes=%u,len=%u,%s), done\n", strobes, packetbuf_totlen(), got_strobe_ack ? "ack" : "no ack"); #if CXMAC_CONF_COMPOWER /* Accumulate the power consumption for the packet transmission. */ compower_accumulate(¤t_packet); /* Convert the accumulated power consumption for the transmitted packet to packet attributes so that the higher levels can keep track of the amount of energy spent on transmitting the packet. */ compower_attrconv(¤t_packet); /* Clear the accumulated power consumption so that it is ready for the next packet. */ compower_clear(¤t_packet); #endif /* CXMAC_CONF_COMPOWER */ we_are_sending = 0; LEDS_OFF(LEDS_BLUE); if(collisions == 0) { if(!is_broadcast && !got_strobe_ack) { return MAC_TX_NOACK; } else { return MAC_TX_OK; } } else { someone_is_sending++; return MAC_TX_COLLISION; } }
/*---------------------------------------------------------------------------*/ static uint8_t send_packet(struct net_buf *buf, mac_callback_t sent, void *ptr) { frame802154_t params; uint8_t len; uint8_t ret = 0; /* init to zeros */ memset(¶ms, 0, sizeof(params)); /* Build the FCF. */ params.fcf.frame_type = FRAME802154_DATAFRAME; params.fcf.security_enabled = 0; params.fcf.frame_pending = 0; params.fcf.ack_required = packetbuf_attr(buf, PACKETBUF_ATTR_RELIABLE); params.fcf.panid_compression = 0; /* Insert IEEE 802.15.4 (2003) version bit. */ params.fcf.frame_version = FRAME802154_IEEE802154_2003; /* Increment and set the data sequence number. */ params.seq = mac_dsn++; /* 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. */ params.fcf.src_addr_mode = FRAME802154_LONGADDRMODE; params.dest_pid = mac_dst_pan_id; if(packetbuf_holds_broadcast(buf)) { /* 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(buf, PACKETBUF_ADDR_RECEIVER)); params.fcf.dest_addr_mode = FRAME802154_LONGADDRMODE; } /* Set the source PAN ID to the global variable. */ params.src_pid = mac_src_pan_id; /* * Set up the source address using only the long address mode for * phase 1. */ #if NETSTACK_CONF_BRIDGE_MODE linkaddr_copy((linkaddr_t *)¶ms.src_addr,packetbuf_addr(PACKETBUF_ADDR_SENDER)); #else linkaddr_copy((linkaddr_t *)¶ms.src_addr, &linkaddr_node_addr); #endif params.payload = packetbuf_dataptr(buf); params.payload_len = packetbuf_datalen(buf); len = frame802154_hdrlen(¶ms); if(packetbuf_hdralloc(buf, len)) { frame802154_create(¶ms, packetbuf_hdrptr(buf), len); PRINTF("6MAC-UT: type %X dest ", params.fcf.frame_type); PRINTLLADDR((uip_lladdr_t *)params.dest_addr); PRINTF(" len %u datalen %u (totlen %u)\n", len, packetbuf_datalen(buf), packetbuf_totlen(buf)); ret = NETSTACK_RADIO.send(buf, packetbuf_hdrptr(buf), packetbuf_totlen(buf)); if(sent) { switch(ret) { case RADIO_TX_OK: sent(buf, ptr, MAC_TX_OK, 1); break; case RADIO_TX_ERR: sent(buf, ptr, MAC_TX_ERR, 1); break; case RADIO_TX_COLLISION: sent(buf, ptr, MAC_TX_COLLISION, 1); break; } } } else { PRINTF("6MAC-UT: too large header: %u\n", len); } return ret; }
/*---------------------------------------------------------------------------*/ int sicslowmac_dataRequest(void) { _delay_ms(SICSLOW_CORRECTION_DELAY); /* create structure to store result. */ frame_create_params_t params; frame_result_t result; /* Save the msduHandle in a global variable. */ msduHandle = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID); /* Build the FCF. */ params.fcf.frameType = DATAFRAME; params.fcf.securityEnabled = false; params.fcf.framePending = false; params.fcf.ackRequired = packetbuf_attr(PACKETBUF_ATTR_RELIABLE); params.fcf.panIdCompression = false; /* Insert IEEE 802.15.4 (2003) version bit. */ params.fcf.frameVersion = IEEE802154_2003; /* Increment and set the data sequence number. */ params.seq = macDSN++; /* 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. */ params.fcf.srcAddrMode = LONGADDRMODE; params.dest_pid = ieee15_4ManagerAddress.get_dst_panid(); if(packetbuf_holds_broadcast()) { /* Broadcast requires short address mode. */ params.fcf.destAddrMode = SHORTADDRMODE; params.dest_pid = BROADCASTPANDID; params.dest_addr.addr16 = BROADCASTADDR; } else { /* Phase 1.5 - end nodes send to anyone? */ memcpy(¶ms.dest_addr, (uint8_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER), LONG_ADDR_LEN); /* Change from sicslowpan byte arrangement to sicslowmac */ byte_reverse((uint8_t*)¶ms.dest_addr.addr64, LONG_ADDR_LEN); /* Phase 1 - end nodes only sends to pan coordinator node. */ /* params.dest_addr.addr64 = ieee15_4ManagerAddress.get_coord_long_addr(); */ params.fcf.destAddrMode = LONGADDRMODE; } /* Set the source PAN ID to the global variable. */ params.src_pid = ieee15_4ManagerAddress.get_src_panid(); /* * Set up the source address using only the long address mode for * phase 1. */ params.src_addr.addr64 = ieee15_4ManagerAddress.get_long_addr(); /* Copy the payload data. */ params.payload_len = packetbuf_datalen(); params.payload = packetbuf_dataptr(); /* Create transmission frame. */ frame_tx_create(¶ms, &result); /* Log if needed */ LOG_FRAME(¶ms, &result); /* Retry up to this many times to send the packet if radio is busy */ uint8_t retry_count = 3; while(retry_count) { PRINTF("sicslowmac: sending packet of length %d to radio, result:", result.length); /* Send data to radio. */ radio_status_t rv = radio_send_data(result.length, result.frame); if (rv == RADIO_SUCCESS) { PRINTF(" Success\n"); return 1; /* True says that the packet could be sent */ } if (rv != RADIO_WRONG_STATE) { PRINTF(" Failed\n"); return 0; } PRINTF(" Radio busy, retrying\n"); /** \todo: Fix delay in sicslowmac so they do not block receiving */ //We have blocking delay here, it is safest this way. BUT doesn't solve the //problem of TX when you are RXing.. as the RX code can't execute! if (retry_count == 3) { _delay_ms(10); } else if (retry_count == 2) { _delay_ms(50); } else if (retry_count == 1) { _delay_ms(200); } retry_count--; } PRINTF("sicslowmac: Unable to send packet, dropped\n"); return 0; }
/*---------------------------------------------------------------------------*/ static int send_one_packet(mac_callback_t sent, void *ptr) { int ret; int last_sent_ok = 0; packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); if(NETSTACK_FRAMER.create_and_secure() < 0){ /* Failed to allocate space for headers */ PRINTF("nullrdc: send failed, too large header\n"); ret = MAC_TX_ERR_FATAL; }else{ int is_broadcast; uint8_t dsn; dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff; NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen()); is_broadcast = packetbuf_holds_broadcast(); if(NETSTACK_RADIO.receiving_packet() || (!is_broadcast && NETSTACK_RADIO.pending_packet())){ /* Currently receiving a packet over air or the radio has already received a packet that needs to be read before sending with auto ack. */ ret = MAC_TX_COLLISION; }else{ if(!is_broadcast){ RIMESTATS_ADD(reliabletx); } switch(NETSTACK_RADIO.transmit(packetbuf_totlen())){ case RADIO_TX_OK: if(is_broadcast) { ret = MAC_TX_OK; }else{ rtimer_clock_t wt; /* Check for ack */ wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)); ret = MAC_TX_NOACK; if(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet() || NETSTACK_RADIO.channel_clear() == 0){ int len; uint8_t ackbuf[ACK_LEN]; if(AFTER_ACK_DETECTED_WAIT_TIME > 0){ wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTED_WAIT_TIME)); } if(NETSTACK_RADIO.pending_packet()){ len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); if(len == ACK_LEN && ackbuf[2] == dsn){ /* Ack received */ RIMESTATS_ADD(ackrx); ret = MAC_TX_OK; }else{ /* Not an ack or ack not for us: collision */ ret = MAC_TX_COLLISION; } } }else{ PRINTF("nullrdc tx noack\n"); } } break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; default: ret = MAC_TX_ERR; break; } } } if(ret == MAC_TX_OK) { last_sent_ok = 1; } mac_call_sent_callback(sent, ptr, ret, 1); return last_sent_ok; }
/*---------------------------------------------------------------------------*/ static void input_packet(void) { static struct ctimer ct; if(!we_are_receiving_burst) { off(); } /* printf("cycle_start 0x%02x 0x%02x\n", cycle_start, cycle_start % CYCLE_TIME);*/ if(packetbuf_totlen() > 0 && NETSTACK_FRAMER.parse() >= 0) { if(packetbuf_datalen() > 0 && packetbuf_totlen() > 0 && (linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_node_addr) || packetbuf_holds_broadcast())) { /* This is a regular packet that is destined to us or to the broadcast address. */ /* If FRAME_PENDING is set, we are receiving a packets in a burst */ /* TODO To prevent denial-of-sleep attacks, the transceiver should be disabled upon receipt of an unauthentic frame. */ we_are_receiving_burst = packetbuf_attr(PACKETBUF_ATTR_PENDING); if(we_are_receiving_burst) { on(); /* Set a timer to turn the radio off in case we do not receive a next packet */ ctimer_set(&ct, INTER_PACKET_DEADLINE, recv_burst_off, NULL); } else { off(); ctimer_stop(&ct); } #if RDC_WITH_DUPLICATE_DETECTION /* Check for duplicate packet. */ if(mac_sequence_is_duplicate()) { /* Drop the packet. */ /* printf("Drop duplicate ContikiMAC layer packet\n");*/ return; } mac_sequence_register_seqno(); #endif /* RDC_WITH_DUPLICATE_DETECTION */ #if CONTIKIMAC_CONF_COMPOWER /* Accumulate the power consumption for the packet reception. */ compower_accumulate(¤t_packet); /* Convert the accumulated power consumption for the received packet to packet attributes so that the higher levels can keep track of the amount of energy spent on receiving the packet. */ compower_attrconv(¤t_packet); /* Clear the accumulated power consumption so that it is ready for the next packet. */ compower_clear(¤t_packet); #endif /* CONTIKIMAC_CONF_COMPOWER */ PRINTDEBUG("contikimac: data (%u)\n", packetbuf_datalen()); NETSTACK_MAC.input(); return; } else { PRINTDEBUG("contikimac: data not for us\n"); } } else { PRINTF("contikimac: failed to parse (%u)\n", packetbuf_totlen()); } }
/*---------------------------------------------------------------------------*/ static int create_frame(int type, int do_create) { frame802154_t params; int hdr_len; /* 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); } params.fcf.panid_compression = 0; /* Insert IEEE 802.15.4 (2006) version bits. */ params.fcf.frame_version = FRAME802154_IEEE802154_2006; #if LLSEC802154_SECURITY 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); 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); #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_SECURITY */ /* 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 = mac_dst_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 = mac_src_pan_id; /* * Set up the source address using only the long address mode for * phase 1. */ linkaddr_copy((linkaddr_t *)¶ms.src_addr, packetbuf_addr(PACKETBUF_ADDR_SENDER)); 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; } }
/*---------------------------------------------------------------------------*/ static void packet_input(void) { radio_value_t channel; #if NULLRDC_SEND_802154_ACK int original_datalen; uint8_t *original_dataptr; original_datalen = packetbuf_datalen(); original_dataptr = packetbuf_dataptr(); #endif NETSTACK_RADIO.get_value(RADIO_PARAM_CHANNEL, &channel); packetbuf_set_attr(PACKETBUF_ATTR_CHANNEL, channel); #if NULLRDC_802154_AUTOACK if(packetbuf_datalen() == ACK_LEN) { /* Ignore ack packets */ PRINTF("nullrdc: ignored ack\n"); } else #endif /* NULLRDC_802154_AUTOACK */ if(NETSTACK_FRAMER.parse() < 0) { PRINTF("nullrdc: failed to parse %u\n", packetbuf_datalen()); #if NULLRDC_ADDRESS_FILTER } else if(!linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_node_addr) && !packetbuf_holds_broadcast()) { PRINTF("nullrdc: not for us\n"); #endif /* NULLRDC_ADDRESS_FILTER */ } else { int duplicate = 0; #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW #if RDC_WITH_DUPLICATE_DETECTION /* Check for duplicate packet. */ duplicate = mac_sequence_is_duplicate(); if(duplicate) { /* Drop the packet. */ PRINTF("nullrdc: drop duplicate link layer packet %u\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)); } else { mac_sequence_register_seqno(); } #endif /* RDC_WITH_DUPLICATE_DETECTION */ #endif /* NULLRDC_802154_AUTOACK */ /* TODO We may want to acknowledge only authentic frames */ #if NULLRDC_SEND_802154_ACK { frame802154_t info154; frame802154_parse(original_dataptr, original_datalen, &info154); if(info154.fcf.frame_type == FRAME802154_DATAFRAME && info154.fcf.ack_required != 0 && linkaddr_cmp((linkaddr_t *)&info154.dest_addr, &linkaddr_node_addr)) { uint8_t ackdata[ACK_LEN] = {0, 0, 0}; ackdata[0] = FRAME802154_ACKFRAME; ackdata[1] = 0; ackdata[2] = info154.seq; NETSTACK_RADIO.send(ackdata, ACK_LEN); } } #endif /* NULLRDC_SEND_ACK */ if(!duplicate) { NETSTACK_MAC.input(); } } }