[Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/c/blip/driver Makefile, NONE, 1.1 config.c, NONE, 1.1 config.h, NONE, 1.1 hashtable.c, NONE, 1.1 hashtable.h, NONE, 1.1 hashtable_private.h, NONE, 1.1 logging.c, NONE, 1.1 logging.h, NONE, 1.1 nwstate.c, NONE, 1.1 nwstate.h, NONE, 1.1 radvd-wrapper.c, NONE, 1.1 routing.c, NONE, 1.1 routing.h, NONE, 1.1 serial_tun.c, NONE, 1.1 tun_dev.c, NONE, 1.1 tun_dev.h, NONE, 1.1 tunnel.c, NONE, 1.1

sdhsdh sdhsdh at users.sourceforge.net
Mon Jan 19 16:28:16 PST 2009


Update of /cvsroot/tinyos/tinyos-2.x/support/sdk/c/blip/driver
In directory ddv4jf1.ch3.sourceforge.com:/tmp/cvs-serv6583/support/sdk/c/blip/driver

Added Files:
	Makefile config.c config.h hashtable.c hashtable.h 
	hashtable_private.h logging.c logging.h nwstate.c nwstate.h 
	radvd-wrapper.c routing.c routing.h serial_tun.c tun_dev.c 
	tun_dev.h tunnel.c 
Log Message:
 - initial commit of blip (berkeley low-power ip) stack


--- NEW FILE: Makefile ---

SOURCES=serial_tun.c tun_dev.c hashtable.c routing.c nwstate.c \
	logging.c config.c radvd-wrapper.c

COMMON_SRC = radvd/log.c radvd/socket.c radvd/recv.c radvd/util.c radvd/radvd.h \
	radvd/defaults.h radvd/pathnames.h \
        radvd/includes.h
radvd_SOURCES = $(COMMON_SRC) radvd/timer.c radvd/send.c radvd/process.c radvd/interface.c \
        radvd/device.c radvd/device-common.c radvd/gram.h 

LIBS=../lib6lowpan.a ${TOSROOT}/support/sdk/c/sf/libmote.a 
TARGET=ip-driver
INCLUDE=../include/

ifndef GCC
GCC=gcc
endif

TFLAGS=-Wall -g -DPC
TFLAGS+=-I${TOSROOT}/support/sdk/c/sf -I$(INCLUDE) -Iradvd/


ifneq ($(filter sim-null,$(MAKECMDGOALS)),)
  TFLAGS+=-DSIM
endif

# CFLAGS+=-DFULL_PATH_INSTALL
all: $(TARGET)

sim: lib
	make $(TARGET) sim-null

sim-null:
	echo Built $(TARGET) for TOSSIM

$(TARGET): $(SOURCES) $(LIBS)
	$(GCC) $(TFLAGS) $(CFLAGS) -o $(TARGET) $(SOURCES) $(radvd_SOURCES) $(LIBS) -lm

clean:
	rm $(TARGET)


--- NEW FILE: config.c ---

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "ip.h"
#include "config.h"
#include "logging.h"

#define BUF_LEN 200

void rm_comment (char *buf) {
  while (*buf != '#' && *buf != '\0')
    buf++;
  *buf = '\0';
}

void upd_start(char **buf) {
  while ((**buf == ' ' || **buf == '\t' || **buf == '\n') && **buf != '\0')
    *buf = (*buf) + 1;
}

int config_parse(const char *file, struct config *c) {
  char *buf, real_buf[BUF_LEN], arg[BUF_LEN];
  FILE *fp = fopen(file, "r");
  int gotargs = 0;
  if (fp == NULL) return 1;

  while (fgets(real_buf, BUF_LEN, fp) != NULL) {
    buf = real_buf;
    rm_comment(buf);
    upd_start(&buf);
    if (sscanf(buf, "addr %s\n", arg) > 0) {
      inet_pton6(arg, &c->router_addr);
      gotargs ++;
    } else if (sscanf(buf, "proxy %s\n", c->proxy_dev) > 0) {
      gotargs ++;
    } else if (sscanf(buf, "channel %i\n", &c->channel) > 0) {
      if (c->channel < 11 || c->channel > 26) {
        fatal("Invalid channel specified in '%s'\n", file);
        exit(1);
      }
      gotargs ++;
    } else if (sscanf(buf, "log %s\n", arg) > 0) {
      int i;
      for (i = 0; i < 5; i++) {
        if (strncmp(log_names[i], arg, strlen(log_names[i])) == 0) {
          info("Read log level: %s\n", arg);
          log_setlevel(i);
          break;
        }
      }
    } else if (*buf != '\0') {
      // anything else indicates that there's invalid input.
      return 1;
    }
  }
  fclose(fp);

  if (gotargs != 3) return 1;

  info("Read config from '%s'\n", file);
  info("\tProxying neighbor advertisements to %s\n", c->proxy_dev);
  info("\tUsing channel %i\n", c->channel);
  return 0;
}

int config_print(struct config *c) {
  char buf[64];
  printf ("configuration:\n");
  inet_ntop(AF_INET6, &c->router_addr, buf, 64);
  printf ("  router address: %s\n", buf);
  printf("  proxy dev: %s\n", c->proxy_dev);
  printf("  channel: %i\n", c->channel);
  return 0;
}

--- NEW FILE: config.h ---
#ifndef _CONFIG_H
#define _CONFIG_H

#include <net/if.h>

struct config {
  struct in6_addr router_addr;
  char proxy_dev[IFNAMSIZ];
  int channel;
};


int config_parse(const char *file, struct config *c);
int config_print(struct config *c);

#endif

--- NEW FILE: hashtable.c ---
/* Copyright (C) 2004 Christopher Clark <firstname.lastname at cl.cam.ac.uk> */

#include "hashtable.h"
#include "hashtable_private.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

/*
Credit for primes table: Aaron Krowne
 http://br.endernet.org/~akrowne/
 http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
*/
static const unsigned int primes[] = {
53, 97, 193, 389,
769, 1543, 3079, 6151,
12289, 24593, 49157, 98317,
196613, 393241, 786433, 1572869,
3145739, 6291469, 12582917, 25165843,
50331653, 100663319, 201326611, 402653189,
805306457, 1610612741
};
const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
const float max_load_factor = 0.65;

/*****************************************************************************/
struct hashtable *
create_hashtable(unsigned int minsize,
                 unsigned int (*hashf) (void*),
                 int (*eqf) (void*,void*))
{
    struct hashtable *h;
    unsigned int pindex, size = primes[0];
    /* Check requested hashtable isn't too large */
    if (minsize > (1u << 30)) return NULL;
    /* Enforce size as prime */
    for (pindex=0; pindex < prime_table_length; pindex++) {
        if (primes[pindex] > minsize) { size = primes[pindex]; break; }
    }
    h = (struct hashtable *)malloc(sizeof(struct hashtable));
    if (NULL == h) return NULL; /*oom*/
    h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
    if (NULL == h->table) { free(h); return NULL; } /*oom*/
    memset(h->table, 0, size * sizeof(struct entry *));
    h->tablelength  = size;
    h->primeindex   = pindex;
    h->entrycount   = 0;
    h->hashfn       = hashf;
    h->eqfn         = eqf;
    h->loadlimit    = (unsigned int) ceil(size * max_load_factor);
    return h;
}

/*****************************************************************************/
unsigned int
hash(struct hashtable *h, void *k)
{
    /* Aim to protect against poor hash functions by adding logic here
     * - logic taken from java 1.4 hashtable source */
    unsigned int i = h->hashfn(k);
    i += ~(i << 9);
    i ^=  ((i >> 14) | (i << 18)); /* >>> */
    i +=  (i << 4);
    i ^=  ((i >> 10) | (i << 22)); /* >>> */
    return i;
}

/*****************************************************************************/
static int
hashtable_expand(struct hashtable *h)
{
    /* Double the size of the table to accomodate more entries */
    struct entry **newtable;
    struct entry *e;
    struct entry **pE;
    unsigned int newsize, i, index;
    /* Check we're not hitting max capacity */
    if (h->primeindex == (prime_table_length - 1)) return 0;
    newsize = primes[++(h->primeindex)];

    newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
    if (NULL != newtable)
    {
        memset(newtable, 0, newsize * sizeof(struct entry *));
        /* This algorithm is not 'stable'. ie. it reverses the list
         * when it transfers entries between the tables */
        for (i = 0; i < h->tablelength; i++) {
            while (NULL != (e = h->table[i])) {
                h->table[i] = e->next;
                index = indexFor(newsize,e->h);
                e->next = newtable[index];
                newtable[index] = e;
            }
        }
        free(h->table);
        h->table = newtable;
    }
    /* Plan B: realloc instead */
    else 
    {
        newtable = (struct entry **)
                   realloc(h->table, newsize * sizeof(struct entry *));
        if (NULL == newtable) { (h->primeindex)--; return 0; }
        h->table = newtable;
        memset(newtable[h->tablelength], 0, newsize - h->tablelength);
        for (i = 0; i < h->tablelength; i++) {
            for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
                index = indexFor(newsize,e->h);
                if (index == i)
                {
                    pE = &(e->next);
                }
                else
                {
                    *pE = e->next;
                    e->next = newtable[index];
                    newtable[index] = e;
                }
            }
        }
    }
    h->tablelength = newsize;
    h->loadlimit   = (unsigned int) ceil(newsize * max_load_factor);
    return -1;
}

