Exemple #1
0
/* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */
static void
send_packet(mac_callback_t sent, void *ptr)
{
  int ret = MAC_TX_DEFERRED;
  int packet_count_before;
  int hdr_len = 0;
  const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);

  if(!tsch_is_associated) {
    if(!tsch_is_initialized) {
      PRINTF("TSCH:! not initialized (see earlier logs), drop outgoing packet\n");
    } else {
      PRINTF("TSCH:! not associated, drop outgoing packet\n");
    }
    ret = MAC_TX_ERR;
    mac_call_sent_callback(sent, ptr, ret, 1);
    return;
  }

  /* Ask for ACK if we are sending anything other than broadcast */
  if(!linkaddr_cmp(addr, &linkaddr_null)) {
    packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
  } else {
    /* Broadcast packets shall be added to broadcast queue
     * The broadcast address in Contiki is linkaddr_null which is equal
     * to tsch_eb_address */
    addr = &tsch_broadcast_address;
  }

  packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);

#if LLSEC802154_ENABLED
  if(tsch_is_pan_secured) {
    /* Set security level, key id and index */
    packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_OTHER);
    packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); /* Use 1-byte key index */
    packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_OTHER);
  }
#endif /* LLSEC802154_ENABLED */

  packet_count_before = tsch_queue_packet_count(addr);

#if !NETSTACK_CONF_BRIDGE_MODE
  /*
   * In the Contiki stack, the source address of a frame is set at the RDC
   * layer. Since TSCH doesn't use any RDC protocol and bypasses the layer to
   * transmit a frame, it should set the source address by itself.
   */
  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
#endif

  if((hdr_len = NETSTACK_FRAMER.create()) < 0) {
    PRINTF("TSCH:! can't send packet due to framer error\n");
    ret = MAC_TX_ERR;
  } else {
    struct tsch_packet *p;
    /* Enqueue packet */
    p = tsch_queue_add_packet(addr, sent, ptr);
    if(p == NULL) {
      PRINTF("TSCH:! can't send packet to %u with seqno %u, queue %u %u\n",
          TSCH_LOG_ID_FROM_LINKADDR(addr),
          packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
          packet_count_before,
          tsch_queue_packet_count(addr));
      ret = MAC_TX_ERR;
    } else {
      p->header_len = hdr_len;
      PRINTF("TSCH: send packet to %u with seqno %u, queue %u %u, len %u %u\n",
             TSCH_LOG_ID_FROM_LINKADDR(addr),
             packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
             packet_count_before,
             tsch_queue_packet_count(addr),
             p->header_len,
             queuebuf_datalen(p->qb));
      (void)packet_count_before; /* Discard "variable set but unused" warning in case of TSCH_LOG_LEVEL of 0 */
    }
  }
  if(ret != MAC_TX_DEFERRED) {
    mac_call_sent_callback(sent, ptr, ret, 1);
  }
}
Exemple #2
0
/*---------------------------------------------------------------------------*/
static int
send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_list *buf_list)
{
  rtimer_clock_t t0;
  rtimer_clock_t encounter_time = 0, previous_txtime = 0;
  int strobes;
  uint8_t got_strobe_ack = 0;
  int hdrlen, 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;
#if WITH_CONTIKIMAC_HEADER
  struct hdr *chdr;
#endif /* WITH_CONTIKIMAC_HEADER */

  if(packetbuf_totlen() == 0) {
    PRINTF("contikimac: send_packet data len 0\n");
    return MAC_TX_ERR_FATAL;
  }

  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
  if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
    is_broadcast = 1;
    PRINTDEBUG("contikimac: send broadcast\n");

    if(broadcast_rate_drop()) {
      return MAC_TX_COLLISION;
    }
  } else {
#if UIP_CONF_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 /* UIP_CONF_IPV6 */
    PRINTDEBUG("contikimac: send unicast to %u.%u\n",
               packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
               packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
#endif /* UIP_CONF_IPV6 */
  }
  is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
    packetbuf_attr(PACKETBUF_ATTR_ERELIABLE);

  packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);

#if WITH_CONTIKIMAC_HEADER
  hdrlen = packetbuf_totlen();
  if(packetbuf_hdralloc(sizeof(struct hdr)) == 0) {
    /* Failed to allocate space for contikimac header */
    PRINTF("contikimac: send failed, too large header\n");
    return MAC_TX_ERR_FATAL;
  }
  chdr = packetbuf_hdrptr();
  chdr->id = CONTIKIMAC_ID;
  chdr->len = hdrlen;
  
  /* Create the MAC header for the data packet. */
  hdrlen = NETSTACK_FRAMER.create();
  if(hdrlen < 0) {
    /* Failed to send */
    PRINTF("contikimac: send failed, too large header\n");
    packetbuf_hdr_remove(sizeof(struct hdr));
    return MAC_TX_ERR_FATAL;
  }
  hdrlen += sizeof(struct hdr);
#else
  /* Create the MAC header for the data packet. */
  hdrlen = NETSTACK_FRAMER.create();
  if(hdrlen < 0) {
    /* Failed to send */
    PRINTF("contikimac: send failed, too large header\n");
    return MAC_TX_ERR_FATAL;
  }
#endif


  /* Make sure that the packet is longer or equal to the shortest
     packet length. */
  transmit_len = packetbuf_totlen();
  if(transmit_len < SHORTEST_PACKET_SIZE) {
    /* Pad with zeroes */
    uint8_t *ptr;
    ptr = packetbuf_dataptr();
    memset(ptr + packetbuf_datalen(), 0, SHORTEST_PACKET_SIZE - packetbuf_totlen());

    PRINTF("contikimac: shorter than shortest (%d)\n", packetbuf_totlen());
    transmit_len = SHORTEST_PACKET_SIZE;
  }


  packetbuf_compact();

  NETSTACK_RADIO.prepare(packetbuf_hdrptr(), transmit_len);

  /* Remove the MAC-layer header since it will be recreated next time around. */
  packetbuf_hdr_remove(hdrlen);

  if(!is_broadcast && !is_receiver_awake) {
#if WITH_PHASE_OPTIMIZATION
    ret = phase_wait(&phase_list, 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_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;

    previous_txtime = RTIMER_NOW();
    {
      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 = previous_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
     /* 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 = previous_txtime;
          break;
        } else {
          PRINTF("contikimac: collisions while sending\n");
          collisions++;
        }
      }
#endif /* RDC_CONF_HARDWARE_ACK */

      previous_txtime = txtime;
    }
  }

  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(&current_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(&current_packet);

  /* Clear the accumulated power consumption so that it is ready for
     the next packet. */
  compower_clear(&current_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(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time,
                   ret);
    }
  }
#endif /* WITH_PHASE_OPTIMIZATION */

  return ret;
}
Exemple #3
0
/*---------------------------------------------------------------------------*/
static int
parse(void)
{
	frame802154_t frame;
	int hdr_len;

	hdr_len = frame_emmac_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 != mac_src_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(!is_broadcast_addr(frame.fcf.dest_addr_mode, frame.dest_addr)) {
				packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, (linkaddr_t *)&frame.dest_addr);
			}
		}
		if(frame.fcf.timestamp_flag){
			packetbuf_set_attr(PACKETBUF_ATTR_NODE_TIMESTAMP, frame.timestamp);
			packetbuf_set_attr(PACKETBUF_ATTR_NODE_CLOCK_TIME, frame.clock_time);
		}

		if(frame.fcf.rand_seed_flag)
			packetbuf_set_attr(PACKETBUF_ATTR_NODE_RAND_SEED, frame.random_seed);

		if(frame.fcf.frame_type==0)
			packetbuf_set_attr(PACKETBUF_ATTR_NODE_BLACKLIST, frame.blacklist);

		packetbuf_set_attr(PACKETBUF_ATTR_NODE_TIMESTAMP_FLAG, frame.fcf.timestamp_flag);
		packetbuf_set_attr(PACKETBUF_ATTR_NODE_RAND_SEED_FLAG, frame.fcf.rand_seed_flag);
		packetbuf_set_attr(PACKETBUF_ATTR_NODE_STATE_FLAG, frame.fcf.state_flag);

		packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (linkaddr_t *)&frame.src_addr);
		packetbuf_set_attr(PACKETBUF_ATTR_PENDING, frame.fcf.frame_pending);
		/*    packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, frame.fcf.ack_required);*/
		packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, frame.seq);

