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;
}
Example #2
0
/*-----------------------------------------------------------------------------------*/
void
uip_arp_arpin(struct net_buf *buf)
{

  if(uip_len(buf) < sizeof(struct arp_hdr)) {
    uip_len(buf) = 0;
    return;
  }
  uip_len(buf) = 0;

  switch(BUF(buf)->opcode) {
  case UIP_HTONS(ARP_REQUEST):
    /* ARP request. If it asked for our address, we send out a
       reply. */
    /*    if(BUF->dipaddr[0] == uip_hostaddr[0] &&
	  BUF->dipaddr[1] == uip_hostaddr[1]) {*/
    PRINTF("uip_arp_arpin: request for %d.%d.%d.%d (we are %d.%d.%d.%d)\n",
	   BUF(buf)->dipaddr.u8[0], BUF(buf)->dipaddr.u8[1],
	   BUF(buf)->dipaddr.u8[2], BUF(buf)->dipaddr.u8[3],
	   uip_hostaddr.u8[0], uip_hostaddr.u8[1],
	   uip_hostaddr.u8[2], uip_hostaddr.u8[3]);
    if(uip_ipaddr_cmp(&BUF(buf)->dipaddr, &uip_hostaddr)) {
      /* First, we register the one who made the request in our ARP
	 table, since it is likely that we will do more communication
	 with this host in the future. */
      uip_arp_update(&BUF(buf)->sipaddr, &BUF(buf)->shwaddr);

      BUF(buf)->opcode = UIP_HTONS(ARP_REPLY);

      memcpy(BUF(buf)->dhwaddr.addr, BUF(buf)->shwaddr.addr, 6);
      memcpy(BUF(buf)->shwaddr.addr, uip_lladdr.addr, 6);
      memcpy(BUF(buf)->ethhdr.src.addr, uip_lladdr.addr, 6);
      memcpy(BUF(buf)->ethhdr.dest.addr, BUF(buf)->dhwaddr.addr, 6);

      uip_ipaddr_copy(&BUF(buf)->dipaddr, &BUF(buf)->sipaddr);
      uip_ipaddr_copy(&BUF(buf)->sipaddr, &uip_hostaddr);

      BUF(buf)->ethhdr.type = UIP_HTONS(UIP_ETHTYPE_ARP);
      uip_len(buf) = sizeof(struct arp_hdr);
    }
    break;
  case UIP_HTONS(ARP_REPLY):
    /* ARP reply. We insert or update the ARP table if it was meant
       for us. */
    if(uip_ipaddr_cmp(&BUF(buf)->dipaddr, &uip_hostaddr)) {
      uip_arp_update(&BUF(buf)->sipaddr, &BUF(buf)->shwaddr);
    }
    break;
  }

  return;
}
/* Copy all the fragments that are associated with a specific context into uip */
static struct net_buf *copy_frags2uip(int context)
{
  int i, total_len = 0;
  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), &frag_info[context].receiver);
  linkaddr_copy(&ip_buf_ll_src(buf), &frag_info[context].sender);

  for(i = 0; i < SICSLOWPAN_FRAGMENT_BUFFERS; i++) {
    /* And also copy all matching fragments */
    if(frag_buf[i].len > 0 && frag_buf[i].index == context) {
      memcpy(uip_buf(buf) + (uint16_t)(frag_buf[i].offset << 3),
            (uint8_t *)frag_buf[i].data, frag_buf[i].len);
      total_len += frag_buf[i].len;
    }
  }
  net_buf_add(buf, total_len);
  uip_len(buf) = total_len;

  /* deallocate all the fragments for this context */
  clear_fragments(context);

  return buf;
}
Example #4
0
/*---------------------------------------------------------------------------*/
static uint8_t
packet_input(struct net_buf *buf)
{
  uint8_t ret = 0;
#if UIP_CONF_IP_FORWARD
  if(uip_len > 0) {
    tcpip_is_forwarding = 1;
    if(uip_fw_forward() == UIP_FW_LOCAL) {
      tcpip_is_forwarding = 0;
      check_for_tcp_syn();
      uip_input();
      if(uip_len > 0) {
#if UIP_CONF_TCP_SPLIT
        uip_split_output();
#else /* UIP_CONF_TCP_SPLIT */
#if NETSTACK_CONF_WITH_IPV6
        tcpip_ipv6_output();
#else
	PRINTF("tcpip packet_input forward output len %d\n", uip_len);
        tcpip_output();
#endif
#endif /* UIP_CONF_TCP_SPLIT */
      }
    }
    tcpip_is_forwarding = 0;
  }
#else /* UIP_CONF_IP_FORWARD */
  if(uip_len(buf) > 0) {
    check_for_tcp_syn(buf);
    ret = uip_input(buf);
    if(ret && uip_len(buf) > 0) {
#if UIP_CONF_TCP_SPLIT
      uip_split_output(buf);
#else /* UIP_CONF_TCP_SPLIT */
#if NETSTACK_CONF_WITH_IPV6
      PRINTF("tcpip packet_input output len %d\n", uip_len(buf));
      ret = tcpip_ipv6_output(buf);
#else
      PRINTF("tcpip packet_input output len %d\n", uip_len(buf));
      ret = tcpip_output(buf, NULL);
#endif
#endif /* UIP_CONF_TCP_SPLIT */
    }
  }
#endif /* UIP_CONF_IP_FORWARD */
  return ret;
}
Example #5
0
/*---------------------------------------------------------------------------*/
uint8_t
tcpip_input(struct net_buf *buf)
{
  process_post_synch(&tcpip_process, PACKET_INPUT, NULL, buf);
  if (uip_len(buf) == 0) {
    /* This indicates that there was a parsing/other error
     * in packet.
     */
    return 0;
  }

  uip_len(buf) = 0;
#if NETSTACK_CONF_WITH_IPV6
  uip_ext_len(buf) = 0;
#endif /*NETSTACK_CONF_WITH_IPV6*/

  return 1;
}
Example #6
0
static void eth_rx(struct device *port)
{
	struct eth_runtime *context = port->driver_data;
	struct eth_config *config = port->config->config_info;
	uint32_t base_addr = config->base_addr;
	struct net_buf *buf;
	uint32_t frm_len = 0;

	/* Check whether the RX descriptor is still owned by the device.  If not,
	 * process the received frame or an error that may have occurred.
	 */
	if (context->rx_desc.own == 1) {
		ETH_ERR("Spurious receive interrupt from Ethernet MAC.\n");
		return;
	}

	if (!net_driver_ethernet_is_opened()) {
		goto release_desc;
	}

	if (context->rx_desc.err_summary) {
		ETH_ERR("Error receiving frame: RDES0 = %08x, RDES1 = %08x.\n",
			context->rx_desc.rdes0, context->rx_desc.rdes1);
		goto release_desc;
	}

	frm_len = context->rx_desc.frm_len;
	if (frm_len > UIP_BUFSIZE) {
		ETH_ERR("Frame too large: %u.\n", frm_len);
		goto release_desc;
	}

	buf = ip_buf_get_reserve_rx(0);
	if (buf == NULL) {
		ETH_ERR("Failed to obtain RX buffer.\n");
		goto release_desc;
	}

	memcpy(net_buf_add(buf, frm_len), (void *)context->rx_buf, frm_len);
	uip_len(buf) = frm_len;

	net_driver_ethernet_recv(buf);

release_desc:
	/* Return ownership of the RX descriptor to the device. */
	context->rx_desc.own = 1;

	/* Request that the device check for an available RX descriptor, since
	 * ownership of the descriptor was just transferred to the device.
	 */
	eth_write(base_addr, REG_ADDR_RX_POLL_DEMAND, 1);
}
Example #7
0
/* @brief Transmit the current Ethernet frame.
 *
 *        This procedure will block indefinitely until the Ethernet device is
 *        ready to accept a new outgoing frame.  It then copies the current
 *        Ethernet frame from the global uip_buf buffer to the device DMA
 *        buffer and signals to the device that a new frame is available to be
 *        transmitted.
 */
