mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
712 lines
21 KiB
C
712 lines
21 KiB
C
/*
|
|
* @f ccnl-ext-frag.c
|
|
* @b CCN lite extension: fragmentation support (including scheduling interface)
|
|
*
|
|
* Copyright (C) 2011-13, Christian Tschudin, University of Basel
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* File history:
|
|
* 2011-10-05 created
|
|
* 2013-05-02 prototyped a new fragment format CCNL_FRAG_TYPE_CCNx2013
|
|
*/
|
|
|
|
// ----------------------------------------------------------------------
|
|
//#define USE_FRAG
|
|
#ifdef USE_FRAG
|
|
|
|
#include "ccnl-includes.h"
|
|
#include "ccnl-core.h"
|
|
#include "ccnl-ext.h"
|
|
#include "ccnx.h"
|
|
|
|
|
|
|
|
/* see ccnl-core.h for available fragmentation protocols.
|
|
*
|
|
* CCNL_FRAG_NONE
|
|
* passthrough, i.e. no header is added at all
|
|
*
|
|
* CCNL_FRAG_SEQUENCED2012
|
|
* - a ccnb encoded header is prepended,
|
|
* - the driver is configurable for arbitrary MTU
|
|
* - packets have sequence numbers (can detect lost packets)
|
|
*
|
|
* CCNL_FRAG_CCNx2013
|
|
* - a ccnb encoded wire format as currently discussed with PARC.
|
|
* It serves as a container for various wire format types,
|
|
* including carrying fragments of bigger CCNX objects
|
|
* - all attributes from SEQUENCED2012 are retained
|
|
*
|
|
*/
|
|
|
|
// ----------------------------------------------------------------------
|
|
struct ccnl_frag_s *
|
|
ccnl_frag_new(int protocol, int mtu)
|
|
{
|
|
struct ccnl_frag_s *e = NULL;
|
|
|
|
DEBUGMSG(8, "ccnl_frag_new proto=%d mtu=%d\n", protocol, mtu);
|
|
|
|
switch (protocol) {
|
|
case CCNL_FRAG_SEQUENCED2012:
|
|
case CCNL_FRAG_CCNx2013:
|
|
e = (struct ccnl_frag_s *) ccnl_calloc(1, sizeof(struct ccnl_frag_s));
|
|
|
|
if (e) {
|
|
e->protocol = protocol;
|
|
e->mtu = mtu;
|
|
e->flagwidth = 1;
|
|
e->sendseqwidth = 4;
|
|
e->losscountwidth = 2;
|
|
e->recvseqwidth = 4;
|
|
}
|
|
|
|
break;
|
|
|
|
case CCNL_FRAG_NONE:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return e;
|
|
}
|
|
|
|
void ccnl_frag_reset(struct ccnl_frag_s *e, struct ccnl_buf_s *buf, int ifndx,
|
|
sockunion *dst)
|
|
{
|
|
DEBUGMSG(99, "ccnl_frag_reset (%d bytes)\n", buf ? buf->datalen : -1);
|
|
|
|
if (!e) {
|
|
return;
|
|
}
|
|
|
|
e->ifndx = ifndx;
|
|
memcpy(&e->dest, dst, sizeof(*dst));
|
|
ccnl_free(e->bigpkt);
|
|
e->bigpkt = buf;
|
|
e->sendoffs = 0;
|
|
}
|
|
|
|
int ccnl_frag_getfragcount(struct ccnl_frag_s *e, int origlen, int *totallen)
|
|
{
|
|
int cnt = 0, len = 0;
|
|
unsigned char dummy[256];
|
|
int hdrlen, blobtaglen, datalen;
|
|
int offs = 0;
|
|
|
|
if (!e) {
|
|
cnt = 1;
|
|
}
|
|
else if (e && e->protocol == CCNL_FRAG_SEQUENCED2012) {
|
|
while (offs < origlen) { // we could do better than to simulate this:
|
|
hdrlen = mkHeader(dummy, CCNL_DTAG_FRAGMENT2012, CCN_TT_DTAG);
|
|
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_FLAGS, CCN_TT_DTAG, 0,
|
|
e->flagwidth);
|
|
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_SEQNR, CCN_TT_DTAG, 0,
|
|
e->sendseqwidth);
|
|
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_OLOSS, CCN_TT_DTAG, 0,
|
|
e->losscountwidth);
|
|
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_YSEQN, CCN_TT_DTAG, 0,
|
|
e->recvseqwidth);
|
|
|
|
hdrlen += mkHeader(dummy, CCN_DTAG_CONTENT, CCN_TT_DTAG);
|
|
blobtaglen = mkHeader(dummy, e->mtu - hdrlen - 1, CCN_TT_BLOB);
|
|
datalen = e->mtu - hdrlen - blobtaglen - 1;
|
|
|
|
if (datalen > (origlen - offs)) {
|
|
datalen = origlen - offs;
|
|
}
|
|
|
|
hdrlen += mkHeader(dummy, datalen, CCN_TT_BLOB);
|
|
len += hdrlen + datalen + 1;
|
|
offs += datalen;
|
|
cnt++;
|
|
}
|
|
}
|
|
else if (e && e->protocol == CCNL_FRAG_CCNx2013) {
|
|
while (offs < origlen) { // we could do better than to simulate this:
|
|
hdrlen = mkHeader(dummy, CCNL_DTAG_FRAGMENT, CCN_TT_DTAG);
|
|
hdrlen += mkHeader(dummy, CCNL_DTAG_FRAG_TYPE, CCN_TT_DTAG);
|
|
hdrlen += 4; // three BLOB bytes plus end-of-entry
|
|
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_SEQNR, CCN_TT_DTAG, 0,
|
|
e->sendseqwidth);
|
|
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_FLAGS, CCN_TT_DTAG, 0,
|
|
e->flagwidth);
|
|
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_OLOSS, CCN_TT_DTAG, 0,
|
|
e->losscountwidth);
|
|
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_YSEQN, CCN_TT_DTAG, 0,
|
|
e->recvseqwidth);
|
|
|
|
hdrlen += mkHeader(dummy, CCN_DTAG_CONTENT, CCN_TT_DTAG);
|
|
blobtaglen = mkHeader(dummy, e->mtu - hdrlen - 1, CCN_TT_BLOB);
|
|
datalen = e->mtu - hdrlen - blobtaglen - 1;
|
|
|
|
if (datalen > (origlen - offs)) {
|
|
datalen = origlen - offs;
|
|
}
|
|
|
|
hdrlen += mkHeader(dummy, datalen, CCN_TT_BLOB);
|
|
len += hdrlen + datalen + 1;
|
|
offs += datalen;
|
|
cnt++;
|
|
}
|
|
}
|
|
|
|
if (totallen) {
|
|
*totallen = len;
|
|
}
|
|
|
|
return cnt;
|
|
}
|
|
|
|
struct ccnl_buf_s *
|
|
ccnl_frag_getnextSEQD2012(struct ccnl_frag_s *e, int *ifndx, sockunion *su)
|
|
{
|
|
struct ccnl_buf_s *buf = 0;
|
|
unsigned char header[256];
|
|
int hdrlen = 0, blobtaglen, flagoffs;
|
|
unsigned int datalen;
|
|
|
|
DEBUGMSG(16, "ccnl_frag_getnextSEQD2012 e=%p, mtu=%d\n", (void *) e, e->mtu);
|
|
DEBUGMSG(17, " %d bytes to fragment, offset=%d\n", e->bigpkt->datalen,
|
|
e->sendoffs);
|
|
|
|
hdrlen = mkHeader(header, CCNL_DTAG_FRAGMENT2012, CCN_TT_DTAG);
|
|
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_FLAGS,
|
|
CCN_TT_DTAG, 0, e->flagwidth);
|
|
flagoffs = hdrlen - 2;
|
|
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_YSEQN,
|
|
CCN_TT_DTAG, e->recvseq, e->recvseqwidth);
|
|
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_OLOSS, CCN_TT_DTAG,
|
|
e->losscount, e->losscountwidth);
|
|
|
|
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_SEQNR,
|
|
CCN_TT_DTAG, e->sendseq, e->sendseqwidth);
|
|
hdrlen += mkHeader(header + hdrlen, CCN_DTAG_CONTENT, CCN_TT_DTAG);
|
|
blobtaglen = mkHeader(header + hdrlen, e->mtu - hdrlen - 2, CCN_TT_BLOB);
|
|
|
|
datalen = e->mtu - hdrlen - blobtaglen - 2;
|
|
|
|
if (datalen > (e->bigpkt->datalen - e->sendoffs)) {
|
|
datalen = e->bigpkt->datalen - e->sendoffs;
|
|
}
|
|
|
|
hdrlen += mkHeader(header + hdrlen, datalen, CCN_TT_BLOB);
|
|
|
|
buf = ccnl_buf_new(NULL, hdrlen + datalen + 2);
|
|
|
|
if (!buf) {
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(buf->data, header, hdrlen);
|
|
memcpy(buf->data + hdrlen, e->bigpkt->data + e->sendoffs, datalen);
|
|
buf->data[hdrlen + datalen] = '\0'; // end of content/any field
|
|
buf->data[hdrlen + datalen + 1] = '\0'; // end of fragment/pdu
|
|
|
|
if (datalen >= e->bigpkt->datalen) { // fits in a single fragment
|
|
buf->data[flagoffs + e->flagwidth - 1] =
|
|
CCNL_DTAG_FRAG_FLAG_FIRST | CCNL_DTAG_FRAG_FLAG_LAST;
|
|
ccnl_free(e->bigpkt);
|
|
e->bigpkt = NULL;
|
|
}
|
|
else if (e->sendoffs == 0) { // this is the start fragment
|
|
buf->data[flagoffs + e->flagwidth - 1] = CCNL_DTAG_FRAG_FLAG_FIRST;
|
|
}
|
|
else if (datalen >= (e->bigpkt->datalen - e->sendoffs)) { // the end
|
|
buf->data[flagoffs + e->flagwidth - 1] = CCNL_DTAG_FRAG_FLAG_LAST;
|
|
ccnl_free(e->bigpkt);
|
|
e->bigpkt = NULL;
|
|
}
|
|
else
|
|
// in the middle
|
|
{
|
|
buf->data[flagoffs + e->flagwidth - 1] = 0x00;
|
|
}
|
|
|
|
e->sendoffs += datalen;
|
|
e->sendseq++;
|
|
|
|
DEBUGMSG(17, " e->offset now %d\n", e->sendoffs);
|
|
|
|
if (ifndx) {
|
|
*ifndx = e->ifndx;
|
|
}
|
|
|
|
if (su) {
|
|
memcpy(su, &e->dest, sizeof(*su));
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
struct ccnl_buf_s *
|
|
ccnl_frag_getnextCCNx2013(struct ccnl_frag_s *fr, int *ifndx, sockunion *su)
|
|
{
|
|
struct ccnl_buf_s *buf = 0;
|
|
unsigned char header[256];
|
|
int hdrlen, blobtaglen, flagoffs;
|
|
unsigned int datalen;
|
|
|
|
// switch among encodings of fragments here (ccnb, TLV, etc)
|
|
|
|
hdrlen = mkHeader(header, CCNL_DTAG_FRAGMENT, CCN_TT_DTAG); // fragment
|
|
|
|
hdrlen += mkHeader(header + hdrlen, CCNL_DTAG_FRAG_TYPE, CCN_TT_DTAG);
|
|
hdrlen += mkHeader(header + hdrlen, 3, CCN_TT_BLOB);
|
|
memcpy(header + hdrlen, CCNL_FRAG_TYPE_CCNx2013_VAL, 3); // "FHBH"
|
|
header[hdrlen + 3] = '\0';
|
|
hdrlen += 4;
|
|
|
|
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_SEQNR, CCN_TT_DTAG,
|
|
fr->sendseq, fr->sendseqwidth);
|
|
|
|
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_FLAGS, CCN_TT_DTAG, 0,
|
|
fr->flagwidth);
|
|
flagoffs = hdrlen - 2; // most significant byte of flag element
|
|
|
|
// other optional fields would go here
|
|
|
|
hdrlen += mkHeader(header + hdrlen, CCN_DTAG_CONTENT, CCN_TT_DTAG);
|
|
|
|
blobtaglen = mkHeader(header + hdrlen, fr->mtu - hdrlen - 2, CCN_TT_BLOB);
|
|
datalen = fr->mtu - hdrlen - blobtaglen - 2;
|
|
|
|
if (datalen > (fr->bigpkt->datalen - fr->sendoffs)) {
|
|
datalen = fr->bigpkt->datalen - fr->sendoffs;
|
|
}
|
|
|
|
hdrlen += mkHeader(header + hdrlen, datalen, CCN_TT_BLOB);
|
|
|
|
buf = ccnl_buf_new(NULL, hdrlen + datalen + 2);
|
|
|
|
if (!buf) {
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(buf->data, header, hdrlen);
|
|
memcpy(buf->data + hdrlen, fr->bigpkt->data + fr->sendoffs, datalen);
|
|
buf->data[hdrlen + datalen] = '\0'; // end of content field
|
|
buf->data[hdrlen + datalen + 1] = '\0'; // end of fragment
|
|
|
|
// patch flag field:
|
|
if (datalen >= fr->bigpkt->datalen) { // single
|
|
buf->data[flagoffs] = CCNL_DTAG_FRAG_FLAG_SINGLE;
|
|
ccnl_free(fr->bigpkt);
|
|
fr->bigpkt = NULL;
|
|
}
|
|
else if (fr->sendoffs == 0) { // start
|
|
buf->data[flagoffs] = CCNL_DTAG_FRAG_FLAG_FIRST;
|
|
}
|
|
else if (datalen >= (fr->bigpkt->datalen - fr->sendoffs)) { // end
|
|
buf->data[flagoffs] = CCNL_DTAG_FRAG_FLAG_LAST;
|
|
ccnl_free(fr->bigpkt);
|
|
fr->bigpkt = NULL;
|
|
}
|
|
else {
|
|
buf->data[flagoffs] = CCNL_DTAG_FRAG_FLAG_MID;
|
|
}
|
|
|
|
fr->sendoffs += datalen;
|
|
fr->sendseq++;
|
|
|
|
if (ifndx) {
|
|
*ifndx = fr->ifndx;
|
|
}
|
|
|
|
if (su) {
|
|
memcpy(su, &fr->dest, sizeof(*su));
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
struct ccnl_buf_s *
|
|
ccnl_frag_getnext(struct ccnl_frag_s *fr, int *ifndx, sockunion *su)
|
|
{
|
|
if (!fr->bigpkt) {
|
|
return NULL;
|
|
}
|
|
|
|
DEBUGMSG(99, "fragmenting %d bytes (@ %d)\n", fr->bigpkt->datalen,
|
|
fr->sendoffs);
|
|
|
|
switch (fr->protocol) {
|
|
case CCNL_FRAG_SEQUENCED2012:
|
|
return ccnl_frag_getnextSEQD2012(fr, ifndx, su);
|
|
|
|
case CCNL_FRAG_CCNx2013:
|
|
return ccnl_frag_getnextCCNx2013(fr, ifndx, su);
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
int ccnl_frag_nomorefragments(struct ccnl_frag_s *e)
|
|
{
|
|
if (!e || !e->bigpkt) {
|
|
return 1;
|
|
}
|
|
|
|
return e->bigpkt->datalen <= e->sendoffs;
|
|
}
|
|
|
|
void ccnl_frag_destroy(struct ccnl_frag_s *e)
|
|
{
|
|
if (e) {
|
|
ccnl_free(e->bigpkt);
|
|
ccnl_free(e->defrag);
|
|
ccnl_free(e);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
struct serialFragPDU_s { // collect all fields of a numbered HBH fragment
|
|
int contlen;
|
|
unsigned char *content;
|
|
unsigned int flags, ourseq, ourloss, yourseq, HAS;
|
|
unsigned char flagwidth, ourseqwidth, ourlosswidth, yourseqwidth;
|
|
};
|
|
|
|
void serialFragPDU_init(struct serialFragPDU_s *s)
|
|
{
|
|
memset(s, 0, sizeof(*s));
|
|
s->contlen = -1;
|
|
s->flagwidth = 1;
|
|
s->ourseqwidth = s->ourlosswidth = s->yourseqwidth = sizeof(int);
|
|
}
|
|
|
|
void ccnl_frag_RX_serialfragment(RX_datagram callback,
|
|
struct ccnl_relay_s *relay, struct ccnl_face_s *from,
|
|
struct serialFragPDU_s *s)
|
|
{
|
|
struct ccnl_buf_s *buf = NULL;
|
|
struct ccnl_frag_s *e = from->frag;
|
|
DEBUGMSG(8, " frag %p protocol=%d, flags=%04x, seq=%d (%d)\n", (void *) e,
|
|
e->protocol, s->flags, s->ourseq, e->recvseq);
|
|
|
|
if (e->recvseq != s->ourseq) {
|
|
// should increase error counter here
|
|
if (e->defrag) {
|
|
DEBUGMSG(17, " >> seqnum mismatch (%d/%d), dropped defrag buf\n",
|
|
s->ourseq, e->recvseq);
|
|
ccnl_free(e->defrag);
|
|
e->defrag = NULL;
|
|
}
|
|
}
|
|
|
|
switch (s->flags & (CCNL_DTAG_FRAG_FLAG_FIRST | CCNL_DTAG_FRAG_FLAG_LAST)) {
|
|
case CCNL_DTAG_FRAG_FLAG_SINGLE: // single packet
|
|
DEBUGMSG(17, " >> single fragment\n");
|
|
|
|
if (e->defrag) {
|
|
DEBUGMSG(18, " had to drop defrag buf\n");
|
|
ccnl_free(e->defrag);
|
|
e->defrag = NULL;
|
|
}
|
|
|
|
// no need to copy the buffer:
|
|
callback(relay, from, &s->content, &s->contlen);
|
|
return;
|
|
|
|
case CCNL_DTAG_FRAG_FLAG_FIRST: // start of fragment sequence
|
|
DEBUGMSG(17, " >> start of fragment series\n");
|
|
|
|
if (e->defrag) {
|
|
DEBUGMSG(18, " had to drop defrag buf\n");
|
|
ccnl_free(e->defrag);
|
|
}
|
|
|
|
e->defrag = ccnl_buf_new(s->content, s->contlen);
|
|
break;
|
|
|
|
case CCNL_DTAG_FRAG_FLAG_LAST: // end of fragment sequence
|
|
DEBUGMSG(17, " >> last fragment of a series\n");
|
|
|
|
if (!e->defrag) {
|
|
break;
|
|
}
|
|
|
|
buf = ccnl_buf_new(NULL, e->defrag->datalen + s->contlen);
|
|
|
|
if (buf) {
|
|
memcpy(buf->data, e->defrag->data, e->defrag->datalen);
|
|
memcpy(buf->data + e->defrag->datalen, s->content, s->contlen);
|
|
}
|
|
|
|
ccnl_free(e->defrag);
|
|
e->defrag = NULL;
|
|
break;
|
|
|
|
case CCNL_DTAG_FRAG_FLAG_MID: // fragment in the middle of a squence
|
|
default:
|
|
DEBUGMSG(17, " >> fragment in the middle of a series\n");
|
|
|
|
if (!e->defrag) {
|
|
break;
|
|
}
|
|
|
|
buf = ccnl_buf_new(NULL, e->defrag->datalen + s->contlen);
|
|
|
|
if (buf) {
|
|
memcpy(buf->data, e->defrag->data, e->defrag->datalen);
|
|
memcpy(buf->data + e->defrag->datalen, s->content, s->contlen);
|
|
ccnl_free(e->defrag);
|
|
e->defrag = buf;
|
|
buf = NULL;
|
|
}
|
|
else {
|
|
ccnl_free(e->defrag);
|
|
e->defrag = NULL;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// FIXME: we should only bump recvseq if s->ourseq is ahead, or 0
|
|
e->recvseq = s->ourseq + 1;
|
|
DEBUGMSG(1, ">>> seq from %d to %d (w=%d)\n", s->ourseq, e->recvseq,
|
|
s->ourseqwidth);
|
|
|
|
if (buf) {
|
|
unsigned char *frag = buf->data;
|
|
int fraglen = buf->datalen;
|
|
DEBUGMSG(1, " >> reassembled fragment is %d bytes\n", buf->datalen);
|
|
callback(relay, from, &frag, &fraglen);
|
|
ccnl_free(buf);
|
|
}
|
|
|
|
DEBUGMSG(1, "leaving function\n");
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
#define getNumField(var,len,flag,rem) \
|
|
DEBUGMSG(19, " parsing " rem "\n"); \
|
|
if (unmkBinaryInt(data, datalen, &var, &len) != 0) \
|
|
goto Bail; \
|
|
s.HAS |= flag
|
|
#define HAS_FLAGS 0x01
|
|
#define HAS_OSEQ 0x02
|
|
#define HAS_OLOS 0x04
|
|
#define HAS_YSEQ 0x08
|
|
|
|
int ccnl_frag_RX_frag2012(RX_datagram callback, struct ccnl_relay_s *relay,
|
|
struct ccnl_face_s *from, unsigned char **data, int *datalen)
|
|
{
|
|
int num, typ;
|
|
struct serialFragPDU_s s;
|
|
DEBUGMSG(99, "ccnl_frag_RX_frag2012 (%d bytes)\n", *datalen);
|
|
|
|
serialFragPDU_init(&s);
|
|
|
|
while (dehead(data, datalen, &num, &typ) == 0) {
|
|
if (num == 0 && typ == 0) {
|
|
break; // end
|
|
}
|
|
|
|
if (typ == CCN_TT_DTAG) {
|
|
switch (num) {
|
|
case CCN_DTAG_CONTENT:
|
|
DEBUGMSG(18, " frag content\n");
|
|
|
|
// if (s.content) // error: more than one content entry
|
|
if (consume(typ, num, data, datalen, &s.content, &s.contlen)
|
|
< 0) {
|
|
goto Bail;
|
|
}
|
|
|
|
continue;
|
|
|
|
case CCNL_DTAG_FRAG_FLAGS:
|
|
getNumField(s.flags, s.flagwidth, HAS_FLAGS, "flags")
|
|
;
|
|
continue;
|
|
|
|
case CCNL_DTAG_FRAG_SEQNR:
|
|
getNumField(s.ourseq, s.ourseqwidth, HAS_OSEQ, "ourseq")
|
|
;
|
|
continue;
|
|
|
|
case CCNL_DTAG_FRAG_OLOSS:
|
|
getNumField(s.ourloss, s.ourlosswidth, HAS_OLOS, "ourloss")
|
|
;
|
|
continue;
|
|
|
|
case CCNL_DTAG_FRAG_YSEQN:
|
|
getNumField(s.yourseq, s.yourseqwidth, HAS_YSEQ, "yourseq")
|
|
;
|
|
continue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (consume(typ, num, data, datalen, 0, 0) < 0) {
|
|
goto Bail;
|
|
}
|
|
}
|
|
|
|
if (!s.content || s.HAS != 15) {
|
|
DEBUGMSG(1, "* incomplete frag\n");
|
|
return 0;
|
|
}
|
|
|
|
if (from) {
|
|
if (!from->frag)
|
|
from->frag = ccnl_frag_new(CCNL_FRAG_SEQUENCED2012,
|
|
relay->ifs[from->ifndx].mtu);
|
|
|
|
if (from->frag && from->frag->protocol == CCNL_FRAG_SEQUENCED2012) {
|
|
ccnl_frag_RX_serialfragment(callback, relay, from, &s);
|
|
}
|
|
else {
|
|
DEBUGMSG(1, "WRONG FRAG PROTOCOL\n");
|
|
}
|
|
}
|
|
else {
|
|
ccnl_frag_RX_serialfragment(callback, relay, from, &s);
|
|
}
|
|
|
|
return 0;
|
|
Bail:
|
|
DEBUGMSG(1, "* frag bailing\n");
|
|
return -1;
|
|
}
|
|
|
|
int ccnl_frag_RX_CCNx2013(RX_datagram callback, struct ccnl_relay_s *relay,
|
|
struct ccnl_face_s *from, unsigned char **data, int *datalen)
|
|
{
|
|
int rc, num, typ, pdutypelen;
|
|
unsigned char *pdutype = 0;
|
|
struct serialFragPDU_s s;
|
|
|
|
DEBUGMSG(99, "ccnl_frag_RX_CCNx2013 (%d bytes)\n", *datalen);
|
|
serialFragPDU_init(&s);
|
|
|
|
while (dehead(data, datalen, &num, &typ) == 0) {
|
|
if (num == 0 && typ == 0) {
|
|
break; // end
|
|
}
|
|
|
|
if (typ == CCN_TT_DTAG) {
|
|
switch (num) {
|
|
case CCNL_DTAG_FRAG_TYPE:
|
|
if (hunt_for_end(data, datalen, &pdutype, &pdutypelen)
|
|
|| pdutypelen != 3) {
|
|
goto Bail;
|
|
}
|
|
|
|
continue;
|
|
|
|
case CCNL_DTAG_FRAG_SEQNR:
|
|
getNumField(s.ourseq, s.ourseqwidth, HAS_OSEQ, "ourseq")
|
|
;
|
|
continue;
|
|
|
|
case CCNL_DTAG_FRAG_FLAGS:
|
|
getNumField(s.flags, s.flagwidth, HAS_FLAGS, "flags")
|
|
;
|
|
continue;
|
|
|
|
case CCN_DTAG_CONTENT:
|
|
|
|
// if (frag) // error: more than one content entry
|
|
if (consume(typ, num, data, datalen, &s.content, &s.contlen)
|
|
< 0) {
|
|
goto Bail;
|
|
}
|
|
|
|
continue;
|
|
|
|
// CCNL extensions:
|
|
case CCN_DTAG_INTEREST:
|
|
case CCN_DTAG_CONTENTOBJ:
|
|
rc = ccnl_core_RX_i_or_c(relay, from, data, datalen);
|
|
|
|
if (rc < 0) {
|
|
return rc;
|
|
}
|
|
|
|
continue;
|
|
|
|
case CCNL_DTAG_FRAG_OLOSS:
|
|
getNumField(s.ourloss, s.ourlosswidth, HAS_OLOS, "ourloss")
|
|
;
|
|
continue;
|
|
|
|
case CCNL_DTAG_FRAG_YSEQN:
|
|
getNumField(s.yourseq, s.yourseqwidth, HAS_YSEQ, "yourseq")
|
|
;
|
|
continue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (consume(typ, num, data, datalen, 0, 0) < 0) {
|
|
goto Bail;
|
|
}
|
|
}
|
|
|
|
if (!pdutype || !s.content) {
|
|
/* ||
|
|
(s.HAS&(HAS_FLAGS|HAS_OSEQ)) != (HAS_FLAGS|HAS_OSEQ) ) {
|
|
*/
|
|
DEBUGMSG(1, "* incomplete frag\n");
|
|
return 0;
|
|
}
|
|
|
|
DEBUGMSG(1, "hop-by-hop\n");
|
|
|
|
if (memcmp(pdutype, CCNL_FRAG_TYPE_CCNx2013_VAL, 3) == 0) { // hop-by-hop
|
|
if (from) {
|
|
if (!from->frag)
|
|
from->frag = ccnl_frag_new(CCNL_FRAG_CCNx2013,
|
|
relay->ifs[from->ifndx].mtu);
|
|
|
|
if (from->frag && from->frag->protocol == CCNL_FRAG_CCNx2013) {
|
|
ccnl_frag_RX_serialfragment(callback, relay, from, &s);
|
|
}
|
|
else {
|
|
DEBUGMSG(1, "WRONG FRAG PROTOCOL\n");
|
|
}
|
|
}
|
|
else {
|
|
ccnl_frag_RX_serialfragment(callback, relay, from, &s);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* echo "FMTE" | base64 -d | hexdump -v -e '/1 "@x%02x"'| tr @ '\\'; echo
|
|
*/
|
|
if (memcmp(pdutype, "\x14\xc4\xc4", 3) == 0) { // mid-to-end fragment
|
|
// not implemented yet
|
|
}
|
|
|
|
DEBUGMSG(1, "mid-to-end fragment\n");
|
|
|
|
return 0;
|
|
Bail:
|
|
DEBUGMSG(1, "* frag bailing\n");
|
|
return -1;
|
|
}
|
|
|
|
#endif // USE_FRAG
|
|
// eof
|