#if LLSEC802154_SECURITY_LEVEL
		if(frame.fcf.security_enabled) {
			packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, frame.aux_hdr.security_control.security_level);
			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]);
#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_SECURITY_LEVEL */

		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;
}
Exemple #4
0
/*---------------------------------------------------------------------------*/
static void
input_packet(void)
{
    struct xmac_hdr *hdr;

    if(NETSTACK_FRAMER.parse() >= 0)
    {
        hdr = packetbuf_dataptr();

        if(hdr->dispatch != DISPATCH)
        {
            someone_is_sending = 0;
            if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
                            &rimeaddr_node_addr) ||
                    rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
                                 &rimeaddr_null))
            {
                /* This is a regular packet that is destined to us or to the
                   broadcast address. */

                /* We have received the final packet, so we can go back to being
                   asleep. */
                off();

                /* Check for duplicate packet by comparing the sequence number
                   of the incoming packet with the last few ones we saw. */
                {
                    int i;
                    for(i = 0; i < MAX_SEQNOS; ++i)
                    {
                        if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == received_seqnos[i].seqno &&
                                rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
                                             &received_seqnos[i].sender))
                        {
                            /* Drop the packet. */
                            return;
                        }
                    }
                    for(i = MAX_SEQNOS - 1; i > 0; --i)
                    {
                        memcpy(&received_seqnos[i], &received_seqnos[i - 1],
                               sizeof(struct seqno));
                    }
                    received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
                    rimeaddr_copy(&received_seqnos[0].sender,
                                  packetbuf_addr(PACKETBUF_ADDR_SENDER));
                }

#if XMAC_CONF_COMPOWER
                /* Accumulate the power consumption for the packet reception. */
                compower_accumulate(&current_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(&current_packet);

                /* Clear the accumulated power consumption so that it is ready
                   for the next packet. */
                compower_clear(&current_packet);
#endif /* XMAC_CONF_COMPOWER */

                waiting_for_packet = 0;

                PRINTDEBUG("xmac: data(%u)\n", packetbuf_datalen());
                NETSTACK_MAC.input();
                return;
            }
            else
            {
                PRINTDEBUG("xmac: data not for us\n");
            }

        }
        else if(hdr->type == TYPE_STROBE)
        {
            someone_is_sending = 2;

            if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
                            &rimeaddr_node_addr))
            {
                /* This is a strobe packet for us. */

                /* If the sender address is someone else, we should
                   acknowledge the strobe and wait for the packet. By using
                   the same address as both sender and receiver, we flag the
                   message is a strobe ack. */
                waiting_for_packet = 1;
#if 0
                hdr->type = TYPE_STROBE_ACK;
                packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER,
                                   packetbuf_addr(PACKETBUF_ADDR_SENDER));
                packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
                packetbuf_compact();
                if(NETSTACK_FRAMER.create() >= 0)
                {
                    /* We turn on the radio in anticipation of the incoming
                       packet. */
                    someone_is_sending = 1;
                    waiting_for_packet = 1;
                    on();
                    NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
                    PRINTDEBUG("xmac: send strobe ack %u\n", packetbuf_totlen());
                }
                else
                {
                    PRINTF("xmac: failed to send strobe ack\n");
                }
#endif /* 0 */
            }
            else if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
                                 &rimeaddr_null))
            {
                /* If the receiver address is null, the strobe is sent to
                   prepare for an incoming broadcast packet. If this is the
                   case, we turn on the radio and wait for the incoming
                   broadcast packet. */
                waiting_for_packet = 1;
                on();
            }
            else
            {
                PRINTDEBUG("xmac: strobe not for us\n");
            }

            /* We are done processing the strobe and we therefore return
            	 to the caller. */
            return;
#if XMAC_CONF_ANNOUNCEMENTS
        }
        else if(hdr->type == TYPE_ANNOUNCEMENT)
        {
            packetbuf_hdrreduce(sizeof(struct xmac_hdr));
            parse_announcements(packetbuf_addr(PACKETBUF_ADDR_SENDER));
#endif /* XMAC_CONF_ANNOUNCEMENTS */
        }
        else if(hdr->type == TYPE_STROBE_ACK)
        {
            PRINTDEBUG("xmac: stray strobe ack\n");
        }
        else
        {
            PRINTF("xmac: unknown type %u (%u/%u)\n", hdr->type,
                   packetbuf_datalen(), len);
        }
    }
    else
    {
        PRINTF("xmac: failed to parse (%u)\n", packetbuf_totlen());
    }
}
Exemple #5
0
static void
ieee_mcpspt(MAC_McpsDcfmInd_s *ev)
  /* packet input and output thread */
{
  rimeaddr_t rime;
  switch(ev->u8Type)
  {
    case MAC_MCPS_IND_DATA:
      GDB2_PUTS(",");
      /* new frame received */
      packetbuf_clear();
      packetbuf_copyfrom(asdataframe(ev).au8Sdu,
          asdataframe(ev).u8SduLength);
      packetbuf_set_datalen(asdataframe(ev).u8SduLength);
      packetbuf_set_addr(PACKETBUF_ADDR_SENDER,
          asrimeaddr(&asdataframe(ev).sSrcAddr.uAddr.sExt, &rime));

      if(asdataframe(ev).sDstAddr.u8AddrMode==LONG) {
        /* addressed frame */
        packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER,
            asrimeaddr(&asdataframe(ev).sDstAddr.uAddr.sExt, &rime));
      } else if(asdataframe(ev).sDstAddr.u8AddrMode==SHORT &&
         asdataframe(ev).sDstAddr.u16PanId==BROADCAST_PANID &&
         asdataframe(ev).sDstAddr.uAddr.u16Short==BROADCAST_ADDR) {
        /* broadcast frame */
        packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &rimeaddr_null);
      }

      /* update lqi stuff and call lqi callback */
      packetbuf_set_attr(PACKETBUF_ATTR_RSSI, asdataframe(ev).u8LinkQuality);

      if (asdataframe(ev).sSrcAddr.u8AddrMode == LONG && lqicb)
        lqicb(asrimeaddr(&asdataframe(ev).sSrcAddr.uAddr.sExt, &rime),
              asdataframe(ev).u8LinkQuality);
      else if (lqicb)
        lqicb(NULL, asdataframe(ev).u8LinkQuality);

#if USE_TS
      current_timestamp = asdataframe(ev).timestamp;
#endif

      //{
      //  static char buf[512];
      //  uint8_t i;
      //  uint16_t j;
      //  printf("delay:%d len:%d data:", (int32_t) (clock_hrtime()-asdataframe(ev).timestamp), asdataframe(ev).u8SduLength);
      //  for (i=0,j=0; i<asdataframe(ev).u8SduLength; i++)
      //    j+=snprintf(buf+j,sizeof(buf)-j,"0x%x ",asdataframe(ev).au8Sdu[i]);
      //  buf[j]='\n';

      //  puts(buf);
      //}

      /* call upper layer */
      NETSTACK_NETWORK.input();
      break;
    case MAC_MCPS_DCFM_DATA:
      mac_call_sent_callback(mac_cb, mac_cb_ptr, tx_status(&asdataind(ev)), 1);
      break;
    case MAC_MCPS_DCFM_PURGE:
    default:
      HAL_BREAKPOINT();
      break;
  }
}
Exemple #6
0
/*---------------------------------------------------------------------------*/
static void real_send(mac_callback_t sent, void *ptr, struct queuebuf *pkt) {
    int ret;
    uint8_t contention_strobe[MAX_STROBE_SIZE];
    unsigned char won_contention = 0;

    int len = NETSTACK_FRAMER.create();
    if(len < 0) {
        // off(TURN_OFF);
        /* Failed to send */
        printf("WPI-MAC: send failed, too large header\n");
        mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 1);
    } else {
        // randomly pick slot
        random_init(RTIMER_NOW() * node_id);
        unsigned short rand_slot = map_rand(random_rand());
        // make filler packet
        memcpy(contention_strobe, packetbuf_hdrptr(), len);
        // strobe needs to cover at least one CCA_CONTENTION slot
        // plus any additional slots we need to cover
        unsigned short j;
        unsigned short fill_amount = (CCA_CONTENTION_SIZE - len) + (CONTENTION_SIZE * ((CONTENTION_SLOTS - 1) - rand_slot));
        for(j = 0; j < fill_amount; j++) {
            contention_strobe[len] = 7;
            len++;
        }

        rtimer_clock_t start_of_cont;

        // wait for prep period to end
        while(RTIMER_CLOCK_LT(RTIMER_NOW(), last + CONTENTION_PREPARE));
        start_of_cont = RTIMER_NOW();

        // wait for our random slot
        unsigned short cont_slot = 0;
        while(!(cont_slot == rand_slot)) {
            while(RTIMER_CLOCK_LT(RTIMER_NOW(), start_of_cont + CONTENTION_TICKS));
            start_of_cont = RTIMER_NOW();
            cont_slot++;
        }

        // NOW its our turn
        if(!radio_is_on) on();
        queuebuf_to_packetbuf(pkt);
        // first, test the air
        if(NETSTACK_RADIO.channel_clear()) {
            // send filler, if no err, we won contention
            int c_ret = NETSTACK_RADIO.send(contention_strobe, len);
            if(c_ret == RADIO_TX_OK) {
                won_contention = 1;
            } else {
                won_contention = 0;
            }
        } else { // another packet in the air, we lost contention
            won_contention = 0;
        }

        if(won_contention) {
            packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
            if(NETSTACK_FRAMER.create() < 0) {
                /* Failed to allocate space for headers */
                printf("WPI-MAC: send failed, too large header\n");
                ret = MAC_TX_ERR_FATAL;
            } else {
                // printf("%s - %u - %u\n", "Waiting to send...", current_slot, needed_slot);
                // while(radio_is_on == 0 && !(current_slot == needed_slot)); //wish i knew why this didn't work
                // rtimer_clock_t recent = RTIMER_TIME(&taskSlot);
                // rtimer_clock_t until = calcNext(current_slot, needed_slot);
                // while(RTIMER_CLOCK_LT(RTIMER_NOW(), recent + until));
                // printf("%s - %u - %u\n", "sending!", current_slot, needed_slot);
                // printf("%u\n", packetbuf_totlen());
                switch(NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen())) {
                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;
                }

            }


            mac_call_sent_callback(sent, ptr, ret, 1);

        } else { // lost contention
            mac_call_sent_callback(sent, ptr, MAC_TX_COLLISION, 1);
        }

    }

    QueuedPacket *head = QPQueue[current_slot];
    QPQueue[current_slot] = head->next;
    head->ptr = NULL;
    queuebuf_free(head->packet);
    head->packet = NULL;
    head->next = NULL;
    free(head);
}
Exemple #7
0
/*---------------------------------------------------------------------------*/
static int
send_packet(void)
{
    rtimer_clock_t t0;
    rtimer_clock_t t;
    rtimer_clock_t encounter_time = 0;
    int strobes;
    int ret;
#if 0
    struct xmac_hdr *hdr;
#endif
    uint8_t got_strobe_ack = 0;
    uint8_t got_ack = 0;
    uint8_t strobe[MAX_STROBE_SIZE];
    int strobe_len, len;
    int is_broadcast = 0;
    /*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. */
    packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
    if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null))
    {
        is_broadcast = 1;
        PRINTDEBUG("xmac: send broadcast\n");
    }
    else
    {
#if UIP_CONF_IPV6
        PRINTDEBUG("xmac: 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("xmac: send unicast to %u.%u\n",
                   packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
                   packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
#endif /* UIP_CONF_IPV6 */
    }
    /*  is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
        packetbuf_attr(PACKETBUF_ATTR_ERELIABLE); */

    packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
    len = NETSTACK_FRAMER.create();
    strobe_len = len + sizeof(struct xmac_hdr);
    if(len < 0 || strobe_len > (int)sizeof(strobe))
    {
        /* Failed to send */
        PRINTF("xmac: 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("xmac: send failed, no queue buffer available (of %u)\n",
               QUEUEBUF_CONF_NUM);
        return MAC_TX_ERR;
    }

#if WITH_STREAMING
    if(is_streaming == 1 &&
            (rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
                          &is_streaming_to) ||
             rimeaddr_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(rimeaddr_cmp(&is_streaming_to, &rimeaddr_null))
        {
            rimeaddr_copy(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
        }
        else if(!rimeaddr_cmp(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)))
        {
            rimeaddr_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 rimeaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);

        if(rimeaddr_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);
            if(wait < 2 * DEFAULT_ON_TIME)
            {
                wait = 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 + xmac_config.strobe_time);
                strobes++)
        {

            while(got_strobe_ack == 0 &&
                    RTIMER_CLOCK_LT(RTIMER_NOW(), t + xmac_config.strobe_wait_time))
            {
#if 0
                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();
                        if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE_ACK)
                        {
                            if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
                                            &rimeaddr_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("xmac: strobe ack for someone else\n");
                            }
                        }
                        else /*if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE)*/
                        {
                            PRINTDEBUG("xmac: strobe from someone else\n");
                            collisions++;
                        }
                    }
                    else
                    {
                        PRINTF("xmac: send failed to parse %u\n", len);
                    }
                }
#endif /* 0 */
            }

            t = RTIMER_NOW();
            /* Send the strobe packet. */
            if(got_strobe_ack == 0 && collisions == 0)
            {

                if(is_broadcast)
                {
#if WITH_STROBE_BROADCAST
                    ret = NETSTACK_RADIO.send(strobe, strobe_len);
#else
                    /* restore the packet to send */
                    queuebuf_to_packetbuf(packet);
                    ret = NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
#endif
                    off();
                }
                else
                {
#if 0
                    rtimer_clock_t wt;
#endif
                    on();
                    ret = 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();
                    wt = RTIMER_NOW();
                    while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + WAIT_TIME_BEFORE_STROBE_ACK));
#endif /* 0 */
#if RDC_CONF_HARDWARE_ACK
                    if(ret == RADIO_TX_OK)
                    {
                        got_strobe_ack = 1;
                    }
                    else
                    {
                        off();
                    }
#else
                    if(detect_ack())
                    {
                        got_strobe_ack = 1;
                    }
                    else
                    {
                        off();
                    }
#endif /* RDC_CONF_HARDWARE_ACK */

                }
            }
        }
    }

