📄 lib6lowpanfrag.c
字号:
/*
* "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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -