Contiki 2.5
bundle.c
Go to the documentation of this file.
1 /**
2  * \addtogroup bundle
3  *
4  * @{
5  */
6 
7 /**
8  * \file
9  * \brief this file implements the bundle memory representation
10  *
11  * \author Georg von Zengen (vonzeng@ibr.cs.tu-bs.de)
12  * \author Daniel Willmann <daniel@totalueberwachung.de>
13  * \author Wolf-Bastian Poettner <poettner@ibr.cs.tu-bs.de>
14  */
15 
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 
20 #include "mmem.h"
21 #include "sys/process.h"
22 #include "clock.h"
23 #include "logging.h"
24 
25 #include "sdnv.h"
26 #include "bundleslot.h"
27 #include "agent.h"
28 
29 #include "bundle.h"
30 
31 /**
32  * "Internal" functions
33  */
34 static uint8_t bundle_decode_block(struct mmem *bundlemem, uint8_t *buffer, int max_len);
35 static int bundle_encode_block(struct bundle_block_t *block, uint8_t *buffer, uint8_t max_len);
36 
37 
38 struct mmem * bundle_create_bundle()
39 {
40  int ret;
41  struct bundle_slot_t *bs;
42  struct bundle_t *bundle;
43 
44  bs = bundleslot_get_free();
45 
46  if( bs == NULL ) {
47  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Could not allocate slot for a bundle");
48  return NULL;
49  }
50 
51  ret = mmem_alloc(&bs->bundle, sizeof(struct bundle_t));
52  if (!ret) {
53  bundleslot_free(bs);
54  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Could not allocate memory for a bundle");
55  return NULL;
56  }
57 
58  bundle = (struct bundle_t *) MMEM_PTR(&bs->bundle);
59  memset(bundle, 0, sizeof(struct bundle_t));
60  bundle->rec_time=(uint32_t) clock_seconds();
61  bundle->num_blocks = 0;
62  bundle->source_process = PROCESS_CURRENT();
63 
64  return &bs->bundle;
65 }
66 
67 int bundle_add_block(struct mmem *bundlemem, uint8_t type, uint8_t flags, uint8_t *data, uint8_t d_len)
68 {
69  struct bundle_t *bundle;
70  struct bundle_block_t *block;
71  uint8_t i;
72  int n;
73 
74  n = mmem_realloc(bundlemem, bundlemem->size + d_len + sizeof(struct bundle_block_t));
75  if( !n ) {
76  return -1;
77  }
78 
79  bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
80 
81  /* FIXME: Make sure we don't traverse outside of our allocated memory */
82 
83  /* Go through the blocks until we're behind the last one */
84  block = (struct bundle_block_t *) bundle->block_data;
85  for (i=0;i<bundle->num_blocks;i++) {
86  /* None of these is the last block anymore */
87  block->flags &= ~BUNDLE_BLOCK_FLAG_LAST;
88  block = (struct bundle_block_t *) &block->payload[block->block_size];
89  }
90 
91  block->type = type;
92  block->flags = BUNDLE_BLOCK_FLAG_LAST | flags;
93  block->block_size = d_len;
94 
95  bundle->num_blocks++;
96 
97  memcpy(block->payload, data, d_len);
98 
99  return d_len;
100 }
101 
102 struct bundle_block_t *bundle_get_block(struct mmem *bundlemem, uint8_t i)
103 {
104  struct bundle_t *bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
105  struct bundle_block_t *block = (struct bundle_block_t *) bundle->block_data;
106 
107  if (i >= bundle->num_blocks)
108  return NULL;
109 
110  for (;i!=0;i--) {
111  block = (struct bundle_block_t *) &block->payload[block->block_size];
112  }
113 
114  return block;
115 }
116 
117 struct bundle_block_t *bundle_get_block_by_type(struct mmem *bundlemem, uint8_t type)
118 {
119  struct bundle_t *bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
120  struct bundle_block_t *block = (struct bundle_block_t *) bundle->block_data;
121  int i = 0;
122 
123  for(i=0; i<bundle->num_blocks; i++) {
124  if( block->type == type ) {
125  return block;
126  }
127 
128  block = (struct bundle_block_t *) &block->payload[block->block_size];
129  }
130 
131  return NULL;
132 }
133 
134 struct bundle_block_t * bundle_get_payload_block(struct mmem * bundlemem) {
135  return bundle_get_block_by_type(bundlemem, BUNDLE_BLOCK_TYPE_PAYLOAD);
136 }
137 
138 uint8_t bundle_set_attr(struct mmem *bundlemem, uint8_t attr, uint32_t *val)
139 {
140  struct bundle_t *bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
141  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_DBG, "set attr %lx",*val);
142  switch (attr) {
143  case FLAGS:
144  bundle->flags = *val;
145  bundle->custody = 0x08 &(uint8_t) *val;
146  break;
147  case DEST_NODE:
148  bundle->dst_node = *val;
149  break;
150  case DEST_SERV:
151  bundle->dst_srv = *val;
152  break;
153  case SRC_NODE:
154  bundle->src_node = *val;
155  break;
156  case SRC_SERV:
157  bundle->src_srv = *val;
158  break;
159  case REP_NODE:
160  bundle->rep_node = *val;
161  break;
162  case REP_SERV:
163  bundle->rep_srv = *val;
164  break;
165  case CUST_NODE:
166  bundle->cust_node = *val;
167  break;
168  case CUST_SERV:
169  bundle->cust_srv = *val;
170  break;
171  case TIME_STAMP:
172  bundle->tstamp = *val;
173  break;
174  case TIME_STAMP_SEQ_NR:
175  bundle->tstamp_seq = *val;
176  break;
177  case LIFE_TIME:
178  bundle->lifetime = *val;
179  break;
180  case DIRECTORY_LEN:
181  if (*val != 0)
182  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Dictionary length needs to be 0 for CBHE");
183  break;
184  case FRAG_OFFSET:
185  bundle->frag_offs = *val;
186  break;
187  case LENGTH:
188  /* FIXME */
189  default:
190  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Unknown attribute");
191  return 0;
192  }
193  return 1;
194 }
195 
196 uint8_t bundle_get_attr(struct mmem *bundlemem, uint8_t attr, uint32_t *val)
197 {
198  struct bundle_t *bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
199  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_DBG, "get attr: %d in %lx", attr, *val);
200  switch (attr) {
201  case FLAGS:
202  *val = bundle->flags;
203  break;
204  case DEST_NODE:
205  *val = bundle->dst_node;
206  break;
207  case DEST_SERV:
208  *val = bundle->dst_srv;
209  break;
210  case SRC_NODE:
211  *val = bundle->src_node;
212  break;
213  case SRC_SERV:
214  *val = bundle->src_srv;
215  break;
216  case REP_NODE:
217  *val = bundle->rep_node;
218  break;
219  case REP_SERV:
220  *val = bundle->rep_srv;
221  break;
222  case CUST_NODE:
223  *val = bundle->cust_node;
224  break;
225  case CUST_SERV:
226  *val = bundle->cust_srv;
227  break;
228  case TIME_STAMP:
229  *val = bundle->tstamp;
230  break;
231  case TIME_STAMP_SEQ_NR:
232  *val = bundle->tstamp_seq;
233  break;
234  case LIFE_TIME:
235  *val = bundle->lifetime;
236  break;
237  case DIRECTORY_LEN:
238  *val = 0;
239  break;
240  case FRAG_OFFSET:
241  *val = bundle->frag_offs;
242  break;
243  case LENGTH:
244  /* FIXME */
245  default:
246  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Unknown attribute");
247  return 0;
248  }
249  return 1;
250 }
251 
252 struct mmem *bundle_recover_bundle(uint8_t *buffer, int size)
253 {
254  uint32_t primary_size, value;
255  uint8_t offs = 0;
256  struct mmem *bundlemem;
257  struct bundle_t *bundle;
258  uint8_t ret = 0;
259 
260  bundlemem = bundle_create_bundle();
261  if (!bundlemem)
262  return NULL;
263 
264  bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
265 
266  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_DBG, "rec bptr: %p blptr:%p",bundle,buffer);
267 
268  /* Version 0x06 is the one described and supported in RFC5050 */
269  if (buffer[0] != 0x06) {
270  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Version 0x%02x not supported", buffer[0]);
271  goto err;
272  }
273  offs++;
274 
275  /* Flags */
276  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->flags);
277 
278  /* Block Length - Number of bytes in this block following this
279  * field */
280  offs += sdnv_decode(&buffer[offs], size-offs, &primary_size);
281  primary_size += offs;
282 
283  /* Destination node + SSP */
284  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->dst_node);
285  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->dst_srv);
286 
287  /* Source node + SSP */
288  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->src_node);
289  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->src_srv);
290 
291  /* Report-to node + SSP */
292  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->rep_node);
293  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->rep_srv);
294 
295  /* Custodian node + SSP */
296  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->cust_node);
297  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->cust_srv);
298 
299  /* Creation Timestamp */
300  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->tstamp);
301 
302  /* Creation Timestamp Sequence Number */
303  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->tstamp_seq);
304 
305  /* Lifetime */
306  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->lifetime);
307 
308  /* Directory Length */
309  offs += sdnv_decode(&buffer[offs], size-offs, &value);
310  if (value != 0) {
311  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Bundle does not use CBHE.");
312  goto err;
313  }
314 
315  if (bundle->flags & BUNDLE_FLAG_FRAGMENT) {
316  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_INF, "Bundle is a fragment");
317 
318  /* Fragment Offset */
319  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->frag_offs);
320 
321  /* Total App Data Unit Length */
322  offs += sdnv_decode(&buffer[offs], size-offs, &bundle->app_len);
323  }
324 
325  if (offs != primary_size) {
326  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Problem decoding the primary bundle block.");
327  goto err;
328  }
329 
330  /* FIXME: Loop around and decode all blocks - does this work? */
331  while (size-offs > 1) {
332  ret = bundle_decode_block(bundlemem, &buffer[offs], size-offs);
333 
334  /* If block decode failed, we are out of memory and have to abort */
335  if( ret < 1 ) {
336  goto err;
337  }
338 
339  offs += ret;
340  }
341 
342  return bundlemem;
343 
344 err:
345  bundle_delete_bundle(bundlemem);
346  return NULL;
347 
348 }
349 
350 static uint8_t bundle_decode_block(struct mmem *bundlemem, uint8_t *buffer, int max_len)
351 {
352  uint8_t type, block_offs, offs = 0;
353  uint32_t flags, size;
354  struct bundle_t *bundle;
355  struct bundle_block_t *block;
356  int n;
357 
358  type = buffer[offs];
359  offs++;
360 
361  /* Flags */
362  offs += sdnv_decode(&buffer[offs], max_len-offs, &flags);
363 
364  /* Payload Size */
365  offs += sdnv_decode(&buffer[offs], max_len-offs, &size);
366  if (size > max_len-offs) {
367  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Bundle payload length too big.");
368  return 0;
369  }
370 
371  block_offs = bundlemem->size;
372 
373  n = mmem_realloc(bundlemem, bundlemem->size + sizeof(struct bundle_block_t) + size);
374  if( !n ) {
375  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Bundle payload length too big for MMEM.");
376  return 0;
377  }
378 
379  bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
380  bundle->num_blocks++;
381 
382  /* Add the block to the end of the bundle */
383  block = (struct bundle_block_t *)((uint8_t *)bundle + block_offs);
384  block->type = type;
385  block->flags = flags;
386  block->block_size = size;
387 
388  /* Copy the actual payload over */
389  memcpy(block->payload, &buffer[offs], block->block_size);
390 
391  return offs + block->block_size;
392 }
393 
394 int bundle_encode_bundle(struct mmem *bundlemem, uint8_t *buffer, int max_len)
395 {
396  uint32_t value;
397  uint8_t offs = 0, blklen_offs, i;
398  int ret, blklen_size;
399  struct bundle_t *bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
400  struct bundle_block_t *block;
401 
402  /* Hardcode the version to 0x06 */
403  buffer[0] = 0x06;
404  offs++;
405 
406  /* Flags */
407  ret = sdnv_encode(bundle->flags, &buffer[offs], max_len - offs);
408  if (ret < 0)
409  return -1;
410  offs += ret;
411 
412  /* Block length will be calculated later
413  * reserve one byte for now */
414  blklen_offs = offs;
415  offs++;
416 
417  /* Destination node + SSP */
418  ret = sdnv_encode(bundle->dst_node, &buffer[offs], max_len - offs);
419  if (ret < 0)
420  return -1;
421  offs += ret;
422 
423  ret = sdnv_encode(bundle->dst_srv, &buffer[offs], max_len - offs);
424  if (ret < 0)
425  return -1;
426  offs += ret;
427 
428  /* Source node + SSP */
429  ret = sdnv_encode(bundle->src_node, &buffer[offs], max_len - offs);
430  if (ret < 0)
431  return -1;
432  offs += ret;
433 
434  ret = sdnv_encode(bundle->src_srv, &buffer[offs], max_len - offs);
435  if (ret < 0)
436  return -1;
437  offs += ret;
438 
439  /* Report-to node + SSP */
440  ret = sdnv_encode(bundle->rep_node, &buffer[offs], max_len - offs);
441  if (ret < 0)
442  return -1;
443  offs += ret;
444 
445  ret = sdnv_encode(bundle->rep_srv, &buffer[offs], max_len - offs);
446  if (ret < 0)
447  return -1;
448  offs += ret;
449 
450  /* Custodian node + SSP */
451  ret = sdnv_encode(bundle->cust_node, &buffer[offs], max_len - offs);
452  if (ret < 0)
453  return -1;
454  offs += ret;
455 
456  ret = sdnv_encode(bundle->cust_srv, &buffer[offs], max_len - offs);
457  if (ret < 0)
458  return -1;
459  offs += ret;
460 
461  /* Creation Timestamp */
462  ret = sdnv_encode(bundle->tstamp, &buffer[offs], max_len - offs);
463  if (ret < 0)
464  return -1;
465  offs += ret;
466 
467  /* Creation Timestamp Sequence Number */
468  ret = sdnv_encode(bundle->tstamp_seq, &buffer[offs], max_len - offs);
469  if (ret < 0)
470  return -1;
471  offs += ret;
472 
473  /* Lifetime */
474  ret = sdnv_encode(bundle->lifetime, &buffer[offs], max_len - offs);
475  if (ret < 0)
476  return -1;
477  offs += ret;
478 
479  /* Directory Length */
480  ret = sdnv_encode(0l, &buffer[offs], max_len - offs);
481  if (ret < 0)
482  return -1;
483  offs += ret;
484 
485  if (bundle->flags & BUNDLE_FLAG_FRAGMENT) {
486  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_INF, "Bundle is a fragment");
487 
488  /* Fragment Offset */
489  ret = sdnv_encode(bundle->frag_offs, &buffer[offs], max_len - offs);
490  if (ret < 0)
491  return -1;
492  offs += ret;
493 
494  /* Total App Data Unit Length */
495  ret = sdnv_encode(bundle->app_len, &buffer[offs], max_len - offs);
496  if (ret < 0)
497  return -1;
498  offs += ret;
499  }
500 
501  /* Calculate block length value */
502  value = offs - blklen_offs - 1;
503  blklen_size = sdnv_encoding_len(value);
504  /* Move the data around */
505  if (blklen_size > 1) {
506  memmove(&buffer[blklen_offs+blklen_size], &buffer[blklen_offs+1], value);
507  }
508  ret = sdnv_encode(value, &buffer[blklen_offs], blklen_size);
509 
510  offs += ret-1;
511 
512  block = (struct bundle_block_t *) bundle->block_data;
513  for (i=0;i<bundle->num_blocks;i++) {
514  offs += bundle_encode_block(block, &buffer[offs], max_len - offs);
515  /* Reference the next block */
516  block = (struct bundle_block_t *) &block->payload[block->block_size];
517  }
518 
519  return offs;
520 }
521 
522 static int bundle_encode_block(struct bundle_block_t *block, uint8_t *buffer, uint8_t max_len)
523 {
524  uint8_t offs = 0;
525  int ret;
526  uint32_t value;
527 
528  /* Encode the next block */
529  buffer[offs] = block->type;
530  offs++;
531 
532  /* Flags */
533  ret = sdnv_encode(block->flags, &buffer[offs], max_len - offs);
534  if (ret < 0)
535  return -1;
536  offs += ret;
537 
538  /* Blocksize */
539  value = block->block_size;
540  ret = sdnv_encode(value, &buffer[offs], max_len - offs);
541  if (ret < 0)
542  return -1;
543  offs += ret;
544 
545  /* Payload */
546  memcpy(&buffer[offs], block->payload, block->block_size);
547  offs += block->block_size;
548 
549  return offs;
550 }
551 
552 int bundle_increment(struct mmem *bundlemem)
553 {
554  struct bundle_slot_t *bs;
555  struct bundle_t *bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
556  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_DBG, "bundle_increment(%p) %u", bundle, bundle->rec_time);
557 
558  bs = container_of(bundlemem, struct bundle_slot_t, bundle);
559  return bundleslot_increment(bs);
560 }
561 
562 int bundle_decrement(struct mmem *bundlemem)
563 {
564  struct bundle_slot_t *bs;
565  struct bundle_t *bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
566  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_DBG, "bundle_decrement(%p) %u", bundle, bundle->rec_time);
567 
568  bs = container_of(bundlemem, struct bundle_slot_t, bundle);
569  return bundleslot_decrement(bs);
570 }
571 
572 uint16_t bundle_delete_bundle(struct mmem *bundlemem)
573 {
574  struct bundle_slot_t *bs;
575  struct bundle_t *bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
576  LOG(LOGD_DTN, LOG_BUNDLE, LOGL_DBG, "delete %p %u", bundle,bundle->rec_time);
577 
578  bs = container_of(bundlemem, struct bundle_slot_t, bundle);
579  bundleslot_free(bs);
580  return 1;
581 }
582 
583 rimeaddr_t convert_eid_to_rime(uint32_t eid) {
584  rimeaddr_t dest;
585  dest.u8[1] = (eid & 0x000000FF) >> 0;
586  dest.u8[0] = (eid & 0x0000FF00) >> 8;
587  return dest;
588 }
589 
590 uint32_t convert_rime_to_eid(rimeaddr_t * dest) {
591  uint32_t eid = 0;
592  eid = (dest->u8[1] & 0xFF) + ((dest->u8[0] & 0xFF) << 8);
593  return eid;
594 }