/*---------------------------------------------------------------------------*/ static void handle_beacon_send_timer(struct net_buf *buf, void *p) { struct net_buf *mbuf; frame802154_t params; uint8_t len; mbuf = l2_buf_get_reserve(0); if(!mbuf) { return; } /* init to zeros */ memset(¶ms, 0, sizeof(params)); /* use packetbuf for sending ?? */ packetbuf_clear(mbuf); /* Build the FCF. */ params.fcf.frame_type = FRAME802154_BEACONFRAME; /* Insert IEEE 802.15.4 (2006) version bits. */ params.fcf.frame_version = FRAME802154_IEEE802154_2006; /* assume long for now */ params.fcf.src_addr_mode = FRAME802154_LONGADDRMODE; linkaddr_copy((linkaddr_t *)¶ms.src_addr, &linkaddr_node_addr); /* Set the source PAN ID to the global variable. */ params.src_pid = panid; params.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE; params.dest_addr[0] = 0xFF; params.dest_addr[1] = 0xFF; params.dest_pid = 0xffff; params.seq = framer_802154_next_seqno(); /* Calculate beacon length and copy it to packetbuf */ beacon_payload_len = handler_802154_calculate_beacon_payload_length(beacon_payload, BEACON_PAYLOAD_BUFFER_SIZE); packetbuf_copyfrom(mbuf, beacon_payload, beacon_payload_len); /* Set payload and payload length */ params.payload = packetbuf_dataptr(mbuf); params.payload_len = packetbuf_datalen(mbuf); len = frame802154_hdrlen(¶ms); if(packetbuf_hdralloc(mbuf, len)) { frame802154_create(¶ms, packetbuf_hdrptr(mbuf), len); if(NETSTACK_RADIO.send(mbuf, packetbuf_hdrptr(mbuf), packetbuf_totlen(mbuf)) != RADIO_TX_OK) { l2_buf_unref(mbuf); return; } HANDLER_802154_STAT(handler_802154_stats.beacons_sent++); } }
/* called to send a beacon request */ void handler_802154_send_beacon_request(void) { struct net_buf *mbuf; frame802154_t params; uint8_t len; mbuf = l2_buf_get_reserve(0); if(!mbuf) { return; } /* init to zeros */ memset(¶ms, 0, sizeof(params)); /* use packetbuf for sending ?? */ packetbuf_clear(mbuf); /* Build the FCF. */ params.fcf.frame_type = FRAME802154_CMDFRAME; /* Insert IEEE 802.15.4 (2006) version bits. */ params.fcf.frame_version = FRAME802154_IEEE802154_2006; params.fcf.src_addr_mode = FRAME802154_NOADDR; params.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE; params.dest_addr[0] = 0xFF; params.dest_addr[1] = 0xFF; params.dest_pid = 0xffff; params.seq = chseqno; packetbuf_set_datalen(mbuf, 1); params.payload = packetbuf_dataptr(mbuf); /* set the type in the payload */ params.payload[0] = FRAME802154_BEACONREQ; params.payload_len = packetbuf_datalen(mbuf); len = frame802154_hdrlen(¶ms); if(packetbuf_hdralloc(mbuf, len)) { frame802154_create(¶ms, packetbuf_hdrptr(mbuf), len); if(NETSTACK_RADIO.send(mbuf, packetbuf_hdrptr(mbuf), packetbuf_totlen(mbuf)) != RADIO_TX_OK) { l2_buf_unref(mbuf); return; } HANDLER_802154_STAT(handler_802154_stats.beacons_reqs_sent++); } }
static inline bool send_ack_packet(struct net_buf *buf, uint8_t *status) { struct net_buf *ack_buf; frame802154_t frame; if (packetbuf_attr(buf, PACKETBUF_ATTR_FRAME_TYPE) != FRAME802154_DATAFRAME) { return false; } frame802154_parse(packetbuf_dataptr(buf), packetbuf_datalen(buf), &frame); if (frame.fcf.ack_required == 0 || !linkaddr_cmp((linkaddr_t *)&frame.dest_addr, &linkaddr_node_addr)) { return false; } ack_buf = l2_buf_get_reserve(0); if (!ack_buf) { *status = MAC_TX_ERR; return false; } uip_pkt_packetbuf(ack_buf)[0] = FRAME802154_ACKFRAME; uip_pkt_packetbuf(ack_buf)[1] = 0; uip_pkt_packetbuf(ack_buf)[2] = frame.seq; *status = NETSTACK_RADIO.send(ack_buf, NULL, ACK_LEN); l2_buf_unref(ack_buf); PRINTF("simplerdc: Send ACK to packet %u\n", packetbuf_attr(buf, PACKETBUF_ATTR_MAC_SEQNO)); return true; }
static int fragment(struct net_buf *buf, void *ptr) { struct queuebuf *q; int max_payload; int framer_hdrlen; uint16_t frag_tag; /* Number of bytes processed. */ uint16_t processed_ip_out_len; struct net_buf *mbuf; bool last_fragment = false; #define USE_FRAMER_HDRLEN 0 #if USE_FRAMER_HDRLEN framer_hdrlen = NETSTACK_FRAMER.length(); if(framer_hdrlen < 0) { /* Framing failed, we assume the maximum header length */ framer_hdrlen = 21; } #else /* USE_FRAMER_HDRLEN */ framer_hdrlen = 21; #endif /* USE_FRAMER_HDRLEN */ max_payload = MAC_MAX_PAYLOAD - framer_hdrlen - NETSTACK_LLSEC.get_overhead(); PRINTF("max_payload: %d, framer_hdrlen: %d \n",max_payload, framer_hdrlen); mbuf = l2_buf_get_reserve(0); if (!mbuf) { goto fail; } uip_last_tx_status(mbuf) = MAC_TX_OK; /* * The destination address will be tagged to each outbound * packet. If the argument localdest is NULL, we are sending a * broadcast packet. */ if((int)uip_len(buf) <= max_payload) { /* The packet does not need to be fragmented, send buf */ packetbuf_copyfrom(mbuf, uip_buf(buf), uip_len(buf)); send_packet(mbuf, &ip_buf_ll_dest(buf), true, ptr); ip_buf_unref(buf); return 1; } uip_uncomp_hdr_len(mbuf) = 0; uip_packetbuf_hdr_len(mbuf) = 0; packetbuf_clear(mbuf); uip_packetbuf_ptr(mbuf) = packetbuf_dataptr(mbuf); packetbuf_set_attr(mbuf, PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, SICSLOWPAN_MAX_MAC_TRANSMISSIONS); PRINTF("fragmentation: total packet len %d\n", uip_len(buf)); /* * The outbound IPv6 packet is too large to fit into a single 15.4 * packet, so we fragment it into multiple packets and send them. * The first fragment contains frag1 dispatch, then * IPv6/HC1/HC06/HC_UDP dispatchs/headers. * The following fragments contain only the fragn dispatch. */ int estimated_fragments = ((int)uip_len(buf)) / ((int)MAC_MAX_PAYLOAD - SICSLOWPAN_FRAGN_HDR_LEN) + 1; int freebuf = queuebuf_numfree(mbuf) - 1; PRINTF("uip_len: %d, fragments: %d, free bufs: %d\n", uip_len(buf), estimated_fragments, freebuf); if(freebuf < estimated_fragments) { PRINTF("Dropping packet, not enough free bufs\n"); goto fail; } /* Create 1st Fragment */ SET16(uip_packetbuf_ptr(mbuf), PACKETBUF_FRAG_DISPATCH_SIZE, ((SICSLOWPAN_DISPATCH_FRAG1 << 8) | uip_len(buf))); frag_tag = my_tag++; SET16(uip_packetbuf_ptr(mbuf), PACKETBUF_FRAG_TAG, frag_tag); PRINTF("fragmentation: fragment %d \n", frag_tag); /* Copy payload and send */ uip_packetbuf_hdr_len(mbuf) += SICSLOWPAN_FRAG1_HDR_LEN; uip_packetbuf_payload_len(mbuf) = (max_payload - uip_packetbuf_hdr_len(mbuf)) & 0xfffffff8; PRINTF("(payload len %d, hdr len %d, tag %d)\n", uip_packetbuf_payload_len(mbuf), uip_packetbuf_hdr_len(mbuf), frag_tag); memcpy(uip_packetbuf_ptr(mbuf) + uip_packetbuf_hdr_len(mbuf), uip_buf(buf), uip_packetbuf_payload_len(mbuf)); packetbuf_set_datalen(mbuf, uip_packetbuf_payload_len(mbuf) + uip_packetbuf_hdr_len(mbuf)); q = queuebuf_new_from_packetbuf(mbuf); if(q == NULL) { PRINTF("could not allocate queuebuf for first fragment, dropping packet\n"); goto fail; } net_buf_ref(mbuf); send_packet(mbuf, &ip_buf_ll_dest(buf), last_fragment, ptr); queuebuf_to_packetbuf(mbuf, q); queuebuf_free(q); q = NULL; /* Check tx result. */ if((uip_last_tx_status(mbuf) == MAC_TX_COLLISION) || (uip_last_tx_status(mbuf) == MAC_TX_ERR) || (uip_last_tx_status(mbuf) == MAC_TX_ERR_FATAL)) { PRINTF("error in fragment tx, dropping subsequent fragments.\n"); goto fail; } /* set processed_ip_out_len to what we already sent from the IP payload*/ processed_ip_out_len = uip_packetbuf_payload_len(mbuf); /* * Create following fragments * Datagram tag is already in the buffer, we need to set the * FRAGN dispatch and for each fragment, the offset */ uip_packetbuf_hdr_len(mbuf) = SICSLOWPAN_FRAGN_HDR_LEN; SET16(uip_packetbuf_ptr(mbuf), PACKETBUF_FRAG_DISPATCH_SIZE, ((SICSLOWPAN_DISPATCH_FRAGN << 8) | uip_len(buf))); uip_packetbuf_payload_len(mbuf) = (max_payload - uip_packetbuf_hdr_len(mbuf)) & 0xfffffff8; while(processed_ip_out_len < uip_len(buf)) { PRINTF("fragmentation: fragment:%d, processed_ip_out_len:%d \n", my_tag, processed_ip_out_len); uip_packetbuf_ptr(mbuf)[PACKETBUF_FRAG_OFFSET] = processed_ip_out_len >> 3; /* Copy payload and send */ if(uip_len(buf) - processed_ip_out_len < uip_packetbuf_payload_len(mbuf)) { /* last fragment */ last_fragment = true; uip_packetbuf_payload_len(mbuf) = uip_len(buf) - processed_ip_out_len; } PRINTF("(offset %d, len %d, tag %d)\n", processed_ip_out_len >> 3, uip_packetbuf_payload_len(mbuf), my_tag); memcpy(uip_packetbuf_ptr(mbuf) + uip_packetbuf_hdr_len(mbuf), (uint8_t *)UIP_IP_BUF(buf) + processed_ip_out_len, uip_packetbuf_payload_len(mbuf)); packetbuf_set_datalen(mbuf, uip_packetbuf_payload_len(mbuf) + uip_packetbuf_hdr_len(mbuf)); q = queuebuf_new_from_packetbuf(mbuf); if(q == NULL) { PRINTF("could not allocate queuebuf, dropping fragment\n"); goto fail; } net_buf_ref(mbuf); send_packet(mbuf, &ip_buf_ll_dest(buf), last_fragment, ptr); queuebuf_to_packetbuf(mbuf, q); queuebuf_free(q); q = NULL; processed_ip_out_len += uip_packetbuf_payload_len(mbuf); /* Check tx result. */ if((uip_last_tx_status(mbuf) == MAC_TX_COLLISION) || (uip_last_tx_status(mbuf) == MAC_TX_ERR) || (uip_last_tx_status(mbuf) == MAC_TX_ERR_FATAL)) { PRINTF("error in fragment tx, dropping subsequent fragments.\n"); goto fail; } } ip_buf_unref(buf); l2_buf_unref(mbuf); return 1; fail: if (mbuf) { l2_buf_unref(mbuf); } return 0; }