static void packet_sent(struct net_buf *buf, void *ptr, int status, int transmissions) { const linkaddr_t *dest = packetbuf_addr(buf, PACKETBUF_ADDR_RECEIVER); uip_ds6_link_neighbor_callback(dest, status, transmissions); uip_last_tx_status(buf) = status; l2_buf_unref(buf); }
/*---------------------------------------------------------------------------*/ 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 reassemble(struct net_buf *mbuf) { /* size of the IP packet (read from fragment) */ uint16_t frag_size = 0; int8_t frag_context = 0; /* offset of the fragment in the IP packet */ uint8_t frag_offset = 0; uint8_t is_fragment = 0; /* tag of the fragment */ uint16_t frag_tag = 0; uint8_t first_fragment = 0, last_fragment = 0; struct net_buf *buf = NULL; /* init */ uip_uncomp_hdr_len(mbuf) = 0; uip_packetbuf_hdr_len(mbuf) = 0; /* The MAC puts the 15.4 payload inside the packetbuf data buffer */ uip_packetbuf_ptr(mbuf) = packetbuf_dataptr(mbuf); /* Save the RSSI of the incoming packet in case the upper layer will want to query us for it later. */ last_rssi = (signed short)packetbuf_attr(mbuf, PACKETBUF_ATTR_RSSI); /* * Since we don't support the mesh and broadcast header, the first header * we look for is the fragmentation header */ switch((GET16(uip_packetbuf_ptr(mbuf), PACKETBUF_FRAG_DISPATCH_SIZE) & 0xf800) >> 8) { case SICSLOWPAN_DISPATCH_FRAG1: PRINTF("reassemble: FRAG1 "); frag_offset = 0; frag_size = GET16(uip_packetbuf_ptr(mbuf), PACKETBUF_FRAG_DISPATCH_SIZE) & 0x07ff; frag_tag = GET16(uip_packetbuf_ptr(mbuf), PACKETBUF_FRAG_TAG); PRINTF("size %d, tag %d, offset %d\n", frag_size, frag_tag, frag_offset); if (frag_size > IP_BUF_MAX_DATA) { PRINTF("Too big packet %d bytes (max %d), fragment discarded\n", frag_size, IP_BUF_MAX_DATA); goto fail; } uip_packetbuf_hdr_len(mbuf) += SICSLOWPAN_FRAG1_HDR_LEN; first_fragment = 1; is_fragment = 1; /* Add the fragment to the fragmentation context (this will also copy the payload)*/ frag_context = add_fragment(mbuf, frag_tag, frag_size, frag_offset); if(frag_context == -1) { goto fail; } break; case SICSLOWPAN_DISPATCH_FRAGN: /* * set offset, tag, size * Offset is in units of 8 bytes */ PRINTF("reassemble: FRAGN "); frag_offset = uip_packetbuf_ptr(mbuf)[PACKETBUF_FRAG_OFFSET]; frag_tag = GET16(uip_packetbuf_ptr(mbuf), PACKETBUF_FRAG_TAG); frag_size = GET16(uip_packetbuf_ptr(mbuf), PACKETBUF_FRAG_DISPATCH_SIZE) & 0x07ff; PRINTF("reassemble: size %d, tag %d, offset %d\n", frag_size, frag_tag, frag_offset); uip_packetbuf_hdr_len(mbuf) += SICSLOWPAN_FRAGN_HDR_LEN; /* If this is the last fragment, we may shave off any extrenous bytes at the end. We must be liberal in what we accept. */ /* Add the fragment to the fragmentation context (this will also copy the payload) */ frag_context = add_fragment(mbuf, frag_tag, frag_size, frag_offset); if(frag_context == -1) { goto fail; } if(frag_info[frag_context].reassembled_len >= frag_size) { last_fragment = 1; } is_fragment = 1; break; default: /* If there is no fragmentation header, then assume that the packet * is not fragmented and pass it as is to IP stack. */ buf = copy_buf(mbuf); if(!buf || net_driver_15_4_recv(buf) < 0) { goto fail; } goto out; } /* * copy "payload" from the packetbuf buffer to the sicslowpan_buf * if this is a first fragment or not fragmented packet, * we have already copied the compressed headers, uncomp_hdr_len * and packetbuf_hdr_len are non 0, frag_offset is. * If this is a subsequent fragment, this is the contrary. */ if(packetbuf_datalen(mbuf) < uip_packetbuf_hdr_len(mbuf)) { PRINTF("reassemble: packet dropped due to header > total packet\n"); goto fail; } uip_packetbuf_payload_len(mbuf) = packetbuf_datalen(mbuf) - uip_packetbuf_hdr_len(mbuf); /* Sanity-check size of incoming packet to avoid buffer overflow */ { int req_size = UIP_LLH_LEN + (uint16_t)(frag_offset << 3) + uip_packetbuf_payload_len(mbuf); if(req_size > UIP_BUFSIZE) { PRINTF("reassemble: packet dropped, minimum required IP_BUF size: %d+%d+%d=%d (current size: %d)\n", UIP_LLH_LEN, (uint16_t)(frag_offset << 3), uip_packetbuf_payload_len(mbuf), req_size, UIP_BUFSIZE); goto fail; } } if(frag_size > 0) { /* Add the size of the header only for the first fragment. */ if(first_fragment != 0) { frag_info[frag_context].reassembled_len = uip_uncomp_hdr_len(mbuf) + uip_packetbuf_payload_len(mbuf); } /* For the last fragment, we are OK if there is extrenous bytes at the end of the packet. */ if(last_fragment != 0) { frag_info[frag_context].reassembled_len = frag_size; /* copy to uip(net_buf) */ buf = copy_frags2uip(frag_context); if(!buf) goto fail; } } /* * If we have a full IP packet in sicslowpan_buf, deliver it to * the IP stack */ if(!is_fragment || last_fragment) { /* packet is in uip already - just set length */ if(is_fragment != 0 && last_fragment != 0) { uip_len(buf) = frag_size; } else { uip_len(buf) = uip_packetbuf_payload_len(mbuf) + uip_uncomp_hdr_len(mbuf); } PRINTF("reassemble: IP packet ready (length %d)\n", uip_len(buf)); if(net_driver_15_4_recv(buf) < 0) { goto fail; } } out: /* free MAC buffer */ l2_buf_unref(mbuf); return 1; fail: if(buf) { ip_buf_unref(buf); } return 0; }
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; }