#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) ||
                          packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) ||
                          packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
                          PACKETBUF_ATTR_PACKET_TYPE_STREAM))
    {
        on(); /* Wait for ACK packet */
        waiting_for_packet = 1;
    }
    else
    {
        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)
    {
        ret = NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());

        if(!is_broadcast)
        {
#if RDC_CONF_HARDWARE_ACK
            if(ret == RADIO_TX_OK)
            {
                got_ack = 1;
            }
#else
            if(detect_ack())
            {
                got_ack = 1;
            }
#endif /* RDC_CONF_HARDWARE_ACK */
        }
    }
    off();

#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("xmac: send (strobes=%u,len=%u,%s), done\n", strobes,
           packetbuf_totlen(), got_strobe_ack ? "ack" : "no ack");

#if XMAC_CONF_COMPOWER
    /* Accumulate the power consumption for the packet transmission. */
    compower_accumulate(&current_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(&current_packet);

    /* Clear the accumulated power consumption so that it is ready for
       the next packet. */
    compower_clear(&current_packet);
#endif /* XMAC_CONF_COMPOWER */

    we_are_sending = 0;

    LEDS_OFF(LEDS_BLUE);
    if(collisions == 0)
    {
        if(is_broadcast == 0 && got_ack == 0)
        {
            return MAC_TX_NOACK;
        }
        else
        {
            return MAC_TX_OK;
        }
    }
    else
    {
        someone_is_sending++;
        return MAC_TX_COLLISION;
    }

}
Exemple #8
0
void
sicslowmac_unknownIndication(void)
{
  if (sicslowmac_snifferhook) {

	  packetbuf_clear();

	  /* Finally, get the stuff into the rime buffer.... */
	  packetbuf_copyfrom(parsed_frame->payload, parsed_frame->payload_length);
	  packetbuf_set_datalen(parsed_frame->payload_length);
	  
  #if UIP_LLADDR_LEN == 8
  	memcpy(dest_reversed, (uint8_t *)parsed_frame->dest_addr, UIP_LLADDR_LEN);
	memcpy(src_reversed, (uint8_t *)parsed_frame->src_addr, UIP_LLADDR_LEN);
  
	/* Change addresses to expected byte order */
	byte_reverse((uint8_t *)dest_reversed, UIP_LLADDR_LEN);
	byte_reverse((uint8_t *)src_reversed, UIP_LLADDR_LEN);
  
	packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, (const linkaddr_t *)dest_reversed);
	packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (const linkaddr_t *)src_reversed);
	
  #elif UIP_CONF_USE_RUM	
	
	dest_reversed[0] = MSB(parsed_frame->dest_pid);
	dest_reversed[1] = LSB(parsed_frame->dest_pid);
	dest_reversed[2] = 0;
	dest_reversed[3] = 0;  
	dest_reversed[4] = MSB(parsed_frame->payload[0]); //FinalDestAddr
	dest_reversed[5] = LSB(parsed_frame->payload[1]);
	
	src_reversed[0] = MSB(parsed_frame->src_pid);
	src_reversed[1] = LSB(parsed_frame->src_pid);
	src_reversed[2] = 0;
	src_reversed[3] = 0;  
	src_reversed[4] = MSB(parsed_frame->payload[2]); //originAddr
	src_reversed[5] = LSB(parsed_frame->payload[3]);	

  #else
  
	dest_reversed[0] = MSB(parsed_frame->dest_pid);
	dest_reversed[1] = LSB(parsed_frame->dest_pid);
	dest_reversed[2] = 0;
	dest_reversed[3] = 0;  
	dest_reversed[4] = MSB(parsed_frame->dest_addr->addr16);
	dest_reversed[5] = LSB(parsed_frame->dest_addr->addr16);
	
	src_reversed[0] = MSB(parsed_frame->src_pid);
	src_reversed[1] = LSB(parsed_frame->src_pid);
	src_reversed[2] = 0;
	src_reversed[3] = 0;  
	src_reversed[4] = MSB(parsed_frame->src_addr->addr16);
	src_reversed[5] = LSB(parsed_frame->src_addr->addr16);

	packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, (const linkaddr_t *)dest_reversed);
	packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (const linkaddr_t *)src_reversed);	
  
  #endif

	  PRINTF("sicslowmac: hand off frame to sniffer \n");
	  
	  sicslowmac_snifferhook(pmac_driver);
	 }
  
}
Exemple #9
0
void
eth_input(void)
{
#if CETIC_6LBR_TRANSPARENTBRIDGE || CETIC_6LBR_ONE_ITF || CETIC_6LBR_6LR
  uip_lladdr_t srcAddr;
#endif
  uip_lladdr_t destAddr;
  int processFrame = 0;
  int forwardFrame = 0;

  //Packet type filtering
  //---------------------
  //Keep only IPv6 traffic
  if(BUF->type != UIP_HTONS(UIP_ETHTYPE_IPV6)) {
    LOG6LBR_PRINTF(PACKET, PF_IN, "eth_input: Dropping packet type=0x%04x\n", uip_ntohs(BUF->type));
    uip_len = 0;
    return;
  }
  //Packet source Filtering
  //-----------------------
  /* IPv6 uses 33-33-xx-xx-xx-xx prefix for multicast ND stuff */
  if((BUF->dest.addr[0] == 0x33) && (BUF->dest.addr[1] == 0x33)) {
    forwardFrame = 1;
    processFrame = 1;
    linkaddr_copy((linkaddr_t *) & destAddr, &linkaddr_null);
  } else if((BUF->dest.addr[0] == 0xFF)
            && (BUF->dest.addr[1] == 0xFF)
            && (BUF->dest.addr[2] == 0xFF)
            && (BUF->dest.addr[3] == 0xFF)
            && (BUF->dest.addr[4] == 0xFF)
            && (BUF->dest.addr[5] == 0xFF)) {
    /* IPv6 does not use broadcast addresses, hence this should not happen */
    LOG6LBR_PRINTF(PACKET, PF_IN, "eth_input: Dropping broadcast packet\n");
    uip_len = 0;
    return;
  } else {
    /* Complex Address Translation */
    if(mac_createSicslowpanLongAddr(&(BUF->dest.addr[0]), &destAddr) == 0) {
      LOG6LBR_WARN("eth_input: Address translation failed\n");
      uip_len = 0;
      return;
    }
  }

  //Packet content rewriting
  //------------------------
  //Some IP packets have link layer in them, need to change them around!
  uint8_t transReturn = mac_translateIPLinkLayer(ll_802154_type);

  if(transReturn != 0) {
    LOG6LBR_WARN("eth_input: IPTranslation returns %d\n", transReturn);
  }

  //Destination filtering
  //---------------------
  if(memcmp((uint8_t *) & eth_mac_addr, BUF->dest.addr, 6) == 0) {
    processFrame = 1;
  } else {
#if CETIC_6LBR_TRANSPARENTBRIDGE
    //Not for us, forward it directly
    forwardFrame = 1;
#endif
  }

  //Handle packet
  //-------------
#if CETIC_6LBR_TRANSPARENTBRIDGE
  if(forwardFrame) {
    mac_createSicslowpanLongAddr(&(BUF->src.addr[0]), &srcAddr);
#if CETIC_6LBR_LEARN_RPL_MAC
    if (UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type == ICMP6_RPL) {
      uint8_t *buffer = UIP_ICMP_PAYLOAD;
      uint16_t rank = (uint16_t)buffer[2] << 8 | buffer[2 + 1];
      if ( rank == RPL_MIN_HOPRANKINC ) {
    	platform_set_wsn_mac((linkaddr_t *) &srcAddr);
        rpl_mac_known=1;
      }
    }
    if (!rpl_mac_known) {
      //Rpl Relay not yet configured, drop packet
      uip_len = 0;
      return;
    }
    if(linkaddr_cmp((linkaddr_t *) &srcAddr, &linkaddr_node_addr) != 0) {
      //Only forward RplRoot packets
      LOG6LBR_LLADDR_PRINTF(PACKET, PF_IN, &destAddr, "eth_input: Forwarding frame to ");
      wireless_output(NULL, &destAddr);
    }
#else
    LOG6LBR_LLADDR_PRINTF(PACKET, PF_IN, &destAddr, "eth_input: Forwarding frame to ");
    wireless_output(&srcAddr, &destAddr);
#endif
  }
#endif
  if(processFrame) {
    LOG6LBR_PRINTF(PACKET, PF_IN, "eth_input: Processing frame\n");
#if CETIC_6LBR_ONE_ITF || CETIC_6LBR_6LR
  //RPL uses source packet address to populate its neighbor table
  //In this two modes RPL packets are incoming from Eth interface
  mac_createSicslowpanLongAddr(&(BUF->src.addr[0]), &srcAddr);
  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (linkaddr_t *) &srcAddr);
#endif
    send_to_uip();
  } else {
    //Drop packet
    uip_len = 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);