/*****************************************************************************/
unsigned int
hashtable_count(struct hashtable *h)
{
    return h->entrycount;
}

/*****************************************************************************/
int
hashtable_insert(struct hashtable *h, void *k, void *v)
{
    /* This method allows duplicate keys - but they shouldn't be used */
    unsigned int index;
    struct entry *e;
    if (++(h->entrycount) > h->loadlimit)
    {
        /* Ignore the return value. If expand fails, we should
         * still try cramming just this value into the existing table
         * -- we may not have memory for a larger table, but one more
         * element may be ok. Next time we insert, we'll try expanding again.*/
        hashtable_expand(h);
    }
    e = (struct entry *)malloc(sizeof(struct entry));
    if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
    e->h = hash(h,k);
    index = indexFor(h->tablelength,e->h);
    e->k = k;
    e->v = v;
    e->next = h->table[index];
    h->table[index] = e;
    return -1;
}

/*****************************************************************************/
void * /* returns value associated with key */
hashtable_search(struct hashtable *h, void *k)
{
    struct entry *e;
    unsigned int hashvalue, index;
    hashvalue = hash(h,k);
    index = indexFor(h->tablelength,hashvalue);
    e = h->table[index];
    while (NULL != e)
    {
        /* Check hash value to short circuit heavier comparison */
        if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
        e = e->next;
    }
    return NULL;
}

/*****************************************************************************/
void * /* returns value associated with key */
hashtable_remove(struct hashtable *h, void *k)
{
    /* TODO: consider compacting the table when the load factor drops enough,
     *       or provide a 'compact' method. */

    struct entry *e;
    struct entry **pE;
    void *v;
    unsigned int hashvalue, index;

    hashvalue = hash(h,k);
    index = indexFor(h->tablelength,hash(h,k));
    pE = &(h->table[index]);
    e = *pE;
    while (NULL != e)
    {
        /* Check hash value to short circuit heavier comparison */
        if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
        {
            *pE = e->next;
            h->entrycount--;
            v = e->v;
            freekey(e->k);
            free(e);
            return v;
        }
        pE = &(e->next);
        e = e->next;
    }
    return NULL;
}

/*****************************************************************************/
/* destroy */
void
hashtable_destroy(struct hashtable *h, int free_values)
{
    unsigned int i;
    struct entry *e, *f;
    struct entry **table = h->table;
    if (free_values)
    {
        for (i = 0; i < h->tablelength; i++)
        {
            e = table[i];
            while (NULL != e)
            { f = e; e = e->next; freekey(f->k); free(f->v); free(f); }
        }
    }
    else
    {
        for (i = 0; i < h->tablelength; i++)
        {
            e = table[i];
            while (NULL != e)
            { f = e; e = e->next; freekey(f->k); free(f); }
        }
    }
    free(h->table);
    free(h);
}

/*
 * Copyright (c) 2002, Christopher Clark
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * * Neither the name of the original author; nor the names of any contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 * 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

--- NEW FILE: hashtable.h ---
/* Copyright (C) 2002 Christopher Clark <firstname.lastname at cl.cam.ac.uk> */

#ifndef __HASHTABLE_CWC22_H__
#define __HASHTABLE_CWC22_H__

struct hashtable;

/* Example of use:
 *
 *      struct hashtable  *h;
 *      struct some_key   *k;
 *      struct some_value *v;
 *
 *      static unsigned int         hash_from_key_fn( void *k );
 *      static int                  keys_equal_fn ( void *key1, void *key2 );
 *
 *      h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
 *      k = (struct some_key *)     malloc(sizeof(struct some_key));
 *      v = (struct some_value *)   malloc(sizeof(struct some_value));
 *
 *      (initialise k and v to suitable values)
 * 
 *      if (! hashtable_insert(h,k,v) )
 *      {     exit(-1);               }
 *
 *      if (NULL == (found = hashtable_search(h,k) ))
 *      {    printf("not found!");                  }
 *
 *      if (NULL == (found = hashtable_remove(h,k) ))
 *      {    printf("Not found\n");                 }
 *
 */

/* Macros may be used to define type-safe(r) hashtable access functions, with
 * methods specialized to take known key and value types as parameters.
 * 
 * Example:
 *
 * Insert this at the start of your file:
 *
 * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
 * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
 * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
 *
 * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
 * These operate just like hashtable_insert etc., with the same parameters,
 * but their function signatures have 'struct some_key *' rather than
 * 'void *', and hence can generate compile time errors if your program is
 * supplying incorrect data as a key (and similarly for value).
 *
 * Note that the hash and key equality functions passed to create_hashtable
 * still take 'void *' parameters instead of 'some key *'. This shouldn't be
 * a difficult issue as they're only defined and passed once, and the other
 * functions will ensure that only valid keys are supplied to them.
 *
 * The cost for this checking is increased code size and runtime overhead
 * - if performance is important, it may be worth switching back to the
 * unsafe methods once your program has been debugged with the safe methods.
 * This just requires switching to some simple alternative defines - eg:
 * #define insert_some hashtable_insert
 *
 */

/*****************************************************************************
 * create_hashtable
   
 * @name                    create_hashtable
 * @param   minsize         minimum initial size of hashtable
 * @param   hashfunction    function for hashing keys
 * @param   key_eq_fn       function for determining key equality
 * @return                  newly created hashtable or NULL on failure
 */

struct hashtable *
create_hashtable(unsigned int minsize,
                 unsigned int (*hashfunction) (void*),
                 int (*key_eq_fn) (void*,void*));

