]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - support/sdk/c/blip/lib6lowpan/lib6lowpanFrag.c
Merge TinyOS 2.1.1 into master.
[tinyos-2.x.git] / support / sdk / c / blip / lib6lowpan / lib6lowpanFrag.c
diff --git a/support/sdk/c/blip/lib6lowpan/lib6lowpanFrag.c b/support/sdk/c/blip/lib6lowpan/lib6lowpanFrag.c
new file mode 100644 (file)
index 0000000..dfb4df4
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * "Copyright (c) 2008 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+/*
+ * @author Stephen Dawson-Haggerty <stevedh@cs.berkeley.edu>
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "ip.h"
+#include "ip_malloc.h"
+#include "6lowpan.h"
+#include "lib6lowpan.h"
+
+#define min(a,b) ( ((a)>(b)) ? (b) : (a) )
+#define max(a,b) ( ((a)<(b)) ? (b) : (a) )
+
+uint16_t lib6lowpan_frag_tag = 0;
+
+void ip_memclr(uint8_t *buf, uint16_t len) {
+  for (; len > 0; len--)
+    *buf++ = 0;
+  
+}
+
+void *ip_memcpy(void *dst0, const void *src0, uint16_t len) {
+  uint8_t *dst = (uint8_t *) dst0;
+  uint8_t *src = (uint8_t *) src0;
+  void *ret = dst0;
+  
+  for (; len > 0; len--)
+    *dst++ = *src++;
+  
+  return ret;
+}
+
+/*
+ *  this function writes the next fragment which needs to be sent into
+ *  the buffer passed in.  It updates the structures in process to
+ *  reflect how much of the packet has been sent so far.
+ *
+ *  if the packet does not require fragmentation, this function will
+ *  not insert a fragmentation header and will merely compress the
+ *  headers into the packet.
+ *
+ *  returns the number of bytes used in buf, or zero if there was no
+ *  fragment to be sent.
+ *
+ */
+uint8_t getNextFrag(struct split_ip_msg *msg, fragment_t *progress,
+                    uint8_t *buf, uint16_t len) {
+  if (msg == NULL || progress == NULL || buf == NULL) return 0;
+  packed_lowmsg_t pkt;
+  uint16_t frag_length = 0;
+  pkt.headers = 0;
+  pkt.data = buf;
+  pkt.len = len;
+
+  // if this is the first fragment, we will compress the headers in
+  // the ip message, and only insert a fragmentation header if
+  // necessary to pack it into buffer
+  if (progress->offset == 0) {
+    uint8_t *compressed_headers;
+    uint8_t lowpan_len = 0;
+    uint8_t cmpr_header_len = 0, header_length = 0;
+    
+    compressed_headers = malloc(LIB6LOWPAN_MAX_LEN);
+    if (compressed_headers == NULL) return 0;
+
+    // pack the headers into a temporary buffer
+    cmpr_header_len = packHeaders(msg, compressed_headers, LIB6LOWPAN_MAX_LEN);
+    
+    {
+      struct generic_header *cur = msg->headers;
+      while (cur != NULL) {
+        header_length += cur->len;
+        cur = cur->next;
+      }
+    }
+
+    // printBuf(compressed_headers, compressed_len);
+    // printf("payload: %p\n", payload);
+
+    // maybe add a fragmentation header
+    if (cmpr_header_len + msg->data_len > len) {
+      pkt.headers |= LOWMSG_FRAG1_HDR;
+      if (setupHeaders(&pkt, pkt.headers)) goto free_fail;
+      if (setFragDgramTag(&pkt, ++lib6lowpan_frag_tag)) goto free_fail;
+      if (setFragDgramSize(&pkt, ntoh16(msg->hdr.plen) + sizeof(struct ip6_hdr))) goto free_fail;
+      lowpan_len += LOWMSG_FRAG1_LEN;
+    } else {
+      if (setupHeaders(&pkt, pkt.headers)) goto free_fail;
+    }
+    ip_memcpy(getLowpanPayload(&pkt), compressed_headers, cmpr_header_len);
+    
+    /*
+     * calculate how much to put into this fragment
+     *
+     * if the whole packet fits in the buffer, this is easy; it's the
+     * compressed headers plus the payload length.
+     *
+     * given fragmentation, we need to do a little more work.
+     */
+    if (pkt.headers & LOWMSG_FRAG1_HDR) {
+      frag_length = len - cmpr_header_len - LOWMSG_FRAG1_LEN + sizeof(struct ip6_hdr) + header_length;
+      frag_length -= (frag_length % 8);
+      frag_length -= (sizeof(struct ip6_hdr) + header_length);
+    } else {
+      frag_length = ntoh16(msg->hdr.plen) - header_length;
+    }
+    // frag_length contains the number of bytes in uncompressed headers.
+
+    ip_memcpy(getLowpanPayload(&pkt) + cmpr_header_len,
+              msg->data, frag_length);
+
+    progress->tag = lib6lowpan_frag_tag;
+    progress->offset = frag_length + sizeof(struct ip6_hdr) + header_length;
+
+    // printfUART("frag: 0x%x 0x%x 0x%x\n", header_len, frag_length, compressed_len);
+
+    // return the length we wrote, which comes in three pieces;
+    free(compressed_headers);
+    return lowpan_len + cmpr_header_len + frag_length;
+  free_fail:
+    free(compressed_headers);
+    goto fail;
+  } else {
+    /*
+     * we've already sent the first fragment; we only need to send a
+     * subsequent one or return zero if we're at the end of the buffer;
+     *
+     */
+    //printf("offset: 0x%x plen: 0x%x\n", progress->offset, ntoh16(ip->plen) + sizeof(struct ip6_hdr));
+
+    // NOTE : this should be a >= to detect runaway lengths.  However,
+    // it is useful for debugging to require equality.
+    if (progress->offset == ntoh16(msg->hdr.plen) + sizeof(struct ip6_hdr)) return 0;
+    // the only headers we need now is the fragn header.
+
+    pkt.headers |= LOWMSG_FRAGN_HDR;
+    
+    // send out the fragments some frasgments.
+    //printf ("--- sending fragment\n");
+    // now we're pointing at the start of the 6loWPAN frame in the packet.
+    pkt.data = buf;
+    pkt.len = len;
+    // setup the fragmentation headers
+    if (setupHeaders(&pkt, pkt.headers)) goto fail;
+    if (setFragDgramTag(&pkt, progress->tag)) goto fail;
+
+    //printf ("frag dgram size 0x%x progress: 0x%x\n", ntoh16(ip->plen) + sizeof(struct ip6_hdr),
+/*     progress->offset); */
+
+    if (setFragDgramSize(&pkt, ntoh16(msg->hdr.plen) + sizeof(struct ip6_hdr))) goto fail;
+    if (setFragDgramOffset(&pkt, (progress->offset) / 8)) goto fail;
+
+    frag_length = min(len - LOWMSG_FRAGN_LEN, 
+                      ntoh16(msg->hdr.plen) + sizeof(struct ip6_hdr) - progress->offset);
+
+    
+
+    // unless this is the last fragment, we must sent a multiple of 8 bytes;
+    if (frag_length + progress->offset != ntoh16(msg->hdr.plen) + sizeof(struct ip6_hdr))
+      frag_length -= (frag_length % 8);
+
+    pkt.len = frag_length + LOWMSG_FRAGN_LEN;
+
+    {
+      uint8_t header_length = sizeof(struct ip6_hdr);
+      struct generic_header *cur = msg->headers;
+      while (cur != NULL) {
+        header_length += cur->len;
+        cur = cur->next;
+      }
+      ip_memcpy(buf + LOWMSG_FRAGN_LEN, msg->data + progress->offset - header_length, frag_length);
+    } 
+    progress->offset += frag_length;
+    //printf("frag length is: 0x%x offset: 0x%x max: 0x%x\n", frag_length, progress->offset, LOWPAN_MTU);
+    
+    return frag_length + LOWMSG_FRAGN_LEN;
+  }
+ fail:
+  return 0;
+}