#if DISCOVERY_AWARE_RDC_802154_AUTOACK || DISCOVERY_AWARE_RDC_802154_AUTOACK_HW
	packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
#endif /* DISCOVERY_AWARE_RDC_802154_AUTOACK || DISCOVERY_AWARE_RDC_802154_AUTOACK_HW */

	if (!radio_status) {
		on();
	}


	if(NETSTACK_FRAMER.create() < 0) {
		/* Failed to allocate space for headers */
	    PRINTF("RDC: send failed, too large header\n");
		ret = MAC_TX_ERR_FATAL;
	} else {

#ifdef NETSTACK_ENCRYPT
		NETSTACK_ENCRYPT();
#endif /* NETSTACK_ENCRYPT */

#if DISCOVERY_AWARE_RDC_802154_AUTOACK
		int is_broadcast;
		uint8_t dsn;
		dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff;

		NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen());

		is_broadcast = linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
				&linkaddr_null);

		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)) {
#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("RDC tx noack\n");
					}
				}
				break;
			case RADIO_TX_COLLISION:
				ret = MAC_TX_COLLISION;
				break;
			default:
				ret = MAC_TX_ERR;
				break;
			}
		}

#else /* ! DISCOVERY_AWARE_RDC_802154_AUTOACK */

		switch(NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen())) {
		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 /* ! DISCOVERY_AWARE_RDC_802154_AUTOACK */
	}



	if (!linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_null)
			&&  ret == MAC_TX_OK) {
		send_flag = 1;
		to_modifier+=10;
	}

	if(ret == MAC_TX_OK) {
		last_sent_ok = 1;
	}

	mac_call_sent_callback(sent, ptr, ret, 1);

	return last_sent_ok;
}
Exemple #11
0
/*---------------------------------------------------------------------------*/
static void
send_packet(mac_callback_t sent, void *ptr)
{
  int ret;
  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
#if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW
  packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
#endif /* NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW */

  if(NETSTACK_FRAMER.create() < 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 = rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
                                &rimeaddr_null);

    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 {
      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];

            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 */
                ret = MAC_TX_OK;
              } else {
                /* Not an ack or ack not for us: collision */
                ret = MAC_TX_COLLISION;
              }
            }
          }
        }
        break;
      case RADIO_TX_COLLISION:
        ret = MAC_TX_COLLISION;
        break;
      default:
        ret = MAC_TX_ERR;
        break;
      }
    }

#else /* ! NULLRDC_802154_AUTOACK */

    switch(NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen())) {
    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 */
  }
  mac_call_sent_callback(sent, ptr, ret, 1);
}
/*---------------------------------------------------------------------------*/
static int
send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
{
  rtimer_clock_t t0;
  rtimer_clock_t t;
  rtimer_clock_t encounter_time = 0, last_transmission_time = 0;
  uint8_t first_transmission = 1;
  int strobes;
  uint8_t got_strobe_ack = 0;
  int hdrlen, len;
  uint8_t is_broadcast = 0;
  uint8_t is_reliable = 0;
  uint8_t is_known_receiver = 0;
  uint8_t collisions;
  int transmit_len;
  int i;
  int ret;
#if WITH_CONTIKIMAC_HEADER
  struct hdr *chdr;
#endif /* WITH_CONTIKIMAC_HEADER */

  if(packetbuf_totlen() == 0) {
    PRINTF("contikimac: send_packet data len 0\n");
    return MAC_TX_ERR_FATAL;
  }

  
  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
  if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
    is_broadcast = 1;
    PRINTDEBUG("contikimac: send broadcast\n");

    if(broadcast_rate_drop()) {
      return MAC_TX_COLLISION;
    }
  } else {
#if UIP_CONF_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 /* UIP_CONF_IPV6 */
    PRINTDEBUG("contikimac: send unicast to %u.%u\n",
               packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
               packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
#endif /* UIP_CONF_IPV6 */
  }
  is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
    packetbuf_attr(PACKETBUF_ATTR_ERELIABLE);
  
  if(WITH_STREAMING) {
    if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
       PACKETBUF_ATTR_PACKET_TYPE_STREAM) {
      if(rimeaddr_cmp(&is_streaming_to, &rimeaddr_null)) {
        rimeaddr_copy(&is_streaming_to,
                      packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
      } else if(!rimeaddr_cmp
                (&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) {
        rimeaddr_copy(&is_streaming_to_too,
                      packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
      }
      stream_until = RTIMER_NOW() + DEFAULT_STREAM_TIME;
      is_streaming = 1;
    } else {
      is_streaming = 0;
    }
  }

  if(is_streaming) {
    packetbuf_set_attr(PACKETBUF_ATTR_PENDING, 1);
  }
  packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);

#if WITH_CONTIKIMAC_HEADER
  hdrlen = packetbuf_totlen();
  if(packetbuf_hdralloc(sizeof(struct hdr)) == 0) {
    /* Failed to allocate space for contikimac header */
    PRINTF("contikimac: send failed, too large header\n");
    return MAC_TX_ERR_FATAL;
  }
  chdr = packetbuf_hdrptr();
  chdr->id = CONTIKIMAC_ID;
  chdr->len = hdrlen;

  /* Create the MAC header for the data packet. */
  hdrlen = NETSTACK_FRAMER.create();
  if(hdrlen == 0) {
    /* Failed to send */
    PRINTF("contikimac: send failed, too large header\n");
    packetbuf_hdr_remove(sizeof(struct hdr));
    return MAC_TX_ERR_FATAL;
  }
  hdrlen += sizeof(struct hdr);
#else /* WITH_CONTIKIMAC_HEADER */
  /* Create the MAC header for the data packet. */
  hdrlen = NETSTACK_FRAMER.create();
  if(hdrlen == 0) {
    /* Failed to send */
    PRINTF("contikimac: send failed, too large header\n");
    return MAC_TX_ERR_FATAL;
  }
#endif /* WITH_CONTIKIMAC_HEADER */

  /* Make sure that the packet is longer or equal to the shortest
     packet length. */
  transmit_len = packetbuf_totlen();
  if(transmit_len < SHORTEST_PACKET_SIZE) {
#if 0
    /* Pad with zeroes */
    uint8_t *ptr;
    ptr = packetbuf_dataptr();
    memset(ptr + packetbuf_datalen(), 0, SHORTEST_PACKET_SIZE - packetbuf_totlen());
#endif

    PRINTF("contikimac: shorter than shortest (%d)\n", packetbuf_totlen());
    transmit_len = SHORTEST_PACKET_SIZE;
  }


  packetbuf_compact();

  NETSTACK_RADIO.prepare(packetbuf_hdrptr(), transmit_len);

  /* Remove the MAC-layer header since it will be recreated next time around. */
  packetbuf_hdr_remove(hdrlen);

  if(!is_broadcast && !is_streaming) {
#if WITH_PHASE_OPTIMIZATION
    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) {
        
        ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
                         CYCLE_TIME, GUARD_TIME,
                         mac_callback, mac_callback_ptr);
        if(ret == PHASE_DEFERRED) {
          return MAC_TX_DEFERRED;
        }
        if(ret != PHASE_UNKNOWN) {
          is_known_receiver = 1;
        }
      }
    } else {
      ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
                       CYCLE_TIME, GUARD_TIME,
                       mac_callback, mac_callback_ptr);
      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;

  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) !=
     PACKETBUF_ATTR_PACKET_TYPE_ACK && is_streaming == 0) {
    /* Check if there are any transmissions by others. */
    for(i = 0; i < CCA_COUNT_MAX; ++i) {
      t0 = RTIMER_NOW();
      on();
#if NURTIMER
      while(RTIMER_CLOCK_LT(t0, RTIMER_NOW(), t0 + CCA_CHECK_TIME));
#else
      while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + CCA_CHECK_TIME)) { }