/*****************************************************************************
 * hashtable_insert
   
 * @name        hashtable_insert
 * @param   h   the hashtable to insert into
 * @param   k   the key - hashtable claims ownership and will free on removal
 * @param   v   the value - does not claim ownership
 * @return      non-zero for successful insertion
 *
 * This function will cause the table to expand if the insertion would take
 * the ratio of entries to table size over the maximum load factor.
 *
 * This function does not check for repeated insertions with a duplicate key.
 * The value returned when using a duplicate key is undefined -- when
 * the hashtable changes size, the order of retrieval of duplicate key
 * entries is reversed.
 * If in doubt, remove before insert.
 */

int 
hashtable_insert(struct hashtable *h, void *k, void *v);

#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
int fnname (struct hashtable *h, keytype *k, valuetype *v) \
{ \
    return hashtable_insert(h,k,v); \
}

/*****************************************************************************
 * hashtable_search
   
 * @name        hashtable_search
 * @param   h   the hashtable to search
 * @param   k   the key to search for  - does not claim ownership
 * @return      the value associated with the key, or NULL if none found
 */

void *
hashtable_search(struct hashtable *h, void *k);

#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
valuetype * fnname (struct hashtable *h, keytype *k) \
{ \
    return (valuetype *) (hashtable_search(h,k)); \
}

/*****************************************************************************
 * hashtable_remove
   
 * @name        hashtable_remove
 * @param   h   the hashtable to remove the item from
 * @param   k   the key to search for  - does not claim ownership
 * @return      the value associated with the key, or NULL if none found
 */

void * /* returns value */
hashtable_remove(struct hashtable *h, void *k);

#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
valuetype * fnname (struct hashtable *h, keytype *k) \
{ \
    return (valuetype *) (hashtable_remove(h,k)); \
}


/*****************************************************************************
 * hashtable_count
   
 * @name        hashtable_count
 * @param   h   the hashtable
 * @return      the number of items stored in the hashtable
 */
unsigned int
hashtable_count(struct hashtable *h);


/*****************************************************************************
 * hashtable_destroy
   
 * @name        hashtable_destroy
 * @param   h   the hashtable
 * @param       free_values     whether to call 'free' on the remaining values
 */

void
hashtable_destroy(struct hashtable *h, int free_values);

#endif /* __HASHTABLE_CWC22_H__ */

/*
 * Copyright (c) 2002, Christopher Clark
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * * Neither the name of the original author; nor the names of any contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 * 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

--- NEW FILE: hashtable_private.h ---
/*
 * "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."
 *
 */
/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname at cl.cam.ac.uk> */

#ifndef __HASHTABLE_PRIVATE_CWC22_H__
#define __HASHTABLE_PRIVATE_CWC22_H__

#include "hashtable.h"

/*****************************************************************************/
struct entry
{
    void *k, *v;
    unsigned int h;
    struct entry *next;
};

struct hashtable {
    unsigned int tablelength;
    struct entry **table;
    unsigned int entrycount;
    unsigned int loadlimit;
    unsigned int primeindex;
    unsigned int (*hashfn) (void *k);
    int (*eqfn) (void *k1, void *k2);
};

/*****************************************************************************/
unsigned int
hash(struct hashtable *h, void *k);

/*****************************************************************************/
/* indexFor */
static inline unsigned int
indexFor(unsigned int tablelength, unsigned int hashvalue) {
    return (hashvalue % tablelength);
};

/* Only works if tablelength == 2^N */
/*static inline unsigned int
indexFor(unsigned int tablelength, unsigned int hashvalue)
{
    return (hashvalue & (tablelength - 1u));
}
*/

/*****************************************************************************/
#define freekey(X) free(X)
/*define freekey(X) ; */


/*****************************************************************************/

#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/

/*
 * Copyright (c) 2002, Christopher Clark
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * * Neither the name of the original author; nor the names of any contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 * 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

--- NEW FILE: logging.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."
 *
 */
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <stdarg.h>
#include "logging.h"


loglevel_t log_level;
FILE *log_dest;


char *log_names[5] = {"DEBUG",
                      "INFO",
                      "WARN",
                      "ERROR",
                      "FATAL"};

static void timestamp(){
  struct timeval tv;
  struct timezone tz;
  struct tm *ltime;
  gettimeofday(&tv, &tz);
  ltime = localtime(&tv.tv_sec);
  fprintf(log_dest, "%02d:%02d:%02d.%03d: ", 
          ltime->tm_hour, ltime->tm_min, ltime->tm_sec, (int)tv.tv_usec);
}

loglevel_t log_setlevel(loglevel_t l) {
  loglevel_t old_lvl = log_level;
  log_level = l;
  return old_lvl;
}

loglevel_t log_getlevel() {
  return log_level;
}

void log_init() {
  log_level = LOGLVL_INFO;
  log_dest = stderr;
}

void log_log  (loglevel_t level, const char *fmt, ...) {
    if (log_level > level) return;
    va_list ap;
    va_start(ap, fmt);
    timestamp();
    fprintf(log_dest, "%s: ", log_names[level]);
    vfprintf(log_dest, fmt, ap);
    va_end(ap);
}

void log_clear (loglevel_t level, const char *fmt, ...) {
  if (log_level > level) return;
  va_list ap;
  va_start(ap, fmt);
  vfprintf(log_dest, fmt, ap);
  va_end(ap);
}

/* print char* in hex format */
void log_dump_serial_packet(unsigned char *packet, const int len) {
    int i;
    if (log_level > LOGLVL_DEBUG) return;

    printf("len: %d\n", len);
    if (!packet)
	return;
    for (i = 0; i < len; i++) {
	printf("%02x ", packet[i]);
	//printf("%02x(%c) ", packet[i], packet[i]);
	//printf("%c", packet[i]);
    }
    putchar('\n');
}

--- NEW FILE: logging.h ---
/*
 * "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."
 *
 */
#ifndef LOGGING_H_
#define LOGGING_H_

#include <stdio.h>

// SDH : log levels defined here
//      also edit the log names in logging.h
typedef enum {
  LOGLVL_DEBUG = 0,
  LOGLVL_INFO = 1,
  LOGLVL_WARN = 2,
  LOGLVL_ERROR = 3,
  LOGLVL_FATAL = 4,
} loglevel_t;

extern char *log_names[5];
extern loglevel_t log_level;
extern FILE *log_dest;

void log_init();

loglevel_t log_setlevel(loglevel_t l);
loglevel_t log_getlevel();

void log_log  (loglevel_t level, const char *fmt, ...);
void log_clear (loglevel_t level, const char *fmt, ...);