static int eth_tx(struct device *port, struct net_buf *buf)
{
	struct eth_runtime *context = port->driver_data;
	struct eth_config *config = port->config->config_info;
	uint32_t base_addr = config->base_addr;

	/* Wait until the TX descriptor is no longer owned by the device. */
	while (context->tx_desc.own == 1) {
	}

#ifdef CONFIG_ETHERNET_DEBUG
	/* Check whether an error occurred transmitting the previous frame. */
	if (context->tx_desc.err_summary) {
		ETH_ERR("Error transmitting frame: TDES0 = %08x, TDES1 = %08x.\n",
			context->tx_desc.tdes0, context->tx_desc.tdes1);
	}
#endif

	/* Transmit the next frame. */
	if (uip_len(buf) > UIP_BUFSIZE) {
		ETH_ERR("Frame too large to TX: %u\n", uip_len(buf));

		return -1;
	}

	memcpy((void *)context->tx_buf, uip_buf(buf), uip_len(buf));

	context->tx_desc.tx_buf1_sz = uip_len(buf);

	context->tx_desc.own = 1;

	/* Request that the device check for an available TX descriptor, since
	 * ownership of the descriptor was just transferred to the device.
	 */
	eth_write(base_addr, REG_ADDR_TX_POLL_DEMAND, 1);

	return 1;
}
Example #8
0
/*---------------------------------------------------------------------------*/
static int
get_from_peer(struct dtls_context_t *ctx, session_t *session,
              uint8 *data, size_t len)
{
  coap_context_t *coap_ctx;
  coap_ctx = dtls_get_app_data(ctx);

  if(coap_ctx != COAP_CONTEXT_NONE && coap_ctx->is_used) {
    uip_len(coap_ctx->buf) = len;
    memmove(uip_appdata(coap_ctx->buf), data, len);
    coap_engine_receive(coap_ctx);
  }
  return 0;
}
Example #9
0
/*---------------------------------------------------------------------------*/
int
coap_context_send_message(coap_context_t *coap_ctx,
                          uip_ipaddr_t *addr, uint16_t port,
                          const uint8_t *data, uint16_t length)
{
  int ret;

  if(coap_ctx == NULL || coap_ctx->is_used == 0) {
    PRINTF("coap-context: can not send on non-used context\n");
    return 0;
  }

  ip_buf_appdatalen(coap_ctx->buf) = length;

  if (!uip_udp_conn(coap_ctx->buf)) {
    /* Normal send, not a reply */
    ret = coap_context_send(coap_ctx, coap_ctx->buf);

  } else {

    /* We need to set the uIP buffer lengths in net_buf properly as
     * otherwise the final buffer length in
     * net_init.c:udp_prepare_and_send() will be usually incorrect
     * (uip_len() will be length of the received packet). So by setting
     * uip_len() to 0 here, we let the sending in net_init.c to
     * set the send buffer length correctly.
     */
    uip_len(coap_ctx->buf) = 0;
    memcpy(ip_buf_appdata(coap_ctx->buf), data, length);

    ret = coap_context_reply(coap_ctx, coap_ctx->buf);
  }

  coap_ctx->buf = NULL;
  return ret;
}
Example #10
0
/* Switch the ports and addresses and set route and neighbor cache.
 * Returns 1 if packet was sent properly, in this case it is the caller
 * that needs to release the net_buf. If 0 is returned, then uIP stack
 * has released the net_buf already because there was an some net related
 * error when sending the buffer.
 */