#endif
      if(NETSTACK_RADIO.channel_clear() == 0) {
        collisions++;
        off();
        break;
      }
      off();
      t0 = RTIMER_NOW();
#if NURTIMER
      while(RTIMER_CLOCK_LT(t0, RTIMER_NOW(), t0 + CCA_SLEEP_TIME));
#else
      while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + CCA_SLEEP_TIME)) { }
#endif
    }
  }

  if(collisions > 0) {
    we_are_sending = 0;
    off();
    PRINTF("contikimac: collisions before sending\n");
    return MAC_TX_COLLISION;
  }

  if(!is_broadcast) {
    on();
  }
  
  watchdog_periodic();
  t0 = RTIMER_NOW();
  t = RTIMER_NOW();
#if NURTIMER
  for(strobes = 0, collisions = 0;
      got_strobe_ack == 0 && collisions == 0 &&
      RTIMER_CLOCK_LT(t0, RTIMER_NOW(), t0 + STROBE_TIME); strobes++) {
#else
  for(strobes = 0, collisions = 0;
      got_strobe_ack == 0 && collisions == 0 &&
      RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + STROBE_TIME); strobes++) {
#endif

    watchdog_periodic();
    
    if(is_known_receiver && !RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + MAX_PHASE_STROBE_TIME)) {
      break;
    }
    
    len = 0;

    t = RTIMER_NOW();
    
    {
      rtimer_clock_t wt;
      rtimer_clock_t now = RTIMER_NOW();
      int ret;

      ret = NETSTACK_RADIO.transmit(transmit_len);

      wt = RTIMER_NOW();
#if NURTIMER
      while(RTIMER_CLOCK_LT(wt, RTIMER_NOW(), wt + INTER_PACKET_INTERVAL));
#else
      while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + INTER_PACKET_INTERVAL)) { }
#endif
      if(!is_broadcast && (NETSTACK_RADIO.receiving_packet() ||
                           NETSTACK_RADIO.pending_packet() ||
                           NETSTACK_RADIO.channel_clear() == 0)) {
        uint8_t ackbuf[ACK_LEN];
        wt = RTIMER_NOW();
#if NURTIMER
        while(RTIMER_CLOCK_LT(wt, RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME));
#else
        while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { }
#endif
        len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
        if(len == ACK_LEN) {
          got_strobe_ack = 1;
          //          encounter_time = last_transmission_time;
          encounter_time = now;
          break;
        } else {
          PRINTF("contikimac: collisions while sending\n");
          collisions++;
        }
      }
      last_transmission_time = now;
      first_transmission = 0;
    }
  }

  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 && is_reliable) {
      on();                       /* Wait for ACK packet */
    } else {
      off();
    }
  } else {
    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(&current_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(&current_packet);

  /* Clear the accumulated power consumption so that it is ready for
     the next packet. */
  compower_clear(&current_packet);
#endif /* CONTIKIMAC_CONF_COMPOWER */

  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(!first_transmission)*/ {

    /*    COOJA_DEBUG_PRINTF("first phase 0x%02x\n", encounter_time % CYCLE_TIME);*/
    
    if(WITH_ACK_OPTIMIZATION) {
      if(collisions == 0 && packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) !=
         PACKETBUF_ATTR_PACKET_TYPE_ACK && is_streaming == 0) {
        phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time,
                     ret);
      }
    } else {
      if(collisions == 0 && is_streaming == 0) {
        phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time,
                     ret);
      }
    }
  }
