int lowpan_recon_add(struct lowpan_reconstruct *recon,
                     uint8_t *pkt, size_t len) {
  struct packed_lowmsg msg;
  uint8_t *buf;

  msg.data = pkt;
  msg.len  = len;
  msg.headers = getHeaderBitmap(&msg);
  if (msg.headers == LOWMSG_NALP) return -1;

  if (!hasFragNHeader(&msg)) {
    return -2;
  }

  buf = getLowpanPayload(&msg);
  len -= (buf - pkt);

  if (recon->r_size < recon->r_bytes_rcvd + len) return -3;

  /* just need to copy the new payload in and return */
  memcpy(recon->r_buf + recon->r_bytes_rcvd, buf, len);
  recon->r_bytes_rcvd += len;

  return 0;
}
void *pan_read(void * arg) {
  while (run_state == S_RUNNING) {
    struct packed_lowmsg lowmsg;
    struct ieee154_frame_addr frame_address;
    int length;
    uint8_t *frame = read_pan_packet(&length);
    uint8_t *buf = frame + 1;   /* skip the dispatch byte */

    if (!frame) 
      continue;

    if (frame[0] != TOS_SERIAL_802_15_4_ID) {
      warn("invalid frame received!\n");
      goto done;
    }

    info("serial packet arrived! (len: %i)\n", length);
    print_buffer(buf, length);

    buf     = unpack_ieee154_hdr(buf, &frame_address);
    length -= buf - frame;

    if (!buf) {
      warn("unpacking IEEE154 header failed!\n");
      goto done;
    }

    lowmsg.data = buf;
    lowmsg.len  = length;
    lowmsg.headers = getHeaderBitmap(&lowmsg);
    if (lowmsg.headers == LOWMSG_NALP) {
      warn("lowmsg NALP!\n");
      goto done;
    }

    if (hasFrag1Header(&lowmsg) || hasFragNHeader(&lowmsg)) {
      struct lowpan_reconstruct *recon;
      uint16_t tag, source_key;
      int rv;
      pthread_mutex_lock(&reconstruct_lock);

      source_key = ieee154_hashaddr(&frame_address.ieee_src);
      getFragDgramTag(&lowmsg, &tag);
      recon = get_reconstruct(source_key, tag);
      if (!recon) {
        pthread_mutex_unlock(&reconstruct_lock);
        goto done;
      }

      if (hasFrag1Header(&lowmsg))
        rv = lowpan_recon_start(&frame_address, recon, buf, length);
      else rv = lowpan_recon_add(recon, buf, length);

      if (rv < 0) {
        recon->r_timeout = T_FAILED1;
        pthread_mutex_unlock(&reconstruct_lock);
        goto done;
      } else {
        recon->r_timeout = T_ACTIVE;
        recon->r_source_key = source_key;
        recon->r_tag = tag;
      }

      if (recon->r_size == recon->r_bytes_rcvd) {
        deliver_to_kernel(recon);
      }
      pthread_mutex_unlock(&reconstruct_lock);

    } else {
      int rv;
      struct lowpan_reconstruct recon;

      buf = getLowpanPayload(&lowmsg);

      if ((rv = lowpan_recon_start(&frame_address, &recon, buf, length)) < 0) {
        warn("reconstruction failed!\n");
        goto done;
      }

      if (recon.r_size == recon.r_bytes_rcvd) {
        deliver_to_kernel(&recon);
      } else {
        free(recon.r_buf);
      }
    }

  done:
    free(frame);
  }
}