static inline int udp_prepare_and_send(struct net_context *context,
				       struct net_buf *buf)
{
#ifdef CONFIG_NETWORKING_WITH_IPV6
	uip_ds6_route_t *route_old, *route_new = NULL;
	uip_ds6_nbr_t *nbr;
#endif
	uip_ipaddr_t tmp;
	uint16_t port;
	uint8_t ret;

	if (uip_len(buf) == 0) {
		/* This is expected as uIP will typically set the
		 * packet length to 0 after receiving it. So we need
		 * to fix the length here. The protocol specific
		 * part is added also here.
		 */
		uip_len(buf) = uip_slen(buf) = uip_appdatalen(buf);
		buf->data = buf->buf + UIP_IPUDPH_LEN;
	}

	port = UIP_UDP_BUF(buf)->srcport;
	UIP_UDP_BUF(buf)->srcport = UIP_UDP_BUF(buf)->destport;
	UIP_UDP_BUF(buf)->destport = port;

	uip_ipaddr_copy(&tmp, &UIP_IP_BUF(buf)->srcipaddr);
	uip_ipaddr_copy(&UIP_IP_BUF(buf)->srcipaddr,
			&UIP_IP_BUF(buf)->destipaddr);
	uip_ipaddr_copy(&UIP_IP_BUF(buf)->destipaddr, &tmp);

#ifdef CONFIG_NETWORKING_WITH_IPV6
	/* The peer needs to be in neighbor cache before route can be added.
	 */
	nbr = uip_ds6_nbr_lookup((uip_ipaddr_t *)&UIP_IP_BUF(buf)->destipaddr);
	if (!nbr) {
		const uip_lladdr_t *lladdr = (const uip_lladdr_t *)&buf->src;
		nbr = uip_ds6_nbr_add(
			(uip_ipaddr_t *)&UIP_IP_BUF(buf)->destipaddr,
			lladdr, 0, NBR_REACHABLE);
		if (!nbr) {
			NET_DBG("Cannot add peer ");
			PRINT6ADDR(&UIP_IP_BUF(buf)->destipaddr);
			PRINT(" to neighbor cache\n");
		}
	}

	/* Temporarily add route to peer, delete the route after
	 * sending the packet. Check if there was already a
	 * route and do not remove it if there was existing
	 * route to this peer.
	 */
	route_old = uip_ds6_route_lookup(&UIP_IP_BUF(buf)->destipaddr);
	if (!route_old) {
		route_new = uip_ds6_route_add(&UIP_IP_BUF(buf)->destipaddr,
					      128,
					      &UIP_IP_BUF(buf)->destipaddr);
		if (!route_new) {
			NET_DBG("Cannot add route to peer ");
			PRINT6ADDR(&UIP_IP_BUF(buf)->destipaddr);
			PRINT("\n");
		}
	}
#endif