#endif /* WITH_PHASE_OPTIMIZATION */

  return ret;
}
/*---------------------------------------------------------------------------*/
static void
qsend_packet(mac_callback_t sent, void *ptr)
{
  int ret = send_packet(sent, ptr);
  if(ret != MAC_TX_DEFERRED) {
    //    printf("contikimac qsend_packet %p\n", ptr);
    mac_call_sent_callback(sent, ptr, ret, 1);
  }
}
static void
send_announcement(void *ptr)
{
  int announcement_len;
  int transmit_len;
#if WITH_CONTIKIMAC_HEADER
  struct hdr *chdr;
#endif /* WITH_CONTIKIMAC_HEADER */
  
  /* Set up the probe header. */
  packetbuf_clear();
  announcement_len = format_announcement(packetbuf_dataptr());

  if(announcement_len > 0) {
    packetbuf_set_datalen(announcement_len);

    packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
    packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &rimeaddr_null);
    packetbuf_set_attr(PACKETBUF_ATTR_RADIO_TXPOWER,
                       announcement_radio_txpower);
#if WITH_CONTIKIMAC_HEADER
    transmit_len = packetbuf_totlen();
    if(packetbuf_hdralloc(sizeof(struct hdr)) == 0) {
      /* Failed to allocate space for contikimac header */
      PRINTF("contikimac: send announcement failed, too large header\n");
      return;
    }
    chdr = packetbuf_hdrptr();
    chdr->id = CONTIKIMAC_ID;
    chdr->len = transmit_len;
#endif /* WITH_CONTIKIMAC_HEADER */

    if(NETSTACK_FRAMER.create()) {
      rtimer_clock_t t;
      int i, collisions;
      we_are_sending = 1;

      /* Make sure that the packet is longer or equal to the shorest
         packet length. */
      transmit_len = packetbuf_totlen();
      if(transmit_len < SHORTEST_PACKET_SIZE) {
#if 0
        /* Pad with zeroes */
        uint8_t *ptr;
        ptr = packetbuf_dataptr();
        memset(ptr + packetbuf_datalen(), 0, SHORTEST_PACKET_SIZE - transmit_len);
#endif

        PRINTF("contikimac: shorter than shortest (%d)\n", packetbuf_totlen());
        transmit_len = SHORTEST_PACKET_SIZE;
      }

      collisions = 0;
      /* Check for collisions */
      for(i = 0; i < CCA_COUNT_MAX; ++i) {
        t = RTIMER_NOW();
        on();
#if NURTIMER
        while(RTIMER_CLOCK_LT(t, RTIMER_NOW(), t + CCA_CHECK_TIME));
#else
        while(RTIMER_CLOCK_LT(RTIMER_NOW(), t + CCA_CHECK_TIME));
#endif
        if(NETSTACK_RADIO.channel_clear() == 0) {
          collisions++;
          off();
          break;
        }
        off();
#if NURTIMER
        while(RTIMER_CLOCK_LT(t0, RTIMER_NOW(), t + CCA_SLEEP_TIME + CCA_CHECK_TIME));
#else
        while(RTIMER_CLOCK_LT(RTIMER_NOW(), t + CCA_SLEEP_TIME + CCA_CHECK_TIME)) { }
#endif
      }

      if(collisions == 0) {
        
        NETSTACK_RADIO.prepare(packetbuf_hdrptr(), transmit_len);
        
        NETSTACK_RADIO.transmit(transmit_len);
        t = RTIMER_NOW();
#if NURTIMER
        while(RTIMER_CLOCK_LT(t, RTIMER_NOW(), t + INTER_PACKET_INTERVAL));
#else
        while(RTIMER_CLOCK_LT(RTIMER_NOW(), t + INTER_PACKET_INTERVAL)) { }
#endif
        NETSTACK_RADIO.transmit(transmit_len);
      }
      we_are_sending = 0;
    }
  }
}
Exemple #14
0
/*---------------------------------------------------------------------------*/
static int parse_80211(void)
{
	int len;
	uint16_t pan_id;
	rimeaddr_t* dst_mac_address;
	rimeaddr_t* src_mac_address;
	len = packetbuf_datalen();
	/* The first 8 bytes are the destination address 
	 * of the remote node [IEEE 802.11 MAC address]
	 * and it can well be an Ethernet broadcast one. 
	 */
	dst_mac_address = (rimeaddr_t*)(packetbuf_dataptr());
	packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, (rimeaddr_t *)dst_mac_address);
	/* We now need to remove these bytes from the 
	 * packet buffer so the plain IPv6 packet can
	 * be sent properly.
	 */
	if(packetbuf_hdrreduce(RIMEADDR_SIZE) == 0) {
		PRINTF("SLIP_FRAMER: ERROR; Could not remove MAC address info from incoming slip frame.\n");
		return -1;
	}
	/* The following 8 bytes contain the source address
	 * of the local [host] interface. 
	 */
	src_mac_address = (rimeaddr_t*)(packetbuf_dataptr());
	packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (rimeaddr_t *)src_mac_address);
	/* TODO Sanity check; this address should be the local node. */
	if (!ether_addr_equal((uint8_t*)src_mac_address, uip_lladdr.addr)) {
		PRINTF("SLIP_FRAMER; Packet coming from UART has a wrong source MAC Address!\n");
		PRINTADDR(src_mac_address);
		return -1;
	}
	/* We now need to remove these bytes from the 
	 * packet buffer so the plain IPv6 packet can
	 * be sent properly.
	 */
	if(packetbuf_hdrreduce(RIMEADDR_SIZE) == 0) {
		PRINTF("SLIP_FRAMER: ERROR; Could not remove MAC address info from incoming slip frame.\n");
		return -1;
	}
	
	/* The next 2 bytes contain the PAN ID. We should drop
	 * the packet if it does not carry the selected PAN ID
	 */
	pan_id = *((uint16_t*)(packetbuf_dataptr()));
	if (pan_id != mac_src_pan_id && pan_id != FRAME802154_BROADCASTPANDID) {
		/* Packet to another PAN */
		PRINTF("15.4: for another pan %04x\n", pan_id);
		return -1;
	}
	/* We now need to remove these bytes from the 
	 * packet buffer so the plain IPv6 packet can
	 * be sent properly.
	 */
	if(packetbuf_hdrreduce(sizeof(uint16_t)) == 0) {
		PRINTF("SLIP_FRAMER: ERROR; Could not remove PAN ID info from incoming slip frame.\n");
		return -1;
	}
	/* We would like to print some log information. */
	PRINTF("802.11-framer-IN: %02x%02x ",(uint8_t)pan_id,(uint8_t)(pan_id>>8));
	PRINTADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
	PRINTF(" After parse: %u (%u)\n", packetbuf_datalen(), len);
	/* We are now ready to send the packet down. */
	return 0;	
}
Exemple #15
0
/*---------------------------------------------------------------------------*/
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;
#if WITH_PHASE_OPTIMIZATION
  rtimer_clock_t encounter_time = 0;
#endif
  int strobes;
  uint8_t got_strobe_ack = 0;
  uint8_t is_broadcast = 0;
  uint8_t is_known_receiver = 0;
  uint8_t collisions;
  int transmit_len;
  int ret;
  uint8_t contikimac_was_on;
#if !RDC_CONF_HARDWARE_ACK
  int len;
  uint8_t seqno;
#endif
  
  /* 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 */
  }

  if(!packetbuf_attr(PACKETBUF_ATTR_IS_CREATED_AND_SECURED)) {
    packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
    if(NETSTACK_FRAMER.create() < 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();
  }
  seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
#endif

  watchdog_periodic();
  t0 = RTIMER_NOW();
  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;
    }

#if !RDC_CONF_HARDWARE_ACK
    len = 0;
