/*---------------------------------------------------------------------------*/ static int coap_context_send(coap_context_t *ctx, struct net_buf *buf) { int max_data_len, ret; max_data_len = IP_BUF_MAX_DATA - UIP_IPUDPH_LEN; PRINTF("%s: send to peer data %p len %d\n", __FUNCTION__, ip_buf_appdata(buf), ip_buf_appdatalen(buf)); if (ip_buf_appdatalen(buf) > max_data_len) { PRINTF("%s: too much (%d bytes) data to send (max %d bytes)\n", __FUNCTION__, ip_buf_appdatalen(buf), max_data_len); ip_buf_unref(buf); ret = -EINVAL; goto out; } ret = net_send(buf); if (ret < 0) { PRINT("%s: sending %d bytes failed\n", __FUNCTION__, ip_buf_appdatalen(buf)); ip_buf_unref(buf); } out: return ret; }
static inline void receive_and_reply(struct net_context *recv, struct net_context *mcast_recv) { struct net_buf *buf; buf = net_receive(recv, TICKS_UNLIMITED); if (buf) { prepare_reply("unicast ", buf); if (net_reply(recv, buf)) { ip_buf_unref(buf); } return; } buf = net_receive(mcast_recv, TICKS_UNLIMITED); if (buf) { prepare_reply("multicast ", buf); if (net_reply(mcast_recv, buf)) { ip_buf_unref(buf); } return; } }
/*---------------------------------------------------------------------------*/ static int prepare_and_send_buf(coap_context_t *ctx, session_t *session, uint8_t *data, size_t len) { struct net_buf *buf; int max_data_len; /* This net_buf gets sent to network, so it is not released * by this function unless there was an error and buf was * not actually sent. */ buf = ip_buf_get_tx(ctx->net_ctx); if (!buf) { len = -ENOBUFS; goto out; } max_data_len = IP_BUF_MAX_DATA - UIP_IPUDPH_LEN; PRINTF("%s: reply to peer data %p len %d\n", __FUNCTION__, data, len); if (len > max_data_len) { PRINTF("%s: too much (%d bytes) data to send (max %d bytes)\n", __FUNCTION__, len, max_data_len); ip_buf_unref(buf); len = -EINVAL; goto out; } /* Note that we have reversed the addresses here * because net_reply() will reverse them again. */ #ifdef CONFIG_NETWORKING_WITH_IPV6 uip_ip6addr_copy(&NET_BUF_IP(buf)->destipaddr, (uip_ip6addr_t *)&ctx->my_addr.in6_addr); uip_ip6addr_copy(&NET_BUF_IP(buf)->srcipaddr, (uip_ip6addr_t *)&session->addr.ipaddr); #else uip_ip4addr_copy(&NET_BUF_IP(buf)->destipaddr, (uip_ip4addr_t *)&ctx->my_addr.in_addr); uip_ip4addr_copy(&NET_BUF_IP(buf)->srcipaddr, (uip_ip4addr_t *)&session->addr.ipaddr); #endif NET_BUF_UDP(buf)->destport = uip_ntohs(ctx->my_port); NET_BUF_UDP(buf)->srcport = session->addr.port; uip_set_udp_conn(buf) = net_context_get_udp_connection(ctx->net_ctx); memcpy(net_buf_add(buf, len), data, len); ip_buf_appdatalen(buf) = len; ip_buf_appdata(buf) = buf->data + ip_buf_reserve(buf); if (net_reply(ctx->net_ctx, buf)) { ip_buf_unref(buf); } out: return len; }
/*---------------------------------------------------------------------------*/ static int event(struct dtls_context_t *ctx, session_t *session, dtls_alert_level_t level, unsigned short code) { coap_context_t *coap_ctx; coap_ctx = dtls_get_app_data(ctx); if(coap_ctx == COAP_CONTEXT_NONE || coap_ctx->is_used == 0) { /* The context is no longer in use */ } else if(code == DTLS_EVENT_CONNECTED) { coap_ctx->status = STATUS_CONNECTED; PRINTF("coap-context: DTLS CLIENT CONNECTED!\n"); process_post(coap_ctx->process, coap_context_event, coap_ctx); } else if(code == DTLS_EVENT_CONNECT || code == DTLS_EVENT_RENEGOTIATE) { coap_ctx->status = STATUS_CONNECTING; PRINTF("coap-context: DTLS CLIENT NOT CONNECTED!\n"); process_post(coap_ctx->process, coap_context_event, coap_ctx); } else if(level == DTLS_ALERT_LEVEL_FATAL && code < 256) { /* Fatal alert */ if (coap_ctx && coap_ctx->buf) { ip_buf_unref(coap_ctx->buf); coap_ctx->buf = NULL; } coap_ctx->status = STATUS_ALERT; PRINTF("coap-context: DTLS CLIENT ALERT %u!\n", code); process_post(coap_ctx->process, coap_context_event, coap_ctx); } return 0; }
static void send_data(const char *taskname, struct net_context *ctx) { int len = strlen(lorem_ipsum); struct net_buf *buf; buf = ip_buf_get_tx(ctx); if (buf) { uint8_t *ptr; uint16_t sent_len; ptr = net_buf_add(buf, 0); memcpy(ptr, lorem_ipsum, len); ptr = net_buf_add(buf, len); ptr = net_buf_add(buf, 1); /* add \0 */ *ptr = '\0'; sent_len = buf->len; if (net_send(buf) < 0) { PRINT("%s: %s(): sending %d bytes failed\n", taskname, __func__, len); ip_buf_unref(buf); } else { PRINT("%s: %s(): sent %d bytes\n", taskname, __func__, sent_len); } } }
static inline bool send_packet(const char *name, struct net_context *ctx, int ipsum_len, int pos) { struct net_buf *buf; bool fail = false; buf = ip_buf_get_tx(ctx); if (buf) { uint8_t *ptr; int sending_len = ipsum_len - pos; ptr = net_buf_add(buf, sending_len); memcpy(ptr, lorem_ipsum + pos, sending_len); sending_len = buf->len; if (net_send(buf) < 0) { PRINT("%s: sending %d bytes failed\n", __func__, sending_len); ip_buf_unref(buf); fail = true; goto out; } else { PRINT("%s: sent %d bytes\n", __func__, sending_len); } } out: return fail; }
static struct net_buf *copy_buf(struct net_buf *mbuf) { struct net_buf *buf; buf = ip_buf_get_reserve_rx(0); if(!buf) { return NULL; } /* Copy from the fragment context info buffer first */ linkaddr_copy(&ip_buf_ll_dest(buf), packetbuf_addr(mbuf, PACKETBUF_ADDR_RECEIVER)); linkaddr_copy(&ip_buf_ll_src(buf), packetbuf_addr(mbuf, PACKETBUF_ADDR_SENDER)); PRINTF("%s: mbuf datalen %d dataptr %p buf %p\n", __FUNCTION__, packetbuf_datalen(mbuf), packetbuf_dataptr(mbuf), uip_buf(buf)); if(packetbuf_datalen(mbuf) > 0 && packetbuf_datalen(mbuf) <= UIP_BUFSIZE - UIP_LLH_LEN) { memcpy(uip_buf(buf), packetbuf_dataptr(mbuf), packetbuf_datalen(mbuf)); uip_len(buf) = packetbuf_datalen(mbuf); net_buf_add(buf, uip_len(buf)); } else { ip_buf_unref(buf); buf = NULL; } return buf; }
int tcp_tx(struct net_context *ctx, uint8_t *buf, size_t size) { struct net_buf *nbuf = NULL; uint8_t *ptr; int rc = 0; nbuf = ip_buf_get_tx(ctx); if (nbuf == NULL) { printk("[%s:%d] Unable to get buffer\n", __func__, __LINE__); return -EINVAL; } ptr = net_buf_add(nbuf, size); memcpy(ptr, buf, size); ip_buf_appdatalen(nbuf) = size; do { rc = net_send(nbuf); if (rc >= 0) { ip_buf_unref(nbuf); return 0; } switch (rc) { case -EINPROGRESS: printk("%s: no connection yet, try again\n", __func__); fiber_sleep(TCP_RETRY_TIMEOUT); break; case -EAGAIN: case -ECONNRESET: printk("%s: no connection, try again later\n", __func__); fiber_sleep(TCP_RETRY_TIMEOUT); break; default: printk("%s: sending %d bytes failed\n", __func__, size); ip_buf_unref(nbuf); return -EIO; } } while (1); return 0; }
/*---------------------------------------------------------------------------*/ int coap_context_reply(coap_context_t *ctx, struct net_buf *buf) { int max_data_len, ret; max_data_len = IP_BUF_MAX_DATA - UIP_IPUDPH_LEN; PRINTF("%s: reply to peer data %p len %d\n", __FUNCTION__, ip_buf_appdata(buf), ip_buf_appdatalen(buf)); if (ip_buf_appdatalen(buf) > max_data_len) { PRINTF("%s: too much (%d bytes) data to send (max %d bytes)\n", __FUNCTION__, ip_buf_appdatalen(buf), max_data_len); ip_buf_unref(buf); ret = -EINVAL; goto out; } if (net_reply(ctx->net_ctx, buf)) { ip_buf_unref(buf); } out: return ret; }
static inline bool wait_reply(const char *name, struct net_context *ctx, int ipsum_len, int pos) { struct net_buf *buf; bool fail = false; int expected_len = ipsum_len - pos; /* Wait for the answer */ buf = net_receive(ctx, WAIT_TICKS); if (buf) { if (ip_buf_appdatalen(buf) != expected_len) { PRINT("%s: received %d bytes, expected %d\n", name, ip_buf_appdatalen(buf), expected_len); fail = true; goto free_buf; } /* In this test we reverse the received bytes. * We could just pass the data back as is but * this way it is possible to see how the app * can manipulate the received data. */ reverse(ip_buf_appdata(buf), ip_buf_appdatalen(buf)); /* Did we get all the data back? */ if (memcmp(lorem_ipsum + pos, ip_buf_appdata(buf), expected_len)) { PRINT("%s: received data mismatch.\n", name); fail = true; goto free_buf; } PRINT("%s: received %d bytes\n", __func__, expected_len); free_buf: ip_buf_unref(buf); } else { PRINT("%s: expected data, got none\n", name); fail = true; } return fail; }
int tcp_rx(struct net_context *ctx, uint8_t *buf, size_t *read_bytes, size_t size) { struct net_buf *nbuf; int rc; nbuf = net_receive(ctx, TCP_RX_TIMEOUT); rc = -EIO; if (nbuf != NULL) { *read_bytes = ip_buf_appdatalen(nbuf); if (*read_bytes > size) { rc = -ENOMEM; } else { memcpy(buf, ip_buf_appdata(nbuf), *read_bytes); rc = 0; } ip_buf_unref(nbuf); } return rc; }
/*---------------------------------------------------------------------------*/ int coap_context_wait_data(coap_context_t *coap_ctx, int32_t ticks) { struct net_buf *buf; buf = net_receive(coap_ctx->net_ctx, ticks); if (buf) { session_t session; int ret; uip_ipaddr_copy(&session.addr.ipaddr, &UIP_IP_BUF(buf)->srcipaddr); session.addr.port = UIP_UDP_BUF(buf)->srcport; session.size = sizeof(session.addr); session.ifindex = 1; PRINTF("coap-context: got dtls message from "); PRINT6ADDR(&session.addr.ipaddr); PRINTF(":%d %u bytes\n", uip_ntohs(session.addr.port), uip_appdatalen(buf)); PRINTF("Received appdata %p appdatalen %d\n", ip_buf_appdata(buf), ip_buf_appdatalen(buf)); coap_ctx->buf = buf; ret = dtls_handle_message(coap_ctx->dtls_context, &session, ip_buf_appdata(buf), ip_buf_appdatalen(buf)); /* We always release the buffer here as this buffer is never sent * to network anyway. */ if (coap_ctx->buf) { ip_buf_unref(coap_ctx->buf); coap_ctx->buf = NULL; } return ret; } return 0; }
static void receive_data(const char *taskname, struct net_context *ctx) { struct net_buf *buf; #ifdef CONFIG_NET_SANITY_TEST int rp; #endif buf = net_receive(ctx, TICKS_NONE); if (buf) { PRINT("%s: %s(): received %d bytes\n", taskname, __func__, ip_buf_appdatalen(buf)); if (memcmp(ip_buf_appdata(buf), lorem_ipsum, sizeof(lorem_ipsum))) { PRINT("ERROR: data does not match\n"); #ifdef CONFIG_NET_SANITY_TEST rp = TC_FAIL; } else { rp = TC_PASS; #endif } ip_buf_unref(buf); #ifdef CONFIG_NET_SANITY_TEST loopback++; test_rp = test_rp && rp; TC_END_RESULT(rp); if (loopback == CONFIG_NET_15_4_LOOPBACK_NUM) { loopback = 0; TC_END_REPORT(test_rp); } #endif } }
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; }