	ret = simple_udp_sendto_port(buf,
				     net_context_get_udp_connection(context),
				     buf->data, buf->len,
				     &UIP_IP_BUF(buf)->destipaddr,
				     uip_ntohs(UIP_UDP_BUF(buf)->destport));
	if (!ret) {
		NET_DBG("Packet could not be sent properly.\n");
	}

#ifdef CONFIG_NETWORKING_WITH_IPV6
	if (!route_old && route_new) {
		/* This will also remove the neighbor cache entry */
		uip_ds6_route_rm(route_new);
	}
#endif

	return ret;
}
Example #11
0
/* This is called by contiki/ip/tcpip.c:tcpip_uipcall() when packet
 * is processed.
 */
PROCESS_THREAD(tcp, ev, data, buf, user_data)
{
	PROCESS_BEGIN();

	while(1) {
		PROCESS_YIELD_UNTIL(ev == tcpip_event);

		if (POINTER_TO_INT(data) == TCP_WRITE_EVENT) {
			/* We want to send data to peer. */
			struct net_context *context = user_data;

			if (!context) {
				continue;
			}

			do {
				context = user_data;
				if (!context || !buf) {
					break;
				}

				if (!context->ps.net_buf ||
				    context->ps.net_buf != buf) {
					NET_DBG("psock init %p buf %p\n",
						&context->ps, buf);
					PSOCK_INIT(&context->ps, buf);
				}

				handle_tcp_connection(&context->ps,
						      POINTER_TO_INT(data),
						      buf);

				PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event);

				if (POINTER_TO_INT(data) != TCP_WRITE_EVENT) {
					goto read_data;
				}
			} while(!(uip_closed(buf)  ||
				  uip_aborted(buf) ||
				  uip_timedout(buf)));

			context = user_data;

			if (context &&
			    context->tcp_type == NET_TCP_TYPE_CLIENT) {
				NET_DBG("\nConnection closed.\n");
				ip_buf_sent_status(buf) = -ECONNRESET;
			}

			continue;
		}

	read_data:
		/* We are receiving data from peer. */
		if (buf && uip_newdata(buf)) {
			struct net_buf *clone;

			if (!uip_len(buf)) {
				continue;
			}

			/* Note that uIP stack will reuse the buffer when
			 * sending ACK to peer host. The sending will happen
			 * right after this function returns. Because of this
			 * we cannot use the same buffer to pass data to
			 * application.
			 */
			clone = net_buf_clone(buf);
			if (!clone) {
				NET_ERR("No enough RX buffers, "
					"packet %p discarded\n", buf);
				continue;
			}

			ip_buf_appdata(clone) = uip_buf(clone) +
				(ip_buf_appdata(buf) - (void *)uip_buf(buf));
			ip_buf_appdatalen(clone) = uip_len(buf);
			ip_buf_len(clone) = ip_buf_len(buf);
			ip_buf_context(clone) = user_data;
			uip_set_conn(clone) = uip_conn(buf);
			uip_flags(clone) = uip_flags(buf);
			uip_flags(clone) |= UIP_CONNECTED;

			NET_DBG("packet received context %p buf %p len %d "
				"appdata %p appdatalen %d\n",
				ip_buf_context(clone),
				clone,
				ip_buf_len(clone),
				ip_buf_appdata(clone),
				ip_buf_appdatalen(clone));

			nano_fifo_put(net_context_get_queue(user_data), clone);

			/* We let the application to read the data now */
			fiber_yield();
		}
	}

	PROCESS_END();
}
Example #12
0
/*---------------------------------------------------------------------------*/
void
uip_ds6_neighbor_periodic(struct net_buf *buf)
{
  /* Periodic processing on neighbors */
  uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
  while(nbr != NULL) {
    switch(nbr->state) {
    case NBR_REACHABLE:
      if(stimer_expired(&nbr->reachable)) {
#if UIP_CONF_IPV6_RPL
        /* when a neighbor leave it's REACHABLE state and is a default router,
           instead of going to STALE state it enters DELAY state in order to
           force a NUD on it. Otherwise, if there is no upward traffic, the
           node never knows if the default router is still reachable. This
           mimics the 6LoWPAN-ND behavior.
         */
        if(uip_ds6_defrt_lookup(&nbr->ipaddr) != NULL) {
          PRINTF("REACHABLE: defrt moving to DELAY (");
          PRINT6ADDR(&nbr->ipaddr);
          PRINTF(")\n");
          nbr->state = NBR_DELAY;
          stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME);
          nbr->nscount = 0;
        } else {
          PRINTF("REACHABLE: moving to STALE (");
          PRINT6ADDR(&nbr->ipaddr);
          PRINTF(")\n");
          nbr->state = NBR_STALE;
        }
#else /* UIP_CONF_IPV6_RPL */
        PRINTF("REACHABLE: moving to STALE (");
        PRINT6ADDR(&nbr->ipaddr);
        PRINTF(")\n");
        nbr->state = NBR_STALE;
#endif /* UIP_CONF_IPV6_RPL */
      }
      break;
#if UIP_ND6_SEND_NA
    case NBR_INCOMPLETE:
      if(nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) {
        uip_ds6_nbr_rm(nbr);
      } else if(stimer_expired(&nbr->sendns) && (uip_len(buf) == 0)) {
        nbr->nscount++;
        PRINTF("NBR_INCOMPLETE: NS %u\n", nbr->nscount);
        uip_nd6_ns_output(buf, NULL, NULL, &nbr->ipaddr);
        stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
      }
      break;
    case NBR_DELAY:
      if(stimer_expired(&nbr->reachable)) {
        nbr->state = NBR_PROBE;
        nbr->nscount = 0;
        PRINTF("DELAY: moving to PROBE\n");
        stimer_set(&nbr->sendns, 0);
      }
      break;
    case NBR_PROBE:
      if(nbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) {
        uip_ds6_defrt_t *locdefrt;
        PRINTF("PROBE END\n");
        if((locdefrt = uip_ds6_defrt_lookup(&nbr->ipaddr)) != NULL) {
          if (!locdefrt->isinfinite) {
            uip_ds6_defrt_rm(locdefrt);
          }
        }
        uip_ds6_nbr_rm(nbr);
      } else if(stimer_expired(&nbr->sendns) && (uip_len(buf) == 0)) {
        nbr->nscount++;
        PRINTF("PROBE: NS %u\n", nbr->nscount);
        uip_nd6_ns_output(buf, NULL, &nbr->ipaddr, &nbr->ipaddr);
        stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
      }
      break;
#endif /* UIP_ND6_SEND_NA */
    default:
      break;
    }
    nbr = nbr_table_next(ds6_neighbors, nbr);
  }
}
Example #13
0
uint8_t
tcpip_ipv6_output(struct net_buf *buf)
{
  uip_ds6_nbr_t *nbr = NULL;
  uip_ipaddr_t *nexthop;
  uint8_t ret = 0; /* return value 0 == failed, 1 == ok */

  PRINTF("%s(): buf %p len %d\n", __FUNCTION__, buf, uip_len(buf));

  if(uip_len(buf) == 0) {
    return 0;
  }

  if(uip_len(buf) > UIP_LINK_MTU) {
    UIP_LOG("tcpip_ipv6_output: Packet to big");
    uip_len(buf) = 0;
    return 0;
  }

  if(uip_is_addr_unspecified(&UIP_IP_BUF(buf)->destipaddr)){
    UIP_LOG("tcpip_ipv6_output: Destination address unspecified");
    uip_len(buf) = 0;
    return 0;
  }

  if(!uip_is_addr_mcast(&UIP_IP_BUF(buf)->destipaddr)) {
    /* Next hop determination */
    nbr = NULL;

    /* We first check if the destination address is on our immediate
       link. If so, we simply use the destination address as our
       nexthop address. */
    if(uip_ds6_is_addr_onlink(&UIP_IP_BUF(buf)->destipaddr)){
      nexthop = &UIP_IP_BUF(buf)->destipaddr;
    } else {
      uip_ds6_route_t *route;
      /* Check if we have a route to the destination address. */
      route = uip_ds6_route_lookup(&UIP_IP_BUF(buf)->destipaddr);

      /* No route was found - we send to the default route instead. */
      if(route == NULL) {
        PRINTF("tcpip_ipv6_output: no route found, using default route\n");
        nexthop = uip_ds6_defrt_choose();
        if(nexthop == NULL) {
#ifdef UIP_FALLBACK_INTERFACE
	  PRINTF("FALLBACK: removing ext hdrs & setting proto %d %d\n", 
		 uip_ext_len(buf), *((uint8_t *)UIP_IP_BUF(buf) + 40));
	  if(uip_ext_len(buf) > 0) {
	    extern void remove_ext_hdr(void);
	    uint8_t proto = *((uint8_t *)UIP_IP_BUF(buf) + 40);
	    remove_ext_hdr();
	    /* This should be copied from the ext header... */
	    UIP_IP_BUF(buf)->proto = proto;
	  }
	  UIP_FALLBACK_INTERFACE.output();
#else
          PRINTF("tcpip_ipv6_output: Destination off-link but no route\n");
#endif /* !UIP_FALLBACK_INTERFACE */
          uip_len(buf) = 0;
          return 0;
        }

      } else {
        /* A route was found, so we look up the nexthop neighbor for
           the route. */
        nexthop = uip_ds6_route_nexthop(route);

        /* If the nexthop is dead, for example because the neighbor
           never responded to link-layer acks, we drop its route. */
        if(nexthop == NULL) {
#if UIP_CONF_IPV6_RPL
          /* If we are running RPL, and if we are the root of the
             network, we'll trigger a global repair berfore we remove
             the route. */
          rpl_dag_t *dag;
          rpl_instance_t *instance;

          dag = (rpl_dag_t *)route->state.dag;
          if(dag != NULL) {
            instance = dag->instance;

            rpl_repair_root(buf, instance->instance_id);
          }
#endif /* UIP_CONF_IPV6_RPL */
          uip_ds6_route_rm(route);

          /* We don't have a nexthop to send the packet to, so we drop
             it. */
          return 0;
        }
      }
#if TCPIP_CONF_ANNOTATE_TRANSMISSIONS
      if(nexthop != NULL) {
        static uint8_t annotate_last;
        static uint8_t annotate_has_last = 0;

        if(annotate_has_last) {
          printf("#L %u 0; red\n", annotate_last);
        }
        printf("#L %u 1; red\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
        annotate_last = nexthop->u8[sizeof(uip_ipaddr_t) - 1];
        annotate_has_last = 1;
      }
#endif /* TCPIP_CONF_ANNOTATE_TRANSMISSIONS */
    }

    /* End of next hop determination */

#if UIP_CONF_IPV6_RPL
    if(rpl_update_header_final(buf, nexthop)) {
      uip_len(buf) = 0;
      return 0;
    }
#endif /* UIP_CONF_IPV6_RPL */
    nbr = uip_ds6_nbr_lookup(nexthop);
    if(nbr == NULL) {
#if UIP_ND6_SEND_NA
      if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE)) == NULL) {
        uip_len(buf) = 0;
        return 0;
      } else {
#if UIP_CONF_IPV6_QUEUE_PKT
        /* Copy outgoing pkt in the queuing buffer for later transmit. */
        if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) {
          memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF(buf), uip_len(buf));
          uip_packetqueue_set_buflen(&nbr->packethandle, uip_len(buf));
        }