#endif

    {
      rtimer_clock_t wt;
#if WITH_PHASE_OPTIMIZATION
      rtimer_clock_t txtime = RTIMER_NOW();
#endif
#if RDC_CONF_HARDWARE_ACK
      int ret = NETSTACK_RADIO.transmit(transmit_len);
#else
      NETSTACK_RADIO.transmit(transmit_len);
#endif

#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;
#if WITH_PHASE_OPTIMIZATION
          encounter_time = txtime;
#endif
          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;
#if WITH_PHASE_OPTIMIZATION
          encounter_time = txtime;
#endif
          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(&current_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(&current_packet);

  /* Clear the accumulated power consumption so that it is ready for
     the next packet. */
  compower_clear(&current_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;
}
Exemple #16
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;
}
Exemple #17
0
/**
 * Read a packet from the underlying radio driver. If the incoming
 * packet is a probe packet and the sender of the probe matches the
 * destination address of the queued packet (if any), the queued packet
 * is sent.
 */
static void
input_packet(void)
{
  struct lpp_hdr hdr;
  clock_time_t reception_time;

  reception_time = clock_time();

  if(!NETSTACK_FRAMER.parse()) {
    printf("lpp input_packet framer error\n");
  }

  memcpy(&hdr, packetbuf_dataptr(), sizeof(struct lpp_hdr));;
  packetbuf_hdrreduce(sizeof(struct lpp_hdr));
  /*    PRINTF("got packet type %d\n", hdr->type);*/

  if(hdr.type == TYPE_PROBE) {
    struct announcement_msg adata;
    
    /* Register the encounter with the sending node. We now know the
       neighbor's phase. */
    register_encounter(&hdr.sender, reception_time);

    /* Parse incoming announcements */
    memcpy(&adata, packetbuf_dataptr(),
           MIN(packetbuf_datalen(), sizeof(adata)));
#if 0
    PRINTF("%d.%d: probe from %d.%d with %d announcements\n",
           rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
           hdr.sender.u8[0], hdr.sender.u8[1], adata->num);
    
    if(adata.num / sizeof(struct announcement_data) > sizeof(struct announcement_msg)) {
      /* Sanity check. The number of announcements is too large -
         corrupt packet has been received. */
      return 0;
    }

    for(i = 0; i < adata.num; ++i) {
      /*	  PRINTF("%d.%d: announcement %d: %d\n",
		  rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
		  adata->data[i].id,
		  adata->data[i].value);*/

      announcement_heard(&hdr.sender,
                         adata.data[i].id,
                         adata.data[i].value);
    }
#endif  /* 0 */

    /* Go through the list of packets to be sent to see if any of
       them match the sender of the probe, or if they are a
       broadcast packet that should be sent. */
    if(list_length(queued_packets_list) > 0) {
      struct queue_list_item *i;
      for(i = list_head(queued_packets_list); i != NULL; i = list_item_next(i)) {
        const rimeaddr_t *receiver;
        uint8_t sent;

        sent = 0;
 
        receiver = queuebuf_addr(i->packet, PACKETBUF_ADDR_RECEIVER);
        if(rimeaddr_cmp(receiver, &hdr.sender) ||
           rimeaddr_cmp(receiver, &rimeaddr_null)) {
          queuebuf_to_packetbuf(i->packet);

#if WITH_PENDING_BROADCAST
          if(i->broadcast_flag == BROADCAST_FLAG_NONE ||
             i->broadcast_flag == BROADCAST_FLAG_SEND) {
            i->num_transmissions = 1;
            NETSTACK_RADIO.send(queuebuf_dataptr(i->packet),
                                queuebuf_datalen(i->packet));
            sent = 1;
            PRINTF("%d.%d: got a probe from %d.%d, sent packet to %d.%d\n",
		   rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
                   hdr.sender.u8[0], hdr.sender.u8[1],
                   receiver->u8[0], receiver->u8[1]);
	      
          } else {
            PRINTF("%d.%d: got a probe from %d.%d, did not send packet\n",
                   rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
                   hdr.sender.u8[0], hdr.sender.u8[1]);
          }
#else /* WITH_PENDING_BROADCAST */
          i->num_transmissions = 1;
          NETSTACK_RADIO.send(queuebuf_dataptr(i->packet),
                               queuebuf_datalen(i->packet));
          PRINTF("%d.%d: got a probe from %d.%d, sent packet to %d.%d\n",
                 rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
                 hdr.sender.u8[0], hdr.sender.u8[1],
                 receiver->u8[0], receiver->u8[1]);
#endif /* WITH_PENDING_BROADCAST */

          /*          off();*/

          /* Attribute the energy spent on listening for the probe
             to this packet transmission. */
          compower_accumulate(&i->compower);
	    
          /* If the packet was not a broadcast packet, we dequeue it
             now. Broadcast packets should be transmitted to all
             neighbors, and are dequeued by the dutycycling function
             instead, after the appropriate time. */
          if(!rimeaddr_cmp(receiver, &rimeaddr_null)) {
            if(detect_ack()) {
              remove_queued_packet(i, 1);
            } else {
              remove_queued_packet(i, 0);
            }

#if WITH_PROBE_AFTER_TRANSMISSION
            /* Send a probe packet to catch any reply from the other node. */
            restart_dutycycle(PROBE_AFTER_TRANSMISSION_TIME);
#endif /* WITH_PROBE_AFTER_TRANSMISSION */

#if WITH_STREAMING
            if(is_streaming) {
              ctimer_set(&stream_probe_timer, STREAM_PROBE_TIME,
                         send_stream_probe, NULL);
            }
#endif /* WITH_STREAMING */
          }

          if(sent) {
            turn_radio_off();
          }

#if WITH_ACK_OPTIMIZATION
          if(packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
             packetbuf_attr(PACKETBUF_ATTR_ERELIABLE)) {
            /* We're sending a packet that needs an ACK, so we keep
               the radio on in anticipation of the ACK. */
            turn_radio_on();
          }
#endif /* WITH_ACK_OPTIMIZATION */

        }
      }
    }

  } else if(hdr.type == TYPE_DATA) {
    turn_radio_off();
    if(!rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) {
      if(!rimeaddr_cmp(&hdr.receiver, &rimeaddr_node_addr)) {
        /* Not broadcast or for us */
        PRINTF("%d.%d: data not for us from %d.%d\n",
               rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
               hdr.sender.u8[0], hdr.sender.u8[1]);
        return;
      }
      packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &hdr.receiver);
    }
    packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &hdr.sender);

    PRINTF("%d.%d: got data from %d.%d\n",
           rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
           hdr.sender.u8[0], hdr.sender.u8[1]);

    /* Accumulate the power consumption for the packet reception. */
    compower_accumulate(&current_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(&current_packet);
      
    /* Clear the accumulated power consumption so that it is ready
       for the next packet. */
    compower_clear(&current_packet);

#if WITH_PENDING_BROADCAST
    if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) {
      /* This is a broadcast packet. Check the list of pending
         packets to see if we are currently sending a broadcast. If
         so, we refrain from sending our broadcast until one sleep
         cycle period, so that the other broadcaster will have
         finished sending. */
	
      struct queue_list_item *i;
      for(i = list_head(queued_packets_list); i != NULL; i = list_item_next(i)) {
        /* If the packet is a broadcast packet that is not yet
           ready to be sent, we do not send it. */
        if(i->broadcast_flag == BROADCAST_FLAG_PENDING) {
          PRINTF("Someone else is sending, pending -> waiting\n");
          set_broadcast_flag(i, BROADCAST_FLAG_WAITING);
        }
      }
    }
#endif /* WITH_PENDING_BROADCAST */


#if WITH_PROBE_AFTER_RECEPTION
    /* XXX send probe after receiving a packet to facilitate data
       streaming. We must first copy the contents of the packetbuf into
       a queuebuf to avoid overwriting the data with the probe packet. */
    if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_node_addr)) {
      struct queuebuf *q;
      q = queuebuf_new_from_packetbuf();
      if(q != NULL) {
        send_probe();
        queuebuf_to_packetbuf(q);
        queuebuf_free(q);
      }
    }
#endif /* WITH_PROBE_AFTER_RECEPTION */

#if WITH_ADAPTIVE_OFF_TIME
    off_time = LOWEST_OFF_TIME;
    restart_dutycycle(off_time);
#endif /* WITH_ADAPTIVE_OFF_TIME */

    NETSTACK_MAC.input();
  }
}
Exemple #18
0
/*---------------------------------------------------------------------------*/
static void
send_packet(mac_callback_t sent, void *ptr)
{
  int size;

  /* 3 bytes per packet attribute is required for serialization */
  uint8_t buf[PACKETBUF_NUM_ATTRS * 3 + PACKETBUF_SIZE + 3];
  uint8_t sid;

  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);

  /* ack or not ? */
  packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);

  if(NETSTACK_FRAMER.create() < 0) {
    /* Failed to allocate space for headers */
    LOG6LBR_ERROR("br-rdc: send failed, too large header\n");
    mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 1);

  } else {
    /* here we send the data over SLIP to the radio-chip */
    size = 0;
#if SERIALIZE_ATTRIBUTES
    size = packetutils_serialize_atts(&buf[3], sizeof(buf) - 3);
#endif
    if(size < 0 || size + packetbuf_totlen() + 3 > sizeof(buf)) {
      LOG6LBR_ERROR("br-rdc: send failed, too large header\n");
      mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 1);
    } else {
      LOG6LBR_PRINTF(PACKET, RADIO_OUT, "write: %d\n", packetbuf_datalen());
      if (LOG6LBR_COND(DUMP, RADIO_OUT)) {
        uint8_t *data = packetbuf_dataptr();
        int len = packetbuf_datalen();
        int i;
    #if WIRESHARK_IMPORT_FORMAT
        printf("0000");
        for(i = 0; i < len; i++)
          printf(" %02x", data[i]);
    #else
        printf("         ");
        for(i = 0; i < len; i++) {
          printf("%02x", data[i]);
          if((i & 3) == 3)
            printf(" ");
          if((i & 15) == 15)
            printf("\n         ");
        }
    #endif
        printf("\n");
      }

      sid = setup_callback(sent, ptr);

      buf[0] = '!';
      buf[1] = 'S';
      buf[2] = sid;             /* sequence or session number for this packet */

      /* Copy packet data */
      memcpy(&buf[3 + size], packetbuf_hdrptr(), packetbuf_totlen());

      write_to_slip(buf, packetbuf_totlen() + size + 3);
    }
  }
}