#define debug(fmt, args...) \
           log_log(LOGLVL_DEBUG, fmt, ## args)
#define info(fmt, args...) \
           log_log(LOGLVL_INFO, fmt, ## args)
#define warn(fmt, args...) \
           log_log(LOGLVL_WARN, fmt, ## args)
#define error(fmt, args...) \
           log_log(LOGLVL_ERROR, fmt, ## args)
#define fatal(fmt, args...) \
           log_log(LOGLVL_FATAL, fmt, ## args)

#define log_fprintf(X, FMT, ...) ;

void log_dump_serial_packet(unsigned char *packet, const int len);

#endif

--- NEW FILE: nwstate.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."
 *
 */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include "nwstate.h"
#include "hashtable.h"
#include "logging.h"
#include "lib6lowpan.h"
#include "routing.h"

struct hashtable *links;
struct hashtable *routers;

router_t *router_list = NULL;
int routes_out_of_date = 1;

extern struct in6_addr __my_address;


void compute_routes(node_id_t v1);
//
// general boilerplate
// 

static unsigned int hash_link(void *k) {
  link_key_t *l = (link_key_t *)k;
  if (l->r1 > l->r2)
    return (l->r1 | (l->r2 << 16));
  else
    return (l->r2 | (l->r1 << 16));
}
static int link_equal(void *k1, void *k2) {
  link_key_t *l1 = (link_key_t *)k1;
  link_key_t *l2 = (link_key_t *)k2;
  return ((l1->r1 == l2->r1 && l1->r2 == l2->r2) ||
          (l1->r1 == l2->r2 && l1->r2 == l2->r1));
}

static unsigned int hash_router(void *k) {
  return *((router_key_t *)k);
}

static int router_equal(void *k1, void *k2) {
  return ((router_t *)k1)->id == ((router_t *)k2)->id;
}

int do_print = 0;
int do_routes = 0;
int printCount = 0;

int nw_print_dotfile(char *filename) {
  router_t *r;
  link_t *e;
  FILE *fp = fopen (filename, "w");
  if (fp == NULL) return -1;
  info("writing topology to '%s'\n", filename);
  printCount ++;
  fprintf(fp, "digraph Network {\n");
  
  for (r = router_list; r != NULL; r = r->next) {
    for (e = r->links; e != NULL; e = e->next1) {
      if (e->pc < printCount) {
        fprintf(fp, "  \"0x%x\" -> \"0x%x\" [label=\"%f\"]\n", e->n1->id, e->n2->id, e->qual);
        e->pc = printCount;
      }
    }
    for (e = r->links; e != NULL; e = e->next2) {
      if (e->pc < printCount) {
        fprintf(fp, "  \"0x%x\" -> \"0x%x\" [label=\"%f\"]\n", e->n1->id, e->n2->id, e->qual);
        e->pc = printCount;
      }
    }
  }

  fprintf(fp, "}\n");
  fclose(fp);
  return 0;
}


void nw_print_routes() {
  router_t *r,*s;
  for (r = router_list; r != NULL; r = r->next) {
    log_clear(LOGLVL_INFO, "  0x%x: ", r->id);
    for (s = r->sp.prev; s != NULL; s = s->sp.prev) {
      log_clear(LOGLVL_INFO, "0x%x ", s->id);
    }
    log_clear(LOGLVL_INFO, "\n");
  }
}

void nw_test_routes() {
  node_id_t dest = ntohs(__my_address.s6_addr16[7]);
  debug("nwstate: computing new routes (root: 0x%x)\n", ntohs(__my_address.s6_addr16[7]));
  compute_routes(dest);
}

void nw_print_links() {
  router_t *r;
  link_t *l;
  for (r = router_list; r != NULL; r = r->next) {
    log_clear(LOGLVL_INFO, " 0x%x: dist: %.1f\n", r->id, r->sp.dist);
    for (l = r->links; l != NULL; l = (r == l->n1) ? l->next1 : l->next2) {
      if (r == l->n1) {
        log_clear(LOGLVL_INFO, "  --> 0x%x [%.1f]\n", l->n2->id, l->qual);
      }
    }
    log_clear(LOGLVL_INFO, "\n");
  }
}

//
// helpers
// 

router_t *get_insert_router(node_id_t rid) {
  router_key_t *key;
  router_t *ret = hashtable_search(routers, &rid);
  if (ret == NULL) {
    key = (router_key_t *)malloc(sizeof(router_key_t));
    ret = (router_t *)malloc(sizeof(router_t));

    ret->id = rid;
    ret->links = NULL;
    ret->next = router_list;

    ret->reports = 0;

    ret->sp.dist = FLT_MAX;
    ret->sp.prev = NULL;

    router_list = ret;

    *key = rid;
    hashtable_insert(routers, key, ret);
    routing_add_table_entry(rid);
  }
  return ret;
}


//
// network state API impl.
//

int nw_init() {
  links   = create_hashtable(16, hash_link,   link_equal);
  routers = create_hashtable(16, hash_router, router_equal);
  return 0;
}

/*
 * Adds an observation of the link (v1, v2) to the database.  This
 * implicitly adds the reverse edge for now, as well.
 */
int nw_add_incr_edge(node_id_t v1, struct topology_entry *te) {
  link_key_t key;
  link_t *link_str;
  node_id_t v2 = ntoh16(te->hwaddr);
  key.r1 = v1;
  key.r2 = v2;

  link_str = hashtable_search(links, &key);
  if (link_str == NULL) {
    link_key_t *new_key = (link_key_t *)malloc(sizeof(link_key_t));
    router_t *r1 = get_insert_router(v1);
    router_t *r2 = get_insert_router(v2);
    link_str = (link_t *)malloc(sizeof(link_t));

    new_key->r1 = v1;
    new_key->r2 = v2;

    // point the links at their routers
    link_str->n1 = r1;
    link_str->n2 = r2;
    // add this link to the head of the linked list of edges each router maintains
    link_str->next1 = r1->links;
    link_str->next2 = r2->links;

    link_str->n1_reportcount = 0;
    link_str->n2_reportcount = 0;
    
    r1->links = link_str;
    r2->links = link_str;

    link_str->pc = 0;

    
    hashtable_insert(links, new_key, link_str);

  } 

  link_str->marked = 1;
  link_str->qual = ((float)(te->etx)) / 10.0;
  link_str->conf = te->conf;
  debug("nw_add_incr_edge [%i -> %i]: qual: %f conf: %i\n", 
        v1, v2, link_str->qual, link_str->conf);
  (v1 == link_str->n1->id) ? link_str->n1_reportcount++ :
    link_str->n2_reportcount++;

  return 0;
}

/*
 * Returns a route from v1 to v2 as a linked list.
 *
 * quadratic-time dijkstra implementation: no priority queue
 */
/*
 * relaxes the neighbors of cur
 */
float getMetric(link_t *l) {
  return l->qual;
  //return ((float)l->qual / 3000.0)  + 1.0;
  //return (10. / (float)l->nobs);
}
void update_neighbors(router_t *cur) {
  link_t *l;
  router_t *otherguy;
  // clunky iterator
  for (l = cur->links; l != NULL; l = (cur == l->n1) ? l->next1 : l->next2) {
    otherguy = (cur == l->n1) ? l->n2 : l->n1;
    
    if (cur->sp.dist + getMetric(l) < otherguy->sp.dist) {
      otherguy->sp.dist = cur->sp.dist + getMetric(l);
      otherguy->sp.prev = cur;
    }
  }
}

router_t *extract_min(router_t **list) {
  router_t *r, *prev = NULL, *min = NULL, *prev_min = NULL;
  float min_dist = FLT_MAX;
  for (r = *list; r != NULL; r = r->sp.setptr) {
    if (r->sp.dist < min_dist) {
      min_dist = r->sp.dist;
      min = r;
      prev_min = prev;
    }
    prev = r;
  }

  if (min == NULL) {
    // it might be the case that not everyone is reachable.  In that
    // case, we'll just leave them unconnected.
    *list = NULL;
  } else if (prev_min == NULL) {
    // the first element was the best, set list is pointed at the second element
    *list = (*list)->sp.setptr;
  } else {
    // otherwise just remove the min element from the list
    prev_min->sp.setptr = min->sp.setptr;
  }

  return min;
}

void age_routers() {
  router_t *r;
  int max_reports = 0;
  for (r = router_list; r != NULL; r = r->next) {
    if (r->reports > max_reports) {
      max_reports = r->reports;
    }
    // debug("nwstate: node: %i reports: %i\n", r->id, r->reports);
  }
  if (max_reports == 4) {
    debug("age_routers: max: %i\n", max_reports);
    for (r = router_list; r != NULL; r = r->next) {
      if (r->reports > 0) {
        r->reports = 0;
      } else {
        // debug("nwstate: removing router 0x%x due to age %i\n", r->id, r->reports);
        // nw_inval_node(r->id);
        r->reports = 0;
      }
    }
  }
}

/*
 * compute all destinations shortest path to node v1
 */
void compute_routes(node_id_t v1) {
  router_t *r, *cur = NULL, *not_visited = NULL;
  routes_out_of_date = 0;

  for (r = router_list; r != NULL; r = r->next) {
    r->sp.dist = FLT_MAX;
    r->sp.prev = NULL;
    if (r->id == v1) {
      cur = r;
    } else {
      r->sp.setptr = not_visited;
      not_visited = r;
    }
  }
  if (cur == NULL) return;
  cur->sp.dist = 0;

  while (not_visited != NULL) {
    update_neighbors(cur);
    cur = extract_min (&not_visited);
  }
  // all the prev and distance pointers are now valid.
}

path_t *nw_get_route(node_id_t v1, node_id_t v2) {
  router_t *r, *from, *to;
  path_t *ret = NULL, *new;

  from = hashtable_search(routers, &v1);
  to   = hashtable_search(routers, &v2);

  if (from == NULL || to == NULL) return NULL;

  if (to->sp.prev == NULL || from->sp.prev != NULL || routes_out_of_date) {
    // the current set of shortest paths do not end at node v2, if we
    // haven't computed any paths yet, we will do that when the next
    // test fails.
    debug("nw_get_route: computing new routes\n");
    compute_routes(v1);
  }
  // now the routes should be valid;
  for (r = to; r != NULL; r = r->sp.prev) {
    // this both constructs the return value and reverses the path,
    // since the prev pointers will give you the reverse path.

    // in the future routes will probably be cached.
    
    if (r != from) {
      new = (path_t *)malloc(sizeof(path_t));
      new->node = r->id;
      new->next = ret;
      new->length = (ret == NULL) ? 1 : ret->length + 1;
      ret = new;
    }
  }
  return ret;
}

void nw_free_path(path_t *r) {
  path_t *next;
  while (r != NULL) {
    next = r->next;
    free(r);
    r = next;
  }
}

// remove link from the linked list of links owned by router.
void remove_link(router_t *r, link_t *link) {
  link_t *l;
  link_t **prev = &r->links;
  for (l = r->links; l != NULL; l = (r== l->n1) ? l->next1 : l->next2) {
    if (l == link) {
      *prev = (r == l->n1) ? l->next1 : l->next2;
      return;
    }
    prev = (r == l->n1) ? &l->next1 : &l->next2;
  }
  warn("link_remove: link not removed (inconsistent state)?\n");
}

void nw_inval_node(node_id_t v) {
  router_t *cur;
  link_t *l, *next;
  router_t *otherguy;
  link_key_t key;
  routes_out_of_date = 1;

  cur = hashtable_search(routers, &v);
  if (cur == NULL) return;

  // remove the links from the linked lists of the other guys,
  // and delete them from the hashtable
  for (l = cur->links; l != NULL; l = (cur == l->n1) ? l->next1 : l->next2) {
    otherguy = (cur == l->n1) ? l->n2 : l->n1;
    key.r1 = v;
    key.r2 = otherguy->id;
    remove_link(otherguy, l);
    hashtable_remove(links, &key);
  }
  
  // free the link structures
  l = cur->links;
  while (l != NULL) {
    next = (cur == l->n1) ? l->next1 : l->next2;
    free(l);
    l = next;
  }
  cur->links = NULL;

  // force a route recomputation when this node is used.
  cur->sp.dist = FLT_MAX;
  cur->sp.prev = NULL;
}

/*
 * called before adding the topology from a node 
 * unsets the marked bit * in the link structures to show that they
 * have not been reported
 */ 
void nw_unmark_links(node_id_t v) {
  router_t *cur;
  link_t *l;
  routes_out_of_date = 1;

  cur = hashtable_search(routers, &v);
  if (cur == NULL) return;

  for (l = cur->links; l != NULL; l = (cur == l->n1) ? l->next1 : l->next2) {
    l->marked = 0;
  }

}

void nw_report_node(node_id_t v) {
  router_t *cur;

  cur = hashtable_search(routers, &v);
  if (cur == NULL) return;
  
  cur->reports++;
}

/*
 * called after processing a topology report
 *
 * removes links which were not contained by this topology report, and
 * which were not reported by the router on the other end.
 *
 */
void nw_clear_unmarked(node_id_t v) {
  router_t *cur;
  link_key_t key;
  link_t *l, *next;
  key.r1 = v;

  cur = hashtable_search(routers, &v);
  if (cur == NULL) return;

  for (l = cur->links; l != NULL; l = (cur == l->n1) ? l->next1 : l->next2) {
    if (l->marked == 0) {
      // it's not marked, so it wasn't contained in the topology report
      if (((cur == l->n1) ? l->n2_reportcount : l->n1_reportcount) == 0) {
        // it has never been reported by the router on the other end, so we
        // remove the link from the topology data
        router_t *otherguy = (cur == l->n1) ? l->n2 : l->n1;
        key.r2 = otherguy->id;
        remove_link(otherguy, l);
        hashtable_remove(links, &key);
        //info("removing unmarked link, 0x%x -> 0x%x\n", cur->id, otherguy->id);
        // remove it from our own linked list
      } else {
        // it has been reported by the other size, so we just set its
        // observation count to zero.
        if (cur == l->n1)  l->n1_reportcount = 0 ;
        else l->n2_reportcount = 0;
        l->marked = 1;
        // router_t *otherguy = (cur == l->n1) ? l->n2 : l->n1;
        //debug("unseting obs count on 0x%x -> 0x%x\n", cur->id, otherguy->id);
      }
    }
  }

  // free the links no longer in use
  l = cur->links;
  while (l != NULL) {
    next = (cur == l->n1) ? l->next1 : l->next2;
    // if its still umarked, we mean to remove it from the graph
    if (l->marked == 0) {
      remove_link(cur, l);
      free(l);
    }
    l = next;
  }


  age_routers();
}

--- NEW FILE: nwstate.h ---
/*
 * "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."
 *
 */
#ifndef NWSTATE_H
#define NWSTATE_H

#include <6lowpan.h>
/*
 * Defines a programatic representation of the link state of the network.
 * Also tracks observable statistics about the links present.
 *
 */

typedef uint16_t node_id_t;

struct route_path {
  uint16_t len;
  hw_addr_t path[0];
};

typedef struct {
  node_id_t r1;
  node_id_t r2;
} link_key_t;

struct router;
struct link;

typedef struct link {
  struct router *n1;
  struct router *n2;

  struct link *next1;
  struct link *next2;

  int n1_reportcount;
  int n2_reportcount;

  int marked;

  float qual;
  int conf;
  int pc;
} link_t;

typedef node_id_t router_key_t;

typedef enum bool {
  FALSE,
  TRUE,
} bool_t;

typedef struct router {
  node_id_t id;
  link_t *links;
  struct router *next;
  int reports;

  // fields for shortest path
  // computation
  struct {
    // the current estimate of the 
    // distance to the source
    float dist;
    // the current prev pointer
    struct router *prev;
    // used for maintaining a list of
    // vertices we have not yet visited
    struct router *setptr;
  } sp;
} router_t;

typedef struct path {
  node_id_t node;
  int length;
  struct path *next;
} path_t;

int nw_init();
int nw_add_incr_edge(node_id_t v1, struct topology_entry *v2);
void nw_report_node(node_id_t v);
path_t *nw_get_route(node_id_t v1, node_id_t v2);
void nw_free_path(path_t *path);
void nw_inval_node(node_id_t v);

void nw_unmark_links(node_id_t v);
void nw_clear_unmarked(node_id_t v);

int  nw_print_dotfile(char *filename);
void nw_print_routes();
void nw_print_links();
void nw_test_routes();

#endif

--- NEW FILE: radvd-wrapper.c ---
/* 
 * radvd-wrapper.c
 * author: Stephen Dawson-Haggerty <stevedh at eecs.berkeley.edu>
 *
 * Alternate set of call points for the IPv6 router advertisement
 * daemon.  Using this interface the daemon may be integrated into
 * another program (like ip-driver).  radvd is distributed under a
 * BSD-like license.
 *
 * radvd_init() must be called to set up state for the specified
 *   interface.  If successful, it will return a file descriptor;
 *   radvd_process() must be called whenever there is pending data on
 *   this descriptor (ie, from a select() loop.)
 *
 * radvd has its own logging infrastructure; by default radvd_init()
 * sends that log to stderr and makes no attempt to integrate it with
 * whatever logging facilities may be availabile.  See radvd/log.c for
 * more.
 *
 * NB: radvd uses SIGALRM for its internal timer.  Thus, once
 * radvd_init() has been called, SIGALRM must not be used elsewhere in
 * the application.
 *
 */


#include <includes.h>
#include <radvd.h>
#include <pathnames.h>

#include "logging.h"
#include "config.h"

struct Interface *iface;
int sock;

void radvd_timer_handler(void *data) {
  struct Interface *iface = (struct Interface *) data;
  double next;

  dlog(LOG_DEBUG, 4, "timer_handler called for %s", iface->Name);

  send_ra(sock, iface, NULL);

  next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); 

  if (iface->init_racount < MAX_INITIAL_RTR_ADVERTISEMENTS) {
    iface->init_racount++;
    next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, next);
  }

  set_timer(&iface->tm, next);
}


void radvd_kickoff_adverts(void) {
  init_timer(&iface->tm, radvd_timer_handler, (void *) iface);
  if (iface->AdvSendAdvert) {
    /* send an initial advertisement */
    send_ra(sock, iface, NULL);
    
    iface->init_racount++;

    set_timer(&iface->tm,
              min(MAX_INITIAL_RTR_ADVERT_INTERVAL,
                  iface->MaxRtrAdvInterval));
  }
}

void radvd_process() {
  unsigned char msg[MSG_SIZE];
  int len, hoplimit;
  struct sockaddr_in6 rcv_addr;
  struct in6_pktinfo *pkt_info = NULL;
  
  len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit);
  if (len > 0)
    process(sock, iface, msg, len, 
            &rcv_addr, pkt_info, hoplimit);
  
}


/* Set up all the radvd internal stuff from our own configuration */
int radvd_init(char *ifname, struct config *c) {
  struct AdvPrefix *prefix;
  sigset_t oset, nset;


  if (log_open(L_STDERR, "radvd", NULL, -1) < 0) {
    error("log_open\n");
    return -1;
  }
  srand((unsigned int)time(NULL));
  info("starting radvd on device %s\n", ifname);

  sock = open_icmpv6_socket();
  if (sock < 0) {
    error("open_icmpv6_socket\n");
    return -1;
  }
  sigemptyset(&nset);
  sigaddset(&nset, SIGALRM);
  sigprocmask(SIG_UNBLOCK, &nset, &oset);
  if (sigismember(&oset, SIGALRM))
    flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong.");


  /* setup the radvd struct Interface to know about all our defaults */
  iface = malloc(sizeof(struct Interface));
  if (iface == NULL)
    return -1;

  iface_init_defaults(iface);
  strncpy(iface->Name, ifname, IFNAMSIZ-1);
  iface->Name[IFNAMSIZ-1] = '\0';

  iface->next = NULL;
  iface->AdvSendAdvert = 1;

  /* check the interface exists... this probably shouldn't fail */
  if (check_device(sock, iface) < 0) {
    error("check_device!\n");
    return -1;
  }
  
  if (setup_deviceinfo(sock, iface) < 0) {
    error("setup_deviceinfo\n");
    return -1;
  }
  if (check_iface(iface) < 0) {
    error("check_iface\n");
    return -1;
  }
  if (setup_linklocal_addr(sock, iface) < 0) {
    error("setup_linklocal_addr\n");
    return -1;
  }
  if (setup_allrouters_membership(sock, iface) < 0) {
    error("setup_allrouters_membership\n");
    return -1;
  }


  /* set up the prefix we're advertising from the config struct we get passed in. */
  prefix = malloc(sizeof(struct AdvPrefix));
  if (prefix == NULL)
    return -1;

  prefix_init_defaults(prefix);
  prefix->PrefixLen = 64;
  memcpy(&prefix->Prefix, c->router_addr.s6_addr, sizeof(struct in6_addr));
  prefix->next = NULL;

  iface->AdvPrefixList = prefix;


  // config_interface();
  radvd_kickoff_adverts();

  return sock;
}

--- NEW FILE: routing.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."
 *
 */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <net/if.h>

#include <6lowpan.h>
#include <lib6lowpan.h>
#include "routing.h"
#include "nwstate.h"
#include "logging.h"
#include "config.h"

static hw_addr_t my_short_addr;
extern struct in6_addr  __my_address;

char proxy_dev[IFNAMSIZ], tun_dev[IFNAMSIZ];

/*
 * Call to setup routing tables.
 *
 */
uint8_t routing_init(struct config *c, char *tun_name) {
  nw_init();
  my_short_addr = ntohs(__my_address.s6_addr16[7]);
  strncpy(proxy_dev, c->proxy_dev, IFNAMSIZ);
  strncpy(tun_dev, tun_name, IFNAMSIZ);
/*   nl_fd = socket(AF_NETLINK, SOCK_RAW, protocol); */
/*   if (nl_fd < 0)  */
/*     return -1; */

  return 0;
}

/*
 * @returns: truth value indicating if the destination of the packet
 * is a single hop, and requires no source route.
 */
uint8_t routing_is_onehop(struct split_ip_msg *msg) {
  path_t *path;
  uint8_t ret = ROUTE_NO_ROUTE;

  if (cmpPfx(msg->hdr.ip6_dst.s6_addr, multicast_prefix))
    return ROUTE_ONEHOP;

  if (msg->hdr.nxt_hdr == NXTHDR_SOURCE) {
    debug("routing_is_onehop: Source header\n");
    return ROUTE_SOURCE;
  }

  path = nw_get_route(my_short_addr, ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
  
  if (path != NULL) {
    if (path->length == 1)
      ret = ROUTE_ONEHOP;
    else
      ret = ROUTE_MHOP;
  }
  debug("routing_is_onehop: 0x%x\n", ret);
  nw_free_path(path);
  return ret;
}

/*
 * Identical to routing_insert_route, except allows for a detour route
 */
/*uint8_t routing_insert_route_indirect(struct split_ip_msg *orig, ip6_addr_t detour) {
  int offset = 0;
  path_t *path = nw_get_route(my_short_addr, l2fromIP(detour));
  path_t *path_second = nw_get_route(l2fromIP(detour), l2fromIP(orig->hdr.dst_addr));
  path_t *i;
  struct generic_header *g_hdr = (struct generic_header *)malloc(sizeof(struct generic_header));
  struct source_header *sh;

  debug("routing_insert_route_indirect len1: 0x%x, len2: 0x%x\n", path->length, path_second->length);

  if (ntoh16(orig->hdr.plen) + sizeof(struct source_header) + ((path->length + path_second->length) * sizeof(uint16_t)) + sizeof(struct ip6_hdr) > INET_MTU) {
    warn("packet plus source header too long\n");
    return 1;
  }

  sh = (struct source_header *)malloc(sizeof(struct source_header) + (path->length + path_second->length)*sizeof(uint16_t));
  if (sh == NULL || g_hdr == NULL) return 1;

  sh->nxt_hdr = orig->hdr.nxt_hdr;
  sh->len = sizeof(struct source_header) + ((path->length + path_second->length) * sizeof(uint16_t));
  sh->dispatch = IP_EXT_SOURCE_DISPATCH;
  sh->current = 0;
  orig->hdr.nxt_hdr = NXTHDR_SOURCE;

  fprintf(stderr, "to 0x%x [%i]: ", noths(orig->hdr.ip6_dst.s6_addr16[7]), path->length + path_second->length);
  for (i = path; i != NULL; i = i->next) {
    fprintf(stderr, "0x%x ", i->node);
    sh->hops[offset++] = hton16(i->node);
  }
  for (i = path_second; i != NULL; i = i->next) {
    fprintf(stderr, "0x%x ", i->node);
    sh->hops[offset++] = hton16(i->node);
  }

  fprintf(stderr, "\n");

  orig->hdr.plen = hton16(ntoh16(orig->hdr.plen) + sh->len);

  g_hdr->payload_malloced = 1;
  g_hdr->len = sh->len;
  g_hdr->hdr.sh = sh;
  g_hdr->next = orig->headers;
  orig->headers = g_hdr;

  nw_free_path(path);
  nw_free_path(path_second);

  return 0;
}
*/

/*
 * Copys the IP message at orig to the empty one at ret, inserting
 * necessary routing information.
 */
uint8_t routing_insert_route(struct split_ip_msg *orig) {
  int offset = 0;
  path_t *path = nw_get_route(my_short_addr, ntohs(orig->hdr.ip6_dst.s6_addr16[7]));
  path_t *i;
  struct generic_header *g_hdr = (struct generic_header *)malloc(sizeof(struct generic_header));
  struct source_header *sh;

  if (g_hdr == NULL || path == NULL) {
    if (g_hdr) free(g_hdr);
    if (path) nw_free_path(path);
    return 1;
  }
  if (path->length == 1) {
    free(g_hdr);
    nw_free_path(path);
    return 1;
  }
  debug("routing_insert_route len: 0x%x\n", path->length);

  // if the packet with the source route is longer then the buffer
  // we're putting it into, drop it.
  if (ntoh16(orig->hdr.plen) + sizeof(struct source_header) + 
      (path->length * sizeof(uint16_t)) + sizeof(struct ip6_hdr) > INET_MTU) {
    warn("packet plus source header too long\n");
    free(g_hdr);
    nw_free_path(path);
    return 1;
  }
  
  sh = (struct source_header *)malloc(sizeof(struct source_header) + path->length * sizeof(uint16_t));
  if (sh == NULL) {
    free (g_hdr);
    nw_free_path(path);
    return 1;
  }

  sh->nxt_hdr = orig->hdr.nxt_hdr;
  sh->len = sizeof(struct source_header) + (path->length * sizeof(uint16_t));
  sh->dispatch = IP_EXT_SOURCE_DISPATCH | IP_EXT_SOURCE_CONTROLLER;
  sh->current = 0;
  
  orig->hdr.nxt_hdr = NXTHDR_SOURCE;

  log_clear(LOGLVL_DEBUG, "to 0x%x [%i]: ", ntohs(orig->hdr.ip6_dst.s6_addr16[7]), path->length);
  for (i = path; i != NULL; i = i->next) {
    log_clear(LOGLVL_DEBUG, "0x%x ", i->node);
    sh->hops[offset++] = hton16(i->node);
  }
  log_clear(LOGLVL_DEBUG, "\n");

  orig->hdr.plen = hton16(ntoh16(orig->hdr.plen) + sh->len);

  g_hdr->payload_malloced = 1;
  g_hdr->len = sh->len;
  g_hdr->hdr.sh = sh;
  g_hdr->next = orig->headers;
  orig->headers = g_hdr;

  nw_free_path(path);

  return 0;

}

/*
 * Returns the address of the next router this packet should be send to.
 */
hw_addr_t routing_get_nexthop(struct split_ip_msg *msg) {
  hw_addr_t ret = 0xffff;;
  path_t * path;
  if (cmpPfx(msg->hdr.ip6_dst.s6_addr, multicast_prefix))
    return ret;

  // If it's source routed, just grab the next hop out of the header 
  if (msg->hdr.nxt_hdr == NXTHDR_SOURCE) {
    debug("routing_get_nexthop: src header\n"); 
    return ntoh16((msg->headers->hdr.sh->hops[msg->headers->hdr.sh->current]));
  }

  path = nw_get_route(my_short_addr, ntohs(msg->hdr.ip6_dst.s6_addr16[7]));

  if (path != NULL)
    ret = path->node;

  nw_free_path(path);

  return ret;
}

void routing_proc_msg(struct split_ip_msg *msg) {
  struct generic_header *g_hdr, **prev_hdr;
  uint8_t *prev_next, nxt_hdr = msg->hdr.nxt_hdr;
  int i;
  node_id_t reporter = ntohs(msg->hdr.ip6_src.s6_addr16[7]);

  prev_next = &msg->hdr.nxt_hdr;
  prev_hdr = &msg->headers;

  nw_report_node(reporter);
  for (g_hdr = msg->headers; g_hdr != NULL; g_hdr = g_hdr->next) {
    if (nxt_hdr == NXTHDR_TOPO) {
      // add the topology reports to the database 
      nw_unmark_links(reporter);
      for (i = 0; i < (g_hdr->len - sizeof(struct topology_header))/sizeof(struct topology_entry); i++) {
        //debug("topo neigh: 0x%x hop: %i qual: 0x%x\n", g_hdr->hdr.th->topo[i].hwaddr,
             // g_hdr->hdr.th->topo[i].hops, g_hdr->hdr.th->topo[i].link);
        nw_add_incr_edge(reporter, &g_hdr->hdr.th->topo[i]);
      }
      nw_clear_unmarked(reporter);
      // remove the topology header
      *prev_next = g_hdr->hdr.ext->nxt_hdr;
      *prev_hdr = g_hdr->next;
      if (g_hdr->payload_malloced) free(g_hdr->hdr.data);
      msg->hdr.plen = hton16(ntoh16(msg->hdr.plen) - g_hdr->len);
      free(g_hdr);
      return;
    } else {
      nxt_hdr = g_hdr->hdr.ext->nxt_hdr;
      prev_next = &g_hdr->hdr.ext->nxt_hdr;
      prev_hdr = &g_hdr->next;
    }
  }
}


void routing_add_table_entry(node_id_t id) {
  /* static const char* route_add_fmt = "ip -6 route add %x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x/128 dev %s"; */
  /* static const char* route_proxy_fmt = "ip -6 neigh add proxy %x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x dev %s"; */
 
}

--- NEW FILE: routing.h ---
/*
 * "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."
 *
 */
#ifndef __ROUTING_H_
#define __ROUTING_H_

#include <ip.h>
#include <string.h>
#include "nwstate.h"
#include "config.h"

enum {
  ROUTE_NO_ROUTE,
  ROUTE_ONEHOP,
  ROUTE_MHOP,
  ROUTE_SOURCE,
};


uint8_t routing_init(struct config *c, char *tun_dev);

/*
 * @returns: truth value indicating if the destination of the packet
 * is a single hop, and requires no source route.
 */
uint8_t routing_is_onehop(struct split_ip_msg  *msg);


/*
 * Copys the IP message at orig to the empty one at ret, inserting
 * necessary routing information.
 */
uint8_t routing_insert_route(struct split_ip_msg *orig);

/*
 * Returns the address of the next router this packet should be send to.
 */
hw_addr_t routing_get_nexthop(struct split_ip_msg *msg);


/*
 * Called for all reconstructed packets off serial.
 * allows the router to inpect and remove any extra headers in the message.
 */
void routing_proc_msg(struct split_ip_msg *msg);

/*
 * Update kernel routing state to reflect a new node
 */
void routing_add_table_entry(node_id_t id);


#endif 

--- NEW FILE: serial_tun.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."
[...1069 lines suppressed...]
    exit(1);
  }
#endif

  info("Press 'h' for help\n");

  routing_init(&driver_config, dev);
#ifndef SIM
  configure_reboot();
#endif

  /* start tunneling */
  serial_tunnel(tun_fd);

  /* clean up */
  // close_serial_source(ser_src);
  // close(ser_fd);
  tun_close(tun_fd, dev);
  return 0;
}

--- NEW FILE: tun_dev.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."
 *
 */
/*
 * Copyright (c) 2007 Matus Harvan
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * The name of the author may not be used to endorse or promote
 *       products derived from this software without specific prior
 *       written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <errno.h>

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_ether.h>

#include <netinet/in.h>

#include "lib6lowpan.h"
#include "tun_dev.h"


/*
 *    This is in linux/include/net/ipv6.h.
 *    Thanks, net-tools!
 */
struct in6_ifreq {
    struct in6_addr ifr6_addr;
    __u32 ifr6_prefixlen;
    unsigned int ifr6_ifindex;
};


int tun_open(char *dev)
{
    struct ifreq ifr;
    int fd;

    if ((fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0)
	return -1;

    memset(&ifr, 0, sizeof(ifr));
    /* By default packets are tagged as IPv4. To tag them as IPv6,
     * they need to be prefixed by struct tun_pi.
     */
    //ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
    ifr.ifr_flags = IFF_TUN;
    if (*dev)
	strncpy(ifr.ifr_name, dev, IFNAMSIZ);

    if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0)
	goto failed;

    strcpy(dev, ifr.ifr_name);
    return fd;

  failed:
    perror("tun_open");
    close(fd);
    return -1;
}

int tun_setup(char *dev, struct in6_addr *addr) {
  struct in6_ifreq ifr6;
  struct ifreq ifr;
  int fd;

  if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) < 0)
    return -1;

  memset(&ifr, 0, sizeof(struct ifreq));
  strncpy(ifr.ifr_name, dev, IFNAMSIZ);

  /* set the interface up */
  if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
    perror("SIOCGIFFLAGS");
    return -1;
  }
  ifr.ifr_flags |= IFF_UP;
  if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
    perror("SIOCSIFFLAGS");
    return -1;
  }

  /* MTU */
  ifr.ifr_mtu = 1280;
  if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) {
    perror("SIOCSIFMTU");
    return -1;
  }

  /* Global address */
  memset(&ifr6, 0, sizeof(struct in6_ifreq));
  memcpy(&ifr6.ifr6_addr, addr, 16);
  if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
    perror("SIOGIFINDEX");
    return -1;
  }

  ifr6.ifr6_ifindex = ifr.ifr_ifindex;
  ifr6.ifr6_prefixlen = 64;
  if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
    perror("SIOCSIFADDR (global)");
    return -1;
  }

  memset(&ifr6.ifr6_addr.s6_addr[0], 0, 16);
  ifr6.ifr6_addr.s6_addr16[0] = htons(0xfe80);
  ifr6.ifr6_addr.s6_addr16[7] = addr->s6_addr16[7];
  
  if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
    perror("SIOCSIFADDR (local)");
    return -1;
  }

  close(fd);

  return 0;
}