#endif
      /* RFC4861, 7.2.2:
       * "If the source address of the packet prompting the solicitation is the
       * same as one of the addresses assigned to the outgoing interface, that
       * address SHOULD be placed in the IP Source Address of the outgoing
       * solicitation.  Otherwise, any one of the addresses assigned to the
       * interface should be used."*/
       if(uip_ds6_is_my_addr(&UIP_IP_BUF(buf)->srcipaddr)){
          uip_nd6_ns_output(buf, &UIP_IP_BUF(buf)->srcipaddr, NULL, &nbr->ipaddr);
        } else {
          uip_nd6_ns_output(buf, NULL, NULL, &nbr->ipaddr);
        }

        stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
        nbr->nscount = 1;
      }

      return 1; /* packet was passed to network successfully */
#endif /* UIP_ND6_SEND_NA */
    } else {
#if UIP_ND6_SEND_NA
      if(nbr->state == NBR_INCOMPLETE) {
        PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n");
#if UIP_CONF_IPV6_QUEUE_PKT
        /* Copy outgoing pkt in the queuing buffer for later transmit and set
           the destination nbr to nbr. */
        if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) {
          memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF(buf), uip_len(buf));
          uip_packetqueue_set_buflen(&nbr->packethandle, uip_len(buf));
        }
#endif /*UIP_CONF_IPV6_QUEUE_PKT*/
        uip_len(buf) = 0;
        return 0;
      }
      /* Send in parallel if we are running NUD (nbc state is either STALE,
         DELAY, or PROBE). See RFC 4861, section 7.3.3 on node behavior. */
      if(nbr->state == NBR_STALE) {
        nbr->state = NBR_DELAY;
        stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME);
        nbr->nscount = 0;
        PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n");
      }
#endif /* UIP_ND6_SEND_NA */

      ret = tcpip_output(buf, uip_ds6_nbr_get_ll(nbr));

#if UIP_CONF_IPV6_QUEUE_PKT
      /*
       * Send the queued packets from here, may not be 100% perfect though.
       * This happens in a few cases, for example when instead of receiving a
       * NA after sendiong a NS, you receive a NS with SLLAO: the entry moves
       * to STALE, and you must both send a NA and the queued packet.
       */
      if(uip_packetqueue_buflen(&nbr->packethandle) != 0) {
        uip_len(buf) = uip_packetqueue_buflen(&nbr->packethandle);
        memcpy(UIP_IP_BUF(buf), uip_packetqueue_buf(&nbr->packethandle), uip_len(buf));
        uip_packetqueue_free(&nbr->packethandle);
        ret = tcpip_output(uip_ds6_nbr_get_ll(nbr));
      }