int tun_close(int fd, char *dev)
{
    return close(fd);
}

/* Read/write frames from TUN device */
int tun_write(int fd, struct split_ip_msg *msg)
{
  uint8_t buf[INET_MTU + sizeof(struct tun_pi)], *packet;
  struct tun_pi *pi = (struct tun_pi *)buf;
  struct generic_header *cur;
  packet = (uint8_t *)(pi + 1);


  if (ntohs(msg->hdr.plen) + sizeof(struct ip6_hdr) >= INET_MTU)
    return 1;

  pi->flags = 0;
  pi->proto = htons(ETH_P_IPV6);

  memcpy(packet, &msg->hdr, sizeof(struct ip6_hdr));
  packet += sizeof(struct ip6_hdr);

  cur = msg->headers;
  while (cur != NULL) {
    memcpy(packet, cur->hdr.data, cur->len);
    packet += cur->len;
    cur = cur->next;
  }

  memcpy(packet, msg->data, msg->data_len);

  return write(fd, buf, sizeof(struct tun_pi) + sizeof(struct ip6_hdr) + ntohs(msg->hdr.plen));
}

int tun_read(int fd, char *buf, int len)
{
  int out;
  out = read(fd, buf, sizeof(struct tun_pi) + len);

  return out - sizeof(struct tun_pi);
}