#endif /*UIP_CONF_IPV6_QUEUE_PKT*/

      if (ret == 0) {
        uip_len(buf) = 0;
      }

      return ret;
    }
    return 0; /* discard packet */
  }
  /* Multicast IP destination address. */
  ret = tcpip_output(buf, NULL);
  uip_len(buf) = 0;
  uip_ext_len(buf) = 0;
  return ret;
}
Example #14
0
/*---------------------------------------------------------------------------*/
static void
eventhandler(process_event_t ev, process_data_t data, struct net_buf *buf)
{
#if UIP_TCP
  static unsigned char i;
  register struct listenport *l;
#endif /*UIP_TCP*/
  struct process *p;

  switch(ev) {
    case PROCESS_EVENT_EXITED:
      /* This is the event we get if a process has exited. We go through
         the TCP/IP tables to see if this process had any open
         connections or listening TCP ports. If so, we'll close those
         connections. */

      p = (struct process *)data;
#if UIP_TCP
      l = s.listenports;
      for(i = 0; i < UIP_LISTENPORTS; ++i) {
        if(l->p == p) {
          uip_unlisten(l->port);
          l->port = 0;
          l->p = PROCESS_NONE;
        }
        ++l;
      }
	 
      {
        struct uip_conn *cptr;
	    
        for(cptr = &uip_conns[0]; cptr < &uip_conns[UIP_CONNS]; ++cptr) {
          if(cptr->appstate.p == p) {
            cptr->appstate.p = PROCESS_NONE;
            cptr->tcpstateflags = UIP_CLOSED;
          }
        }
      }
#endif /* UIP_TCP */
#if UIP_UDP
      {
        struct uip_udp_conn *cptr;

        for(cptr = &uip_udp_conns[0];
            cptr < &uip_udp_conns[UIP_UDP_CONNS]; ++cptr) {
          if(cptr->appstate.p == p) {
            cptr->lport = 0;
          }
        }
      }
#endif /* UIP_UDP */
      break;

    case PROCESS_EVENT_TIMER:
      /* We get this event if one of our timers have expired. */
      {
        /* Check the clock so see if we should call the periodic uIP
           processing. */
        if(data == &periodic &&
           etimer_expired(&periodic)) {
#if UIP_TCP
          for(i = 0; i < UIP_CONNS; ++i) {
            if(uip_conn_active(i)) {
              /* Only restart the timer if there are active
                 connections. */
              etimer_restart(&periodic);
              uip_periodic(i);
#if NETSTACK_CONF_WITH_IPV6
	      if (!tcpip_ipv6_output(buf)) {
                net_buf_put(buf);
	      }
#else
              if(uip_len(buf) > 0) {
		PRINTF("tcpip_output from periodic len %d\n", uip_len(buf));
                tcpip_output(buf, NULL);
		PRINTF("tcpip_output after periodic len %d\n", uip_len(buf));
              }
#endif /* NETSTACK_CONF_WITH_IPV6 */
            }
          }
#endif /* UIP_TCP */
#if UIP_CONF_IP_FORWARD
          uip_fw_periodic();
#endif /* UIP_CONF_IP_FORWARD */
        }
        
#if NETSTACK_CONF_WITH_IPV6
#if UIP_CONF_IPV6_REASSEMBLY
        /*
         * check the timer for reassembly
         */
        if(data == &uip_reass_timer &&
           etimer_expired(&uip_reass_timer)) {
          uip_reass_over();
          tcpip_ipv6_output(buf);
        }
#endif /* UIP_CONF_IPV6_REASSEMBLY */
        /*
         * check the different timers for neighbor discovery and
         * stateless autoconfiguration
         */
        /*if(data == &uip_ds6_timer_periodic &&
           etimer_expired(&uip_ds6_timer_periodic)) {
          uip_ds6_periodic();
          tcpip_ipv6_output();
        }*/
#if !UIP_CONF_ROUTER
        if(data == &uip_ds6_timer_rs &&
           etimer_expired(&uip_ds6_timer_rs)) {
          uip_ds6_send_rs(buf);
	  if (!tcpip_ipv6_output(buf)) {
            net_buf_put(buf);
	  }
        }
#endif /* !UIP_CONF_ROUTER */
        if(data == &uip_ds6_timer_periodic &&
           etimer_expired(&uip_ds6_timer_periodic)) {
          uip_ds6_periodic(buf);
	  if (!tcpip_ipv6_output(buf)) {
            net_buf_put(buf);
	  }
        }
#endif /* NETSTACK_CONF_WITH_IPV6 */
      }
      break;
	 
#if UIP_TCP
    case TCP_POLL:
      if(data != NULL) {
        uip_poll_conn(data);
#if NETSTACK_CONF_WITH_IPV6
        tcpip_ipv6_output(buf);
#else /* NETSTACK_CONF_WITH_IPV6 */
        if(uip_len(buf) > 0) {
	  PRINTF("tcpip_output from tcp poll len %d\n", uip_len(buf));
          tcpip_output(buf, NULL);
        }
#endif /* NETSTACK_CONF_WITH_IPV6 */
        /* Start the periodic polling, if it isn't already active. */
        start_periodic_tcp_timer();
      }
      break;
#endif /* UIP_TCP */
#if UIP_UDP
    case UDP_POLL:
      if(data != NULL) {
        uip_udp_periodic_conn(buf, data);
#if NETSTACK_CONF_WITH_IPV6
        if (!tcpip_ipv6_output(buf)) {
          net_buf_put(buf);
	}
#else
        if(uip_len(buf) > 0) {
          tcpip_output(buf, NULL);
        }
#endif /* UIP_UDP */
      }
      break;
#endif /* UIP_UDP */

    case PACKET_INPUT:
      packet_input(buf);
      break;
  };
}
Example #15
0
/*-----------------------------------------------------------------------------------*/
void
uip_arp_out(struct net_buf *buf)
{
  struct arp_entry *tabptr = arp_table;

  /* Find the destination IP address in the ARP table and construct
     the Ethernet header. If the destination IP addres isn't on the
     local network, we use the default router's IP address instead.

     If not ARP table entry is found, we overwrite the original IP
     packet with an ARP request for the IP address. */

  /* First check if destination is a local broadcast. */
  if(uip_ipaddr_cmp(&IPBUF(buf)->destipaddr, &uip_broadcast_addr)) {
    memcpy(IPBUF(buf)->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);
  } else if(IPBUF(buf)->destipaddr.u8[0] == 224) {
    /* Multicast. */
    IPBUF(buf)->ethhdr.dest.addr[0] = 0x01;
    IPBUF(buf)->ethhdr.dest.addr[1] = 0x00;
    IPBUF(buf)->ethhdr.dest.addr[2] = 0x5e;
    IPBUF(buf)->ethhdr.dest.addr[3] = IPBUF(buf)->destipaddr.u8[1];
    IPBUF(buf)->ethhdr.dest.addr[4] = IPBUF(buf)->destipaddr.u8[2];
    IPBUF(buf)->ethhdr.dest.addr[5] = IPBUF(buf)->destipaddr.u8[3];
  } else {
    /* Check if the destination address is on the local network. */
    if(!uip_ipaddr_maskcmp(&IPBUF(buf)->destipaddr, &uip_hostaddr, &uip_netmask)) {
      /* Destination address was not on the local network, so we need to
	 use the default router's IP address instead of the destination
	 address when determining the MAC address. */
      uip_ipaddr_copy(&ipaddr, &uip_draddr);
    } else {
      /* Else, we use the destination IP address. */
      uip_ipaddr_copy(&ipaddr, &IPBUF(buf)->destipaddr);
    }
    for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
      if(uip_ipaddr_cmp(&ipaddr, &tabptr->ipaddr)) {
	break;
      }
	  tabptr++;
    }

    if(i == UIP_ARPTAB_SIZE) {
      /* The destination address was not in our ARP table, so we
	 overwrite the IP packet with an ARP request. */

      memset(BUF(buf)->ethhdr.dest.addr, 0xff, 6);
      memset(BUF(buf)->dhwaddr.addr, 0x00, 6);
      memcpy(BUF(buf)->ethhdr.src.addr, uip_lladdr.addr, 6);
      memcpy(BUF(buf)->shwaddr.addr, uip_lladdr.addr, 6);

      uip_ipaddr_copy(&BUF(buf)->dipaddr, &ipaddr);
      uip_ipaddr_copy(&BUF(buf)->sipaddr, &uip_hostaddr);
      BUF(buf)->opcode = UIP_HTONS(ARP_REQUEST); /* ARP request. */
      BUF(buf)->hwtype = UIP_HTONS(ARP_HWTYPE_ETH);
      BUF(buf)->protocol = UIP_HTONS(UIP_ETHTYPE_IP);
      BUF(buf)->hwlen = 6;
      BUF(buf)->protolen = 4;
      BUF(buf)->ethhdr.type = UIP_HTONS(UIP_ETHTYPE_ARP);

      uip_appdata(buf) = &uip_buf(buf)[UIP_TCPIP_HLEN + UIP_LLH_LEN];

      uip_len(buf) = sizeof(struct arp_hdr);
      return;
    }

    /* Build an ethernet header. */
    memcpy(IPBUF(buf)->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);
  }
  memcpy(IPBUF(buf)->ethhdr.src.addr, uip_lladdr.addr, 6);

  IPBUF(buf)->ethhdr.type = UIP_HTONS(UIP_ETHTYPE_IP);

  uip_len(buf) += sizeof(struct uip_eth_hdr);
}
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;
}