--- NEW FILE: tun_dev.h ---
/*
 * "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."
 *
 */
/*
 * Copyright (c) 2007 Matus Harvan
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * The name of the author may not be used to endorse or promote
 *       products derived from this software without specific prior
 *       written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _TUN_DEV_H
#define _TUN_DEV_H

#include <ip.h>

int tun_open(char *dev);
int tun_close(int fd, char *dev);
int tun_setup(char *dev, struct in6_addr *addr);
int tun_write(int fd, struct split_ip_msg *msg);
int tun_read(int fd, char *buf, int len);

#endif

--- NEW FILE: tunnel.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."
 *
 */
/*
 * Implementation of user-mode driver and IP gateway using a node
 * running IPBaseStation as 802.15.4 hardware.  Uses kernel tun
 * interface to route addresses.
 * 
 */
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

uint16_t shortAddr;
int tun_fd;
char *tun_dev = "/dev/net/tun";

void usage(char **args) {
  fprintf(stderr, "\n\t%s <my-short-addr>\n\n", args[0]);
}

int create_tunnel() {
  struct ifreq ifr;
  if ((tun_fd = open(tun_dev, O_RDWR)) < 0) {
    fprintf(stderr, "Failed to open '%s' : ", tun_dev);
    perror("");
    return 1;
  }
  ifr.irf_flags = IFF_TAP | IFF_NO_PI;
  str

  return 0;
}

int main(int argc, char **argv) {
  if (argc != 2) {
    usage(argv);
    return 1;
  }
  shortAddr = atoi(argv[1]);

  if (create_tunnel())
    return 1;

  sleep(20);

  return 0;
}



More information about the Tinyos-2-commits mailing list