--- /dev/null
+
+all:
+ cd lib6lowpan && make
+ cp lib6lowpan/lib6lowpan.a .
+
+ cd driver && make
+ cp driver/ip-driver .
+
+clean:
+ cd lib6lowpan && make clean
+ cd driver && make clean
+ rm lib6lowpan.a ip-driver
--- /dev/null
+
+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)
+
--- /dev/null
+
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+/* Copyright (C) 2004 Christopher Clark <firstname.lastname@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.
+*/
--- /dev/null
+/* Copyright (C) 2002 Christopher Clark <firstname.lastname@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.
+*/
--- /dev/null
+/*
+ * "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@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.
+*/
--- /dev/null
+/*
+ * "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');
+}
--- /dev/null
+/*
+ * "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
--- /dev/null
+/*
+ * "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 (¬_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();
+}
--- /dev/null
+/*
+ * "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
--- /dev/null
+$Id$
+
+11/01/2006 Release 1.0.
+
+10/09/2006 Perform a static/dynamic code audit; plug some minor
+ bugs (see CVS changelogs for more information) and
+ perform minor clean-up.
+
+08/07/2006 Implement MAX_INITIAL_RTR_ADVERT_INTERVAL handling,
+ patch from Yoshifuji Hideaki / USAGI.
+
+05/23/2006 Unblock SIGALRM signals at startup. Some scripts/programs
+ seem to run radvd from ALRM-blocked context which breaks
+ the timers.
+
+05/23/2006 Redefined IgnoreIfMissing: by default, radvd will now
+ try to reinitialize failed interfaces automatically.
+ IgnoreIfMissing is still needed if radvd is started when the
+ interface isn't up, and it also quenches some messages
+ relating to missing interfaces.
+
+03/29/2006 Implement RDNSS draft, using non-allocated
+ IANA ND type value 25, by Lauréline Provost,
+ Mickaël Guérin, Adrien Clerc, Gaetan Eleouet,
+ Bahattin Demirplak, Lionel Guilmin (at the
+ ENSEEIHT, Toulouse)
+
+03/06/2006 Fix the default STDERR+syslog logging methods, so
+ we don't try to unnecessarily log to STDERR after
+ forking.
+
+01/18/2006 radvd-0.9.1 did not initialize AdvDefaultLifetime (etc.)
+ appropriately, unbreak the "clean-up".
+
+01/13/2006 Release 0.9.1.
+
+12/30/2005 Great cleanup of signed/unsigned values, add
+ -Wall and a number of other warnings to CFLAGS
+ by default. Do not allow signed values for
+ HomeAgentPreference anymore.
+
+12/30/2005 Fix a couple of IPv6 Ready Logo Phase-2 IPv6 Core
+ Protocols Self Test issues, patches from Yoshifuji
+ Hideaki / USAGI.
+
+11/13/2005 Create a short FAQ in README file.
+
+10/28/2005 Get interface MTU automatically, so that you can
+ use jumboframes and advertise MTU >1500.
+
+10/19/2005 Release 0.9.
+
+10/18/2005 Transfer sole maintainership of radvd to Pekka Savola.
+
+10/18/2005 Make the radvd.conf syntax dump default
+ in radvdump and remove the previous default to
+ reduce code duplication.
+
+09/28/2005 Add NEMO Basic support (RFC3961) and fix default
+ HomeAgentLifetime, from Ville Nuorvala.
+
+08/18/2005 Implement more robust timer handler, especially
+ because some Linux kernels don't seem to behave
+ all that well; see http://lkml.org/lkml/2005/4/29/163.
+ Based on extensive testing & reports by
+ Tomasz Grobelny. NB: the bug report was caused by
+ a bad timer patch in PLD's kernel package, and this
+ should not occur often with standard kernels.
+
+07/24/2005 Implement a new logging method "stderr_syslog" which is
+ now also the default. Everything is logged on syslog,
+ while the most important messages (i.e., start-up failures)
+ are also logged on stderr.
+
+07/08/2005 Release 0.8.
+
+07/05/2005 Change the more-specific route ND option code
+ from de-facto '9' to the official '24'. Change
+ back in defaults.h if you need old behaviour.
+
+07/05/2005 Fix wrongly calculated prefix with Base6to4Interface
+ on ppc and maybe other big endian arches, from
+ Debian #301543 by Sam Hathaway.
+
+07/05/2005 Fix Linux-2.6.12-bk4+ error with HUP signal,
+ from YOSHIFUJI Hideaki / USAGI.
+
+03/29/2005 Merge a part of MIPv6/non-MIPv6 code, make printing
+ error messages nicer.
+
+03/22/2005 Be a bit more informative about config file parsing
+ errors.
+
+02/21/2005 Release 0.7.3.
+
+02/19/2005 Fix crash when reloading config with AdvSendAdvert off.
+
+02/15/2005 Merge a few fixes and improvements from USAGI:
+ - support microsecond scheduling and fix RA intervals
+ - send zero router lifetime when forwarding is disabled
+ - use a more flexible inter-RA delay
+
+01/07/2005 Accomodate interface indexes > 9999, from Hagen Fritsch.
+
+12/15/2004 Advertise zero Router Lifetime when shutting down;
+ implements a SHOULD in RFC2461 section 6.2.5.
+
+10/16/2004 Update Mobile IPv6 to match RFC 3775, from Greg Daley.
+
+08/20/2004 Minor documentation cleanups.
+
+03/09/2004 Implement "IgnoreIfMissing" interface flag, which can be
+ used on interfaces which aren't enabled when radvd starts
+ but will later become available (e.g., Bluetooth) --
+ and then you wish to send HUP to radvd to activate the
+ configs.
+
+02/21/2004 Further cleanups, to fix autoconf/autoheader problems
+ with newer toolchain; mostly by Marko Myllynen.
+
+02/20/2004 Clean up a bit: remove old junk from configure.in,
+ rename "log()" to "flog()" to satisfy newer GCCs,
+ allow underscores in the interface names (the last two
+ fixes already committed earlier).
+
+01/19/2004 Make radvd check for forwarding status using procfs on
+ Linux; needed with 2.6 kernels. Loosely based on
+ a patch by USAGI.
+
+11/21/2003 Add support for Router Preferences and More Specific
+ Routes from Markku Savela <msa@burp.tkv.asdf.org>.
+ NOTE! The specification is not final yet, there will be
+ changes! (Man page, documentation and radvdump support
+ by Pekka Savola.)
+
+09/11/2003 When starting up, check if the MAC address is all zero
+ (could happen e.g. with bridge interfaces with no attached
+ physical interfaces), and warn if so. For more information,
+ http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=103469
+
+06/10/2003 When chrooting, check the possible return code
+ from chdir("/").
+
+03/08/2003 Add patch from MAEDA Naoaki <maeda.naoaki@jp.fujitsu.com>
+ to discard RS's from the unspecied source address with
+ link-layer address option, as required by RFC2461.
+
+10/28/2002 Release 0.7.2:
+ - add support for VLANs (from USAGI)
+ - make it compile better on newer NetBSD's (NetBSD)
+ - fix a syntax error in radvd.conf(5) sample documentation
+ - use IPV6_RECV{HOPLIMIT,PKTINFO} not
+ IPV6_{HOPLIMIT,PKTINFO} if supported
+ - (in Red Hat spec file) don't create radvd gid explicitly
+ - a lot of coding style cleanups
+
+01/16/2002 Release 0.7.1.
+
+01/12/2002 Update config.{guess,sub} from ftp.gnu.org; update INTRO.
+ Marko Myllynen and Debian bug #115992.
+
+01/02/2002 Ensure NULL-termination with strncpy.
+
+12/31/2001 Radvdump fixes: eliminate a warning of Prefix Information
+ sections with '-d -f'; add a note that
+ {Min,Max}RtrAdvInterval cannot be obtained with '-f';
+ implement '-e' to be used with '-f' which omits all
+ advertised default settings. Mostly by Marko Myllynen.
+
+12/28/2001 Small cleanups. AdvSendAdvert is implicitly off by
+ default. Check configuration file permissions; must
+ not be writable by others, and if non-root,
+ not by self/own group. By Marko Myllynen.
+
+12/21/2001 Check via sysctl that IPv6 forwarding is enabled;
+ exit unless debugging is enabled. Triggered by
+ Marko Myllynen.
+
+11/22/2001 MinRtrAdvInterval for MIPv6 is 0.05 seconds, not 0.5.
+ (Note: untested).
+
+11/20/2001 Rework BSD device memory management a bit, minor cleanups.
+ Version bumped to 0.7.0.
+
+11/14/2001 Maintainership of radvd transferred from Lars Fenneberg
+ to Pekka Savola and Nathan Lutchansky. Lars' CVS
+ repository adopted, and changes merged from the -pX
+ branch.
+
+08/29/2001 Minor change for NetBSD 1.5.1 compatibility.
+ (Nathan Lutchansky)
+
+07/20/2001 Support for non-multicast links, like ISATAP.
+ (Nathan Lutchansky)
+
+07/03/2001 Minimum MTU has been changed to 1280 in the latest RFC's.
+ (Pekka Savola)
+
+06/30/2001 Check for possible buffer overflows; replace strcpy with
+ strncpy. No fatals found. Remove redunant radvd -t check.
+ (Pekka Savola)
+
+06/24/2001 Fix 1-byte overflow in /proc/net/igmp6 handling,
+ clean out possible memory garbage when sending RA's
+ (patch from <yoshfuji@linux-ipv6.org>).
+
+06/19/2001 When dropping root, also set up supplementary groups
+ properly. On Linux, when sending RA's, check that the
+ interface has joined all-routers multicast group. Add a few
+ RFC2461 MUST sanity checks when receiving datagrams. Clean
+ out non-EUI64 addressing scheme and other minor bits.
+ (Pekka Savola)
+
+04/28/2001 Misc cleanup and bugfixes, automake support.
+
+03/28/2001 Grammar cleanup. Integrated 6to4 support through
+ "Base6to4Interface" option in prefix configuration. Signal
+ handling fixed by blocking on select() rather than recvmsg()
+ so SIGTERM/HUP take effect immediately now. (Nathan Lutchansky)
+
+03/27/2001 Security fixes: close stdin/out and chdir("/") via
+ daemon() to prevent possible exploits, and a flag to allow
+ radvd to set[ug]id to an unprivileged user (from Pekka Savola).
+
+02/01/2001 scope_id is not supported in glibc2.1. So it is now
+ compiled conditionally.
+
+01/31/2001 Add CC variable to Makefile. Fix bug with IPV6_ADD_MEMBERSHIP
+ handling. Set scope_id when sending packets.
+
+12/02/2000 man pages update, rewritten pid file handling, rewritten
+ signal handling (SIGHUP and SIGTERM), gcc warnings cleanup,
+ new radvdump option -f: print received RAs in config file
+ format (by Marko)
+
+11/19/2000 integrated the last two change entries into the main source
+ (patches by Marko Myllynen), fixed bug in log.c, fixed file
+ description leak in readin_config, rewrote code in timer.c,
+ updated man pages again (from Marko Myllynen, too), PID
+ file support (patch from Marko Myllynen, based on a patch
+ from Tommi.Komulainen@iki.fi)
+
+15/08/2000 RFC 2461 updates, Mobile IPv6 extensions added
+
+14/07/2000 added RA interval option and modified some default values
+ for timers
+
+06/15/99 changed to run with glibc 2.1 on RedHat 6.0.
+
+03/03/98 radvd now joins ipv6-allrouters on Linux. Fix contributed
+ by A.N.Kuznetsov <kuznet@ms2.inr.ac.ru>.
+
+10/23/97 radvd will now accept any prefix length in its config
+ file but will warn about unusual ones
+
+10/19/97 removed backwards compatibility code in recv.c.
+ IPV6_HOPLIMIT support is now assumed to exist.
+
+10/19/97 fixed alignment problems in recv.c and send.c.
+
+10/16/97 the Makefile install target now uses mkinstalldirs.
+
+10/16/97 changed all u_int*_t to uint*_t for better POSIX
+ compliance and portability. Needs 2.1.57-CVS or glibc.
+ BSD seems to need patches.
+
+10/16/97 more intelligent configure; tries to figure out
+ where the IPv6 libraries and inclues are (if not in
+ the standard places). Searches in /usr/inet6 and /usr/ipv6.
+
+10/15/97 integrated small patches for glibc and BSD from Craig and
+ Philip
+
+09/14/97 EUI-64 "support"
+
+09/01/97 centralized all includes into includes.h for easier
+ maintainance
+
+08/25/97 changed all occurences of IPV6_TXINFO/IPV6_RXINFO
+ to IPV6_PKTINFO
+
+08/25/97 removed some compatibility stuff for older Linux kernels
+
+03/17/97 changed linux/if_arp.h to net/if_arp.h in device-linux.c
+ and configure.in (for glibc compatibility)
+
+03/17/97 integrated patch from Philip Blundell <pjb27@cam.ac.uk>
+ into configure.in to check for inet_* in libc first and
+ then for libinet6 (for glibc compatibility).
+
+03/16/97 corrected small error in radvd.conf(5) man page and other
+ small changes
+
+03/16/97 removed linklocal.c source file from the distribution
+ because it wasn't used anymore
+
+03/16/97 added html version of the INTRO, removed ascii version.
+
+02/12/97 missing directories are now created on make install
+
+01/19/97 now also the rest of a line followed by a '#' is treated
+ as a comment in the config file
+
+01/16/97 added IPPROTO_IPV6/IPV6_HOPLIMIT support, so now incoming
+ RS' and RAs are checked if there hoplimit is 255 (on Linux
+ this only works with kernel version 2.1.21 and above)
+
+01/15/97 lots of portability cleanups; radvd is now using autoconf
+ for automatic configuration; removed support for the
+ in. prefix
+
+01/05/97 integrated BSD 4.4 patches from Craig <cmetz@inner.net>
+
+12/21/96 release of version 0.3
+
+12/15/96 the AdvSendAdvert flag works now
+
+12/14/96 added radvdump, dumps all received RAs in a human
+ readable form
+
+12/13/96 rewrote radvd to use new advanced API headers
+
+12/08/96 added radvd.conf(5) man page
+
+12/03/96 changed RAW_CHECKSUM to IPV6_CHECKSUM for kernels
+ 2.1.14 and above
+
+11/24/96 added checking of received RAs according to RFC 1970
+
+11/20/96 rewrote the default handling, now it should conform
+ to RFC 1970
+
+11/17/96 release of version 0.2
+
+11/17/96 added -h (--help) and -f (--facility) option
+
+11/17/96 added setsockopt(..., SOL_IPV6, IPV6_MULTICAST_HOPS), so
+ that radvd works for kernel versions >2.1.7 (without this
+ you get "NDISC: fake router advertisment received" on your
+ hosts)
+
+11/17/96 added a man page for radvd(8)
+
+11/17/96 some minor filename changes
+
+11/13/96 first release of this version of in.radvd (0.1)
--- /dev/null
+ The author(s) grant permission for redistribution and use in source and
+binary forms, with or without modification, of the software and documentation
+provided that the following conditions are met:
+
+0. If you receive a version of the software that is specifically labelled
+ as not being for redistribution (check the version message and/or README),
+ you are not permitted to redistribute that version of the software in any
+ way or form.
+1. All terms of all other applicable copyrights and licenses must be
+ followed.
+2. Redistributions of source code must retain the authors' copyright
+ notice(s), this list of conditions, and the following disclaimer.
+3. Redistributions in binary form must reproduce the authors' copyright
+ notice(s), this list of conditions, and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+4. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement with the name(s) of the
+ authors as specified in the copyright notice(s) substituted where
+ indicated:
+
+ This product includes software developed by the authors which are
+ mentioned at the start of the source files and other contributors.
+
+5. Neither the name(s) of the author(s) nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY ITS AUTHORS 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 AUTHORS 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.
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<!-- $Id$ -->
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>RADVD Introduction</title>
+</head>
+
+<body>
+<h1>RADVD Introduction</h1>
+
+<p>
+by <a href="mailto:lf@elemental.net">Lars Fenneberg</a> et al. Updated
+2002-01-12.
+</p>
+
+<p>
+<a href="http://www.ietf.org/rfc/rfc2460.txt">IPv6</a> has a lot more
+support for autoconfiguration than
+<a href="http://www.ietf.org/rfc/rfc791.txt">IPv4</a>. But for this
+autoconfiguration to work on the hosts of a network, the <em>routers</em>
+of the local network have to run a program which answers the
+autoconfiguration requests of the hosts.
+</p>
+
+<p>
+On Linux this program is called
+<a href="http://v6web.litech.org/radvd/">radvd</a>, which stands for
+Router ADVertisement Daemon. This daemon listens to Router Solicitations
+(RS) and answers with Router Advertisement (RA). Furthermore unsolicited
+RAs are also send from time to time.
+<a href="http://www.ietf.org/rfc/rfc2461.txt">RFC 2461</a> defines most
+functions of radvd.
+</p>
+
+<p>
+Router Advertisements contain information, which is used by hosts to
+configure their interfaces. This information includes address prefixes,
+the MTU of the link and information about default routers.
+</p>
+
+<p>
+Of course the routers can't autoconfigure themselves, so the information
+on the routers has to be provided by the administrator of the system.
+This is done by manually configuring the interfaces and routes and by
+configuring the router advertisement daemon.
+</p>
+
+<p>
+A small and simple configuration file for radvd might look like this:
+</p>
+
+<p>
+<pre>
+
+interface eth0
+{
+ AdvSendAdvert on;
+ prefix 2001:db8:0:1::/64
+ {
+ AdvOnLink on;
+ AdvAutonomous on;
+ };
+};
+
+</pre>
+
+<p>
+It says that radvd should advertise (AdvSendAdvert on) the prefix
+2001:db8:0:1:: which has a lenght of 64 on the interface eth0.
+Also the prefix is marked as autonomous (AdvAutonomous on) and as on-link
+(AdvOnLink on). The both currently default to enabled but are included
+here for introductory purposes; it isn't necessary to define them.
+All the other options are left on their default values.
+</p>
+
+<p>
+Autonomous means that the prefix can be used for automatic address
+configuration and on-link means that the hosts can assume that all the hosts
+which use this prefix are reachable via the interface on which the host
+received this RA.
+</p>
+
+<p>
+The prefix must be 64 bits long (apart from very few exceptions), as dictated by
+<a href="http://www.ietf.org/rfc/rfc2464.txt">RFC 2464</a> and other
+standards for different link-layer technologies. For more
+details, see <a href="http://www.ietf.org/rfc/rfc2462.txt">RFC 2462</a>
+(IPv6 Stateless Address Autoconfiguration) and
+<a href="http://www.ietf.org/rfc/rfc2464.txt">RFC 2464</a>
+(Transmission of IPv6 Packets over Ethernet Networks). For more information
+on configuring radvd please look at the manual pages which are included in
+the radvd distribution.
+</p>
+
+<p>
+So, when an interface on a hosts is UPed and a RA is received, the host
+can configure an address on the interface by using the prefix and
+appending the EUI-64 identifier derived from the hardware address
+(also called link-layer token). The EUI-64 identifier is simply appended
+after the prefix. For example:
+</p>
+
+<p>
+<pre>
+
+ Announced prefix: 2001:db8:0:1::
+
+ MAC address: 00:07:E9:7B:02:59
+
+ EUI-64 identifier: 0207:e9ff:fe7b:259
+
+ Configured address: 2001:db8:0:1:207:e9ff:fe7b:259
+
+</pre>
+
+<p>
+The host can also choose a default router by examining the RA.
+the rest works automatically.
+</p>
+
+<p>
+So now we've configured radvd, but we still need to configure the interfaces
+and set the routes (on the router). There's a lot of good material on
+setting up IPv6, and the reader is encouraged to have a look
+at it; for example:
+</p>
+
+<p>
+<ul>
+<li><a href="http://www.bieringer.de/linux/IPv6/IPv6-HOWTO/IPv6-HOWTO.html">http://www.bieringer.de/linux/IPv6/IPv6-HOWTO/IPv6-HOWTO.html</a></li>
+<li><a href="http://people.debian.org/~csmall/ipv6/setup.html">http://people.debian.org/~csmall/ipv6/setup.html</a> (for non-Debian too)</li>
+</ul>
+
+<hr>
+
+<p>
+Copyright © 1997 <a href="mailto:lf@elemental.net">Lars Fenneberg</a>
+</p>
+
+</body>
+</html>
--- /dev/null
+# Generated automatically from Makefile.in by configure.
+# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+#
+# $Id$
+#
+# Authors:
+# Lars Fenneberg <lf@elemental.net>
+#
+# This software is Copyright 1996,1997 by the above mentioned author(s),
+# All Rights Reserved.
+#
+# The license which is distributed with this software in the file COPYRIGHT
+# applies to this software. If your distribution is missing this file, you
+# may request it from <pekkas@netcore.fi>.
+#
+
+
+SHELL = /bin/sh
+
+srcdir = .
+top_srcdir = .
+prefix = /usr/local
+exec_prefix = ${prefix}
+
+bindir = ${exec_prefix}/bin
+sbindir = ${exec_prefix}/sbin
+libexecdir = ${exec_prefix}/libexec
+datadir = ${prefix}/share
+sysconfdir = ${prefix}/etc
+sharedstatedir = ${prefix}/com
+localstatedir = ${prefix}/var
+libdir = ${exec_prefix}/lib
+infodir = ${prefix}/info
+mandir = ${prefix}/man
+includedir = ${prefix}/include
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/radvd
+pkglibdir = $(libdir)/radvd
+pkgincludedir = $(includedir)/radvd
+
+top_builddir = .
+
+ACLOCAL = aclocal
+AUTOCONF = autoconf
+AUTOMAKE = automake
+AUTOHEADER = autoheader
+
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL} $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL_PROGRAM}
+transform = s,x,x,
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = x86_64-unknown-linux-gnu
+build_triplet = x86_64-unknown-linux-gnu
+host_alias = x86_64-unknown-linux-gnu
+host_triplet = x86_64-unknown-linux-gnu
+target_alias = x86_64-unknown-linux-gnu
+target_triplet = x86_64-unknown-linux-gnu
+CC = gcc
+GZIP = /bin/gzip
+LEX = flex
+LN = /bin/ln
+LOG_FACILITY = LOG_DAEMON
+MAKEINFO = makeinfo
+PACKAGE = radvd
+PATH_RADVD_CONF = ${prefix}/etc/radvd.conf
+PATH_RADVD_LOG = /var/log/radvd.log
+PATH_RADVD_PID = /var/run/radvd.pid
+RM = /bin/rm
+SED = /bin/sed
+TAR = /bin/tar
+VERSION = 1.0
+YACC = bison -y
+
+AUTOMAKE_OPTIONS = 1.2 foreign
+
+DEFS = -DPATH_RADVD_CONF=\"$(PATH_RADVD_CONF)\" \
+ -DPATH_RADVD_LOG=\"$(PATH_RADVD_LOG)\" -DLOG_FACILITY=$(LOG_FACILITY) \
+ -DPATH_RADVD_PID=\"$(PATH_RADVD_PID)\" \
+ -DVERSION=\"$(VERSION)\" -DINET6=1
+
+INCLUDES = -I$(srcdir) -I.
+
+########################################################################
+
+COMMON_SRC = log.c socket.c recv.c util.c radvd.h defaults.h pathnames.h \
+ includes.h
+
+
+sbin_PROGRAMS = radvd radvdump
+
+radvd_SOURCES = $(COMMON_SRC) radvd.c timer.c send.c process.c interface.c \
+ device.c device-common.c gram.y gram.h scanner.l
+
+radvd_LDADD = -lfl
+EXTRA_radvd_SOURCES = device-linux.c device-bsd44.c
+YFLAGS = -d
+CFLAGS = -g -O2 -Wall -Wpointer-arith -Wcast-qual -Wcast-align -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
+
+
+radvdump_SOURCES = $(COMMON_SRC) radvdump.c
+
+man_MANS = radvd.8 radvdump.8 radvd.conf.5
+EXTRA_DIST = radvd.8.man radvdump.8.man radvd.conf.5.man VERSION CHANGES \
+ COPYRIGHT INTRO.html copyright.blurb radvd.conf.example
+
+BUILT_SOURCES = device.c
+
+CLEANFILES = radvd.8 radvdump.8 radvd.conf.5
+DISTCLEANFILES = device.c
+
+SUFFIXES = .man
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+PROGRAMS = $(sbin_PROGRAMS)
+
+CPPFLAGS =
+LDFLAGS =
+LIBS = -lc
+radvd_OBJECTS = log.o socket.o recv.o util.o radvd.o timer.o send.o \
+process.o interface.o device.o device-common.o gram.o scanner.o
+radvd_DEPENDENCIES =
+radvd_LDFLAGS =
+radvdump_OBJECTS = log.o socket.o recv.o util.o radvdump.o
+radvdump_LDADD = $(LDADD)
+radvdump_DEPENDENCIES =
+radvdump_LDFLAGS =
+LEX_OUTPUT_ROOT = lex.yy
+LEXLIB = -lfl
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+MANS = $(man_MANS)
+
+NROFF = nroff
+DIST_COMMON = README ./stamp-h.in Makefile.am Makefile.in TODO \
+aclocal.m4 config.guess config.h.in config.sub configure configure.in \
+gram.c install-sh missing mkinstalldirs scanner.c
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+DEP_FILES = .deps/device-bsd44.P .deps/device-common.P \
+.deps/device-linux.P .deps/device.P .deps/gram.P .deps/interface.P \
+.deps/log.P .deps/process.P .deps/radvd.P .deps/radvdump.P .deps/recv.P \
+.deps/scanner.P .deps/send.P .deps/socket.P .deps/timer.P .deps/util.P
+SOURCES = $(radvd_SOURCES) $(EXTRA_radvd_SOURCES) $(radvdump_SOURCES)
+OBJECTS = $(radvd_OBJECTS) $(radvdump_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .l .man .o .s .y
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4): configure.in
+ cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+ cd $(srcdir) && $(AUTOCONF)
+
+config.h: stamp-h
+ @if test ! -f $@; then \
+ rm -f stamp-h; \
+ $(MAKE) stamp-h; \
+ else :; fi
+stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES= CONFIG_HEADERS=config.h \
+ $(SHELL) ./config.status
+ @echo timestamp > stamp-h 2> /dev/null
+$(srcdir)/config.h.in: $(srcdir)/stamp-h.in
+ @if test ! -f $@; then \
+ rm -f $(srcdir)/stamp-h.in; \
+ $(MAKE) $(srcdir)/stamp-h.in; \
+ else :; fi
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+ -rm -f config.h
+
+maintainer-clean-hdr:
+
+mostlyclean-sbinPROGRAMS:
+
+clean-sbinPROGRAMS:
+ -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+
+distclean-sbinPROGRAMS:
+
+maintainer-clean-sbinPROGRAMS:
+
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(sbindir)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ else :; fi; \
+ done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ done
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+radvd: $(radvd_OBJECTS) $(radvd_DEPENDENCIES)
+ @rm -f radvd
+ $(LINK) $(radvd_LDFLAGS) $(radvd_OBJECTS) $(radvd_LDADD) $(LIBS)
+
+radvdump: $(radvdump_OBJECTS) $(radvdump_DEPENDENCIES)
+ @rm -f radvdump
+ $(LINK) $(radvdump_LDFLAGS) $(radvdump_OBJECTS) $(radvdump_LDADD) $(LIBS)
+.l.c:
+ $(LEX) $(AM_LFLAGS) $(LFLAGS) $< && mv $(LEX_OUTPUT_ROOT).c $@
+.y.c:
+ $(YACC) $(AM_YFLAGS) $(YFLAGS) $< && mv y.tab.c $*.c
+ if test -f y.tab.h; then \
+ if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \
+ else :; fi
+gram.h: gram.c
+
+
+install-man5:
+ $(mkinstalldirs) $(DESTDIR)$(man5dir)
+ @list='$(man5_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \
+ done
+
+uninstall-man5:
+ @list='$(man5_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man5dir)/$$inst; \
+ done
+
+install-man8:
+ $(mkinstalldirs) $(DESTDIR)$(man8dir)
+ @list='$(man8_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \
+ done
+
+uninstall-man8:
+ @list='$(man8_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man8dir)/$$inst; \
+ done
+install-man: $(MANS)
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-man5 install-man8
+uninstall-man:
+ @$(NORMAL_UNINSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) uninstall-man5 uninstall-man8
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ -rm -rf $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+ mkdir $(distdir)/=build
+ mkdir $(distdir)/=inst
+ dc_install_base=`cd $(distdir)/=inst && pwd`; \
+ cd $(distdir)/=build \
+ && ../configure --srcdir=.. --prefix=$$dc_install_base \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) dist
+ -rm -rf $(distdir)
+ @banner="$(distdir).tar.gz is ready for distribution"; \
+ dashes=`echo "$$banner" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ echo "$$dashes"
+dist: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+dist-all: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+distdir: $(DISTFILES)
+ -rm -rf $(distdir)
+ mkdir $(distdir)
+ -chmod 777 $(distdir)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+all-recursive-am: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+install-exec-am: install-sbinPROGRAMS
+install-exec: install-exec-am
+
+install-data-am: install-man
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-sbinPROGRAMS uninstall-man
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS) $(MANS) config.h
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man5 \
+ $(DESTDIR)$(mandir)/man8
+
+
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ -test -z "scannerlgramhgramc$(BUILT_SOURCES)" || rm -f scannerl gramh gramc $(BUILT_SOURCES)
+mostlyclean-am: mostlyclean-hdr mostlyclean-sbinPROGRAMS \
+ mostlyclean-compile mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-hdr clean-sbinPROGRAMS clean-compile clean-tags \
+ clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-hdr distclean-sbinPROGRAMS distclean-compile \
+ distclean-tags distclean-depend distclean-generic \
+ clean-am
+
+distclean: distclean-am
+ -rm -f config.status
+
+maintainer-clean-am: maintainer-clean-hdr maintainer-clean-sbinPROGRAMS \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-depend maintainer-clean-generic \
+ distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+ -rm -f config.status
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS clean-sbinPROGRAMS \
+maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \
+install-sbinPROGRAMS mostlyclean-compile distclean-compile \
+clean-compile maintainer-clean-compile install-man5 uninstall-man5 \
+install-man8 uninstall-man8 install-man uninstall-man tags \
+mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \
+distdir mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck all-recursive-am install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+.man:
+ $(SED) -e 's,@''VERSION''@,$(VERSION),g' \
+ -e 's,@''sbindir''@,$(sbindir),g' \
+ -e 's,@''PATH_RADVD_CONF''@,$(PATH_RADVD_CONF),g' \
+ -e 's,@''PATH_RADVD_PID''@,$(PATH_RADVD_PID),g' \
+ -e 's,@''PATH_RADVD_LOG''@,$(PATH_RADVD_LOG),g' \
+ -e 's,@''LOG_FACILITY''@,$(LOG_FACILITY),g' \
+ $< > $@
+
+dist-hook:
+ rm -f $(distdir)/device.c
+ mkdir $(distdir)/redhat
+ cp -p $(srcdir)/redhat/radvd.init $(srcdir)/redhat/radvd.spec \
+ $(srcdir)/redhat/radvd.sysconfig $(distdir)/redhat
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+#
+# $Id$
+#
+# Authors:
+# Lars Fenneberg <lf@elemental.net>
+#
+# This software is Copyright 1996,1997 by the above mentioned author(s),
+# All Rights Reserved.
+#
+# The license which is distributed with this software in the file COPYRIGHT
+# applies to this software. If your distribution is missing this file, you
+# may request it from <pekkas@netcore.fi>.
+#
+
+AUTOMAKE_OPTIONS = 1.2 foreign
+
+DEFS= -DPATH_RADVD_CONF=\"$(PATH_RADVD_CONF)\" \
+ -DPATH_RADVD_LOG=\"$(PATH_RADVD_LOG)\" -DLOG_FACILITY=$(LOG_FACILITY) \
+ -DPATH_RADVD_PID=\"$(PATH_RADVD_PID)\" \
+ -DVERSION=\"$(VERSION)\" -DINET6=1
+INCLUDES=-I$(srcdir) -I.
+
+########################################################################
+
+COMMON_SRC = log.c socket.c recv.c util.c radvd.h defaults.h pathnames.h \
+ includes.h
+
+sbin_PROGRAMS = radvd radvdump
+
+radvd_SOURCES = $(COMMON_SRC) radvd.c timer.c send.c process.c interface.c \
+ device.c device-common.c gram.y gram.h scanner.l
+radvd_LDADD = -lfl
+EXTRA_radvd_SOURCES = device-linux.c device-bsd44.c
+YFLAGS = -d
+CFLAGS = @CFLAGS@ -Wall -Wpointer-arith -Wcast-qual -Wcast-align -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
+
+radvdump_SOURCES = $(COMMON_SRC) radvdump.c
+
+man_MANS = radvd.8 radvdump.8 radvd.conf.5
+EXTRA_DIST = radvd.8.man radvdump.8.man radvd.conf.5.man VERSION CHANGES \
+ COPYRIGHT INTRO.html copyright.blurb radvd.conf.example
+BUILT_SOURCES = device.c
+
+CLEANFILES = radvd.8 radvdump.8 radvd.conf.5
+DISTCLEANFILES = device.c
+
+SUFFIXES = .man
+
+.man:
+ $(SED) -e 's,@''VERSION''@,$(VERSION),g' \
+ -e 's,@''sbindir''@,$(sbindir),g' \
+ -e 's,@''PATH_RADVD_CONF''@,$(PATH_RADVD_CONF),g' \
+ -e 's,@''PATH_RADVD_PID''@,$(PATH_RADVD_PID),g' \
+ -e 's,@''PATH_RADVD_LOG''@,$(PATH_RADVD_LOG),g' \
+ -e 's,@''LOG_FACILITY''@,$(LOG_FACILITY),g' \
+ $< > $@
+
+dist-hook:
+ rm -f $(distdir)/device.c
+ mkdir $(distdir)/redhat
+ cp -p $(srcdir)/redhat/radvd.init $(srcdir)/redhat/radvd.spec \
+ $(srcdir)/redhat/radvd.sysconfig $(distdir)/redhat
--- /dev/null
+# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+#
+# $Id$
+#
+# Authors:
+# Lars Fenneberg <lf@elemental.net>
+#
+# This software is Copyright 1996,1997 by the above mentioned author(s),
+# All Rights Reserved.
+#
+# The license which is distributed with this software in the file COPYRIGHT
+# applies to this software. If your distribution is missing this file, you
+# may request it from <pekkas@netcore.fi>.
+#
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+GZIP = @GZIP@
+LEX = @LEX@
+LN = @LN@
+LOG_FACILITY = @LOG_FACILITY@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+PATH_RADVD_CONF = @PATH_RADVD_CONF@
+PATH_RADVD_LOG = @PATH_RADVD_LOG@
+PATH_RADVD_PID = @PATH_RADVD_PID@
+RM = @RM@
+SED = @SED@
+TAR = @TAR@
+VERSION = @VERSION@
+YACC = @YACC@
+
+AUTOMAKE_OPTIONS = 1.2 foreign
+
+DEFS = -DPATH_RADVD_CONF=\"$(PATH_RADVD_CONF)\" \
+ -DPATH_RADVD_LOG=\"$(PATH_RADVD_LOG)\" -DLOG_FACILITY=$(LOG_FACILITY) \
+ -DPATH_RADVD_PID=\"$(PATH_RADVD_PID)\" \
+ -DVERSION=\"$(VERSION)\" -DINET6=1
+
+INCLUDES = -I$(srcdir) -I.
+
+########################################################################
+
+COMMON_SRC = log.c socket.c recv.c util.c radvd.h defaults.h pathnames.h \
+ includes.h
+
+
+sbin_PROGRAMS = radvd radvdump
+
+radvd_SOURCES = $(COMMON_SRC) radvd.c timer.c send.c process.c interface.c \
+ device.c device-common.c gram.y gram.h scanner.l
+
+radvd_LDADD = -lfl
+EXTRA_radvd_SOURCES = device-linux.c device-bsd44.c
+YFLAGS = -d
+CFLAGS = @CFLAGS@ -Wall -Wpointer-arith -Wcast-qual -Wcast-align -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
+
+
+radvdump_SOURCES = $(COMMON_SRC) radvdump.c
+
+man_MANS = radvd.8 radvdump.8 radvd.conf.5
+EXTRA_DIST = radvd.8.man radvdump.8.man radvd.conf.5.man VERSION CHANGES \
+ COPYRIGHT INTRO.html copyright.blurb radvd.conf.example
+
+BUILT_SOURCES = device.c
+
+CLEANFILES = radvd.8 radvdump.8 radvd.conf.5
+DISTCLEANFILES = device.c
+
+SUFFIXES = .man
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+PROGRAMS = $(sbin_PROGRAMS)
+
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+radvd_OBJECTS = log.o socket.o recv.o util.o radvd.o timer.o send.o \
+process.o interface.o device.o device-common.o gram.o scanner.o
+radvd_DEPENDENCIES =
+radvd_LDFLAGS =
+radvdump_OBJECTS = log.o socket.o recv.o util.o radvdump.o
+radvdump_LDADD = $(LDADD)
+radvdump_DEPENDENCIES =
+radvdump_LDFLAGS =
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LEXLIB = @LEXLIB@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+MANS = $(man_MANS)
+
+NROFF = nroff
+DIST_COMMON = README ./stamp-h.in Makefile.am Makefile.in TODO \
+aclocal.m4 config.guess config.h.in config.sub configure configure.in \
+gram.c install-sh missing mkinstalldirs scanner.c
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+DEP_FILES = .deps/device-bsd44.P .deps/device-common.P \
+.deps/device-linux.P .deps/device.P .deps/gram.P .deps/interface.P \
+.deps/log.P .deps/process.P .deps/radvd.P .deps/radvdump.P .deps/recv.P \
+.deps/scanner.P .deps/send.P .deps/socket.P .deps/timer.P .deps/util.P
+SOURCES = $(radvd_SOURCES) $(EXTRA_radvd_SOURCES) $(radvdump_SOURCES)
+OBJECTS = $(radvd_OBJECTS) $(radvdump_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .l .man .o .s .y
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4): configure.in
+ cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+ cd $(srcdir) && $(AUTOCONF)
+
+config.h: stamp-h
+ @if test ! -f $@; then \
+ rm -f stamp-h; \
+ $(MAKE) stamp-h; \
+ else :; fi
+stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES= CONFIG_HEADERS=config.h \
+ $(SHELL) ./config.status
+ @echo timestamp > stamp-h 2> /dev/null
+$(srcdir)/config.h.in: $(srcdir)/stamp-h.in
+ @if test ! -f $@; then \
+ rm -f $(srcdir)/stamp-h.in; \
+ $(MAKE) $(srcdir)/stamp-h.in; \
+ else :; fi
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+ -rm -f config.h
+
+maintainer-clean-hdr:
+
+mostlyclean-sbinPROGRAMS:
+
+clean-sbinPROGRAMS:
+ -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+
+distclean-sbinPROGRAMS:
+
+maintainer-clean-sbinPROGRAMS:
+
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(sbindir)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ else :; fi; \
+ done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ done
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+radvd: $(radvd_OBJECTS) $(radvd_DEPENDENCIES)
+ @rm -f radvd
+ $(LINK) $(radvd_LDFLAGS) $(radvd_OBJECTS) $(radvd_LDADD) $(LIBS)
+
+radvdump: $(radvdump_OBJECTS) $(radvdump_DEPENDENCIES)
+ @rm -f radvdump
+ $(LINK) $(radvdump_LDFLAGS) $(radvdump_OBJECTS) $(radvdump_LDADD) $(LIBS)
+.l.c:
+ $(LEX) $(AM_LFLAGS) $(LFLAGS) $< && mv $(LEX_OUTPUT_ROOT).c $@
+.y.c:
+ $(YACC) $(AM_YFLAGS) $(YFLAGS) $< && mv y.tab.c $*.c
+ if test -f y.tab.h; then \
+ if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \
+ else :; fi
+gram.h: gram.c
+
+
+install-man5:
+ $(mkinstalldirs) $(DESTDIR)$(man5dir)
+ @list='$(man5_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \
+ done
+
+uninstall-man5:
+ @list='$(man5_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man5dir)/$$inst; \
+ done
+
+install-man8:
+ $(mkinstalldirs) $(DESTDIR)$(man8dir)
+ @list='$(man8_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \
+ done
+
+uninstall-man8:
+ @list='$(man8_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man8dir)/$$inst; \
+ done
+install-man: $(MANS)
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-man5 install-man8
+uninstall-man:
+ @$(NORMAL_UNINSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) uninstall-man5 uninstall-man8
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ -rm -rf $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+ mkdir $(distdir)/=build
+ mkdir $(distdir)/=inst
+ dc_install_base=`cd $(distdir)/=inst && pwd`; \
+ cd $(distdir)/=build \
+ && ../configure --srcdir=.. --prefix=$$dc_install_base \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) dist
+ -rm -rf $(distdir)
+ @banner="$(distdir).tar.gz is ready for distribution"; \
+ dashes=`echo "$$banner" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ echo "$$dashes"
+dist: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+dist-all: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+distdir: $(DISTFILES)
+ -rm -rf $(distdir)
+ mkdir $(distdir)
+ -chmod 777 $(distdir)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+all-recursive-am: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+install-exec-am: install-sbinPROGRAMS
+install-exec: install-exec-am
+
+install-data-am: install-man
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-sbinPROGRAMS uninstall-man
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS) $(MANS) config.h
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man5 \
+ $(DESTDIR)$(mandir)/man8
+
+
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ -test -z "scannerlgramhgramc$(BUILT_SOURCES)" || rm -f scannerl gramh gramc $(BUILT_SOURCES)
+mostlyclean-am: mostlyclean-hdr mostlyclean-sbinPROGRAMS \
+ mostlyclean-compile mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-hdr clean-sbinPROGRAMS clean-compile clean-tags \
+ clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-hdr distclean-sbinPROGRAMS distclean-compile \
+ distclean-tags distclean-depend distclean-generic \
+ clean-am
+
+distclean: distclean-am
+ -rm -f config.status
+
+maintainer-clean-am: maintainer-clean-hdr maintainer-clean-sbinPROGRAMS \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-depend maintainer-clean-generic \
+ distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+ -rm -f config.status
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS clean-sbinPROGRAMS \
+maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \
+install-sbinPROGRAMS mostlyclean-compile distclean-compile \
+clean-compile maintainer-clean-compile install-man5 uninstall-man5 \
+install-man8 uninstall-man8 install-man uninstall-man tags \
+mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \
+distdir mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck all-recursive-am install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+.man:
+ $(SED) -e 's,@''VERSION''@,$(VERSION),g' \
+ -e 's,@''sbindir''@,$(sbindir),g' \
+ -e 's,@''PATH_RADVD_CONF''@,$(PATH_RADVD_CONF),g' \
+ -e 's,@''PATH_RADVD_PID''@,$(PATH_RADVD_PID),g' \
+ -e 's,@''PATH_RADVD_LOG''@,$(PATH_RADVD_LOG),g' \
+ -e 's,@''LOG_FACILITY''@,$(LOG_FACILITY),g' \
+ $< > $@
+
+dist-hook:
+ rm -f $(distdir)/device.c
+ mkdir $(distdir)/redhat
+ cp -p $(srcdir)/redhat/radvd.init $(srcdir)/redhat/radvd.spec \
+ $(srcdir)/redhat/radvd.sysconfig $(distdir)/redhat
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+$Id$
+
+Installation:
+=============
+
+Run configure, e.g.
+
+./configure --prefix=/usr/local --sysconfdir=/etc --mandir=/usr/share/man
+
+See configure --help for additional command line arguments.
+
+Run 'make' and 'make install'. On BSD, you may need to use 'gmake'.
+
+Configuration:
+==============
+
+See INTRO.html, radvd.conf(8) and radvd.conf.example.
+
+Frequently Asked Questions:
+===========================
+
+Setting up radvd is very simple, so the most frequently asked
+questions have been about what radvd _doesn't_ do...
+
+ 1. How do I set up the router running radvd to automatically
+ configure an address from the prefix advertised in Route
+ Advertisements from upstream?
+
+ -- You don't. By the specification, routers ignore RAs.
+ You'll probably need to use manual configuration. But you
+ can't use the same prefix on two links in any case unless you
+ use something like proxy-ND (draft-ietf-ipv6-ndproxy-04.txt).
+ You may need to re-think your topology; prefix delegation
+ (e.g., manually or with RFC3633) may help.
+
+ 2. How do I set up the router running radvd to automatically
+ configure the interfaces to use an EUI64-based address?
+
+ -- You don't. The design philosophy of radvd is that it's
+ not the _router's_ configuration tool, but a route advertising
+ daemon. You'll need to set up all the addresses, routes, etc.
+ yourself. These tasks are something that system initscripts
+ could possibly do instead.
+
+ 3. I have a dynamic /48 prefix. How do I set up radvd to:
+ a) set up interface addresses and routes on downstream
+ interfaces, and
+ b) advertise /64 prefixes from the /48 on downstream interfaces?
+
+ -- For a), this isn't supported. For b), radvd includes special
+ support for 6to4 upstream interface but assumes that the interface
+ addresses/routes are set up manually. This should probably
+ be done in the initscripts or manually. (Though if someone were
+ to send a patch for b), it might be incorporated.)
+
+ 4. How do I set up radvd to do either unicast or multicast routing?
+
+ -- You don't. Radvd is not a routing or forwarding daemon.
+ You need to set any appropriate routing/forwarding first,
+ and then radvd to only advertise the prefixes to hosts as
+ appropriate.
--- /dev/null
+$Id$
+
+ NOTE WELL
+ =========
+
+ *NONE* of the items are being actively worked on.
+ So, if you're interested in one of these features,
+ it means you'll have to submit a patch... :-)
+
+
+read list of interfaces with SIOCGIFCONF (AF_INET6 support in the kernel would
+be nice) or from /proc
+
+Quoting Peter Bieringer (peter@bieringer.de):
+> Das war's schon. Ach ja, wenn Du mal eine neue Version machst, kannst Du
+> noch einen Schalter einbauen, damit radvd trotz debug-level >0 auf Wunsch
+> als daemon in den Hintergrund starten kann?
+[ Peter wants that a debugging level greater than 0 doesn't stop radvd
+from forking.]
+
+support for few protocol constants defined in RFC 2461 Sec 10 is missing.
+
+consider whether UnicastOnly flag should be detected by radvdump.
+
+read the man pages one more time and make sure their are understandable
+and English is correct
+
+The following parts of RFC2461(bis) are not implemented:
+ - section 6.2.1: Adv{Valid,Preferred}Lifetime that decrements in real time,
+ that is, one that will result in a Lifetime of zero at the specified time in
+ the future. (MUST)
+ - section 6.2.5: when AdvSendAdvertisements changes to FALSE, we don't send
+ a final RA with zero Router Lifetime (we just send it when shutting down).
+ (SHOULD)
+ - section 6.2.8: if the link-local address of the router changes, it should
+ multicast a few RAs from the old address with zero router lifetime, and a
+ few from the new address. (SHOULD).
+
+Consider whether to support RFC 4286 (Multicast Router Discovery).
+
+Consider whether to support multiple IPv4 addresses with Base6to4Interface
+(currently the code just uses the first one).
+
+Consider whether to support a generalization of Base6to4Interface for
+arbitrary IPv6 prefixes, to be used for automatic generation of downstream
+prefixes. Also consider whether this would need to support multiple IPv6
+prefixes on the upstream interfaces. See question 3 in README for more on
+this.
+
+Use getifaddrs() instead of ioctl SIOCGIFADDR and other friends. The
+problem with this is that e.g. RHL73's glibc didn't support getifaddrs(),
+and before glibc 2.3.3 getifaddrs() didn't use netlink so it didn't work
+well with IPv6. So, some kind of compat library would be needed if this
+would be used...
+
+Consider whether radvd should work around missing/broken interfaces by
+default, especially if a previously working interface gets disabled.
+
+Implement Secure Neighbor Discovery (RFC 3971).
--- /dev/null
+#
+# $Id$
+#
+# this file is automatically processed by configure
+#
+1.0
--- /dev/null
+dnl aclocal.m4 generated automatically by aclocal 1.4-p5
+
+dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# Do all the work for Automake. This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_REQUIRE([AC_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+ if test "[$]*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftestfile`
+ fi
+ if test "[$]*" != "X $srcdir/configure conftestfile" \
+ && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "[$]2" = conftestfile
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN([AM_MISSING_PROG],
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+ $1=$2
+ AC_MSG_RESULT(found)
+else
+ $1="$3/missing $2"
+ AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
+
+dnl AM_PROG_LEX
+dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT
+AC_DEFUN([AM_PROG_LEX],
+[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1)
+AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex")
+AC_PROG_LEX
+AC_DECL_YYTEXT])
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file.
+
+AC_DEFUN([AM_CONFIG_HEADER],
+[AC_PREREQ([2.12])
+AC_CONFIG_HEADER([$1])
+dnl When config.status generates a header, we must update the stamp-h file.
+dnl This file resides in the same directory as the config header
+dnl that is generated. We must strip everything past the first ":",
+dnl and everything past the last "/".
+AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
+ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
+<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
+<<am_indx=1
+for am_file in <<$1>>; do
+ case " <<$>>CONFIG_HEADERS " in
+ *" <<$>>am_file "*<<)>>
+ echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
+ ;;
+ esac
+ am_indx=`expr "<<$>>am_indx" + 1`
+done<<>>dnl>>)
+changequote([,]))])
+
--- /dev/null
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+ac_cv_c_const=${ac_cv_c_const=yes}
+ac_cv_func_getopt_long=${ac_cv_func_getopt_long=yes}
+ac_cv_header_getopt_h=${ac_cv_header_getopt_h=yes}
+ac_cv_header_inttypes_h=${ac_cv_header_inttypes_h=yes}
+ac_cv_header_machine_limits_h=${ac_cv_header_machine_limits_h=no}
+ac_cv_header_machine_param_h=${ac_cv_header_machine_param_h=no}
+ac_cv_header_net_if_arp_h=${ac_cv_header_net_if_arp_h=yes}
+ac_cv_header_net_if_dl_h=${ac_cv_header_net_if_dl_h=no}
+ac_cv_header_net_if_types_h=${ac_cv_header_net_if_types_h=no}
+ac_cv_header_netinet_ip6_h=${ac_cv_header_netinet_ip6_h=yes}
+ac_cv_header_stdc=${ac_cv_header_stdc=yes}
+ac_cv_header_sys_param_h=${ac_cv_header_sys_param_h=yes}
+ac_cv_header_sys_sockio_h=${ac_cv_header_sys_sockio_h=no}
+ac_cv_header_sys_time_h=${ac_cv_header_sys_time_h=yes}
+ac_cv_header_time=${ac_cv_header_time=yes}
+ac_cv_lib_c_inet_ntop=${ac_cv_lib_c_inet_ntop=yes}
+ac_cv_lib_fl_yywrap=${ac_cv_lib_fl_yywrap=yes}
+ac_cv_path_GZIP=${ac_cv_path_GZIP=/bin/gzip}
+ac_cv_path_LN=${ac_cv_path_LN=/bin/ln}
+ac_cv_path_RM=${ac_cv_path_RM=/bin/rm}
+ac_cv_path_SED=${ac_cv_path_SED=/bin/sed}
+ac_cv_path_TAR=${ac_cv_path_TAR=/bin/tar}
+ac_cv_path_install=${ac_cv_path_install='/usr/bin/install -c'}
+ac_cv_prog_CC=${ac_cv_prog_CC=gcc}
+ac_cv_prog_CPP=${ac_cv_prog_CPP='gcc -E'}
+ac_cv_prog_LEX=${ac_cv_prog_LEX=flex}
+ac_cv_prog_YACC=${ac_cv_prog_YACC='bison -y'}
+ac_cv_prog_cc_cross=${ac_cv_prog_cc_cross=no}
+ac_cv_prog_cc_g=${ac_cv_prog_cc_g=yes}
+ac_cv_prog_cc_works=${ac_cv_prog_cc_works=yes}
+ac_cv_prog_gcc=${ac_cv_prog_gcc=yes}
+ac_cv_prog_lex_root=${ac_cv_prog_lex_root=lex.yy}
+ac_cv_prog_lex_yytext_pointer=${ac_cv_prog_lex_yytext_pointer=yes}
+ac_cv_prog_make_make_set=${ac_cv_prog_make_make_set=yes}
--- /dev/null
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002 Free Software Foundation, Inc.
+
+timestamp='2002-01-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script.
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int dummy(){}" > $dummy.c ;
+ for c in cc gcc c89 ; do
+ ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ;
+ if test $? = 0 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ rm -f $dummy.c $dummy.o $dummy.rel ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ UNAME_MACHINE_ARCH=`(uname -p) 2>/dev/null` || \
+ UNAME_MACHINE_ARCH=unknown
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvmeppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mipseb-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ cat <<EOF >$dummy.s
+ .data
+\$Lformat:
+ .byte 37,100,45,37,120,10,0 # "%d-%x\n"
+
+ .text
+ .globl main
+ .align 4
+ .ent main
+main:
+ .frame \$30,16,\$26,0
+ ldgp \$29,0(\$27)
+ .prologue 1
+ .long 0x47e03d80 # implver \$0
+ lda \$2,-1
+ .long 0x47e20c21 # amask \$2,\$1
+ lda \$16,\$Lformat
+ mov \$0,\$17
+ not \$1,\$18
+ jsr \$26,printf
+ ldgp \$29,0(\$26)
+ mov 0,\$16
+ jsr \$26,exit
+ .end main
+EOF
+ eval $set_cc_for_build
+ $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ case `./$dummy` in
+ 0-0)
+ UNAME_MACHINE="alpha"
+ ;;
+ 1-0)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 1-1)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 1-101)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 2-303)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ 2-307)
+ UNAME_MACHINE="alphaev67"
+ ;;
+ 2-1307)
+ UNAME_MACHINE="alphaev68"
+ ;;
+ esac
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit 0;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit 0 ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy \
+ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null) && HP_ARCH=`./$dummy`
+ if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+ rm -f $dummy.c $dummy
+ fi ;;
+ esac
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3D:*:*:*)
+ echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit 0 ;;
+ x86:Interix*:3*)
+ echo i386-pc-interix3
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i386-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux
+ exit 0 ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ rm -f $dummy.c
+ test x"${CPU}" != x && echo "${CPU}-pc-linux-gnu" && exit 0
+ ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit 0 ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit 0 ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit 0 ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit 0 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit 0 ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit 0 ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit 0 ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ ld_supported_targets=`cd /; ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit 0 ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit 0 ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit 0 ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ LIBC=gnuaout
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ rm -f $dummy.c
+ test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit 0 ;;
+ i*86:*:5:[78]*)
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit 0 ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Darwin:*:*)
+ echo `uname -p`-apple-darwin${UNAME_RELEASE}
+ exit 0 ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ if test "${UNAME_MACHINE}" = "x86pc"; then
+ UNAME_MACHINE=pc
+ fi
+ echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+ exit 0 ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit 0 ;;
+ NSR-[GKLNPTVW]:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit 0 ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit 0 ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit 0 ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit 0 ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit 0 ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit 0 ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit 0 ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit 0 ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit 0 ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit 0 ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit 0 ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit 0 ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit 0 ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
--- /dev/null
+/* config.h. Generated automatically by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if lex declares yytext as a char * by default, not a char[]. */
+#define YYTEXT_POINTER 1
+
+/* Define if you have the getopt_long function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define if you have the <machine/limits.h> header file. */
+/* #undef HAVE_MACHINE_LIMITS_H */
+
+/* Define if you have the <machine/param.h> header file. */
+/* #undef HAVE_MACHINE_PARAM_H */
+
+/* Define if you have the <net/if_arp.h> header file. */
+#define HAVE_NET_IF_ARP_H 1
+
+/* Define if you have the <net/if_dl.h> header file. */
+/* #undef HAVE_NET_IF_DL_H */
+
+/* Define if you have the <net/if_types.h> header file. */
+/* #undef HAVE_NET_IF_TYPES_H */
+
+/* Define if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the c library (-lc). */
+#define HAVE_LIBC 1
+
+/* whether struct sockaddr_in6 has sin6_scope_id */
+#define HAVE_SIN6_SCOPE_ID 1
+
+/* whether struct in6_addr has u6_addrXX and defines s6_addrXX */
+#define HAVE_IN6_ADDR_S6_ADDR 1
+
--- /dev/null
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if lex declares yytext as a char * by default, not a char[]. */
+#undef YYTEXT_POINTER
+
+/* Define if you have the getopt_long function. */
+#undef HAVE_GETOPT_LONG
+
+/* Define if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define if you have the <machine/limits.h> header file. */
+#undef HAVE_MACHINE_LIMITS_H
+
+/* Define if you have the <machine/param.h> header file. */
+#undef HAVE_MACHINE_PARAM_H
+
+/* Define if you have the <net/if_arp.h> header file. */
+#undef HAVE_NET_IF_ARP_H
+
+/* Define if you have the <net/if_dl.h> header file. */
+#undef HAVE_NET_IF_DL_H
+
+/* Define if you have the <net/if_types.h> header file. */
+#undef HAVE_NET_IF_TYPES_H
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the c library (-lc). */
+#undef HAVE_LIBC
+
+/* whether struct sockaddr_in6 has sin6_scope_id */
+#undef HAVE_SIN6_SCOPE_ID
+
+/* whether struct in6_addr has u6_addrXX and defines s6_addrXX */
+#undef HAVE_IN6_ADDR_S6_ADDR
+
--- /dev/null
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+configure:609: checking host system type
+configure:630: checking target system type
+configure:648: checking build system type
+configure:683: checking for a BSD compatible install
+configure:736: checking whether build environment is sane
+configure:793: checking whether make sets ${MAKE}
+configure:832: checking for working aclocal
+configure:845: checking for working autoconf
+configure:858: checking for working automake
+configure:871: checking for working autoheader
+configure:884: checking for working makeinfo
+configure:919: checking for gcc
+configure:1032: checking whether the C compiler (gcc ) works
+configure:1048: gcc -o conftest conftest.c 1>&5
+configure:1074: checking whether the C compiler (gcc ) is a cross-compiler
+configure:1079: checking whether we are using GNU C
+configure:1088: gcc -E conftest.c
+configure:1107: checking whether gcc accepts -g
+configure:1151: checking for a BSD compatible install
+configure:1206: checking for rm
+configure:1245: checking for sed
+configure:1284: checking for ln
+configure:1321: checking for bison
+configure:1352: checking how to run the C preprocessor
+configure:1373: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:1437: checking for flex
+configure:1470: checking for flex
+configure:1504: checking for yywrap in -lfl
+configure:1523: gcc -o conftest -g -O2 conftest.c -lfl 1>&5
+configure:1546: checking lex output file root
+configure:1567: checking whether yytext is a pointer
+configure:1586: gcc -o conftest -g -O2 conftest.c -lfl 1>&5
+configure:1610: checking for tar
+configure:1645: checking for gzip
+configure:1679: checking where to put logfile
+configure:1691: checking where to put pidfile
+configure:1703: checking where to find configfile
+configure:1715: checking which syslog facility to use
+configure:1728: checking for inet_ntop in -lc
+configure:1747: gcc -o conftest -g -O2 conftest.c -lc 1>&5
+configure:1822: checking for ANSI C header files
+configure:1835: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:1902: gcc -o conftest -g -O2 conftest.c -lc 1>&5
+configure: In function 'main':
+configure:1897: warning: incompatible implicit declaration of built-in function 'exit'
+configure:1929: checking for sys/time.h
+configure:1939: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:1966: checking whether time.h and sys/time.h may both be included
+configure:1980: gcc -c -g -O2 conftest.c 1>&5
+configure:2003: checking for netinet/ip6.h
+configure:2013: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:2082: checking for sys/sockio.h
+configure:2092: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:2088:24: error: sys/sockio.h: No such file or directory
+configure: failed program was:
+#line 2087 "configure"
+#include "confdefs.h"
+#include <sys/sockio.h>
+configure:2082: checking for getopt.h
+configure:2092: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:2082: checking for inttypes.h
+configure:2092: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:2122: checking for net/if_dl.h
+configure:2132: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:2128:23: error: net/if_dl.h: No such file or directory
+configure: failed program was:
+#line 2127 "configure"
+#include "confdefs.h"
+#include <net/if_dl.h>
+configure:2122: checking for net/if_types.h
+configure:2132: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:2128:26: error: net/if_types.h: No such file or directory
+configure: failed program was:
+#line 2127 "configure"
+#include "confdefs.h"
+#include <net/if_types.h>
+configure:2122: checking for net/if_arp.h
+configure:2132: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:2162: checking for sys/param.h
+configure:2172: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:2202: checking for machine/param.h
+configure:2212: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:2208:27: error: machine/param.h: No such file or directory
+configure: failed program was:
+#line 2207 "configure"
+#include "confdefs.h"
+#include <machine/param.h>
+configure:2242: checking for machine/limits.h
+configure:2252: gcc -E conftest.c >/dev/null 2>conftest.out
+configure:2248:28: error: machine/limits.h: No such file or directory
+configure: failed program was:
+#line 2247 "configure"
+#include "confdefs.h"
+#include <machine/limits.h>
+configure:2280: checking for working const
+configure:2334: gcc -c -g -O2 conftest.c 1>&5
+configure:2356: checking whether struct sockaddr_in6 has sin6_scope_id
+configure:2367: gcc -c -g -O2 conftest.c 1>&5
+configure:2382: checking whether struct in6_addr has u6_addrXX and defines s6_addrXX
+configure:2392: gcc -c -g -O2 conftest.c 1>&5
+configure: In function 'main':
+configure:2388: warning: initialization makes integer from pointer without a cast
+configure:2409: checking for getopt_long
+configure:2437: gcc -o conftest -g -O2 conftest.c -lc 1>&5
--- /dev/null
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host jackalope.cs.berkeley.edu:
+#
+# ./configure
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: ./config.status [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion"
+ exec ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "./config.status generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "$ac_cs_usage"; exit 0 ;;
+ *) echo "$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=.
+ac_given_INSTALL="/usr/bin/install -c"
+
+trap 'rm -fr Makefile config.h conftest*; exit 1' 1 2 15
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\&%]/\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF
+/^[ ]*VPATH[ ]*=[^:]*$/d
+
+s%@SHELL@%/bin/sh%g
+s%@CFLAGS@%-g -O2%g
+s%@CPPFLAGS@%%g
+s%@CXXFLAGS@%%g
+s%@FFLAGS@%%g
+s%@DEFS@%-DHAVE_CONFIG_H%g
+s%@LDFLAGS@%%g
+s%@LIBS@%-lc %g
+s%@exec_prefix@%${prefix}%g
+s%@prefix@%/usr/local%g
+s%@program_transform_name@%s,x,x,%g
+s%@bindir@%${exec_prefix}/bin%g
+s%@sbindir@%${exec_prefix}/sbin%g
+s%@libexecdir@%${exec_prefix}/libexec%g
+s%@datadir@%${prefix}/share%g
+s%@sysconfdir@%${prefix}/etc%g
+s%@sharedstatedir@%${prefix}/com%g
+s%@localstatedir@%${prefix}/var%g
+s%@libdir@%${exec_prefix}/lib%g
+s%@includedir@%${prefix}/include%g
+s%@oldincludedir@%/usr/include%g
+s%@infodir@%${prefix}/info%g
+s%@mandir@%${prefix}/man%g
+s%@host@%x86_64-unknown-linux-gnu%g
+s%@host_alias@%x86_64-unknown-linux-gnu%g
+s%@host_cpu@%x86_64%g
+s%@host_vendor@%unknown%g
+s%@host_os@%linux-gnu%g
+s%@target@%x86_64-unknown-linux-gnu%g
+s%@target_alias@%x86_64-unknown-linux-gnu%g
+s%@target_cpu@%x86_64%g
+s%@target_vendor@%unknown%g
+s%@target_os@%linux-gnu%g
+s%@build@%x86_64-unknown-linux-gnu%g
+s%@build_alias@%x86_64-unknown-linux-gnu%g
+s%@build_cpu@%x86_64%g
+s%@build_vendor@%unknown%g
+s%@build_os@%linux-gnu%g
+s%@INSTALL_PROGRAM@%${INSTALL}%g
+s%@INSTALL_SCRIPT@%${INSTALL_PROGRAM}%g
+s%@INSTALL_DATA@%${INSTALL} -m 644%g
+s%@PACKAGE@%radvd%g
+s%@VERSION@%1.0%g
+s%@ACLOCAL@%aclocal%g
+s%@AUTOCONF@%autoconf%g
+s%@AUTOMAKE@%automake%g
+s%@AUTOHEADER@%autoheader%g
+s%@MAKEINFO@%makeinfo%g
+s%@SET_MAKE@%%g
+s%@CC@%gcc%g
+s%@RM@%/bin/rm%g
+s%@SED@%/bin/sed%g
+s%@LN@%/bin/ln%g
+s%@YACC@%bison -y%g
+s%@LEX@%flex%g
+s%@LEXLIB@%-lfl%g
+s%@CPP@%gcc -E%g
+s%@LEX_OUTPUT_ROOT@%lex.yy%g
+s%@TAR@%/bin/tar%g
+s%@GZIP@%/bin/gzip%g
+s%@PATH_RADVD_CONF@%${prefix}/etc/radvd.conf%g
+s%@PATH_RADVD_PID@%/var/run/radvd.pid%g
+s%@PATH_RADVD_LOG@%/var/log/radvd.log%g
+s%@LOG_FACILITY@%LOG_DAEMON%g
+
+CEOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+
+CONFIG_FILES=${CONFIG_FILES-"Makefile"}
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+ CONFIG_HEADERS="config.h"
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}YYTEXT_POINTER${ac_dB}YYTEXT_POINTER${ac_dC}1${ac_dD}
+${ac_uA}YYTEXT_POINTER${ac_uB}YYTEXT_POINTER${ac_uC}1${ac_uD}
+${ac_eA}YYTEXT_POINTER${ac_eB}YYTEXT_POINTER${ac_eC}1${ac_eD}
+${ac_dA}HAVE_LIBC${ac_dB}HAVE_LIBC${ac_dC}1${ac_dD}
+${ac_uA}HAVE_LIBC${ac_uB}HAVE_LIBC${ac_uC}1${ac_uD}
+${ac_eA}HAVE_LIBC${ac_eB}HAVE_LIBC${ac_eC}1${ac_eD}
+${ac_dA}STDC_HEADERS${ac_dB}STDC_HEADERS${ac_dC}1${ac_dD}
+${ac_uA}STDC_HEADERS${ac_uB}STDC_HEADERS${ac_uC}1${ac_uD}
+${ac_eA}STDC_HEADERS${ac_eB}STDC_HEADERS${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SYS_TIME_H${ac_dB}HAVE_SYS_TIME_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SYS_TIME_H${ac_uB}HAVE_SYS_TIME_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SYS_TIME_H${ac_eB}HAVE_SYS_TIME_H${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}TIME_WITH_SYS_TIME${ac_dB}TIME_WITH_SYS_TIME${ac_dC}1${ac_dD}
+${ac_uA}TIME_WITH_SYS_TIME${ac_uB}TIME_WITH_SYS_TIME${ac_uC}1${ac_uD}
+${ac_eA}TIME_WITH_SYS_TIME${ac_eB}TIME_WITH_SYS_TIME${ac_eC}1${ac_eD}
+${ac_dA}HAVE_GETOPT_H${ac_dB}HAVE_GETOPT_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_GETOPT_H${ac_uB}HAVE_GETOPT_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_GETOPT_H${ac_eB}HAVE_GETOPT_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_INTTYPES_H${ac_dB}HAVE_INTTYPES_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_INTTYPES_H${ac_uB}HAVE_INTTYPES_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_INTTYPES_H${ac_eB}HAVE_INTTYPES_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_NET_IF_ARP_H${ac_dB}HAVE_NET_IF_ARP_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_NET_IF_ARP_H${ac_uB}HAVE_NET_IF_ARP_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_NET_IF_ARP_H${ac_eB}HAVE_NET_IF_ARP_H${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_SYS_PARAM_H${ac_dB}HAVE_SYS_PARAM_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SYS_PARAM_H${ac_uB}HAVE_SYS_PARAM_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SYS_PARAM_H${ac_eB}HAVE_SYS_PARAM_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SIN6_SCOPE_ID${ac_dB}HAVE_SIN6_SCOPE_ID${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SIN6_SCOPE_ID${ac_uB}HAVE_SIN6_SCOPE_ID${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SIN6_SCOPE_ID${ac_eB}HAVE_SIN6_SCOPE_ID${ac_eC}1${ac_eD}
+${ac_dA}HAVE_IN6_ADDR_S6_ADDR${ac_dB}HAVE_IN6_ADDR_S6_ADDR${ac_dC}1${ac_dD}
+${ac_uA}HAVE_IN6_ADDR_S6_ADDR${ac_uB}HAVE_IN6_ADDR_S6_ADDR${ac_uC}1${ac_uD}
+${ac_eA}HAVE_IN6_ADDR_S6_ADDR${ac_eB}HAVE_IN6_ADDR_S6_ADDR${ac_eC}1${ac_eD}
+${ac_dA}HAVE_GETOPT_LONG${ac_dB}HAVE_GETOPT_LONG${ac_dC}1${ac_dD}
+${ac_uA}HAVE_GETOPT_LONG${ac_uB}HAVE_GETOPT_LONG${ac_uC}1${ac_uD}
+${ac_eA}HAVE_GETOPT_LONG${ac_eB}HAVE_GETOPT_LONG${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+ac_sources="device-linux.c"
+ac_dests="device.c"
+srcdir=$ac_given_srcdir
+while test -n "$ac_sources"; do
+ set $ac_dests; ac_dest=$1; shift; ac_dests=$*
+ set $ac_sources; ac_source=$1; shift; ac_sources=$*
+
+ echo "linking $srcdir/$ac_source to $ac_dest"
+
+ if test ! -r $srcdir/$ac_source; then
+ { echo "configure: error: $srcdir/$ac_source: File not found" 1>&2; exit 1; }
+ fi
+ rm -f $ac_dest
+
+ # Make relative symlinks.
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dest_dir=`echo $ac_dest|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dest_dir" != "$ac_dest" && test "$ac_dest_dir" != .; then
+ # The dest file is in a subdirectory.
+ test ! -d "$ac_dest_dir" && mkdir "$ac_dest_dir"
+ ac_dest_dir_suffix="/`echo $ac_dest_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dest_dir_suffix.
+ ac_dots=`echo $ac_dest_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dest_dir_suffix= ac_dots=
+ fi
+
+ case "$srcdir" in
+ [/$]*) ac_rel_source="$srcdir/$ac_source" ;;
+ *) ac_rel_source="$ac_dots$srcdir/$ac_source" ;;
+ esac
+
+ # Make a symlink if possible; otherwise try a hard link.
+ if ln -s $ac_rel_source $ac_dest 2>/dev/null ||
+ ln $srcdir/$ac_source $ac_dest; then :
+ else
+ { echo "configure: error: can not link $ac_dest to $srcdir/$ac_source" 1>&2; exit 1; }
+ fi
+done
+
+
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+
+exit 0
--- /dev/null
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002 Free Software Foundation, Inc.
+
+timestamp='2002-01-02'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit 0;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | c4x | clipper \
+ | d10v | d30v | dsp16xx \
+ | fr30 \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | m32r | m68000 | m68k | m88k | mcore \
+ | mips16 | mips64 | mips64el | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el | mips64vr4300 \
+ | mips64vr4300el | mips64vr5000 | mips64vr5000el \
+ | mipsbe | mipseb | mipsel | mipsle | mipstx39 | mipstx39el \
+ | mipsisa32 \
+ | mn10200 | mn10300 \
+ | ns16k | ns32k \
+ | openrisc \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | sh | sh[34] | sh[34]eb | shbe | shle \
+ | sparc | sparc64 | sparclet | sparclite | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armv*-* \
+ | avr-* \
+ | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c54x-* \
+ | clipper-* | cray2-* | cydra-* \
+ | d10v-* | d30v-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | m32r-* \
+ | m68000-* | m680[01234]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | mcore-* \
+ | mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \
+ | mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipseb-* \
+ | mipsle-* | mipsel-* | mipstx39-* | mipstx39el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* \
+ | sparc-* | sparc64-* | sparc86x-* | sparclite-* \
+ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* \
+ | t3e-* | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xmp-* | xps100-* | xscale-* | xstormy16-* \
+ | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ cray2)
+ basic_machine=cray2-cray
+ os=-unicos
+ ;;
+ [cjt]90)
+ basic_machine=${basic_machine}-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mipsel*-linux*)
+ basic_machine=mipsel-unknown
+ os=-linux-gnu
+ ;;
+ mips*-linux*)
+ basic_machine=mips-unknown
+ os=-linux-gnu
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ mmix*)
+ basic_machine=mmix-knuth
+ os=-mmixware
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2)
+ basic_machine=i686-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=t3e-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ windows32)
+ basic_machine=i386-pc
+ os=-windows32-msvcrt
+ ;;
+ xmp)
+ basic_machine=xmp-cray
+ os=-unicos
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ mips)
+ if [ x$os = x-linux-gnu ]; then
+ basic_machine=mips-unknown
+ else
+ basic_machine=mips-mips
+ fi
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh3 | sh4 | sh3eb | sh4eb)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ c4x*)
+ basic_machine=c4x-none
+ os=-coff
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* | -morphos*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto*)
+ os=-nto-qnx
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxsim* | -vxworks*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
--- /dev/null
+#! /bin/sh
+
+# From configure.in ($Id$)
+
+
+
+# Do all the work for Automake. This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+
+
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+
+
+
+
+
+
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file.
+
+
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --with-logfile Path to the radvd logfile [/var/log/radvd.log]"
+ac_help="$ac_help
+ --with-pidfile Path to the radvd pidfile [/var/run/radvd.pid]"
+ac_help="$ac_help
+ --with-configfile Path to the radvd config file [SYSCONF/radvd.conf]"
+ac_help="$ac_help
+ --with-facility Syslog facility to use when using syslog logging"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=radvd.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+# Do some error checking and defaulting for the host and target type.
+# The inputs are:
+# configure --host=HOST --target=TARGET --build=BUILD NONOPT
+#
+# The rules are:
+# 1. You are not allowed to specify --host, --target, and nonopt at the
+# same time.
+# 2. Host defaults to nonopt.
+# 3. If nonopt is not specified, then host defaults to the current host,
+# as determined by config.guess.
+# 4. Target and build default to nonopt.
+# 5. If nonopt is not specified, then target and build default to host.
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+case $host---$target---$nonopt in
+NONE---*---* | *---NONE---* | *---*---NONE) ;;
+*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
+esac
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:609: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+ case $nonopt in
+ NONE)
+ if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+ else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+ fi ;;
+ *) host_alias=$nonopt ;;
+ esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+echo $ac_n "checking target system type""... $ac_c" 1>&6
+echo "configure:630: checking target system type" >&5
+
+target_alias=$target
+case "$target_alias" in
+NONE)
+ case $nonopt in
+ NONE) target_alias=$host_alias ;;
+ *) target_alias=$nonopt ;;
+ esac ;;
+esac
+
+target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
+target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$target" 1>&6
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+echo "configure:648: checking build system type" >&5
+
+build_alias=$build
+case "$build_alias" in
+NONE)
+ case $nonopt in
+ NONE) build_alias=$host_alias ;;
+ *) build_alias=$nonopt ;;
+ esac ;;
+esac
+
+build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
+build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$build" 1>&6
+
+test "$host_alias" != "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+VERSION=`cat ${srcdir}/VERSION | grep -v '^#' | tr -d '\012'`
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:683: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:736: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftestfile`
+ fi
+ if test "$*" != "X $srcdir/configure conftestfile" \
+ && test "$*" != "X conftestfile $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ { echo "configure: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+ fi
+
+ test "$2" = conftestfile
+ )
+then
+ # Ok.
+ :
+else
+ { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+ program_transform_name=
+else
+ # Double any \ or $. echo might interpret backslashes.
+ cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+ program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+ rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:793: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+PACKAGE=radvd
+
+VERSION=$VERSION
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+ { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
+echo "configure:832: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+ ACLOCAL=aclocal
+ echo "$ac_t""found" 1>&6
+else
+ ACLOCAL="$missing_dir/missing aclocal"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:845: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+ AUTOCONF=autoconf
+ echo "$ac_t""found" 1>&6
+else
+ AUTOCONF="$missing_dir/missing autoconf"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:858: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+ AUTOMAKE=automake
+ echo "$ac_t""found" 1>&6
+else
+ AUTOMAKE="$missing_dir/missing automake"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:871: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+ AUTOHEADER=autoheader
+ echo "$ac_t""found" 1>&6
+else
+ AUTOHEADER="$missing_dir/missing autoheader"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:884: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+ MAKEINFO=makeinfo
+ echo "$ac_t""found" 1>&6
+else
+ MAKEINFO="$missing_dir/missing makeinfo"
+ echo "$ac_t""missing" 1>&6
+fi
+
+
+
+echo $ac_n "building for architecture""... $ac_c" 1>&6
+case "$target" in
+ *linux*)
+ echo "$ac_t""linux" 1>&6
+ arch=linux
+ ;;
+ *bsd*)
+ echo "$ac_t""bsd44" 1>&6
+ arch=bsd44
+ ;;
+ *)
+ echo "$ac_t""unknown" 1>&6
+ { echo "configure: error: currently only Linux and BSD 4.4 with NRL's IPv6 code are
+supported. If you have such a system and it is not guessed correctly
+you must specifiy it with --target on the configure command line" 1>&2; exit 1; }
+ ;;
+esac
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:919: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:949: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1000: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:1032: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 1043 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:1048: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:1074: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:1079: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1088: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:1107: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1151: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# Extract the first word of "rm", so it can be a program name with args.
+set dummy rm; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1206: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_RM'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$RM" in
+ /*)
+ ac_cv_path_RM="$RM" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_RM="$RM" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_RM="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_RM" && ac_cv_path_RM="NOTFOUND"
+ ;;
+esac
+fi
+RM="$ac_cv_path_RM"
+if test -n "$RM"; then
+ echo "$ac_t""$RM" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test "x$RM" = xNOTFOUND; then
+ { echo "configure: error: can't find rm in your path - check PATH" 1>&2; exit 1; }
+fi
+# Extract the first word of "sed", so it can be a program name with args.
+set dummy sed; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1245: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_SED'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$SED" in
+ /*)
+ ac_cv_path_SED="$SED" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_SED="$SED" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_SED="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_SED" && ac_cv_path_SED="NOTFOUND"
+ ;;
+esac
+fi
+SED="$ac_cv_path_SED"
+if test -n "$SED"; then
+ echo "$ac_t""$SED" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test "x$SED" = xNOTFOUND; then
+ { echo "configure: error: can't find sed in your path - check PATH" 1>&2; exit 1; }
+fi
+# Extract the first word of "ln", so it can be a program name with args.
+set dummy ln; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1284: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_LN'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$LN" in
+ /*)
+ ac_cv_path_LN="$LN" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_LN="$LN" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_LN="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+LN="$ac_cv_path_LN"
+if test -n "$LN"; then
+ echo "$ac_t""$LN" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+for ac_prog in 'bison -y' byacc
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1321: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$YACC"; then
+ ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_YACC="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+YACC="$ac_cv_prog_YACC"
+if test -n "$YACC"; then
+ echo "$ac_t""$YACC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1352: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 1367 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1373: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 1384 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1390: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 1401 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1407: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+missing_dir=`cd $ac_aux_dir && pwd`
+for ac_prog in flex lex
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1437: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$LEX"; then
+ ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_LEX="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+LEX="$ac_cv_prog_LEX"
+if test -n "$LEX"; then
+ echo "$ac_t""$LEX" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=""$missing_dir/missing flex""
+
+# Extract the first word of "flex", so it can be a program name with args.
+set dummy flex; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1470: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$LEX"; then
+ ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_LEX="flex"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_LEX" && ac_cv_prog_LEX="lex"
+fi
+fi
+LEX="$ac_cv_prog_LEX"
+if test -n "$LEX"; then
+ echo "$ac_t""$LEX" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$LEXLIB"
+then
+ case "$LEX" in
+ flex*) ac_lib=fl ;;
+ *) ac_lib=l ;;
+ esac
+ echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6
+echo "configure:1504: checking for yywrap in -l$ac_lib" >&5
+ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-l$ac_lib $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1512 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char yywrap();
+
+int main() {
+yywrap()
+; return 0; }
+EOF
+if { (eval echo configure:1523: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LEXLIB="-l$ac_lib"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking lex output file root""... $ac_c" 1>&6
+echo "configure:1546: checking lex output file root" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_lex_root'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # The minimal lex program is just a single line: %%. But some broken lexes
+# (Solaris, I think it was) want two %% lines, so accommodate them.
+echo '%%
+%%' | $LEX
+if test -f lex.yy.c; then
+ ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+ ac_cv_prog_lex_root=lexyy
+else
+ { echo "configure: error: cannot find output from $LEX; giving up" 1>&2; exit 1; }
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_lex_root" 1>&6
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+echo $ac_n "checking whether yytext is a pointer""... $ac_c" 1>&6
+echo "configure:1567: checking whether yytext is a pointer" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_lex_yytext_pointer'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent. Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c
+ac_save_LIBS="$LIBS"
+LIBS="$LIBS $LEXLIB"
+cat > conftest.$ac_ext <<EOF
+#line 1579 "configure"
+#include "confdefs.h"
+`cat $LEX_OUTPUT_ROOT.c`
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:1586: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_prog_lex_yytext_pointer=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+rm -f "${LEX_OUTPUT_ROOT}.c"
+
+fi
+
+echo "$ac_t""$ac_cv_prog_lex_yytext_pointer" 1>&6
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+ cat >> confdefs.h <<\EOF
+#define YYTEXT_POINTER 1
+EOF
+
+fi
+
+# Extract the first word of "tar", so it can be a program name with args.
+set dummy tar; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1610: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_TAR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$TAR" in
+ /*)
+ ac_cv_path_TAR="$TAR" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_TAR="$TAR" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_TAR="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+TAR="$ac_cv_path_TAR"
+if test -n "$TAR"; then
+ echo "$ac_t""$TAR" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "gzip", so it can be a program name with args.
+set dummy gzip; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1645: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_GZIP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$GZIP" in
+ /*)
+ ac_cv_path_GZIP="$GZIP" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_GZIP="$GZIP" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_GZIP="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+GZIP="$ac_cv_path_GZIP"
+if test -n "$GZIP"; then
+ echo "$ac_t""$GZIP" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking where to put logfile""... $ac_c" 1>&6
+echo "configure:1679: checking where to put logfile" >&5
+# Check whether --with-logfile or --without-logfile was given.
+if test "${with_logfile+set}" = set; then
+ withval="$with_logfile"
+ PATH_RADVD_LOG=$withval
+else
+ PATH_RADVD_LOG=/var/log/radvd.log
+fi
+
+echo "$ac_t""$PATH_RADVD_LOG" 1>&6
+
+echo $ac_n "checking where to put pidfile""... $ac_c" 1>&6
+echo "configure:1691: checking where to put pidfile" >&5
+# Check whether --with-pidfile or --without-pidfile was given.
+if test "${with_pidfile+set}" = set; then
+ withval="$with_pidfile"
+ PATH_RADVD_PID=$withval
+else
+ PATH_RADVD_PID=/var/run/radvd.pid
+fi
+
+echo "$ac_t""$PATH_RADVD_PID" 1>&6
+
+echo $ac_n "checking where to find configfile""... $ac_c" 1>&6
+echo "configure:1703: checking where to find configfile" >&5
+# Check whether --with-configfile or --without-configfile was given.
+if test "${with_configfile+set}" = set; then
+ withval="$with_configfile"
+ PATH_RADVD_CONF=$withval
+else
+ PATH_RADVD_CONF=${sysconfdir}/radvd.conf
+fi
+
+echo "$ac_t""$PATH_RADVD_CONF" 1>&6
+
+echo $ac_n "checking which syslog facility to use""... $ac_c" 1>&6
+echo "configure:1715: checking which syslog facility to use" >&5
+# Check whether --with-facility or --without-facility was given.
+if test "${with_facility+set}" = set; then
+ withval="$with_facility"
+ LOG_FACILITY=$withval
+else
+ LOG_FACILITY=LOG_DAEMON
+fi
+
+echo "$ac_t""$LOG_FACILITY" 1>&6
+
+
+echo $ac_n "checking for inet_ntop in -lc""... $ac_c" 1>&6
+echo "configure:1728: checking for inet_ntop in -lc" >&5
+ac_lib_var=`echo c'_'inet_ntop | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lc $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1736 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inet_ntop();
+
+int main() {
+inet_ntop()
+; return 0; }
+EOF
+if { (eval echo configure:1747: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo c | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lc $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for inet_ntop in -linet6""... $ac_c" 1>&6
+echo "configure:1773: checking for inet_ntop in -linet6" >&5
+ac_lib_var=`echo inet6'_'inet_ntop | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-linet6 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1781 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inet_ntop();
+
+int main() {
+inet_ntop()
+; return 0; }
+EOF
+if { (eval echo configure:1792: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -linet6"
+
+else
+ echo "$ac_t""no" 1>&6
+{ echo "configure: error: can't continue without libinet6.a library - check your LDFLAGS" 1>&2; exit 1; }
+
+fi
+
+
+fi
+
+# prevent caching
+unset ac_cv_lib_inet6_inet_ntop
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1822: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1827 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1835: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1852 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1870 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1891 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1902: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in sys/time.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1929: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1934 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1939: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1966: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1971 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1980: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+
+ac_safe=`echo "netinet/ip6.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for netinet/ip6.h""... $ac_c" 1>&6
+echo "configure:2003: checking for netinet/ip6.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2008 "configure"
+#include "confdefs.h"
+#include <netinet/ip6.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2013: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ hdrfound=yes
+else
+ echo "$ac_t""no" 1>&6
+hdrfound=no
+fi
+
+if test "$hdrfound" = no
+then
+ # deprecated
+ ac_safe=`echo "netinet/ipv6.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for netinet/ipv6.h""... $ac_c" 1>&6
+echo "configure:2040: checking for netinet/ipv6.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2045 "configure"
+#include "confdefs.h"
+#include <netinet/ipv6.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2050: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ hdrfound=yes
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+if test "$hdrfound" = no
+then
+ echo "$ac_t""no" 1>&6
+fi
+unset hdrfound
+
+for ac_hdr in sys/sockio.h getopt.h inttypes.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2082: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2087 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2092: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in net/if_dl.h net/if_types.h net/if_arp.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2122: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2127 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2132: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in sys/param.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2162: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2167 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2172: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in machine/param.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2202: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2207 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2212: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in machine/limits.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2242: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2247 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2252: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:2280: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2285 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:2334: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+
+echo $ac_n "checking whether struct sockaddr_in6 has sin6_scope_id""... $ac_c" 1>&6
+echo "configure:2356: checking whether struct sockaddr_in6 has sin6_scope_id" >&5
+cat > conftest.$ac_ext <<EOF
+#line 2358 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <netinet/in.h>
+int main() {
+static struct sockaddr_in6 ac_sin6; int ac_size =
+sizeof (ac_sin6.sin6_scope_id);
+; return 0; }
+EOF
+if { (eval echo configure:2367: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define HAVE_SIN6_SCOPE_ID 1
+EOF
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+echo $ac_n "checking whether struct in6_addr has u6_addrXX and defines s6_addrXX""... $ac_c" 1>&6
+echo "configure:2382: checking whether struct in6_addr has u6_addrXX and defines s6_addrXX" >&5
+cat > conftest.$ac_ext <<EOF
+#line 2384 "configure"
+#include "confdefs.h"
+#include <netinet/in.h>
+int main() {
+static struct in6_addr in6_u;
+int u = in6_u.s6_addr16;
+; return 0; }
+EOF
+if { (eval echo configure:2392: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define HAVE_IN6_ADDR_S6_ADDR 1
+EOF
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+for ac_func in getopt_long
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2409: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2414 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2437: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+
+
+
+
+
+
+
+
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@target@%$target%g
+s%@target_alias@%$target_alias%g
+s%@target_cpu@%$target_cpu%g
+s%@target_vendor@%$target_vendor%g
+s%@target_os@%$target_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@RM@%$RM%g
+s%@SED@%$SED%g
+s%@LN@%$LN%g
+s%@YACC@%$YACC%g
+s%@LEX@%$LEX%g
+s%@LEXLIB@%$LEXLIB%g
+s%@CPP@%$CPP%g
+s%@LEX_OUTPUT_ROOT@%$LEX_OUTPUT_ROOT%g
+s%@TAR@%$TAR%g
+s%@GZIP@%$GZIP%g
+s%@PATH_RADVD_CONF@%$PATH_RADVD_CONF%g
+s%@PATH_RADVD_PID@%$PATH_RADVD_PID%g
+s%@PATH_RADVD_LOG@%$PATH_RADVD_LOG%g
+s%@LOG_FACILITY@%$LOG_FACILITY%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+ac_sources="device-${arch}.c"
+ac_dests="device.c"
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+srcdir=$ac_given_srcdir
+while test -n "$ac_sources"; do
+ set $ac_dests; ac_dest=$1; shift; ac_dests=$*
+ set $ac_sources; ac_source=$1; shift; ac_sources=$*
+
+ echo "linking $srcdir/$ac_source to $ac_dest"
+
+ if test ! -r $srcdir/$ac_source; then
+ { echo "configure: error: $srcdir/$ac_source: File not found" 1>&2; exit 1; }
+ fi
+ rm -f $ac_dest
+
+ # Make relative symlinks.
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dest_dir=`echo $ac_dest|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dest_dir" != "$ac_dest" && test "$ac_dest_dir" != .; then
+ # The dest file is in a subdirectory.
+ test ! -d "$ac_dest_dir" && mkdir "$ac_dest_dir"
+ ac_dest_dir_suffix="/`echo $ac_dest_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dest_dir_suffix.
+ ac_dots=`echo $ac_dest_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dest_dir_suffix= ac_dots=
+ fi
+
+ case "$srcdir" in
+ [/$]*) ac_rel_source="$srcdir/$ac_source" ;;
+ *) ac_rel_source="$ac_dots$srcdir/$ac_source" ;;
+ esac
+
+ # Make a symlink if possible; otherwise try a hard link.
+ if ln -s $ac_rel_source $ac_dest 2>/dev/null ||
+ ln $srcdir/$ac_source $ac_dest; then :
+ else
+ { echo "configure: error: can not link $ac_dest to $srcdir/$ac_source" 1>&2; exit 1; }
+ fi
+done
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
--- /dev/null
+dnl
+dnl $Id$
+dnl
+dnl Authors:
+dnl Lars Fenneberg <lf@elemental.net>
+dnl
+dnl This software is Copyright 1996-2000 by the above mentioned author(s),
+dnl All Rights Reserved.
+dnl
+dnl The license which is distributed with this software in the file COPYRIGHT
+dnl applies to this software. If your distribution is missing this file, you
+dnl may request it from <pekkas@netcore.fi>.
+dnl
+dnl
+
+AC_REVISION ($Id$)
+AC_INIT(radvd.c)
+
+AC_CANONICAL_SYSTEM
+VERSION=`cat ${srcdir}/VERSION | grep -v '^#' | tr -d '\012'`
+AM_INIT_AUTOMAKE(radvd,$VERSION,true)
+
+echo $ac_n "building for architecture""... $ac_c" 1>&6
+case "$target" in
+ *linux*)
+ AC_MSG_RESULT(linux)
+ arch=linux
+ ;;
+ *bsd*)
+ AC_MSG_RESULT(bsd44)
+ arch=bsd44
+ ;;
+ *)
+ AC_MSG_RESULT(unknown)
+ AC_MSG_ERROR(
+[currently only Linux and BSD 4.4 with NRL's IPv6 code are
+supported. If you have such a system and it is not guessed correctly
+you must specifiy it with --target on the configure command line])
+ ;;
+esac
+
+dnl Determine CC and preset CFLAGS
+AC_PROG_CC
+
+dnl Needed for normal compile
+AC_PROG_INSTALL
+AC_PATH_PROG(RM, rm, NOTFOUND)
+if test "x$RM" = xNOTFOUND; then
+ AC_MSG_ERROR(can't find rm in your path - check PATH)
+fi
+AC_PATH_PROG(SED, sed, NOTFOUND)
+if test "x$SED" = xNOTFOUND; then
+ AC_MSG_ERROR(can't find sed in your path - check PATH)
+fi
+dnl Not needed
+AC_PATH_PROG(LN, ln)
+AC_PROG_YACC
+AM_PROG_LEX
+AC_PATH_PROG(TAR, tar)
+AC_PATH_PROG(GZIP, gzip)
+
+dnl Check where to put the logfile
+AC_MSG_CHECKING(where to put logfile)
+AC_ARG_WITH(logfile,
+[ --with-logfile Path to the radvd logfile [/var/log/radvd.log]],
+ PATH_RADVD_LOG=$withval,
+ PATH_RADVD_LOG=/var/log/radvd.log)
+AC_MSG_RESULT($PATH_RADVD_LOG)
+
+dnl Check where to put the pidfile
+AC_MSG_CHECKING(where to put pidfile)
+AC_ARG_WITH(pidfile,
+[ --with-pidfile Path to the radvd pidfile [/var/run/radvd.pid]],
+ PATH_RADVD_PID=$withval,
+ PATH_RADVD_PID=/var/run/radvd.pid)
+AC_MSG_RESULT($PATH_RADVD_PID)
+
+dnl Check where to put the configfile
+AC_MSG_CHECKING(where to find configfile)
+AC_ARG_WITH(configfile,
+[ --with-configfile Path to the radvd config file [SYSCONF/radvd.conf]],
+ PATH_RADVD_CONF=$withval,
+ PATH_RADVD_CONF=${sysconfdir}/radvd.conf)
+AC_MSG_RESULT($PATH_RADVD_CONF)
+
+dnl Checking which syslog facility to use
+AC_MSG_CHECKING(which syslog facility to use)
+AC_ARG_WITH(facility,
+[ --with-facility Syslog facility to use when using syslog logging],
+ LOG_FACILITY=$withval,
+ LOG_FACILITY=LOG_DAEMON)
+AC_MSG_RESULT($LOG_FACILITY)
+
+dnl Checks for libraries.
+
+AC_CHECK_LIB(c, inet_ntop,,
+ AC_CHECK_LIB(inet6, inet_ntop,
+ LIBS="$LIBS -linet6"
+ ,
+ AC_MSG_ERROR(can't continue without libinet6.a library - check your LDFLAGS)
+ )
+)
+# prevent caching
+unset ac_cv_lib_inet6_inet_ntop
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(sys/time.h)
+AC_HEADER_TIME
+
+AC_CHECK_HEADER(netinet/ip6.h, hdrfound=yes, hdrfound=no)
+if test "$hdrfound" = no
+then
+ # deprecated
+ AC_CHECK_HEADER(netinet/ipv6.h, hdrfound=yes)
+fi
+if test "$hdrfound" = no
+then
+ AC_MSG_RESULT(no)
+fi
+unset hdrfound
+
+AC_CHECK_HEADERS(sys/sockio.h getopt.h inttypes.h)
+AC_CHECK_HEADERS(net/if_dl.h net/if_types.h net/if_arp.h)
+AC_CHECK_HEADERS(sys/param.h)
+AC_CHECK_HEADERS(machine/param.h)
+AC_CHECK_HEADERS(machine/limits.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+
+AC_MSG_CHECKING(whether struct sockaddr_in6 has sin6_scope_id)
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <netinet/in.h>], [static struct sockaddr_in6 ac_sin6; int ac_size =
+sizeof (ac_sin6.sin6_scope_id);], [AC_MSG_RESULT(yes); AC_DEFINE([HAVE_SIN6_SCOPE_ID],
+1, [whether struct sockaddr_in6 has sin6_scope_id])],
+AC_MSG_RESULT(no))
+
+AC_MSG_CHECKING(whether struct in6_addr has u6_addrXX and defines s6_addrXX)
+AC_TRY_COMPILE([#include <netinet/in.h>], [static struct in6_addr in6_u;
+int u = in6_u.s6_addr16;], [AC_MSG_RESULT(yes); AC_DEFINE([HAVE_IN6_ADDR_S6_ADDR],
+1, [whether struct in6_addr has u6_addrXX and defines s6_addrXX])],
+AC_MSG_RESULT(no))
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(getopt_long)
+
+AC_LINK_FILES(device-${arch}.c, device.c)
+
+AC_SUBST(VERSION)
+AC_SUBST(PATH_RADVD_CONF)
+AC_SUBST(PATH_RADVD_PID)
+AC_SUBST(PATH_RADVD_LOG)
+AC_SUBST(LOG_FACILITY)
+
+AM_CONFIG_HEADER(config.h)
+AC_OUTPUT(Makefile)
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#ifndef DEFAULTS_H
+#define DEFAULTS_H
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+
+/* maximum message size for incoming and outgoing RSs and RAs */
+
+#define MSG_SIZE 4096
+
+#define MAX2(X,Y) ( (( X ) >= ( Y )) ? ( X ) : ( Y ))
+
+
+/* Router Configuration Variables: */
+
+/* For each multicast interface: */
+
+#define DFLT_IgnoreIfMissing 0
+#define DFLT_AdvSendAdv 0
+#define DFLT_MaxRtrAdvInterval 600
+#define DFLT_MinRtrAdvInterval(iface) (0.33 * (iface)->MaxRtrAdvInterval)
+#define DFLT_AdvManagedFlag 0
+#define DFLT_AdvOtherConfigFlag 0
+#define DFLT_AdvLinkMTU 0
+#define DFLT_AdvReachableTime 0
+#define DFLT_AdvRetransTimer 0
+#define DFLT_AdvCurHopLimit 64 /* as per RFC 1700 or the
+ next incarnation of it :) */
+#define DFLT_AdvDefaultLifetime(iface) MAX2(1, (int)(3.0 * (iface)->MaxRtrAdvInterval))
+#define DFLT_MinDelayBetweenRAs MIN_DELAY_BETWEEN_RAS
+#define DFLT_AdvDefaultPreference 0
+
+/* Options sent with RA */
+
+#define DFLT_AdvSourceLLAddress 1
+
+/* Each prefix has an associated: */
+
+#define DFLT_AdvValidLifetime 2592000 /* seconds */
+#define DFLT_AdvOnLinkFlag 1
+#define DFLT_AdvPreferredLifetime 604800 /* seconds */
+#define DFLT_AdvAutonomousFlag 1
+
+/* Each route has an associated: */
+#define DFLT_AdvRouteLifetime(iface) (3 * (iface)->MaxRtrAdvInterval)
+
+#define DFLT_AdvRoutePreference 0 /* medium*/
+
+/* RDNSS */
+#define DFLT_AdvRDNSSPreference 8 /* medium */
+#define DFLT_AdvRDNSSOpenFlag 0
+#define DFLT_AdvRDNSSLifetime(iface) (iface)->MaxRtrAdvInterval
+
+/* Protocol (RFC2461) constants: */
+
+/* Router constants: */
+
+#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16
+#define MAX_INITIAL_RTR_ADVERTISEMENTS 3
+#define MAX_FINAL_RTR_ADVERTISEMENTS 3
+#define MIN_DELAY_BETWEEN_RAS 3.0
+#define MIN_DELAY_BETWEEN_RAS_MIPv6 (30.0/1000.0)
+#define MAX_RA_DELAY_TIME (1000.0/2.0) /* milliseconds */
+
+/* Host constants: */
+
+#define MAX_RTR_SOLICITATION_DELAY 1
+#define RTR_SOLICITATION_INTERVAL 4
+#define MAX_RTR_SOLICITATIONS 3
+
+/* Node constants: */
+
+#define MAX_MULTICAST_SOLICIT 3
+#define MAX_UNICAST_SOLICIT 3
+#define MAX_ANYCAST_DELAY_TIME 1
+#define MAX_NEIGHBOR_ADVERTISEMENT 3
+#define REACHABLE_TIME 30000 /* milliseconds */
+#define RETRANS_TIMER 1000 /* milliseconds */
+#define DELAY_FIRST_PROBE_TIME 5
+#define MIN_RANDOM_FACTOR (1.0/2.0)
+#define MAX_RANDOM_FACTOR (3.0/2.0)
+
+/* MAX and MIN (RFC2461), Mobile IPv6 extensions will override if in use */
+
+#define MIN_MaxRtrAdvInterval 4
+#define MAX_MaxRtrAdvInterval 1800
+
+#define MIN_MinRtrAdvInterval 3
+#define MAX_MinRtrAdvInterval(iface) (0.75 * (iface)->MaxRtrAdvInterval)
+
+#define MIN_AdvDefaultLifetime(iface) (MAX2(1,(iface)->MaxRtrAdvInterval))
+#define MAX_AdvDefaultLifetime 9000
+
+#define MIN_AdvLinkMTU 1280
+
+#define MAX_AdvReachableTime 3600000 /* 1 hour in milliseconds */
+
+#define MAX_AdvCurHopLimit 255
+
+#define MAX_PrefixLen 128
+
+/*
+ * Mobile IPv6 extensions, off by default
+ */
+
+#define DFLT_AdvRouterAddr 0
+#define DFLT_AdvHomeAgentFlag 0
+#define DFLT_AdvIntervalOpt 0
+#define DFLT_AdvHomeAgentInfo 0
+
+/* Option types (defined also at least in glibc 2.2's netinet/icmp6.h) */
+
+#ifndef ND_OPT_RTR_ADV_INTERVAL
+#define ND_OPT_RTR_ADV_INTERVAL 7
+#endif
+#ifndef ND_OPT_HOME_AGENT_INFO
+#define ND_OPT_HOME_AGENT_INFO 8
+#endif
+
+/* de-facto codepoint used by many implementations was '9',
+ the official IANA assignment will be '24' */
+#undef ND_OPT_ROUTE_INFORMATION
+#define ND_OPT_ROUTE_INFORMATION 24
+
+/* XXX: some libc's like KAME already had nd_opt_route_info! */
+struct nd_opt_route_info_local /* route information */
+ {
+ uint8_t nd_opt_ri_type;
+ uint8_t nd_opt_ri_len;
+ uint8_t nd_opt_ri_prefix_len;
+ uint8_t nd_opt_ri_flags_reserved;
+ uint32_t nd_opt_ri_lifetime;
+ struct in6_addr nd_opt_ri_prefix;
+ };
+
+/* the reserved field is 8 bits and we're interested of the middle two: 000xx000 */
+#define ND_OPT_RI_PRF_SHIFT 3
+#define ND_OPT_RI_PRF_MASK (3 << ND_OPT_RI_PRF_SHIFT) /* 00011000 = 0x18 */
+
+#undef ND_OPT_RDNSS_INFORMATION
+#define ND_OPT_RDNSS_INFORMATION 25
+
+/* */
+struct nd_opt_rdnss_info_local
+{
+ uint8_t nd_opt_rdnssi_type;
+ uint8_t nd_opt_rdnssi_len;
+ uint16_t nd_opt_rdnssi_pref_flag_reserved;
+ uint32_t nd_opt_rdnssi_lifetime;
+ struct in6_addr nd_opt_rdnssi_addr1;
+ struct in6_addr nd_opt_rdnssi_addr2;
+ struct in6_addr nd_opt_rdnssi_addr3;
+};
+/* pref/flag/reserved field : yyyyx00000000000 (big endian) - 00000000yyyyx000 (little indian); where yyyy = pref, x = flag */
+#if BYTE_ORDER == BIG_ENDIAN
+#define ND_OPT_RDNSSI_PREF_SHIFT 12
+#else
+#define ND_OPT_RDNSSI_PREF_SHIFT 4
+#endif
+#define ND_OPT_RDNSSI_PREF_MASK (0xf << ND_OPT_RDNSSI_PREF_SHIFT)
+
+/* Flags */
+
+#ifndef ND_RA_FLAG_HOME_AGENT
+#define ND_RA_FLAG_HOME_AGENT 0x20
+#endif
+#ifndef ND_OPT_PI_FLAG_RADDR
+#define ND_OPT_PI_FLAG_RADDR 0x20
+#endif
+#ifndef ND_OPT_RDNSSI_FLAG_S
+#if BYTE_ORDER == BIG_ENDIAN
+#define ND_OPT_RDNSSI_FLAG_S 0x0800
+#else
+#define ND_OPT_RDNSSI_FLAG_S 0x0008
+#endif
+#endif
+
+/* Configurable values */
+
+#define DFLT_HomeAgentPreference 0
+#define DFLT_HomeAgentLifetime(iface) ((iface)->AdvDefaultLifetime)
+
+/* Other */
+
+#define MIN_MinRtrAdvInterval_MIPv6 (3.0/100.0)
+#define MIN_MaxRtrAdvInterval_MIPv6 (7.0/100.0)
+#define RTR_SOLICITATION_INTERVAL_MIPv6 1 /* Recommended value by MIPv6 */
+
+#define Cautious_MaxRtrAdvInterval (2.0/10.0)
+#define Cautious_MaxRtrAdvInterval_Leeway (2.0/100.0)
+
+#define MIN_HomeAgentLifetime 1 /* 0 must NOT be used */
+#define MAX_HomeAgentLifetime 65520 /* 18.2 hours in secs */
+
+/* #define MAX_RTR_SOLICITATIONS This MAY be ignored by MIPv6 */
+
+/* NEMO extensions, off by default */
+#define DFLT_AdvMobRtrSupportFlag 0
+
+/* Flags */
+
+#ifndef ND_OPT_HAI_FLAG_SUPPORT_MR
+#if BYTE_ORDER == BIG_ENDIAN
+#define ND_OPT_HAI_FLAG_SUPPORT_MR 0x8000
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+#define ND_OPT_HAI_FLAG_SUPPORT_MR 0x0080
+#endif
+#endif
+
+#endif
--- /dev/null
+#! /bin/sh
+
+# depcomp - compile a program generating dependencies as side-effects
+# Copyright 1999, 2000, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+# `libtool' can also be set to `yes' or `no'.
+
+if test -z "$depfile"; then
+ base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'`
+ dir=`echo "$object" | sed 's,/.*$,/,'`
+ if test "$dir" = "$object"; then
+ dir=
+ fi
+ # FIXME: should be _deps on DOS.
+ depfile="$dir.deps/$base"
+fi
+
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+ "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> $depfile
+ echo >> $depfile
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> $depfile
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
+ tmpdepfile="$stripped.u"
+ if test "$libtool" = yes; then
+ "$@" -Wc,-M
+ else
+ "$@" -M
+ fi
+ stat=$?
+
+ if test -f "$tmpdepfile"; then :
+ else
+ stripped=`echo "$stripped" | sed 's,^.*/,,'`
+ tmpdepfile="$stripped.u"
+ fi
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile"; then
+ outname="$stripped.o"
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+ sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ tmpdepfile1="$dir.libs/$base.lo.d"
+ tmpdepfile2="$dir.libs/$base.d"
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1="$dir$base.o.d"
+ tmpdepfile2="$dir$base.d"
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile1"; then
+ tmpdepfile="$tmpdepfile1"
+ else
+ tmpdepfile="$tmpdepfile2"
+ fi
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "$@" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix="`echo $object | sed 's/^.*\././'`"
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ "$@" || exit $?
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Craig Metz <cmetz@inner.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+#include <defaults.h>
+#include <pathnames.h> /* for PATH_PROC_NET_IF_INET6 */
+
+static uint8_t ll_prefix[] = { 0xfe, 0x80 };
+
+/*
+ * this function gets the hardware type and address of an interface,
+ * determines the link layer token length and checks it against
+ * the defined prefixes
+ */
+int
+setup_deviceinfo(int sock, struct Interface *iface)
+{
+ struct ifconf ifconf;
+ struct ifreq ifr;
+ unsigned int nlen;
+ uint8_t *p, *end;
+ struct AdvPrefix *prefix;
+ char zero[sizeof(iface->if_addr)];
+
+ /* just allocate 8192 bytes, should be more than enough.. */
+ if (!(ifconf.ifc_buf = malloc(ifconf.ifc_len = (32 << 8))))
+ {
+ flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
+ goto ret;
+ }
+
+ if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0)
+ {
+ flog(LOG_ERR, "ioctl(SIOCGIFCONF) failed: %s(%d)", strerror(errno), errno);
+ goto ret;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, iface->Name, IFNAMSIZ-1);
+ ifr.ifr_name[IFNAMSIZ-1] = '\0';
+
+ if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) {
+ flog(LOG_ERR, "ioctl(SIOCGIFMTU) failed for %s: %s", iface->Name, strerror(errno));
+ goto ret;
+ }
+
+ dlog(LOG_DEBUG, 3, "mtu for %s is %d", iface->Name, ifr.ifr_mtu);
+ iface->if_maxmtu = ifr.ifr_mtu;
+
+ p = (uint8_t *)ifconf.ifc_buf;
+ end = p + ifconf.ifc_len;
+ nlen = strlen(iface->Name);
+
+ while(p < end)
+ {
+ p += IFNAMSIZ;
+
+ if ((p + 2) >= end)
+ break;
+
+ if ((p + *p) >= end)
+ break;
+
+ if ((*(p + 1) == AF_LINK) &&
+ (((struct sockaddr_dl *)p)->sdl_nlen == nlen) &&
+ (!memcmp(iface->Name, ((struct sockaddr_dl *)p)->sdl_data, nlen)))
+ {
+
+ if (((struct sockaddr_dl *)p)->sdl_alen > sizeof(iface->if_addr))
+ {
+ flog(LOG_ERR, "address length %d too big for",
+ ((struct sockaddr_dl *)p)->sdl_alen,
+ iface->Name);
+ goto ret;
+ }
+
+ memcpy(iface->if_hwaddr, LLADDR((struct sockaddr_dl *)p), ((struct sockaddr_dl *)p)->sdl_alen);
+ iface->if_hwaddr_len = ((struct sockaddr_dl *)p)->sdl_alen << 3;
+
+ switch(((struct sockaddr_dl *)p)->sdl_type) {
+ case IFT_ETHER:
+ case IFT_ISO88023:
+ iface->if_prefix_len = 64;
+ break;
+ case IFT_FDDI:
+ iface->if_prefix_len = 64;
+ break;
+ default:
+ iface->if_prefix_len = -1;
+ iface->if_maxmtu = -1;
+ break;
+ }
+
+ dlog(LOG_DEBUG, 3, "link layer token length for %s is %d", iface->Name,
+ iface->if_hwaddr_len);
+
+ dlog(LOG_DEBUG, 3, "prefix length for %s is %d", iface->Name,
+ iface->if_prefix_len);
+
+ if (iface->if_prefix_len != -1) {
+ memset(zero, 0, ((struct sockaddr_dl *)p)->sdl_alen);
+ if (!memcmp(iface->if_hwaddr, zero, ((struct sockaddr_dl *)p)->sdl_alen))
+ flog(LOG_WARNING, "WARNING, MAC address on %s is all zero!",
+ iface->Name);
+ }
+
+ prefix = iface->AdvPrefixList;
+ while (prefix)
+ {
+ if ((iface->if_prefix_len != -1) &&
+ (iface->if_prefix_len != prefix->PrefixLen))
+ {
+ flog(LOG_WARNING, "prefix length should be %d for %s",
+ iface->if_prefix_len, iface->Name);
+ }
+
+ prefix = prefix->next;
+ }
+
+ free(ifconf.ifc_buf);
+ return 0;
+ }
+
+ p += *p;
+ }
+
+ret:
+ iface->if_maxmtu = -1;
+ iface->if_hwaddr_len = -1;
+ iface->if_prefix_len = -1;
+ free(ifconf.ifc_buf);
+ return -1;
+}
+
+int setup_linklocal_addr(int sock, struct Interface *iface)
+{
+ struct ifconf ifconf;
+ unsigned int nlen;
+ uint8_t *p, *end;
+ int index = 0;
+
+ /* just allocate 8192 bytes, should be more than enough.. */
+ if (!(ifconf.ifc_buf = malloc(ifconf.ifc_len = (32 << 8))))
+ {
+ flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
+ goto ret;
+ }
+
+ if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0)
+ {
+ flog(LOG_ERR, "ioctl(SIOCGIFCONF) failed: %s(%d)", strerror(errno), errno);
+ goto ret;
+ }
+
+ p = (uint8_t *)ifconf.ifc_buf;
+ end = p + ifconf.ifc_len;
+ nlen = strlen(iface->Name);
+
+ while(p < end)
+ {
+ p += IFNAMSIZ;
+
+ if ((p + 2) >= end)
+ break;
+
+ if ((p + *p) >= end)
+ break;
+
+ if ((*(p + 1) == AF_LINK) &&
+ (((struct sockaddr_dl *)p)->sdl_nlen == nlen) &&
+ (!memcmp(iface->Name, ((struct sockaddr_dl *)p)->sdl_data, nlen)))
+ {
+ index = ((struct sockaddr_dl *)p)->sdl_index;
+ }
+
+ if (index && (*(p + 1) == AF_INET6))
+ if (!memcmp(&((struct sockaddr_in6 *)p)->sin6_addr, ll_prefix, sizeof(ll_prefix)))
+ {
+ memcpy(&iface->if_addr, &((struct sockaddr_in6 *)p)->sin6_addr, sizeof(struct in6_addr));
+ iface->if_index = index;
+
+ free(ifconf.ifc_buf);
+ return 0;
+ }
+
+ p += *p;
+
+ }
+
+ret:
+ flog(LOG_ERR, "no linklocal address configured for %s", iface->Name);
+ free(ifconf.ifc_buf);
+ return -1;
+}
+
+int setup_allrouters_membership(int sock, struct Interface *iface)
+{
+ return (0);
+}
+
+int check_allrouters_membership(int sock, struct Interface *iface)
+{
+ return (0);
+}
+
+int
+set_interface_linkmtu(const char *iface, uint32_t mtu)
+{
+ dlog(LOG_DEBUG, 4, "setting LinkMTU (%u) for %s is not supported",
+ mtu, iface);
+ return -1;
+}
+
+int
+set_interface_curhlim(const char *iface, uint8_t hlim)
+{
+ dlog(LOG_DEBUG, 4, "setting CurHopLimit (%u) for %s is not supported",
+ hlim, iface);
+ return -1;
+}
+
+int
+set_interface_reachtime(const char *iface, uint32_t rtime)
+{
+ dlog(LOG_DEBUG, 4, "setting BaseReachableTime (%u) for %s is not supported",
+ rtime, iface);
+ return -1;
+}
+
+int
+set_interface_retranstimer(const char *iface, uint32_t rettimer)
+{
+ dlog(LOG_DEBUG, 4, "setting RetransTimer (%u) for %s is not supported",
+ rettimer, iface);
+ return -1;
+}
+
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+#include <defaults.h>
+
+int
+check_device(int sock, struct Interface *iface)
+{
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, iface->Name, IFNAMSIZ-1);
+ ifr.ifr_name[IFNAMSIZ-1] = '\0';
+
+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0)
+ {
+ if (!iface->IgnoreIfMissing)
+ flog(LOG_ERR, "ioctl(SIOCGIFFLAGS) failed for %s: %s",
+ iface->Name, strerror(errno));
+ return (-1);
+ }
+
+ if (!(ifr.ifr_flags & IFF_UP))
+ {
+ if (!iface->IgnoreIfMissing)
+ flog(LOG_ERR, "interface %s is not UP", iface->Name);
+ return (-1);
+ }
+
+ if (! iface->UnicastOnly && !(ifr.ifr_flags & IFF_MULTICAST))
+ {
+ flog(LOG_WARNING, "interface %s does not support multicast",
+ iface->Name);
+ flog(LOG_WARNING, " do you need to add the UnicastOnly flag?");
+ }
+
+#if 0
+ /* SDH : ignore these warnings... */
+ if (! iface->UnicastOnly && !(ifr.ifr_flags & IFF_BROADCAST))
+ {
+ flog(LOG_WARNING, "interface %s does not support broadcast",
+ iface->Name);
+ flog(LOG_WARNING, " do you need to add the UnicastOnly flag?");
+ }
+#endif
+
+ return 0;
+}
+
+int
+get_v4addr(const char *ifn, unsigned int *dst)
+{
+ struct ifreq ifr;
+ struct sockaddr_in *addr;
+ int fd;
+
+ if( ( fd = socket(AF_INET,SOCK_DGRAM,0) ) < 0 )
+ {
+ flog(LOG_ERR, "create socket for IPv4 ioctl failed for %s: %s",
+ ifn, strerror(errno));
+ return (-1);
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifn, IFNAMSIZ-1);
+ ifr.ifr_name[IFNAMSIZ-1] = '\0';
+ ifr.ifr_addr.sa_family = AF_INET;
+
+ if (ioctl(fd, SIOCGIFADDR, &ifr) < 0)
+ {
+ flog(LOG_ERR, "ioctl(SIOCGIFADDR) failed for %s: %s",
+ ifn, strerror(errno));
+ close( fd );
+ return (-1);
+ }
+
+ addr = (struct sockaddr_in *)(&ifr.ifr_addr);
+
+ dlog(LOG_DEBUG, 3, "IPv4 address for %s is %s", ifn,
+ inet_ntoa( addr->sin_addr ) );
+
+ *dst = addr->sin_addr.s_addr;
+
+ close( fd );
+
+ return 0;
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+#include <defaults.h>
+#include <pathnames.h> /* for PATH_PROC_NET_IF_INET6 */
+
+#ifndef IPV6_ADDR_LINKLOCAL
+#define IPV6_ADDR_LINKLOCAL 0x0020U
+#endif
+
+/*
+ * this function gets the hardware type and address of an interface,
+ * determines the link layer token length and checks it against
+ * the defined prefixes
+ */
+int
+setup_deviceinfo(int sock, struct Interface *iface)
+{
+ struct ifreq ifr;
+ struct AdvPrefix *prefix;
+ char zero[sizeof(iface->if_addr)];
+
+ strncpy(ifr.ifr_name, iface->Name, IFNAMSIZ-1);
+ ifr.ifr_name[IFNAMSIZ-1] = '\0';
+
+ if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) {
+ flog(LOG_ERR, "ioctl(SIOCGIFMTU) failed for %s: %s",
+ iface->Name, strerror(errno));
+ return (-1);
+ }
+
+ dlog(LOG_DEBUG, 3, "mtu for %s is %d", iface->Name, ifr.ifr_mtu);
+ iface->if_maxmtu = ifr.ifr_mtu;
+
+ if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
+ {
+ flog(LOG_ERR, "ioctl(SIOCGIFHWADDR) failed for %s: %s",
+ iface->Name, strerror(errno));
+ return (-1);
+ }
+
+ dlog(LOG_DEBUG, 3, "hardware type for %s is %d", iface->Name,
+ ifr.ifr_hwaddr.sa_family);
+
+ switch(ifr.ifr_hwaddr.sa_family)
+ {
+ case ARPHRD_ETHER:
+ iface->if_hwaddr_len = 48;
+ iface->if_prefix_len = 64;
+ break;
+#ifdef ARPHRD_FDDI
+ case ARPHRD_FDDI:
+ iface->if_hwaddr_len = 48;
+ iface->if_prefix_len = 64;
+ break;
+#endif /* ARPHDR_FDDI */
+#ifdef ARPHRD_ARCNET
+ case ARPHRD_ARCNET:
+ iface->if_hwaddr_len = 8;
+ iface->if_prefix_len = -1;
+ iface->if_maxmtu = -1;
+ break;
+#endif /* ARPHDR_ARCNET */
+ default:
+ iface->if_hwaddr_len = -1;
+ iface->if_prefix_len = -1;
+ iface->if_maxmtu = -1;
+ break;
+ }
+
+ dlog(LOG_DEBUG, 3, "link layer token length for %s is %d", iface->Name,
+ iface->if_hwaddr_len);
+
+ dlog(LOG_DEBUG, 3, "prefix length for %s is %d", iface->Name,
+ iface->if_prefix_len);
+
+ if (iface->if_hwaddr_len != -1) {
+ unsigned int if_hwaddr_len_bytes = (iface->if_hwaddr_len + 7) >> 3;
+
+ if (if_hwaddr_len_bytes > sizeof(iface->if_hwaddr)) {
+ flog(LOG_ERR, "address length %d too big for %s", if_hwaddr_len_bytes, iface->Name);
+ return(-2);
+ }
+ memcpy(iface->if_hwaddr, ifr.ifr_hwaddr.sa_data, if_hwaddr_len_bytes);
+
+ memset(zero, 0, sizeof(zero));
+ if (!memcmp(iface->if_hwaddr, zero, if_hwaddr_len_bytes))
+ flog(LOG_WARNING, "WARNING, MAC address on %s is all zero!",
+ iface->Name);
+ }
+
+ prefix = iface->AdvPrefixList;
+ while (prefix)
+ {
+ if ((iface->if_prefix_len != -1) &&
+ (iface->if_prefix_len != prefix->PrefixLen))
+ {
+ flog(LOG_WARNING, "prefix length should be %d for %s",
+ iface->if_prefix_len, iface->Name);
+ }
+
+ prefix = prefix->next;
+ }
+
+ return (0);
+}
+
+/*
+ * this function extracts the link local address and interface index
+ * from PATH_PROC_NET_IF_INET6. Note: 'sock' unused in Linux.
+ */
+int setup_linklocal_addr(int sock, struct Interface *iface)
+{
+ FILE *fp;
+ char str_addr[40];
+ unsigned int plen, scope, dad_status, if_idx;
+ char devname[IFNAMSIZ];
+
+ if ((fp = fopen(PATH_PROC_NET_IF_INET6, "r")) == NULL)
+ {
+ flog(LOG_ERR, "can't open %s: %s", PATH_PROC_NET_IF_INET6,
+ strerror(errno));
+ return (-1);
+ }
+
+ while (fscanf(fp, "%32s %x %02x %02x %02x %15s\n",
+ str_addr, &if_idx, &plen, &scope, &dad_status,
+ devname) != EOF)
+ {
+ if (scope == IPV6_ADDR_LINKLOCAL &&
+ strcmp(devname, iface->Name) == 0)
+ {
+ struct in6_addr addr;
+ unsigned int ap;
+ int i;
+
+ for (i=0; i<16; i++)
+ {
+ sscanf(str_addr + i * 2, "%02x", &ap);
+ addr.s6_addr[i] = (unsigned char)ap;
+ }
+ memcpy(&iface->if_addr, &addr, sizeof(iface->if_addr));
+
+ iface->if_index = if_idx;
+ fclose(fp);
+ return 0;
+ }
+ }
+
+ flog(LOG_ERR, "no linklocal address configured for %s", iface->Name);
+ fclose(fp);
+ return (-1);
+}
+
+int setup_allrouters_membership(int sock, struct Interface *iface)
+{
+ struct ipv6_mreq mreq;
+
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.ipv6mr_interface = iface->if_index;
+
+ /* ipv6-allrouters: ff02::2 */
+ mreq.ipv6mr_multiaddr.s6_addr32[0] = htonl(0xFF020000);
+ mreq.ipv6mr_multiaddr.s6_addr32[3] = htonl(0x2);
+
+ if (setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
+ {
+ /* linux-2.6.12-bk4 returns error with HUP signal but keep listening */
+ if (errno != EADDRINUSE)
+ {
+ flog(LOG_ERR, "can't join ipv6-allrouters on %s", iface->Name);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+int check_allrouters_membership(int sock, struct Interface *iface)
+{
+ #define ALL_ROUTERS_MCAST "ff020000000000000000000000000002"
+
+ FILE *fp;
+ unsigned int if_idx, allrouters_ok=0;
+ char addr[32+1];
+ int ret=0;
+
+ if ((fp = fopen(PATH_PROC_NET_IGMP6, "r")) == NULL)
+ {
+ flog(LOG_ERR, "can't open %s: %s", PATH_PROC_NET_IGMP6,
+ strerror(errno));
+ return (-1);
+ }
+
+ while ( (ret=fscanf(fp, "%u %*s %32[0-9A-Fa-f] %*x %*x %*x\n", &if_idx, addr)) != EOF) {
+ if (ret == 2) {
+ if (iface->if_index == if_idx) {
+ if (strncmp(addr, ALL_ROUTERS_MCAST, sizeof(addr)) == 0)
+ allrouters_ok = 1;
+ }
+ }
+ }
+
+ fclose(fp);
+
+ if (!allrouters_ok) {
+ flog(LOG_WARNING, "resetting ipv6-allrouters membership on %s", iface->Name);
+ setup_allrouters_membership(sock, iface);
+ }
+
+ return(0);
+}
+
+static int
+set_interface_var(const char *iface,
+ const char *var, const char *name,
+ uint32_t val)
+{
+ FILE *fp;
+ char spath[64+IFNAMSIZ]; /* XXX: magic constant */
+ snprintf(spath, sizeof(spath), var, iface);
+
+ fp = fopen(spath, "w");
+ if (!fp) {
+ if (name)
+ flog(LOG_ERR, "failed to set %s (%u) for %s",
+ name, val, iface);
+ return -1;
+ }
+ fprintf(fp, "%u", val);
+ fclose(fp);
+
+ return 0;
+}
+
+int
+set_interface_linkmtu(const char *iface, uint32_t mtu)
+{
+ return set_interface_var(iface,
+ PROC_SYS_IP6_LINKMTU, "LinkMTU",
+ mtu);
+}
+
+int
+set_interface_curhlim(const char *iface, uint8_t hlim)
+{
+ return set_interface_var(iface,
+ PROC_SYS_IP6_CURHLIM, "CurHopLimit",
+ hlim);
+}
+
+int
+set_interface_reachtime(const char *iface, uint32_t rtime)
+{
+ int ret;
+ ret = set_interface_var(iface,
+ PROC_SYS_IP6_BASEREACHTIME_MS,
+ NULL,
+ rtime);
+ if (ret)
+ ret = set_interface_var(iface,
+ PROC_SYS_IP6_BASEREACHTIME,
+ "BaseReachableTimer",
+ rtime / 1000);
+ return ret;
+}
+
+int
+set_interface_retranstimer(const char *iface, uint32_t rettimer)
+{
+ int ret;
+ ret = set_interface_var(iface,
+ PROC_SYS_IP6_RETRANSTIMER_MS,
+ NULL,
+ rettimer);
+ if (ret)
+ ret = set_interface_var(iface,
+ PROC_SYS_IP6_RETRANSTIMER,
+ "RetransTimer",
+ rettimer / 1000);
+ return ret;
+}
+
--- /dev/null
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ T_INTERFACE = 258,
+ T_PREFIX = 259,
+ T_ROUTE = 260,
+ T_RDNSS = 261,
+ STRING = 262,
+ NUMBER = 263,
+ SIGNEDNUMBER = 264,
+ DECIMAL = 265,
+ SWITCH = 266,
+ IPV6ADDR = 267,
+ INFINITY = 268,
+ T_IgnoreIfMissing = 269,
+ T_AdvSendAdvert = 270,
+ T_MaxRtrAdvInterval = 271,
+ T_MinRtrAdvInterval = 272,
+ T_MinDelayBetweenRAs = 273,
+ T_AdvManagedFlag = 274,
+ T_AdvOtherConfigFlag = 275,
+ T_AdvLinkMTU = 276,
+ T_AdvReachableTime = 277,
+ T_AdvRetransTimer = 278,
+ T_AdvCurHopLimit = 279,
+ T_AdvDefaultLifetime = 280,
+ T_AdvDefaultPreference = 281,
+ T_AdvSourceLLAddress = 282,
+ T_AdvOnLink = 283,
+ T_AdvAutonomous = 284,
+ T_AdvValidLifetime = 285,
+ T_AdvPreferredLifetime = 286,
+ T_AdvRouterAddr = 287,
+ T_AdvHomeAgentFlag = 288,
+ T_AdvIntervalOpt = 289,
+ T_AdvHomeAgentInfo = 290,
+ T_Base6to4Interface = 291,
+ T_UnicastOnly = 292,
+ T_HomeAgentPreference = 293,
+ T_HomeAgentLifetime = 294,
+ T_AdvRoutePreference = 295,
+ T_AdvRouteLifetime = 296,
+ T_AdvRDNSSPreference = 297,
+ T_AdvRDNSSOpenFlag = 298,
+ T_AdvRDNSSLifetime = 299,
+ T_AdvMobRtrSupportFlag = 300,
+ T_BAD_TOKEN = 301
+ };
+#endif
+/* Tokens. */
+#define T_INTERFACE 258
+#define T_PREFIX 259
+#define T_ROUTE 260
+#define T_RDNSS 261
+#define STRING 262
+#define NUMBER 263
+#define SIGNEDNUMBER 264
+#define DECIMAL 265
+#define SWITCH 266
+#define IPV6ADDR 267
+#define INFINITY 268
+#define T_IgnoreIfMissing 269
+#define T_AdvSendAdvert 270
+#define T_MaxRtrAdvInterval 271
+#define T_MinRtrAdvInterval 272
+#define T_MinDelayBetweenRAs 273
+#define T_AdvManagedFlag 274
+#define T_AdvOtherConfigFlag 275
+#define T_AdvLinkMTU 276
+#define T_AdvReachableTime 277
+#define T_AdvRetransTimer 278
+#define T_AdvCurHopLimit 279
+#define T_AdvDefaultLifetime 280
+#define T_AdvDefaultPreference 281
+#define T_AdvSourceLLAddress 282
+#define T_AdvOnLink 283
+#define T_AdvAutonomous 284
+#define T_AdvValidLifetime 285
+#define T_AdvPreferredLifetime 286
+#define T_AdvRouterAddr 287
+#define T_AdvHomeAgentFlag 288
+#define T_AdvIntervalOpt 289
+#define T_AdvHomeAgentInfo 290
+#define T_Base6to4Interface 291
+#define T_UnicastOnly 292
+#define T_HomeAgentPreference 293
+#define T_HomeAgentLifetime 294
+#define T_AdvRoutePreference 295
+#define T_AdvRouteLifetime 296
+#define T_AdvRDNSSPreference 297
+#define T_AdvRDNSSOpenFlag 298
+#define T_AdvRDNSSLifetime 299
+#define T_AdvMobRtrSupportFlag 300
+#define T_BAD_TOKEN 301
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 16 "gram.y"
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+#include <defaults.h>
+
+extern struct Interface *IfaceList;
+struct Interface *iface = NULL;
+struct AdvPrefix *prefix = NULL;
+struct AdvRoute *route = NULL;
+struct AdvRDNSS *rdnss = NULL;
+
+extern char *conf_file;
+extern int num_lines;
+extern char *yytext;
+extern int sock;
+
+static void cleanup(void);
+static void yyerror(char *msg);
+
+#if 0 /* no longer necessary? */
+#ifndef HAVE_IN6_ADDR_S6_ADDR
+# ifdef __FreeBSD__
+# define s6_addr32 __u6_addr.__u6_addr32
+# define s6_addr16 __u6_addr.__u6_addr16
+# endif
+#endif
+#endif
+
+#define ABORT do { cleanup(); YYABORT; } while (0);
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 110 "gram.y"
+{
+ unsigned int num;
+ int snum;
+ double dec;
+ int bool;
+ struct in6_addr *addr;
+ char *str;
+ struct AdvPrefix *pinfo;
+ struct AdvRoute *rinfo;
+ struct AdvRDNSS *rdnssinfo;
+}
+/* Line 187 of yacc.c. */
+#line 233 "y.tab.c"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 246 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 7
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 151
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 51
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 33
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 81
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 170
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 301
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 50, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 49,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 47, 2, 48, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 6, 8, 14, 17, 19, 24, 25,
+ 27, 28, 30, 31, 33, 34, 36, 39, 41, 45,
+ 49, 53, 57, 61, 65, 69, 73, 77, 81, 85,
+ 89, 93, 97, 101, 105, 109, 113, 117, 121, 125,
+ 129, 133, 137, 139, 142, 148, 153, 154, 156, 159,
+ 161, 165, 169, 173, 177, 181, 185, 187, 190, 196,
+ 201, 202, 204, 207, 209, 213, 217, 219, 222, 228,
+ 231, 233, 235, 238, 239, 241, 244, 246, 250, 254,
+ 258, 260
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 52, 0, -1, 52, 53, -1, 53, -1, 54, 47,
+ 56, 48, 49, -1, 3, 55, -1, 7, -1, 57,
+ 58, 59, 60, -1, -1, 61, -1, -1, 63, -1,
+ -1, 69, -1, -1, 75, -1, 61, 62, -1, 62,
+ -1, 17, 8, 49, -1, 16, 8, 49, -1, 18,
+ 8, 49, -1, 17, 10, 49, -1, 16, 10, 49,
+ -1, 18, 10, 49, -1, 14, 11, 49, -1, 15,
+ 11, 49, -1, 19, 11, 49, -1, 20, 11, 49,
+ -1, 21, 8, 49, -1, 22, 8, 49, -1, 23,
+ 8, 49, -1, 25, 8, 49, -1, 26, 9, 49,
+ -1, 24, 8, 49, -1, 27, 11, 49, -1, 34,
+ 11, 49, -1, 35, 11, 49, -1, 33, 11, 49,
+ -1, 38, 8, 49, -1, 39, 8, 49, -1, 37,
+ 11, 49, -1, 45, 11, 49, -1, 64, -1, 63,
+ 64, -1, 65, 47, 66, 48, 49, -1, 4, 12,
+ 50, 8, -1, -1, 67, -1, 67, 68, -1, 68,
+ -1, 28, 11, 49, -1, 29, 11, 49, -1, 32,
+ 11, 49, -1, 30, 83, 49, -1, 31, 83, 49,
+ -1, 36, 55, 49, -1, 70, -1, 69, 70, -1,
+ 71, 47, 72, 48, 49, -1, 5, 12, 50, 8,
+ -1, -1, 73, -1, 73, 74, -1, 74, -1, 40,
+ 9, 49, -1, 41, 83, 49, -1, 76, -1, 75,
+ 76, -1, 79, 47, 80, 48, 49, -1, 77, 78,
+ -1, 78, -1, 12, -1, 6, 77, -1, -1, 81,
+ -1, 81, 82, -1, 82, -1, 42, 8, 49, -1,
+ 43, 11, 49, -1, 44, 83, 49, -1, 8, -1,
+ 13, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 124, 124, 125, 128, 172, 187, 194, 202, 203,
+ 207, 210, 214, 217, 221, 224, 227, 228, 231, 235,
+ 239, 243, 247, 251, 255, 259, 263, 267, 271, 275,
+ 279, 283, 287, 291, 295, 299, 303, 307, 311, 315,
+ 319, 323, 329, 333, 340, 371, 394, 395, 398, 399,
+ 402, 406, 410, 414, 418, 422, 430, 434, 441, 449,
+ 473, 474, 477, 478, 482, 486, 492, 496, 503, 510,
+ 511, 514, 549, 558, 559, 562, 563, 567, 571, 575,
+ 588, 592
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "T_INTERFACE", "T_PREFIX", "T_ROUTE",
+ "T_RDNSS", "STRING", "NUMBER", "SIGNEDNUMBER", "DECIMAL", "SWITCH",
+ "IPV6ADDR", "INFINITY", "T_IgnoreIfMissing", "T_AdvSendAdvert",
+ "T_MaxRtrAdvInterval", "T_MinRtrAdvInterval", "T_MinDelayBetweenRAs",
+ "T_AdvManagedFlag", "T_AdvOtherConfigFlag", "T_AdvLinkMTU",
+ "T_AdvReachableTime", "T_AdvRetransTimer", "T_AdvCurHopLimit",
+ "T_AdvDefaultLifetime", "T_AdvDefaultPreference", "T_AdvSourceLLAddress",
+ "T_AdvOnLink", "T_AdvAutonomous", "T_AdvValidLifetime",
+ "T_AdvPreferredLifetime", "T_AdvRouterAddr", "T_AdvHomeAgentFlag",
+ "T_AdvIntervalOpt", "T_AdvHomeAgentInfo", "T_Base6to4Interface",
+ "T_UnicastOnly", "T_HomeAgentPreference", "T_HomeAgentLifetime",
+ "T_AdvRoutePreference", "T_AdvRouteLifetime", "T_AdvRDNSSPreference",
+ "T_AdvRDNSSOpenFlag", "T_AdvRDNSSLifetime", "T_AdvMobRtrSupportFlag",
+ "T_BAD_TOKEN", "'{'", "'}'", "';'", "'/'", "$accept", "grammar",
+ "ifacedef", "ifacehead", "name", "ifaceparams", "optional_ifacevlist",
+ "optional_prefixlist", "optional_routelist", "optional_rdnsslist",
+ "ifacevlist", "ifaceval", "prefixlist", "prefixdef", "prefixhead",
+ "optional_prefixplist", "prefixplist", "prefixparms", "routelist",
+ "routedef", "routehead", "optional_routeplist", "routeplist",
+ "routeparms", "rdnsslist", "rdnssdef", "rdnssaddrs", "rdnssaddr",
+ "rdnsshead", "optional_rdnssplist", "rdnssplist", "rdnssparms",
+ "number_or_infinity", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 123, 125, 59,
+ 47
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 51, 52, 52, 53, 54, 55, 56, 57, 57,
+ 58, 58, 59, 59, 60, 60, 61, 61, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 63, 63, 64, 65, 66, 66, 67, 67,
+ 68, 68, 68, 68, 68, 68, 69, 69, 70, 71,
+ 72, 72, 73, 73, 74, 74, 75, 75, 76, 77,
+ 77, 78, 79, 80, 80, 81, 81, 82, 82, 82,
+ 83, 83
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 2, 1, 5, 2, 1, 4, 0, 1,
+ 0, 1, 0, 1, 0, 1, 2, 1, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 1, 2, 5, 4, 0, 1, 2, 1,
+ 3, 3, 3, 3, 3, 3, 1, 2, 5, 4,
+ 0, 1, 2, 1, 3, 3, 1, 2, 5, 2,
+ 1, 1, 2, 0, 1, 2, 1, 3, 3, 3,
+ 1, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 0, 0, 3, 0, 6, 5, 1, 2, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 10, 9, 17, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 12, 11, 42, 0, 16, 24, 25, 19, 22,
+ 18, 21, 20, 23, 26, 27, 28, 29, 30, 33,
+ 31, 32, 34, 37, 35, 36, 40, 38, 39, 41,
+ 4, 0, 0, 14, 13, 56, 0, 43, 46, 0,
+ 0, 0, 7, 15, 66, 0, 57, 60, 0, 0,
+ 0, 0, 0, 0, 0, 47, 49, 45, 0, 71,
+ 72, 70, 67, 73, 0, 0, 0, 61, 63, 0,
+ 0, 80, 81, 0, 0, 0, 0, 0, 48, 59,
+ 69, 0, 0, 0, 0, 74, 76, 0, 0, 0,
+ 62, 50, 51, 53, 54, 52, 55, 44, 0, 0,
+ 0, 0, 75, 64, 65, 58, 77, 78, 79, 68
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 2, 3, 4, 6, 31, 32, 61, 93, 102,
+ 33, 34, 62, 63, 64, 114, 115, 116, 94, 95,
+ 96, 126, 127, 128, 103, 104, 120, 121, 105, 144,
+ 145, 146, 133
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -112
+static const yytype_int8 yypact[] =
+{
+ 5, 26, 7, -112, -10, -112, -112, -112, -112, 1,
+ 38, 39, 33, 34, 37, 40, 41, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 59, 60,
+ 58, 0, 56, 1, -112, 9, 12, 21, 22, 23,
+ 24, 25, 27, 28, 29, 30, 31, 32, 35, 36,
+ 42, 43, 44, 57, 61, 62, 63, 64, 65, 66,
+ 70, 78, 56, -112, 69, -112, -112, -112, -112, -112,
+ -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
+ -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
+ -112, 67, 74, 81, 78, -112, 71, -112, -27, 80,
+ 72, 77, -112, 81, -112, 73, -112, -28, 79, 83,
+ -2, -2, 84, 26, 75, -27, -112, -112, 88, -112,
+ 77, -112, -112, -13, 89, -2, 76, -28, -112, 82,
+ 85, -112, -112, 86, 87, 90, 91, 92, -112, -112,
+ -112, 93, 94, -2, 95, -13, -112, 96, 97, 98,
+ -112, -112, -112, -112, -112, -112, -112, -112, 99, 100,
+ 101, 102, -112, -112, -112, -112, -112, -112, -112, -112
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -112, -112, 105, -112, -38, -112, -112, -112, -112, -112,
+ -112, 104, -112, 68, -112, -112, -112, -18, -112, 6,
+ -112, -112, -112, -25, -112, -4, -112, -17, -112, -112,
+ -112, -41, -111
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 134, 108, 109, 110, 111, 112, 131, 7, 1, 113,
+ 1, 132, 124, 125, 148, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 141,
+ 142, 143, 160, 5, 24, 25, 26, 9, 27, 28,
+ 29, 37, 39, 38, 40, 41, 30, 42, 59, 35,
+ 36, 43, 44, 45, 46, 47, 48, 49, 66, 50,
+ 60, 67, 51, 52, 53, 54, 55, 56, 57, 58,
+ 68, 69, 70, 71, 72, 136, 73, 74, 75, 76,
+ 77, 78, 91, 92, 79, 80, 100, 101, 117, 119,
+ 129, 81, 82, 83, 130, 135, 139, 138, 147, 122,
+ 106, 158, 150, 140, 162, 159, 84, 8, 0, 0,
+ 85, 86, 87, 88, 89, 90, 98, 99, 107, 0,
+ 123, 0, 118, 137, 149, 0, 0, 0, 0, 0,
+ 97, 151, 0, 0, 152, 153, 154, 65, 0, 155,
+ 156, 157, 0, 161, 0, 163, 164, 165, 166, 167,
+ 168, 169
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 111, 28, 29, 30, 31, 32, 8, 0, 3, 36,
+ 3, 13, 40, 41, 125, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 42,
+ 43, 44, 143, 7, 33, 34, 35, 47, 37, 38,
+ 39, 8, 8, 10, 10, 8, 45, 10, 48, 11,
+ 11, 11, 11, 8, 8, 8, 8, 8, 49, 9,
+ 4, 49, 11, 11, 11, 11, 11, 8, 8, 11,
+ 49, 49, 49, 49, 49, 113, 49, 49, 49, 49,
+ 49, 49, 12, 5, 49, 49, 12, 6, 8, 12,
+ 11, 49, 49, 49, 11, 11, 8, 115, 9, 103,
+ 94, 8, 127, 120, 145, 11, 49, 2, -1, -1,
+ 49, 49, 49, 49, 49, 49, 47, 50, 47, -1,
+ 47, -1, 50, 48, 48, -1, -1, -1, -1, -1,
+ 62, 49, -1, -1, 49, 49, 49, 33, -1, 49,
+ 49, 49, -1, 48, -1, 49, 49, 49, 49, 49,
+ 49, 49
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 3, 52, 53, 54, 7, 55, 0, 53, 47,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 33, 34, 35, 37, 38, 39,
+ 45, 56, 57, 61, 62, 11, 11, 8, 10, 8,
+ 10, 8, 10, 11, 11, 8, 8, 8, 8, 8,
+ 9, 11, 11, 11, 11, 11, 8, 8, 11, 48,
+ 4, 58, 63, 64, 65, 62, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 12, 5, 59, 69, 70, 71, 64, 47, 50,
+ 12, 6, 60, 75, 76, 79, 70, 47, 28, 29,
+ 30, 31, 32, 36, 66, 67, 68, 8, 50, 12,
+ 77, 78, 76, 47, 40, 41, 72, 73, 74, 11,
+ 11, 8, 13, 83, 83, 11, 55, 48, 68, 8,
+ 78, 42, 43, 44, 80, 81, 82, 9, 83, 48,
+ 74, 49, 49, 49, 49, 49, 49, 49, 8, 11,
+ 83, 48, 82, 49, 49, 49, 49, 49, 49, 49
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+\f
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+\f
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 129 "gram.y"
+ {
+ struct Interface *iface2;
+
+ iface2 = IfaceList;
+ while (iface2)
+ {
+ if (!strcmp(iface2->Name, iface->Name))
+ {
+ flog(LOG_ERR, "duplicate interface "
+ "definition for %s", iface->Name);
+ ABORT;
+ }
+ iface2 = iface2->next;
+ }
+
+ if (check_device(sock, iface) < 0) {
+ if (iface->IgnoreIfMissing) {
+ dlog(LOG_DEBUG, 4, "interface %s did not exist, ignoring the interface", iface->Name);
+ goto skip_interface;
+ }
+ else {
+ flog(LOG_ERR, "interface %s does not exist", iface->Name);
+ ABORT;
+ }
+ }
+ if (setup_deviceinfo(sock, iface) < 0)
+ ABORT;
+ if (check_iface(iface) < 0)
+ ABORT;
+ if (setup_linklocal_addr(sock, iface) < 0)
+ ABORT;
+ if (setup_allrouters_membership(sock, iface) < 0)
+ ABORT;
+
+ iface->next = IfaceList;
+ IfaceList = iface;
+
+ dlog(LOG_DEBUG, 4, "interface definition for %s is ok", iface->Name);
+
+skip_interface:
+ iface = NULL;
+ }
+ break;
+
+ case 5:
+#line 173 "gram.y"
+ {
+ iface = malloc(sizeof(struct Interface));
+
+ if (iface == NULL) {
+ flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
+ ABORT;
+ }
+
+ iface_init_defaults(iface);
+ strncpy(iface->Name, (yyvsp[(2) - (2)].str), IFNAMSIZ-1);
+ iface->Name[IFNAMSIZ-1] = '\0';
+ }
+ break;
+
+ case 6:
+#line 188 "gram.y"
+ {
+ /* check vality */
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+ }
+ break;
+
+ case 7:
+#line 195 "gram.y"
+ {
+ iface->AdvPrefixList = (yyvsp[(2) - (4)].pinfo);
+ iface->AdvRouteList = (yyvsp[(3) - (4)].rinfo);
+ iface->AdvRDNSSList = (yyvsp[(4) - (4)].rdnssinfo);
+ }
+ break;
+
+ case 10:
+#line 207 "gram.y"
+ {
+ (yyval.pinfo) = NULL;
+ }
+ break;
+
+ case 12:
+#line 214 "gram.y"
+ {
+ (yyval.rinfo) = NULL;
+ }
+ break;
+
+ case 14:
+#line 221 "gram.y"
+ {
+ (yyval.rdnssinfo) = NULL;
+ }
+ break;
+
+ case 18:
+#line 232 "gram.y"
+ {
+ iface->MinRtrAdvInterval = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 19:
+#line 236 "gram.y"
+ {
+ iface->MaxRtrAdvInterval = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 20:
+#line 240 "gram.y"
+ {
+ iface->MinDelayBetweenRAs = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 21:
+#line 244 "gram.y"
+ {
+ iface->MinRtrAdvInterval = (yyvsp[(2) - (3)].dec);
+ }
+ break;
+
+ case 22:
+#line 248 "gram.y"
+ {
+ iface->MaxRtrAdvInterval = (yyvsp[(2) - (3)].dec);
+ }
+ break;
+
+ case 23:
+#line 252 "gram.y"
+ {
+ iface->MinDelayBetweenRAs = (yyvsp[(2) - (3)].dec);
+ }
+ break;
+
+ case 24:
+#line 256 "gram.y"
+ {
+ iface->IgnoreIfMissing = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 25:
+#line 260 "gram.y"
+ {
+ iface->AdvSendAdvert = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 26:
+#line 264 "gram.y"
+ {
+ iface->AdvManagedFlag = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 27:
+#line 268 "gram.y"
+ {
+ iface->AdvOtherConfigFlag = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 28:
+#line 272 "gram.y"
+ {
+ iface->AdvLinkMTU = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 29:
+#line 276 "gram.y"
+ {
+ iface->AdvReachableTime = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 30:
+#line 280 "gram.y"
+ {
+ iface->AdvRetransTimer = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 31:
+#line 284 "gram.y"
+ {
+ iface->AdvDefaultLifetime = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 32:
+#line 288 "gram.y"
+ {
+ iface->AdvDefaultPreference = (yyvsp[(2) - (3)].snum);
+ }
+ break;
+
+ case 33:
+#line 292 "gram.y"
+ {
+ iface->AdvCurHopLimit = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 34:
+#line 296 "gram.y"
+ {
+ iface->AdvSourceLLAddress = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 35:
+#line 300 "gram.y"
+ {
+ iface->AdvIntervalOpt = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 36:
+#line 304 "gram.y"
+ {
+ iface->AdvHomeAgentInfo = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 37:
+#line 308 "gram.y"
+ {
+ iface->AdvHomeAgentFlag = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 38:
+#line 312 "gram.y"
+ {
+ iface->HomeAgentPreference = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 39:
+#line 316 "gram.y"
+ {
+ iface->HomeAgentLifetime = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 40:
+#line 320 "gram.y"
+ {
+ iface->UnicastOnly = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 41:
+#line 324 "gram.y"
+ {
+ iface->AdvMobRtrSupportFlag = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 42:
+#line 330 "gram.y"
+ {
+ (yyval.pinfo) = (yyvsp[(1) - (1)].pinfo);
+ }
+ break;
+
+ case 43:
+#line 334 "gram.y"
+ {
+ (yyvsp[(2) - (2)].pinfo)->next = (yyvsp[(1) - (2)].pinfo);
+ (yyval.pinfo) = (yyvsp[(2) - (2)].pinfo);
+ }
+ break;
+
+ case 44:
+#line 341 "gram.y"
+ {
+ unsigned int dst;
+
+ if (prefix->AdvPreferredLifetime >
+ prefix->AdvValidLifetime)
+ {
+ flog(LOG_ERR, "AdvValidLifeTime must be "
+ "greater than AdvPreferredLifetime in %s, line %d",
+ conf_file, num_lines);
+ ABORT;
+ }
+
+ if( prefix->if6to4[0] )
+ {
+ if (get_v4addr(prefix->if6to4, &dst) < 0)
+ {
+ flog(LOG_ERR, "interface %s has no IPv4 addresses, disabling 6to4 prefix", prefix->if6to4 );
+ prefix->enabled = 0;
+ } else
+ {
+ *((uint16_t *)(prefix->Prefix.s6_addr)) = htons(0x2002);
+ memcpy( prefix->Prefix.s6_addr + 2, &dst, sizeof( dst ) );
+ }
+ }
+
+ (yyval.pinfo) = prefix;
+ prefix = NULL;
+ }
+ break;
+
+ case 45:
+#line 372 "gram.y"
+ {
+ prefix = malloc(sizeof(struct AdvPrefix));
+
+ if (prefix == NULL) {
+ flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
+ ABORT;
+ }
+
+ prefix_init_defaults(prefix);
+
+ if ((yyvsp[(4) - (4)].num) > MAX_PrefixLen)
+ {
+ flog(LOG_ERR, "invalid prefix length in %s, line %d", conf_file, num_lines);
+ ABORT;
+ }
+
+ prefix->PrefixLen = (yyvsp[(4) - (4)].num);
+
+ memcpy(&prefix->Prefix, (yyvsp[(2) - (4)].addr), sizeof(struct in6_addr));
+ }
+ break;
+
+ case 50:
+#line 403 "gram.y"
+ {
+ prefix->AdvOnLinkFlag = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 51:
+#line 407 "gram.y"
+ {
+ prefix->AdvAutonomousFlag = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 52:
+#line 411 "gram.y"
+ {
+ prefix->AdvRouterAddr = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 53:
+#line 415 "gram.y"
+ {
+ prefix->AdvValidLifetime = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 54:
+#line 419 "gram.y"
+ {
+ prefix->AdvPreferredLifetime = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 55:
+#line 423 "gram.y"
+ {
+ dlog(LOG_DEBUG, 4, "using interface %s for 6to4", (yyvsp[(2) - (3)].str));
+ strncpy(prefix->if6to4, (yyvsp[(2) - (3)].str), IFNAMSIZ-1);
+ prefix->if6to4[IFNAMSIZ-1] = '\0';
+ }
+ break;
+
+ case 56:
+#line 431 "gram.y"
+ {
+ (yyval.rinfo) = (yyvsp[(1) - (1)].rinfo);
+ }
+ break;
+
+ case 57:
+#line 435 "gram.y"
+ {
+ (yyvsp[(2) - (2)].rinfo)->next = (yyvsp[(1) - (2)].rinfo);
+ (yyval.rinfo) = (yyvsp[(2) - (2)].rinfo);
+ }
+ break;
+
+ case 58:
+#line 442 "gram.y"
+ {
+ (yyval.rinfo) = route;
+ route = NULL;
+ }
+ break;
+
+ case 59:
+#line 450 "gram.y"
+ {
+ route = malloc(sizeof(struct AdvRoute));
+
+ if (route == NULL) {
+ flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
+ ABORT;
+ }
+
+ route_init_defaults(route, iface);
+
+ if ((yyvsp[(4) - (4)].num) > MAX_PrefixLen)
+ {
+ flog(LOG_ERR, "invalid route prefix length in %s, line %d", conf_file, num_lines);
+ ABORT;
+ }
+
+ route->PrefixLen = (yyvsp[(4) - (4)].num);
+
+ memcpy(&route->Prefix, (yyvsp[(2) - (4)].addr), sizeof(struct in6_addr));
+ }
+ break;
+
+ case 64:
+#line 483 "gram.y"
+ {
+ route->AdvRoutePreference = (yyvsp[(2) - (3)].snum);
+ }
+ break;
+
+ case 65:
+#line 487 "gram.y"
+ {
+ route->AdvRouteLifetime = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 66:
+#line 493 "gram.y"
+ {
+ (yyval.rdnssinfo) = (yyvsp[(1) - (1)].rdnssinfo);
+ }
+ break;
+
+ case 67:
+#line 497 "gram.y"
+ {
+ (yyvsp[(2) - (2)].rdnssinfo)->next = (yyvsp[(1) - (2)].rdnssinfo);
+ (yyval.rdnssinfo) = (yyvsp[(2) - (2)].rdnssinfo);
+ }
+ break;
+
+ case 68:
+#line 504 "gram.y"
+ {
+ (yyval.rdnssinfo) = rdnss;
+ rdnss = NULL;
+ }
+ break;
+
+ case 71:
+#line 515 "gram.y"
+ {
+ if (!rdnss) {
+ /* first IP found */
+ rdnss = malloc(sizeof(struct AdvRDNSS));
+
+ if (rdnss == NULL) {
+ flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
+ ABORT;
+ }
+
+ rdnss_init_defaults(rdnss, iface);
+ }
+
+ switch (rdnss->AdvRDNSSNumber) {
+ case 0:
+ memcpy(&rdnss->AdvRDNSSAddr1, (yyvsp[(1) - (1)].addr), sizeof(struct in6_addr));
+ rdnss->AdvRDNSSNumber++;
+ break;
+ case 1:
+ memcpy(&rdnss->AdvRDNSSAddr2, (yyvsp[(1) - (1)].addr), sizeof(struct in6_addr));
+ rdnss->AdvRDNSSNumber++;
+ break;
+ case 2:
+ memcpy(&rdnss->AdvRDNSSAddr3, (yyvsp[(1) - (1)].addr), sizeof(struct in6_addr));
+ rdnss->AdvRDNSSNumber++;
+ break;
+ default:
+ flog(LOG_CRIT, "Too many addresses in RDNSS section");
+ ABORT;
+ }
+
+ }
+ break;
+
+ case 72:
+#line 550 "gram.y"
+ {
+ if (!rdnss) {
+ flog(LOG_CRIT, "No address specified in RDNSS section");
+ ABORT;
+ }
+ }
+ break;
+
+ case 77:
+#line 568 "gram.y"
+ {
+ rdnss->AdvRDNSSPreference = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 78:
+#line 572 "gram.y"
+ {
+ rdnss->AdvRDNSSOpenFlag = (yyvsp[(2) - (3)].bool);
+ }
+ break;
+
+ case 79:
+#line 576 "gram.y"
+ {
+ if ((yyvsp[(2) - (3)].num) < iface->MaxRtrAdvInterval && (yyvsp[(2) - (3)].num) != 0) {
+ flog(LOG_ERR, "AdvRDNSSLifetime must be at least MaxRtrAdvInterval");
+ ABORT;
+ }
+ if ((yyvsp[(2) - (3)].num) > 2*(iface->MaxRtrAdvInterval))
+ flog(LOG_WARNING, "Warning: AdvRDNSSLifetime <= 2*MaxRtrAdvInterval would allow stale DNS servers to be deleted faster");
+
+ rdnss->AdvRDNSSLifetime = (yyvsp[(2) - (3)].num);
+ }
+ break;
+
+ case 80:
+#line 589 "gram.y"
+ {
+ (yyval.num) = (yyvsp[(1) - (1)].num);
+ }
+ break;
+
+ case 81:
+#line 593 "gram.y"
+ {
+ (yyval.num) = (uint32_t)~0;
+ }
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 2152 "y.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+#line 598 "gram.y"
+
+
+static
+void cleanup(void)
+{
+ if (iface)
+ free(iface);
+
+ if (prefix)
+ free(prefix);
+
+ if (route)
+ free(route);
+
+ if (rdnss)
+ free(rdnss);
+}
+
+static void
+yyerror(char *msg)
+{
+ cleanup();
+ flog(LOG_ERR, "%s in %s, line %d: %s", msg, conf_file, num_lines, yytext);
+}
+
--- /dev/null
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ T_INTERFACE = 258,
+ T_PREFIX = 259,
+ T_ROUTE = 260,
+ T_RDNSS = 261,
+ STRING = 262,
+ NUMBER = 263,
+ SIGNEDNUMBER = 264,
+ DECIMAL = 265,
+ SWITCH = 266,
+ IPV6ADDR = 267,
+ INFINITY = 268,
+ T_IgnoreIfMissing = 269,
+ T_AdvSendAdvert = 270,
+ T_MaxRtrAdvInterval = 271,
+ T_MinRtrAdvInterval = 272,
+ T_MinDelayBetweenRAs = 273,
+ T_AdvManagedFlag = 274,
+ T_AdvOtherConfigFlag = 275,
+ T_AdvLinkMTU = 276,
+ T_AdvReachableTime = 277,
+ T_AdvRetransTimer = 278,
+ T_AdvCurHopLimit = 279,
+ T_AdvDefaultLifetime = 280,
+ T_AdvDefaultPreference = 281,
+ T_AdvSourceLLAddress = 282,
+ T_AdvOnLink = 283,
+ T_AdvAutonomous = 284,
+ T_AdvValidLifetime = 285,
+ T_AdvPreferredLifetime = 286,
+ T_AdvRouterAddr = 287,
+ T_AdvHomeAgentFlag = 288,
+ T_AdvIntervalOpt = 289,
+ T_AdvHomeAgentInfo = 290,
+ T_Base6to4Interface = 291,
+ T_UnicastOnly = 292,
+ T_HomeAgentPreference = 293,
+ T_HomeAgentLifetime = 294,
+ T_AdvRoutePreference = 295,
+ T_AdvRouteLifetime = 296,
+ T_AdvRDNSSPreference = 297,
+ T_AdvRDNSSOpenFlag = 298,
+ T_AdvRDNSSLifetime = 299,
+ T_AdvMobRtrSupportFlag = 300,
+ T_BAD_TOKEN = 301
+ };
+#endif
+/* Tokens. */
+#define T_INTERFACE 258
+#define T_PREFIX 259
+#define T_ROUTE 260
+#define T_RDNSS 261
+#define STRING 262
+#define NUMBER 263
+#define SIGNEDNUMBER 264
+#define DECIMAL 265
+#define SWITCH 266
+#define IPV6ADDR 267
+#define INFINITY 268
+#define T_IgnoreIfMissing 269
+#define T_AdvSendAdvert 270
+#define T_MaxRtrAdvInterval 271
+#define T_MinRtrAdvInterval 272
+#define T_MinDelayBetweenRAs 273
+#define T_AdvManagedFlag 274
+#define T_AdvOtherConfigFlag 275
+#define T_AdvLinkMTU 276
+#define T_AdvReachableTime 277
+#define T_AdvRetransTimer 278
+#define T_AdvCurHopLimit 279
+#define T_AdvDefaultLifetime 280
+#define T_AdvDefaultPreference 281
+#define T_AdvSourceLLAddress 282
+#define T_AdvOnLink 283
+#define T_AdvAutonomous 284
+#define T_AdvValidLifetime 285
+#define T_AdvPreferredLifetime 286
+#define T_AdvRouterAddr 287
+#define T_AdvHomeAgentFlag 288
+#define T_AdvIntervalOpt 289
+#define T_AdvHomeAgentInfo 290
+#define T_Base6to4Interface 291
+#define T_UnicastOnly 292
+#define T_HomeAgentPreference 293
+#define T_HomeAgentLifetime 294
+#define T_AdvRoutePreference 295
+#define T_AdvRouteLifetime 296
+#define T_AdvRDNSSPreference 297
+#define T_AdvRDNSSOpenFlag 298
+#define T_AdvRDNSSLifetime 299
+#define T_AdvMobRtrSupportFlag 300
+#define T_BAD_TOKEN 301
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 110 "gram.y"
+{
+ unsigned int num;
+ int snum;
+ double dec;
+ int bool;
+ struct in6_addr *addr;
+ char *str;
+ struct AdvPrefix *pinfo;
+ struct AdvRoute *rinfo;
+ struct AdvRDNSS *rdnssinfo;
+}
+/* Line 1489 of yacc.c. */
+#line 153 "y.tab.h"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996-2000 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+%{
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+#include <defaults.h>
+
+extern struct Interface *IfaceList;
+struct Interface *iface = NULL;
+struct AdvPrefix *prefix = NULL;
+struct AdvRoute *route = NULL;
+struct AdvRDNSS *rdnss = NULL;
+
+extern char *conf_file;
+extern int num_lines;
+extern char *yytext;
+extern int sock;
+
+static void cleanup(void);
+static void yyerror(char *msg);
+
+#if 0 /* no longer necessary? */
+#ifndef HAVE_IN6_ADDR_S6_ADDR
+# ifdef __FreeBSD__
+# define s6_addr32 __u6_addr.__u6_addr32
+# define s6_addr16 __u6_addr.__u6_addr16
+# endif
+#endif
+#endif
+
+#define ABORT do { cleanup(); YYABORT; } while (0);
+
+%}
+
+%token T_INTERFACE
+%token T_PREFIX
+%token T_ROUTE
+%token T_RDNSS
+
+%token <str> STRING
+%token <num> NUMBER
+%token <snum> SIGNEDNUMBER
+%token <dec> DECIMAL
+%token <bool> SWITCH
+%token <addr> IPV6ADDR
+%token INFINITY
+
+%token T_IgnoreIfMissing
+%token T_AdvSendAdvert
+%token T_MaxRtrAdvInterval
+%token T_MinRtrAdvInterval
+%token T_MinDelayBetweenRAs
+%token T_AdvManagedFlag
+%token T_AdvOtherConfigFlag
+%token T_AdvLinkMTU
+%token T_AdvReachableTime
+%token T_AdvRetransTimer
+%token T_AdvCurHopLimit
+%token T_AdvDefaultLifetime
+%token T_AdvDefaultPreference
+%token T_AdvSourceLLAddress
+
+%token T_AdvOnLink
+%token T_AdvAutonomous
+%token T_AdvValidLifetime
+%token T_AdvPreferredLifetime
+
+%token T_AdvRouterAddr
+%token T_AdvHomeAgentFlag
+%token T_AdvIntervalOpt
+%token T_AdvHomeAgentInfo
+
+%token T_Base6to4Interface
+%token T_UnicastOnly
+
+%token T_HomeAgentPreference
+%token T_HomeAgentLifetime
+
+%token T_AdvRoutePreference
+%token T_AdvRouteLifetime
+
+%token T_AdvRDNSSPreference
+%token T_AdvRDNSSOpenFlag
+%token T_AdvRDNSSLifetime
+
+%token T_AdvMobRtrSupportFlag
+
+%token T_BAD_TOKEN
+
+%type <str> name
+%type <pinfo> optional_prefixlist prefixdef prefixlist
+%type <rinfo> optional_routelist routedef routelist
+%type <rdnssinfo> optional_rdnsslist rdnssdef rdnsslist
+%type <num> number_or_infinity
+
+%union {
+ unsigned int num;
+ int snum;
+ double dec;
+ int bool;
+ struct in6_addr *addr;
+ char *str;
+ struct AdvPrefix *pinfo;
+ struct AdvRoute *rinfo;
+ struct AdvRDNSS *rdnssinfo;
+};
+
+%%
+
+grammar : grammar ifacedef
+ | ifacedef
+ ;
+
+ifacedef : ifacehead '{' ifaceparams '}' ';'
+ {
+ struct Interface *iface2;
+
+ iface2 = IfaceList;
+ while (iface2)
+ {
+ if (!strcmp(iface2->Name, iface->Name))
+ {
+ flog(LOG_ERR, "duplicate interface "
+ "definition for %s", iface->Name);
+ ABORT;
+ }
+ iface2 = iface2->next;
+ }
+
+ if (check_device(sock, iface) < 0) {
+ if (iface->IgnoreIfMissing) {
+ dlog(LOG_DEBUG, 4, "interface %s did not exist, ignoring the interface", iface->Name);
+ goto skip_interface;
+ }
+ else {
+ flog(LOG_ERR, "interface %s does not exist", iface->Name);
+ ABORT;
+ }
+ }
+ if (setup_deviceinfo(sock, iface) < 0)
+ ABORT;
+ if (check_iface(iface) < 0)
+ ABORT;
+ if (setup_linklocal_addr(sock, iface) < 0)
+ ABORT;
+ if (setup_allrouters_membership(sock, iface) < 0)
+ ABORT;
+
+ iface->next = IfaceList;
+ IfaceList = iface;
+
+ dlog(LOG_DEBUG, 4, "interface definition for %s is ok", iface->Name);
+
+skip_interface:
+ iface = NULL;
+ };
+
+ifacehead : T_INTERFACE name
+ {
+ iface = malloc(sizeof(struct Interface));
+
+ if (iface == NULL) {
+ flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
+ ABORT;
+ }
+
+ iface_init_defaults(iface);
+ strncpy(iface->Name, $2, IFNAMSIZ-1);
+ iface->Name[IFNAMSIZ-1] = '\0';
+ }
+ ;
+
+name : STRING
+ {
+ /* check vality */
+ $$ = $1;
+ }
+ ;
+
+ifaceparams : optional_ifacevlist optional_prefixlist optional_routelist optional_rdnsslist
+ {
+ iface->AdvPrefixList = $2;
+ iface->AdvRouteList = $3;
+ iface->AdvRDNSSList = $4;
+ }
+ ;
+
+optional_ifacevlist: /* empty */
+ | ifacevlist
+ ;
+
+optional_prefixlist: /* empty */
+ {
+ $$ = NULL;
+ }
+ | prefixlist
+ ;
+
+optional_routelist: /* empty */
+ {
+ $$ = NULL;
+ }
+ | routelist
+ ;
+
+optional_rdnsslist: /* empty */
+ {
+ $$ = NULL;
+ }
+ | rdnsslist
+ ;
+
+ifacevlist : ifacevlist ifaceval
+ | ifaceval
+ ;
+
+ifaceval : T_MinRtrAdvInterval NUMBER ';'
+ {
+ iface->MinRtrAdvInterval = $2;
+ }
+ | T_MaxRtrAdvInterval NUMBER ';'
+ {
+ iface->MaxRtrAdvInterval = $2;
+ }
+ | T_MinDelayBetweenRAs NUMBER ';'
+ {
+ iface->MinDelayBetweenRAs = $2;
+ }
+ | T_MinRtrAdvInterval DECIMAL ';'
+ {
+ iface->MinRtrAdvInterval = $2;
+ }
+ | T_MaxRtrAdvInterval DECIMAL ';'
+ {
+ iface->MaxRtrAdvInterval = $2;
+ }
+ | T_MinDelayBetweenRAs DECIMAL ';'
+ {
+ iface->MinDelayBetweenRAs = $2;
+ }
+ | T_IgnoreIfMissing SWITCH ';'
+ {
+ iface->IgnoreIfMissing = $2;
+ }
+ | T_AdvSendAdvert SWITCH ';'
+ {
+ iface->AdvSendAdvert = $2;
+ }
+ | T_AdvManagedFlag SWITCH ';'
+ {
+ iface->AdvManagedFlag = $2;
+ }
+ | T_AdvOtherConfigFlag SWITCH ';'
+ {
+ iface->AdvOtherConfigFlag = $2;
+ }
+ | T_AdvLinkMTU NUMBER ';'
+ {
+ iface->AdvLinkMTU = $2;
+ }
+ | T_AdvReachableTime NUMBER ';'
+ {
+ iface->AdvReachableTime = $2;
+ }
+ | T_AdvRetransTimer NUMBER ';'
+ {
+ iface->AdvRetransTimer = $2;
+ }
+ | T_AdvDefaultLifetime NUMBER ';'
+ {
+ iface->AdvDefaultLifetime = $2;
+ }
+ | T_AdvDefaultPreference SIGNEDNUMBER ';'
+ {
+ iface->AdvDefaultPreference = $2;
+ }
+ | T_AdvCurHopLimit NUMBER ';'
+ {
+ iface->AdvCurHopLimit = $2;
+ }
+ | T_AdvSourceLLAddress SWITCH ';'
+ {
+ iface->AdvSourceLLAddress = $2;
+ }
+ | T_AdvIntervalOpt SWITCH ';'
+ {
+ iface->AdvIntervalOpt = $2;
+ }
+ | T_AdvHomeAgentInfo SWITCH ';'
+ {
+ iface->AdvHomeAgentInfo = $2;
+ }
+ | T_AdvHomeAgentFlag SWITCH ';'
+ {
+ iface->AdvHomeAgentFlag = $2;
+ }
+ | T_HomeAgentPreference NUMBER ';'
+ {
+ iface->HomeAgentPreference = $2;
+ }
+ | T_HomeAgentLifetime NUMBER ';'
+ {
+ iface->HomeAgentLifetime = $2;
+ }
+ | T_UnicastOnly SWITCH ';'
+ {
+ iface->UnicastOnly = $2;
+ }
+ | T_AdvMobRtrSupportFlag SWITCH ';'
+ {
+ iface->AdvMobRtrSupportFlag = $2;
+ }
+ ;
+
+prefixlist : prefixdef
+ {
+ $$ = $1;
+ }
+ | prefixlist prefixdef
+ {
+ $2->next = $1;
+ $$ = $2;
+ }
+ ;
+
+prefixdef : prefixhead '{' optional_prefixplist '}' ';'
+ {
+ unsigned int dst;
+
+ if (prefix->AdvPreferredLifetime >
+ prefix->AdvValidLifetime)
+ {
+ flog(LOG_ERR, "AdvValidLifeTime must be "
+ "greater than AdvPreferredLifetime in %s, line %d",
+ conf_file, num_lines);
+ ABORT;
+ }
+
+ if( prefix->if6to4[0] )
+ {
+ if (get_v4addr(prefix->if6to4, &dst) < 0)
+ {
+ flog(LOG_ERR, "interface %s has no IPv4 addresses, disabling 6to4 prefix", prefix->if6to4 );
+ prefix->enabled = 0;
+ } else
+ {
+ *((uint16_t *)(prefix->Prefix.s6_addr)) = htons(0x2002);
+ memcpy( prefix->Prefix.s6_addr + 2, &dst, sizeof( dst ) );
+ }
+ }
+
+ $$ = prefix;
+ prefix = NULL;
+ }
+ ;
+
+prefixhead : T_PREFIX IPV6ADDR '/' NUMBER
+ {
+ prefix = malloc(sizeof(struct AdvPrefix));
+
+ if (prefix == NULL) {
+ flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
+ ABORT;
+ }
+
+ prefix_init_defaults(prefix);
+
+ if ($4 > MAX_PrefixLen)
+ {
+ flog(LOG_ERR, "invalid prefix length in %s, line %d", conf_file, num_lines);
+ ABORT;
+ }
+
+ prefix->PrefixLen = $4;
+
+ memcpy(&prefix->Prefix, $2, sizeof(struct in6_addr));
+ }
+ ;
+
+optional_prefixplist: /* empty */
+ | prefixplist
+ ;
+
+prefixplist : prefixplist prefixparms
+ | prefixparms
+ ;
+
+prefixparms : T_AdvOnLink SWITCH ';'
+ {
+ prefix->AdvOnLinkFlag = $2;
+ }
+ | T_AdvAutonomous SWITCH ';'
+ {
+ prefix->AdvAutonomousFlag = $2;
+ }
+ | T_AdvRouterAddr SWITCH ';'
+ {
+ prefix->AdvRouterAddr = $2;
+ }
+ | T_AdvValidLifetime number_or_infinity ';'
+ {
+ prefix->AdvValidLifetime = $2;
+ }
+ | T_AdvPreferredLifetime number_or_infinity ';'
+ {
+ prefix->AdvPreferredLifetime = $2;
+ }
+ | T_Base6to4Interface name ';'
+ {
+ dlog(LOG_DEBUG, 4, "using interface %s for 6to4", $2);
+ strncpy(prefix->if6to4, $2, IFNAMSIZ-1);
+ prefix->if6to4[IFNAMSIZ-1] = '\0';
+ }
+ ;
+
+routelist : routedef
+ {
+ $$ = $1;
+ }
+ | routelist routedef
+ {
+ $2->next = $1;
+ $$ = $2;
+ }
+ ;
+
+routedef : routehead '{' optional_routeplist '}' ';'
+ {
+ $$ = route;
+ route = NULL;
+ }
+ ;
+
+
+routehead : T_ROUTE IPV6ADDR '/' NUMBER
+ {
+ route = malloc(sizeof(struct AdvRoute));
+
+ if (route == NULL) {
+ flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
+ ABORT;
+ }
+
+ route_init_defaults(route, iface);
+
+ if ($4 > MAX_PrefixLen)
+ {
+ flog(LOG_ERR, "invalid route prefix length in %s, line %d", conf_file, num_lines);
+ ABORT;
+ }
+
+ route->PrefixLen = $4;
+
+ memcpy(&route->Prefix, $2, sizeof(struct in6_addr));
+ }
+ ;
+
+
+optional_routeplist: /* empty */
+ | routeplist
+ ;
+
+routeplist : routeplist routeparms
+ | routeparms
+ ;
+
+
+routeparms : T_AdvRoutePreference SIGNEDNUMBER ';'
+ {
+ route->AdvRoutePreference = $2;
+ }
+ | T_AdvRouteLifetime number_or_infinity ';'
+ {
+ route->AdvRouteLifetime = $2;
+ }
+ ;
+
+rdnsslist : rdnssdef
+ {
+ $$ = $1;
+ }
+ | rdnsslist rdnssdef
+ {
+ $2->next = $1;
+ $$ = $2;
+ }
+ ;
+
+rdnssdef : rdnsshead '{' optional_rdnssplist '}' ';'
+ {
+ $$ = rdnss;
+ rdnss = NULL;
+ }
+ ;
+
+rdnssaddrs : rdnssaddrs rdnssaddr
+ | rdnssaddr
+ ;
+
+rdnssaddr : IPV6ADDR
+ {
+ if (!rdnss) {
+ /* first IP found */
+ rdnss = malloc(sizeof(struct AdvRDNSS));
+
+ if (rdnss == NULL) {
+ flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
+ ABORT;
+ }
+
+ rdnss_init_defaults(rdnss, iface);
+ }
+
+ switch (rdnss->AdvRDNSSNumber) {
+ case 0:
+ memcpy(&rdnss->AdvRDNSSAddr1, $1, sizeof(struct in6_addr));
+ rdnss->AdvRDNSSNumber++;
+ break;
+ case 1:
+ memcpy(&rdnss->AdvRDNSSAddr2, $1, sizeof(struct in6_addr));
+ rdnss->AdvRDNSSNumber++;
+ break;
+ case 2:
+ memcpy(&rdnss->AdvRDNSSAddr3, $1, sizeof(struct in6_addr));
+ rdnss->AdvRDNSSNumber++;
+ break;
+ default:
+ flog(LOG_CRIT, "Too many addresses in RDNSS section");
+ ABORT;
+ }
+
+ }
+ ;
+
+rdnsshead : T_RDNSS rdnssaddrs
+ {
+ if (!rdnss) {
+ flog(LOG_CRIT, "No address specified in RDNSS section");
+ ABORT;
+ }
+ }
+ ;
+
+optional_rdnssplist: /* empty */
+ | rdnssplist
+ ;
+
+rdnssplist : rdnssplist rdnssparms
+ | rdnssparms
+ ;
+
+
+rdnssparms : T_AdvRDNSSPreference NUMBER ';'
+ {
+ rdnss->AdvRDNSSPreference = $2;
+ }
+ | T_AdvRDNSSOpenFlag SWITCH ';'
+ {
+ rdnss->AdvRDNSSOpenFlag = $2;
+ }
+ | T_AdvRDNSSLifetime number_or_infinity ';'
+ {
+ if ($2 < iface->MaxRtrAdvInterval && $2 != 0) {
+ flog(LOG_ERR, "AdvRDNSSLifetime must be at least MaxRtrAdvInterval");
+ ABORT;
+ }
+ if ($2 > 2*(iface->MaxRtrAdvInterval))
+ flog(LOG_WARNING, "Warning: AdvRDNSSLifetime <= 2*MaxRtrAdvInterval would allow stale DNS servers to be deleted faster");
+
+ rdnss->AdvRDNSSLifetime = $2;
+ }
+ ;
+
+number_or_infinity : NUMBER
+ {
+ $$ = $1;
+ }
+ | INFINITY
+ {
+ $$ = (uint32_t)~0;
+ }
+ ;
+
+%%
+
+static
+void cleanup(void)
+{
+ if (iface)
+ free(iface);
+
+ if (prefix)
+ free(prefix);
+
+ if (route)
+ free(route);
+
+ if (rdnss)
+ free(rdnss);
+}
+
+static void
+yyerror(char *msg)
+{
+ cleanup();
+ flog(LOG_ERR, "%s in %s, line %d: %s", msg, conf_file, num_lines, yytext);
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#ifndef INCLUDES_H
+#define INCLUDES_H
+
+#include <config.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <time.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <sys/types.h>
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#else
+# ifdef HAVE_MACHINE_PARAM_H
+# include <machine/param.h>
+# endif
+# ifdef HAVE_MACHINE_LIMITS_H
+# include <machine/limits.h>
+# endif
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <netinet/in.h>
+
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+#include <arpa/inet.h>
+
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+
+#ifdef HAVE_NET_IF_DL_H
+# include <net/if_dl.h>
+#endif
+#ifdef HAVE_NET_IF_TYPES_H
+# include <net/if_types.h>
+#endif
+#if defined(HAVE_NET_IF_ARP_H) && !defined(ARPHRD_ETHER)
+# include <net/if_arp.h>
+#endif /* defined(HAVE_NET_IF_ARP_H) && !defined(ARPHRD_ETHER) */
+
+#ifdef HAVE_SYS_SOCKIO_H
+# include <sys/sockio.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#endif /* INCLUDES_H */
--- /dev/null
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+#include <defaults.h>
+
+void
+iface_init_defaults(struct Interface *iface)
+{
+ memset(iface, 0, sizeof(struct Interface));
+
+ iface->HasFailed = 0;
+ iface->IgnoreIfMissing = DFLT_IgnoreIfMissing;
+ iface->AdvSendAdvert = DFLT_AdvSendAdv;
+ iface->MaxRtrAdvInterval = DFLT_MaxRtrAdvInterval;
+ iface->AdvSourceLLAddress = DFLT_AdvSourceLLAddress;
+ iface->AdvReachableTime = DFLT_AdvReachableTime;
+ iface->AdvRetransTimer = DFLT_AdvRetransTimer;
+ iface->AdvLinkMTU = DFLT_AdvLinkMTU;
+ iface->AdvCurHopLimit = DFLT_AdvCurHopLimit;
+ iface->AdvIntervalOpt = DFLT_AdvIntervalOpt;
+ iface->AdvHomeAgentInfo = DFLT_AdvHomeAgentInfo;
+ iface->AdvHomeAgentFlag = DFLT_AdvHomeAgentFlag;
+ iface->HomeAgentPreference = DFLT_HomeAgentPreference;
+ iface->MinDelayBetweenRAs = DFLT_MinDelayBetweenRAs;
+ iface->AdvMobRtrSupportFlag = DFLT_AdvMobRtrSupportFlag;
+
+ iface->MinRtrAdvInterval = -1;
+ iface->AdvDefaultLifetime = -1;
+ iface->AdvDefaultPreference = DFLT_AdvDefaultPreference;
+ iface->HomeAgentLifetime = -1;
+}
+
+void
+prefix_init_defaults(struct AdvPrefix *prefix)
+{
+ memset(prefix, 0, sizeof(struct AdvPrefix));
+
+ prefix->AdvOnLinkFlag = DFLT_AdvOnLinkFlag;
+ prefix->AdvAutonomousFlag = DFLT_AdvAutonomousFlag;
+ prefix->AdvRouterAddr = DFLT_AdvRouterAddr;
+ prefix->AdvValidLifetime = DFLT_AdvValidLifetime;
+ prefix->AdvPreferredLifetime = DFLT_AdvPreferredLifetime;
+ prefix->if6to4[0] = 0;
+ prefix->enabled = 1;
+}
+
+void
+route_init_defaults(struct AdvRoute *route, struct Interface *iface)
+{
+ memset(route, 0, sizeof(struct AdvRoute));
+
+ route->AdvRouteLifetime = DFLT_AdvRouteLifetime(iface);
+ route->AdvRoutePreference = DFLT_AdvRoutePreference;
+}
+
+void
+rdnss_init_defaults(struct AdvRDNSS *rdnss, struct Interface *iface)
+{
+ memset(rdnss, 0, sizeof(struct AdvRDNSS));
+
+ rdnss->AdvRDNSSPreference = DFLT_AdvRDNSSPreference;
+ rdnss->AdvRDNSSOpenFlag = DFLT_AdvRDNSSOpenFlag;
+ rdnss->AdvRDNSSLifetime = DFLT_AdvRDNSSLifetime(iface);
+ rdnss->AdvRDNSSNumber = 0;
+}
+
+int
+check_iface(struct Interface *iface)
+{
+ struct AdvPrefix *prefix;
+ struct AdvRoute *route;
+ int res = 0;
+ int MIPv6 = 0;
+
+ /* Check if we use Mobile IPv6 extensions */
+ if (iface->AdvHomeAgentFlag || iface->AdvHomeAgentInfo ||
+ iface->AdvIntervalOpt)
+ {
+ MIPv6 = 1;
+ flog(LOG_INFO, "using Mobile IPv6 extensions");
+ }
+
+ prefix = iface->AdvPrefixList;
+ while (!MIPv6 && prefix)
+ {
+ if (prefix->AdvRouterAddr)
+ {
+ MIPv6 = 1;
+ }
+ prefix = prefix->next;
+ }
+
+ if (iface->MinRtrAdvInterval < 0)
+ iface->MinRtrAdvInterval = DFLT_MinRtrAdvInterval(iface);
+
+ if ((iface->MinRtrAdvInterval < (MIPv6 ? MIN_MinRtrAdvInterval_MIPv6 : MIN_MinRtrAdvInterval)) ||
+ (iface->MinRtrAdvInterval > MAX_MinRtrAdvInterval(iface)))
+ {
+ flog(LOG_ERR,
+ "MinRtrAdvInterval for %s (%.2f) must be at least %.2f but no more than 3/4 of MaxRtrAdvInterval (%.2f)",
+ iface->Name, iface->MinRtrAdvInterval,
+ MIPv6 ? MIN_MinRtrAdvInterval_MIPv6 : (int)MIN_MinRtrAdvInterval,
+ MAX_MinRtrAdvInterval(iface));
+ res = -1;
+ }
+
+ if ((iface->MaxRtrAdvInterval < (MIPv6 ? MIN_MaxRtrAdvInterval_MIPv6 : MIN_MaxRtrAdvInterval))
+ || (iface->MaxRtrAdvInterval > MAX_MaxRtrAdvInterval))
+ {
+ flog(LOG_ERR,
+ "MaxRtrAdvInterval for %s (%.2f) must be between %.2f and %d",
+ iface->Name, iface->MaxRtrAdvInterval,
+ MIPv6 ? MIN_MaxRtrAdvInterval_MIPv6 : (int)MIN_MaxRtrAdvInterval,
+ MAX_MaxRtrAdvInterval);
+ res = -1;
+ }
+
+ if (iface->MinDelayBetweenRAs < (MIPv6 ? MIN_DELAY_BETWEEN_RAS_MIPv6 : MIN_DELAY_BETWEEN_RAS))
+ {
+ flog(LOG_ERR,
+ "MinDelayBetweenRAs for %s (%.2f) must be at least %.2f",
+ iface->Name, iface->MinDelayBetweenRAs,
+ MIPv6 ? MIN_DELAY_BETWEEN_RAS_MIPv6 : MIN_DELAY_BETWEEN_RAS);
+ res = -1;
+ }
+
+ if ((iface->AdvLinkMTU != 0) &&
+ ((iface->AdvLinkMTU < MIN_AdvLinkMTU) ||
+ (iface->if_maxmtu != -1 && (iface->AdvLinkMTU > iface->if_maxmtu))))
+ {
+ flog(LOG_ERR, "AdvLinkMTU for %s (%u) must be zero or between %u and %u",
+ iface->Name, iface->AdvLinkMTU, MIN_AdvLinkMTU, iface->if_maxmtu);
+ res = -1;
+ }
+
+ if (iface->AdvReachableTime > MAX_AdvReachableTime)
+ {
+ flog(LOG_ERR,
+ "AdvReachableTime for %s (%u) must not be greater than %u",
+ iface->Name, iface->AdvReachableTime, MAX_AdvReachableTime);
+ res = -1;
+ }
+
+ if (iface->AdvCurHopLimit > MAX_AdvCurHopLimit)
+ {
+ flog(LOG_ERR, "AdvCurHopLimit for %s (%u) must not be greater than %u",
+ iface->Name, iface->AdvCurHopLimit, MAX_AdvCurHopLimit);
+ res = -1;
+ }
+
+ if (iface->AdvDefaultLifetime < 0)
+ iface->AdvDefaultLifetime = DFLT_AdvDefaultLifetime(iface);
+
+ if ((iface->AdvDefaultLifetime != 0) &&
+ ((iface->AdvDefaultLifetime > MAX_AdvDefaultLifetime) ||
+ (iface->AdvDefaultLifetime < MIN_AdvDefaultLifetime(iface))))
+ {
+ flog(LOG_ERR,
+ "AdvDefaultLifetime for %s (%u) must be zero or between %u and %u",
+ iface->Name, iface->AdvDefaultLifetime, (int)MIN_AdvDefaultLifetime(iface),
+ MAX_AdvDefaultLifetime);
+ res = -1;
+ }
+
+ /* Mobile IPv6 ext */
+ if (iface->HomeAgentLifetime < 0)
+ iface->HomeAgentLifetime = DFLT_HomeAgentLifetime(iface);
+
+ /* Mobile IPv6 ext */
+ if (iface->AdvHomeAgentInfo)
+ {
+ if ((iface->HomeAgentLifetime > MAX_HomeAgentLifetime) ||
+ (iface->HomeAgentLifetime < MIN_HomeAgentLifetime))
+ {
+ flog(LOG_ERR,
+ "HomeAgentLifetime for %s (%u) must be between %u and %u",
+ iface->Name, iface->HomeAgentLifetime,
+ MIN_HomeAgentLifetime, MAX_HomeAgentLifetime);
+ res = -1;
+ }
+ }
+
+ /* Mobile IPv6 ext */
+ if (iface->AdvHomeAgentInfo && !(iface->AdvHomeAgentFlag))
+ {
+ flog(LOG_ERR,
+ "AdvHomeAgentFlag for %s must be set with HomeAgentInfo", iface->Name);
+ res = -1;
+ }
+ if (iface->AdvMobRtrSupportFlag && !(iface->AdvHomeAgentInfo))
+ {
+ flog(LOG_ERR,
+ "AdvHomeAgentInfo for %s must be set with AdvMobRtrSupportFlag", iface->Name);
+ res = -1;
+ }
+
+ /* XXX: need this? prefix = iface->AdvPrefixList; */
+
+ while (prefix)
+ {
+ if (prefix->PrefixLen > MAX_PrefixLen)
+ {
+ flog(LOG_ERR, "invalid prefix length (%u) for %s", prefix->PrefixLen, iface->Name);
+ res = -1;
+ }
+
+ if (prefix->AdvPreferredLifetime > prefix->AdvValidLifetime)
+ {
+ flog(LOG_ERR, "AdvValidLifetime for %s (%u) must be "
+ "greater than AdvPreferredLifetime for",
+ iface->Name, prefix->AdvValidLifetime);
+ res = -1;
+ }
+
+ prefix = prefix->next;
+ }
+
+
+ route = iface->AdvRouteList;
+
+ while(route)
+ {
+ if (route->PrefixLen > MAX_PrefixLen)
+ {
+ flog(LOG_ERR, "invalid route prefix length (%u) for %s", route->PrefixLen, iface->Name);
+ res = -1;
+ }
+
+ route = route->next;
+ }
+
+ return res;
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file
+ * COPYRIGHT applies to this software. If your distribution is missing
+ * this file, you may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+
+static int log_method = L_NONE;
+static char *log_ident;
+static char *log_file;
+static FILE *log_file_fd;
+static int log_facility;
+static int debug_level = 0;
+
+int
+log_open(int method, char *ident, char *log, int facility)
+{
+ log_method = method;
+ log_ident = ident;
+
+ switch (log_method) {
+ case L_NONE:
+ case L_STDERR:
+ break;
+ case L_STDERR_SYSLOG:
+ /* fallthrough */
+ case L_SYSLOG:
+ if (facility == -1)
+ log_facility = LOG_DAEMON;
+ else
+ log_facility = facility;
+
+ openlog(log_ident, LOG_PID, log_facility);
+ break;
+ case L_LOGFILE:
+ if (!log)
+ {
+ fprintf(stderr, "%s: no logfile specified\n", log_ident);
+ return (-1);
+ }
+ log_file = log;
+ if ((log_file_fd = fopen(log_file, "a")) == NULL)
+ {
+ fprintf(stderr, "%s: can't open %s: %s\n", log_ident, log_file, strerror(errno));
+ return (-1);
+ }
+ break;
+ default:
+ fprintf(stderr, "%s: unknown logging method: %d\n", log_ident, log_method);
+ log_method = L_NONE;
+ return (-1);
+ }
+ return 0;
+}
+
+static int
+vlog(int prio, char *format, va_list ap)
+{
+ char tstamp[64], buff[1024];
+ struct tm *tm;
+ time_t current;
+
+ switch (log_method) {
+ case L_NONE:
+ break;
+ case L_SYSLOG:
+ vsnprintf(buff, sizeof(buff), format, ap);
+ syslog(prio, "%s", buff);
+ break;
+ case L_STDERR_SYSLOG:
+ vsnprintf(buff, sizeof(buff), format, ap);
+ syslog(prio, "%s", buff);
+ if (prio > LOG_ERR) /* fall through for messages with high priority */
+ break;
+ case L_STDERR:
+ current = time(NULL);
+ tm = localtime(¤t);
+ (void) strftime(tstamp, sizeof(tstamp), LOG_TIME_FORMAT, tm);
+
+ fprintf(stderr, "[%s] %s: ", tstamp, log_ident);
+ vfprintf(stderr, format, ap);
+ fputs("\n", stderr);
+ fflush(stderr);
+ break;
+ case L_LOGFILE:
+ current = time(NULL);
+ tm = localtime(¤t);
+ (void) strftime(tstamp, sizeof(tstamp), LOG_TIME_FORMAT, tm);
+
+ fprintf(log_file_fd, "[%s] %s: ", tstamp, log_ident);
+ vfprintf(log_file_fd, format, ap);
+ fputs("\n", log_file_fd);
+ fflush(log_file_fd);
+ break;
+ default:
+ fprintf(stderr, "%s: unknown logging method: %d\n", log_ident, log_method);
+ log_method = L_NONE;
+ return (-1);
+ }
+ return 0;
+}
+
+void
+dlog(int prio, int level, char *format, ...)
+{
+ va_list ap;
+ int res;
+
+ if (debug_level < level)
+ return;
+
+ va_start(ap, format);
+ res = vlog(prio, format, ap);
+ va_end(ap);
+
+ /* XXX: should we do something if res < 0.. */
+}
+
+void
+flog(int prio, char *format, ...)
+{
+ va_list ap;
+ int res;
+
+ va_start(ap, format);
+ res = vlog(prio, format, ap);
+ va_end(ap);
+
+ /* XXX: should we do something if res < 0.. */
+}
+
+int
+log_close(void)
+{
+ switch (log_method) {
+ case L_NONE:
+ case L_STDERR:
+ break;
+ case L_SYSLOG:
+ closelog();
+ break;
+ case L_LOGFILE:
+ fclose(log_file_fd);
+ break;
+ default:
+ fprintf(stderr, "%s: unknown logging method: %d\n", log_ident, log_method);
+ log_method = L_NONE;
+ return (-1);
+ }
+ return 0;
+}
+
+int
+log_reopen(void)
+{
+ log_close();
+ return log_open(log_method, log_ident, log_file, log_facility);
+}
+
+void
+set_debuglevel(int level)
+{
+ debug_level = level;
+}
+
+int
+get_debuglevel(void)
+{
+ return debug_level;
+}
--- /dev/null
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+case "$1" in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing 0.4 - GNU automake"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal*)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+ test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+ fi
+ if [ -f "$file" ]; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
+ # We have makeinfo, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ tar)
+ shift
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ fi
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case "$firstarg" in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case "$firstarg" in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id$
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#ifndef PATHNAMES_H
+#define PATHNAMES_H
+
+#ifndef PATH_RADVD_CONF
+#define PATH_RADVD_CONF "/etc/radvd.conf"
+#endif
+
+#ifndef PATH_RADVD_PID
+#define PATH_RADVD_PID "/var/run/radvd.pid"
+#endif
+
+#ifndef PATH_RADVD_LOG
+#define PATH_RADVD_LOG "/var/log/radvd.log"
+#endif
+
+#define PATH_PROC_NET_IF_INET6 "/proc/net/if_inet6"
+#define PATH_PROC_NET_IGMP6 "/proc/net/igmp6"
+
+#ifdef __linux__
+#define SYSCTL_IP6_FORWARDING CTL_NET, NET_IPV6, NET_IPV6_CONF, NET_PROTO_CONF_ALL, NET_IPV6_FORWARDING
+#define PROC_SYS_IP6_FORWARDING "/proc/sys/net/ipv6/conf/all/forwarding"
+#define PROC_SYS_IP6_LINKMTU "/proc/sys/net/ipv6/conf/%s/mtu"
+#define PROC_SYS_IP6_CURHLIM "/proc/sys/net/ipv6/conf/%s/hop_limit"
+#define PROC_SYS_IP6_BASEREACHTIME_MS "/proc/sys/net/ipv6/neigh/%s/base_reachable_time_ms"
+#define PROC_SYS_IP6_BASEREACHTIME "/proc/sys/net/ipv6/neigh/%s/base_reachable_time"
+#define PROC_SYS_IP6_RETRANSTIMER_MS "/proc/sys/net/ipv6/neigh/%s/retrans_time_ms"
+#define PROC_SYS_IP6_RETRANSTIMER "/proc/sys/net/ipv6/neigh/%s/retrans_time"
+#else /* BSD */
+#define SYSCTL_IP6_FORWARDING CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_FORWARDING
+#endif
+
+#endif
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+
+static void process_rs(int, struct Interface *, unsigned char *msg,
+ int len, struct sockaddr_in6 *);
+static void process_ra(struct Interface *, unsigned char *msg, int len,
+ struct sockaddr_in6 *);
+static int addr_match(struct in6_addr *a1, struct in6_addr *a2,
+ int prefixlen);
+
+void
+process(int sock, struct Interface *ifacel, unsigned char *msg, int len,
+ struct sockaddr_in6 *addr, struct in6_pktinfo *pkt_info, int hoplimit)
+{
+ struct Interface *iface;
+ struct icmp6_hdr *icmph;
+ char addr_str[INET6_ADDRSTRLEN];
+
+ if ( ! pkt_info )
+ {
+ flog(LOG_WARNING, "received packet with no pkt_info!" );
+ return;
+ }
+
+ /*
+ * can this happen?
+ */
+
+ if (len < sizeof(struct icmp6_hdr))
+ {
+ flog(LOG_WARNING, "received icmpv6 packet with invalid length: %d",
+ len);
+ return;
+ }
+
+ icmph = (struct icmp6_hdr *) msg;
+
+ if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
+ icmph->icmp6_type != ND_ROUTER_ADVERT)
+ {
+ /*
+ * We just want to listen to RSs and RAs
+ */
+
+ flog(LOG_ERR, "icmpv6 filter failed");
+ return;
+ }
+
+ if (icmph->icmp6_type == ND_ROUTER_ADVERT)
+ {
+ if (len < sizeof(struct nd_router_advert)) {
+ flog(LOG_WARNING, "received icmpv6 RA packet with invalid length: %d",
+ len);
+ return;
+ }
+
+ if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
+ flog(LOG_WARNING, "received icmpv6 RA packet with non-linklocal source address");
+ return;
+ }
+ }
+
+ if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
+ {
+ if (len < sizeof(struct nd_router_solicit)) {
+ flog(LOG_WARNING, "received icmpv6 RS packet with invalid length: %d",
+ len);
+ return;
+ }
+ }
+
+ if (icmph->icmp6_code != 0)
+ {
+ flog(LOG_WARNING, "received icmpv6 RS/RA packet with invalid code: %d",
+ icmph->icmp6_code);
+ return;
+ }
+
+ dlog(LOG_DEBUG, 4, "if_index %u", pkt_info->ipi6_ifindex);
+
+ /* get iface by received if_index */
+
+ for (iface = ifacel; iface; iface=iface->next)
+ {
+ if (iface->if_index == pkt_info->ipi6_ifindex)
+ {
+ break;
+ }
+ }
+
+ if (iface == NULL)
+ {
+ dlog(LOG_DEBUG, 2, "received packet from unknown interface: %d",
+ pkt_info->ipi6_ifindex);
+ return;
+ }
+
+ if (hoplimit != 255)
+ {
+ print_addr(&addr->sin6_addr, addr_str);
+ flog(LOG_WARNING, "received RS or RA with invalid hoplimit %d from %s",
+ hoplimit, addr_str);
+ return;
+ }
+
+ if (!iface->AdvSendAdvert)
+ {
+ dlog(LOG_DEBUG, 2, "AdvSendAdvert is off for %s", iface->Name);
+ return;
+ }
+
+ dlog(LOG_DEBUG, 4, "found Interface: %s", iface->Name);
+
+ if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
+ {
+ process_rs(sock, iface, msg, len, addr);
+ }
+ else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
+ {
+ process_ra(iface, msg, len, addr);
+ }
+}
+
+static void
+process_rs(int sock, struct Interface *iface, unsigned char *msg, int len,
+ struct sockaddr_in6 *addr)
+{
+ double delay;
+ double next;
+ struct timeval tv;
+ uint8_t *opt_str;
+
+ /* validation */
+ len -= sizeof(struct nd_router_solicit);
+
+ opt_str = (uint8_t *)(msg + sizeof(struct nd_router_solicit));
+
+ while (len > 0)
+ {
+ int optlen;
+
+ if (len < 2)
+ {
+ flog(LOG_WARNING, "trailing garbage in RS");
+ return;
+ }
+
+ optlen = (opt_str[1] << 3);
+
+ if (optlen == 0)
+ {
+ flog(LOG_WARNING, "zero length option in RS");
+ return;
+ }
+ else if (optlen > len)
+ {
+ flog(LOG_WARNING, "option length greater than total length in RS");
+ return;
+ }
+
+ if (*opt_str == ND_OPT_SOURCE_LINKADDR &&
+ IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr)) {
+ flog(LOG_WARNING, "received icmpv6 RS packet with unspecified source address and there is a lladdr option");
+ return;
+ }
+
+ len -= optlen;
+ opt_str += optlen;
+ }
+
+ gettimeofday(&tv, NULL);
+
+ delay = MAX_RA_DELAY_TIME*rand()/(RAND_MAX+1.0);
+ dlog(LOG_DEBUG, 3, "random mdelay for %s: %.2f", iface->Name, delay);
+
+ if (iface->UnicastOnly) {
+ mdelay(delay);
+ send_ra(sock, iface, &addr->sin6_addr);
+ }
+ else if ((tv.tv_sec + tv.tv_usec / 1000000.0) - (iface->last_multicast_sec +
+ iface->last_multicast_usec / 1000000.0) < iface->MinDelayBetweenRAs) {
+ /* last RA was sent only a few moments ago, don't send another immediately */
+ clear_timer(&iface->tm);
+ next = iface->MinDelayBetweenRAs - (tv.tv_sec + tv.tv_usec / 1000000.0) +
+ (iface->last_multicast_sec + iface->last_multicast_usec / 1000000.0) + delay/1000.0;
+ set_timer(&iface->tm, next);
+ }
+ else {
+ /* no RA sent in a while, send an immediate multicast reply */
+ clear_timer(&iface->tm);
+ send_ra(sock, iface, NULL);
+
+ next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval);
+ set_timer(&iface->tm, next);
+ }
+}
+
+/*
+ * check router advertisements according to RFC 2461, 6.2.7
+ */
+static void
+process_ra(struct Interface *iface, unsigned char *msg, int len,
+ struct sockaddr_in6 *addr)
+{
+ struct nd_router_advert *radvert;
+ char addr_str[INET6_ADDRSTRLEN];
+ uint8_t *opt_str;
+
+ print_addr(&addr->sin6_addr, addr_str);
+
+ radvert = (struct nd_router_advert *) msg;
+
+ if ((radvert->nd_ra_curhoplimit && iface->AdvCurHopLimit) &&
+ (radvert->nd_ra_curhoplimit != iface->AdvCurHopLimit))
+ {
+ flog(LOG_WARNING, "our AdvCurHopLimit on %s doesn't agree with %s",
+ iface->Name, addr_str);
+ }
+
+ if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) && !iface->AdvManagedFlag)
+ {
+ flog(LOG_WARNING, "our AdvManagedFlag on %s doesn't agree with %s",
+ iface->Name, addr_str);
+ }
+
+ if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) && !iface->AdvOtherConfigFlag)
+ {
+ flog(LOG_WARNING, "our AdvOtherConfigFlag on %s doesn't agree with %s",
+ iface->Name, addr_str);
+ }
+
+ /* note: we don't check the default router preference here, because they're likely different */
+
+ if ((radvert->nd_ra_reachable && iface->AdvReachableTime) &&
+ (ntohl(radvert->nd_ra_reachable) != iface->AdvReachableTime))
+ {
+ flog(LOG_WARNING, "our AdvReachableTime on %s doesn't agree with %s",
+ iface->Name, addr_str);
+ }
+
+ if ((radvert->nd_ra_retransmit && iface->AdvRetransTimer) &&
+ (ntohl(radvert->nd_ra_retransmit) != iface->AdvRetransTimer))
+ {
+ flog(LOG_WARNING, "our AdvRetransTimer on %s doesn't agree with %s",
+ iface->Name, addr_str);
+ }
+
+ len -= sizeof(struct nd_router_advert);
+
+ if (len == 0)
+ return;
+
+ opt_str = (uint8_t *)(msg + sizeof(struct nd_router_advert));
+
+ while (len > 0)
+ {
+ int optlen;
+ struct nd_opt_prefix_info *pinfo;
+ struct nd_opt_rdnss_info_local *rdnssinfo;
+ struct nd_opt_mtu *mtu;
+ struct AdvPrefix *prefix;
+ struct AdvRDNSS *rdnss;
+ char prefix_str[INET6_ADDRSTRLEN];
+ char rdnss_str[INET6_ADDRSTRLEN];
+ uint32_t preferred, valid, count;
+
+ if (len < 2)
+ {
+ flog(LOG_ERR, "trailing garbage in RA on %s from %s",
+ iface->Name, addr_str);
+ break;
+ }
+
+ optlen = (opt_str[1] << 3);
+
+ if (optlen == 0)
+ {
+ flog(LOG_ERR, "zero length option in RA on %s from %s",
+ iface->Name, addr_str);
+ break;
+ }
+ else if (optlen > len)
+ {
+ flog(LOG_ERR, "option length greater than total"
+ " length in RA on %s from %s",
+ iface->Name, addr_str);
+ break;
+ }
+
+ switch (*opt_str)
+ {
+ case ND_OPT_MTU:
+ mtu = (struct nd_opt_mtu *)opt_str;
+
+ if (iface->AdvLinkMTU && (ntohl(mtu->nd_opt_mtu_mtu) != iface->AdvLinkMTU))
+ {
+ flog(LOG_WARNING, "our AdvLinkMTU on %s doesn't agree with %s",
+ iface->Name, addr_str);
+ }
+ break;
+ case ND_OPT_PREFIX_INFORMATION:
+ pinfo = (struct nd_opt_prefix_info *) opt_str;
+ preferred = ntohl(pinfo->nd_opt_pi_preferred_time);
+ valid = ntohl(pinfo->nd_opt_pi_valid_time);
+
+ prefix = iface->AdvPrefixList;
+ while (prefix)
+ {
+ if (prefix->enabled &&
+ (prefix->PrefixLen == pinfo->nd_opt_pi_prefix_len) &&
+ addr_match(&prefix->Prefix, &pinfo->nd_opt_pi_prefix,
+ prefix->PrefixLen))
+ {
+ print_addr(&prefix->Prefix, prefix_str);
+
+ if (valid != prefix->AdvValidLifetime)
+ {
+ flog(LOG_WARNING, "our AdvValidLifetime on"
+ " %s for %s doesn't agree with %s",
+ iface->Name,
+ prefix_str,
+ addr_str
+ );
+ }
+ if (preferred != prefix->AdvPreferredLifetime)
+ {
+ flog(LOG_WARNING, "our AdvPreferredLifetime on"
+ " %s for %s doesn't agree with %s",
+ iface->Name,
+ prefix_str,
+ addr_str
+ );
+ }
+ }
+
+ prefix = prefix->next;
+ }
+ break;
+ case ND_OPT_ROUTE_INFORMATION:
+ /* not checked: these will very likely vary a lot */
+ break;
+ case ND_OPT_SOURCE_LINKADDR:
+ /* not checked */
+ break;
+ case ND_OPT_TARGET_LINKADDR:
+ case ND_OPT_REDIRECTED_HEADER:
+ flog(LOG_ERR, "invalid option %d in RA on %s from %s",
+ (int)*opt_str, iface->Name, addr_str);
+ break;
+ /* Mobile IPv6 extensions */
+ case ND_OPT_RTR_ADV_INTERVAL:
+ case ND_OPT_HOME_AGENT_INFO:
+ /* not checked */
+ break;
+ case ND_OPT_RDNSS_INFORMATION:
+ rdnssinfo = (struct nd_opt_rdnss_info_local *) opt_str;
+ count = rdnssinfo->nd_opt_rdnssi_len;
+
+ /* Check the RNDSS addresses received */
+ switch (count) {
+ case 7:
+ rdnss = iface->AdvRDNSSList;
+ if (!check_rdnss_presence(rdnss, &rdnssinfo->nd_opt_rdnssi_addr3 )) {
+ /* no match found in iface->AdvRDNSSList */
+ print_addr(&rdnssinfo->nd_opt_rdnssi_addr3, rdnss_str);
+ flog(LOG_WARNING, "RDNSS address %s received on %s from %s is not advertised by us",
+ rdnss_str, iface->Name, addr_str);
+ }
+ /* FALLTHROUGH */
+ case 5:
+ rdnss = iface->AdvRDNSSList;
+ if (!check_rdnss_presence(rdnss, &rdnssinfo->nd_opt_rdnssi_addr2 )) {
+ /* no match found in iface->AdvRDNSSList */
+ print_addr(&rdnssinfo->nd_opt_rdnssi_addr2, rdnss_str);
+ flog(LOG_WARNING, "RDNSS address %s received on %s from %s is not advertised by us",
+ rdnss_str, iface->Name, addr_str);
+ }
+ /* FALLTHROUGH */
+ case 3:
+ rdnss = iface->AdvRDNSSList;
+ if (!check_rdnss_presence(rdnss, &rdnssinfo->nd_opt_rdnssi_addr1 )) {
+ /* no match found in iface->AdvRDNSSList */
+ print_addr(&rdnssinfo->nd_opt_rdnssi_addr1, rdnss_str);
+ flog(LOG_WARNING, "RDNSS address %s received on %s from %s is not advertised by us",
+ rdnss_str, iface->Name, addr_str);
+ }
+
+ break;
+ default:
+ flog(LOG_ERR, "invalid len %i in RDNSS option on %s from %s",
+ count, iface->Name, addr_str);
+ }
+
+ break;
+ default:
+ dlog(LOG_DEBUG, 1, "unknown option %d in RA on %s from %s",
+ (int)*opt_str, iface->Name, addr_str);
+ break;
+ }
+
+ len -= optlen;
+ opt_str += optlen;
+ }
+}
+
+static int
+addr_match(struct in6_addr *a1, struct in6_addr *a2, int prefixlen)
+{
+ unsigned int pdw;
+ unsigned int pbi;
+
+ pdw = prefixlen >> 0x05; /* num of whole uint32_t in prefix */
+ pbi = prefixlen & 0x1f; /* num of bits in incomplete uint32_t in prefix */
+
+ if (pdw)
+ {
+ if (memcmp(a1, a2, pdw << 2))
+ return 0;
+ }
+
+ if (pbi)
+ {
+ uint32_t w1, w2;
+ uint32_t mask;
+
+ w1 = *((uint32_t *)a1 + pdw);
+ w2 = *((uint32_t *)a2 + pdw);
+
+ mask = htonl(((uint32_t) 0xffffffff) << (0x20 - pbi));
+
+ if ((w1 ^ w2) & mask)
+ return 0;
+ }
+
+ return 1;
+}
+
--- /dev/null
+.\"
+.\" $Id$
+.\"
+.\" Authors:
+.\" Lars Fenneberg <lf@elemental.net>
+.\"
+.\" This software is Copyright 1996-2000 by the above mentioned author(s),
+.\" All Rights Reserved.
+.\"
+.\" The license which is distributed with this software in the file COPYRIGHT
+.\" applies to this software. If your distribution is missing this file, you
+.\" may request it from <pekkas@netcore.fi>.
+.\"
+.\"
+.\"
+.TH RADVD 8 "29 Mar 2001" "radvd @VERSION@" ""
+.SH NAME
+radvd \- router advertisement daemon for IPv6
+.SH SYNOPSIS
+.B radvd
+.B "[ \-vh ]"
+.BI "[ \-d " debuglevel " ]"
+.BI "[ \-C " configfile " ]"
+.BI "[ \-p " pidfile " ]"
+.BI "[ \-m " logmethod " ]"
+.BI "[ \-l " logfile " ]"
+.BI "[ \-f " facility " ]"
+.BI "[ \-t " chrootdir " ]"
+.BI "[ \-u " username " ]"
+
+.SH DESCRIPTION
+.B radvd
+is the router advertisement daemon for IPv6. It listens to router
+solicitations and sends router advertisements as described in
+"Neighbor Discovery for IP Version 6 (IPv6)" (RFC 2461).
+With these advertisements hosts can automatically configure their
+addresses and some other parameters. They also can choose a default
+router based on these advertisements.
+
+Note that if debugging is not enabled,
+.B radvd
+will not start if IPv6 forwarding is disabled. IPv6 forwarding can be
+controlled via sysctl(8),
+.B net.ipv6.conf.all.forwarding
+on Linux or
+.B net.inet6.ip6.forwarding
+on BSD.
+
+Similarly, the configuration file must not be writable by others, and if
+non-root operation is requested, not even by self/own group.
+
+.SH OPTIONS
+
+For every one character option there is also a long option, which
+is listed right next to the "short" option name:
+
+.TP
+.BR "\-v" , " \-\-version"
+Displays the version of
+.I radvd
+and then aborts.
+.TP
+.BR "\-h" , " \-\-help"
+Displays a short usage description and then aborts.
+.TP
+.BR "\-d " debuglevel, " \-\-debug " debuglevel
+With this option you turn on debugging information. The debugging level is
+an integer in the range from 1 to 5, from quiet to very verbose. A
+debugging level of 0 completely turns off debugging. If a debugging level
+greater than 0 is used,
+.I radvd
+doesn't background itself on start. The default debugging level is 0.
+.TP
+.BR "\-C " configfile, " \-\-config " configfile
+Specifies an alternate config file. Normally the compiled in default
+.I @PATH_RADVD_CONF@
+is used.
+.TP
+.BR "\-p " pidfile, " \-\-pidfile " pidfile
+Specifies an alternate pidfile. Normally the compiled in default
+.I @PATH_RADVD_PID@
+is used.
+.TP
+.BR "\-m " method, " \-\-logmethod " method
+Specifies the logging method to use. Possibly values are:
+.RS
+.TP
+.B none
+Completely disables any logging.
+.TP
+.B logfile
+Logs to the logfile which is specified by the
+.I \-l
+option. If no logfile is specified on the command line, then
+a compiled in default is used (see next option).
+.TP
+.B stderr
+Logs to standard error.
+.TP
+.B stderr_syslog
+Logs only the high messages (of at least LOG_ERR priority) to standard
+error, and everything to syslog (default method).
+.TP
+.B syslog
+Logs to syslog.
+.RE
+.PP
+.TP
+.BR "\-l " logfile, " \-\-logfile " logfile
+Specifies the logfile to use when using the logging method
+.IR logfile .
+The default logfile is
+.IR @PATH_RADVD_LOG@ .
+.TP
+.BR "\-f " facility, " \-\-facility " facility
+Specifies the facility (as an integer) when using syslog logging. Default
+is @LOG_FACILITY@.
+.TP
+.BR "\-t " chrootdir, " \-\-chrootdir " chrootdir
+If specified, switches to
+.I chrootdir
+before doing anything else. This directory and its
+subdirectories must have been populated first.
+For security reasons,
+.I \-u
+must always be used when using
+.IR chrootdir .
+
+Note that on Linux
+.I radvd
+requires access to the
+.I /proc
+filesystem,
+so it is more challenging to set up the chroot environment.
+.TP
+.BR "\-u " username, " \-\-username " username
+If specified, drops root privileges and changes user ID to
+.I username
+and group ID to the primary group of
+.IR username .
+This is recommended for security reasons.
+You might also need to use
+.I \-p
+to point to a file in a
+.I username
+-writable directory (e.g. /var/run/radvd/radvd.pid).
+.SH FILES
+
+.nf
+@sbindir@/radvd
+@PATH_RADVD_CONF@
+@PATH_RADVD_PID@
+@PATH_RADVD_LOG@
+.fi
+.SH BUGS
+
+There certainly are some bugs. If you find them or have other
+suggestions please contact Pekka Savola <pekkas@netcore.fi>.
+
+.SH "SEE ALSO"
+
+.BR radvd.conf (5),
+.BR radvdump (8)
+.SH AUTHORS
+
+.nf
+Pedro Roque <roque@di.fc.ul.pt> - wrote first version for Linux
+Lars Fenneberg <lf@elemental.net> - previous maintainer
+Nathan Lutchansky <lutchann@litech.org> - previous maintainer
+Pekka Savola <pekkas@netcore.fi> - current maintainer
+Craig Metz <cmetz@inner.net> - port to NRL's IPv6 code for BSD4.4
+Marko Myllynen <myllynen@lut.fi> - RFC 2461 update, Mobile IPv6 support
+.fi
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996-2000 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+#include <pathnames.h>
+
+struct Interface *IfaceList = NULL;
+
+char usage_str[] =
+ "[-vh] [-d level] [-C config_file] [-m log_method] [-l log_file]\n"
+ "\t[-f facility] [-p pid_file] [-u username] [-t chrootdir]";
+
+#ifdef HAVE_GETOPT_LONG
+struct option prog_opt[] = {
+ {"debug", 1, 0, 'd'},
+ {"config", 1, 0, 'C'},
+ {"pidfile", 1, 0, 'p'},
+ {"logfile", 1, 0, 'l'},
+ {"logmethod", 1, 0, 'm'},
+ {"facility", 1, 0, 'f'},
+ {"username", 1, 0, 'u'},
+ {"chrootdir", 1, 0, 't'},
+ {"version", 0, 0, 'v'},
+ {"help", 0, 0, 'h'},
+ {NULL, 0, 0, 0}
+};
+#endif
+
+extern FILE *yyin;
+
+char *conf_file = NULL;
+char *pname;
+int sock = -1;
+
+volatile int sighup_received = 0;
+volatile int sigterm_received = 0;
+volatile int sigint_received = 0;
+
+void sighup_handler(int sig);
+void sigterm_handler(int sig);
+void sigint_handler(int sig);
+void timer_handler(void *data);
+void config_interface(void);
+void kickoff_adverts(void);
+void stop_adverts(void);
+void version(void);
+void usage(void);
+int drop_root_privileges(const char *);
+int readin_config(char *);
+int check_conffile_perm(const char *, const char *);
+
+int
+main(int argc, char *argv[])
+{
+ unsigned char msg[MSG_SIZE];
+ char pidstr[16];
+ int c, log_method;
+ char *logfile, *pidfile;
+ sigset_t oset, nset;
+ int facility, fd;
+ char *username = NULL;
+ char *chrootdir = NULL;
+#ifdef HAVE_GETOPT_LONG
+ int opt_idx;
+#endif
+
+ pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0];
+
+ srand((unsigned int)time(NULL));
+
+ log_method = L_STDERR_SYSLOG;
+ logfile = PATH_RADVD_LOG;
+ conf_file = PATH_RADVD_CONF;
+ facility = LOG_FACILITY;
+ pidfile = PATH_RADVD_PID;
+
+ /* parse args */
+#ifdef HAVE_GETOPT_LONG
+ while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vh", prog_opt, &opt_idx)) > 0)
+#else
+ while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vh")) > 0)
+#endif
+ {
+ switch (c) {
+ case 'C':
+ conf_file = optarg;
+ break;
+ case 'd':
+ set_debuglevel(atoi(optarg));
+ break;
+ case 'f':
+ facility = atoi(optarg);
+ break;
+ case 'l':
+ logfile = optarg;
+ break;
+ case 'p':
+ pidfile = optarg;
+ break;
+ case 'm':
+ if (!strcmp(optarg, "syslog"))
+ {
+ log_method = L_SYSLOG;
+ }
+ else if (!strcmp(optarg, "stderr_syslog"))
+ {
+ log_method = L_STDERR_SYSLOG;
+ }
+ else if (!strcmp(optarg, "stderr"))
+ {
+ log_method = L_STDERR;
+ }
+ else if (!strcmp(optarg, "logfile"))
+ {
+ log_method = L_LOGFILE;
+ }
+ else if (!strcmp(optarg, "none"))
+ {
+ log_method = L_NONE;
+ }
+ else
+ {
+ fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg);
+ exit(1);
+ }
+ break;
+ case 't':
+ chrootdir = strdup(optarg);
+ break;
+ case 'u':
+ username = strdup(optarg);
+ break;
+ case 'v':
+ version();
+ break;
+ case 'h':
+ usage();
+#ifdef HAVE_GETOPT_LONG
+ case ':':
+ fprintf(stderr, "%s: option %s: parameter expected\n", pname,
+ prog_opt[opt_idx].name);
+ exit(1);
+#endif
+ case '?':
+ exit(1);
+ }
+ }
+
+ if (chrootdir) {
+ if (!username) {
+ fprintf(stderr, "Chroot as root is not safe, exiting\n");
+ exit(1);
+ }
+
+ if (chroot(chrootdir) == -1) {
+ perror("chroot");
+ exit (1);
+ }
+
+ if (chdir("/") == -1) {
+ perror("chdir");
+ exit (1);
+ }
+ /* username will be switched later */
+ }
+
+ if (log_open(log_method, pname, logfile, facility) < 0)
+ exit(1);
+
+ flog(LOG_INFO, "version %s started", VERSION);
+
+ /* get a raw socket for sending and receiving ICMPv6 messages */
+ sock = open_icmpv6_socket();
+ if (sock < 0)
+ exit(1);
+
+ /* drop root privileges if requested. */
+ if (username) {
+ if (drop_root_privileges(username) < 0)
+ exit(1);
+ }
+
+ /* check that 'other' cannot write the file
+ * for non-root, also that self/own group can't either
+ */
+ if (check_conffile_perm(username, conf_file) < 0) {
+ if (get_debuglevel() == 0)
+ exit(1);
+ else
+ flog(LOG_WARNING, "Insecure file permissions, but continuing anyway");
+ }
+
+ /* if we know how to do it, check whether forwarding is enabled */
+ if (check_ip6_forwarding()) {
+ if (get_debuglevel() == 0) {
+ flog(LOG_ERR, "IPv6 forwarding seems to be disabled, exiting");
+ exit(1);
+ }
+ else
+ flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway.");
+ }
+
+ /* parse config file */
+ if (readin_config(conf_file) < 0)
+ exit(1);
+
+ /* FIXME: not atomic if pidfile is on an NFS mounted volume */
+ if ((fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0)
+ {
+ flog(LOG_ERR, "another radvd seems to be already running, terminating");
+ exit(1);
+ }
+
+ /*
+ * okay, config file is read in, socket and stuff is setup, so
+ * lets fork now...
+ */
+
+ if (get_debuglevel() == 0) {
+
+ /* Detach from controlling terminal */
+ if (daemon(0, 0) < 0)
+ perror("daemon");
+
+ /* close old logfiles, including stderr */
+ log_close();
+
+ /* reopen logfiles, but don't log to stderr unless explicitly requested */
+ if (log_method == L_STDERR_SYSLOG)
+ log_method = L_SYSLOG;
+ if (log_open(log_method, pname, logfile, facility) < 0)
+ exit(1);
+
+ }
+
+ /*
+ * config signal handlers, also make sure ALRM isn't blocked and raise a warning if so
+ * (some stupid scripts/pppd appears to do this...)
+ */
+ 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.");
+
+ signal(SIGHUP, sighup_handler);
+ signal(SIGTERM, sigterm_handler);
+ signal(SIGINT, sigint_handler);
+
+ snprintf(pidstr, sizeof(pidstr), "%d\n", getpid());
+
+ write(fd, pidstr, strlen(pidstr));
+
+ close(fd);
+
+ config_interface();
+ kickoff_adverts();
+
+ /* enter loop */
+
+ for (;;)
+ {
+ 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, IfaceList, msg, len,
+ &rcv_addr, pkt_info, hoplimit);
+
+ if (sigterm_received || sigint_received) {
+ stop_adverts();
+ break;
+ }
+
+ if (sighup_received)
+ {
+ reload_config();
+ sighup_received = 0;
+ }
+ }
+
+ unlink(pidfile);
+ exit(0);
+}
+
+void
+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
+config_interface(void)
+{
+ struct Interface *iface;
+ for(iface=IfaceList; iface; iface=iface->next)
+ {
+ if (iface->AdvLinkMTU)
+ set_interface_linkmtu(iface->Name, iface->AdvLinkMTU);
+ if (iface->AdvCurHopLimit)
+ set_interface_curhlim(iface->Name, iface->AdvCurHopLimit);
+ if (iface->AdvReachableTime)
+ set_interface_reachtime(iface->Name, iface->AdvReachableTime);
+ if (iface->AdvRetransTimer)
+ set_interface_retranstimer(iface->Name, iface->AdvRetransTimer);
+ }
+}
+
+void
+kickoff_adverts(void)
+{
+ struct Interface *iface;
+
+ /*
+ * send initial advertisement and set timers
+ */
+
+ for(iface=IfaceList; iface; iface=iface->next)
+ {
+ if( ! iface->UnicastOnly )
+ {
+ init_timer(&iface->tm, 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
+stop_adverts(void)
+{
+ struct Interface *iface;
+
+ /*
+ * send final RA (a SHOULD in RFC2461 section 6.2.5)
+ */
+
+ for (iface=IfaceList; iface; iface=iface->next) {
+ if( ! iface->UnicastOnly ) {
+ if (iface->AdvSendAdvert) {
+ /* send a final advertisement with zero Router Lifetime */
+ iface->AdvDefaultLifetime = 0;
+ send_ra(sock, iface, NULL);
+ }
+ }
+ }
+}
+
+void reload_config(void)
+{
+ struct Interface *iface;
+
+ flog(LOG_INFO, "attempting to reread config file");
+
+ dlog(LOG_DEBUG, 4, "reopening log");
+ if (log_reopen() < 0)
+ exit(1);
+
+ /* disable timers, free interface and prefix structures */
+ for(iface=IfaceList; iface; iface=iface->next)
+ {
+ /* check that iface->tm was set in the first place */
+ if (iface->tm.next && iface->tm.prev)
+ {
+ dlog(LOG_DEBUG, 4, "disabling timer for %s", iface->Name);
+ clear_timer(&iface->tm);
+ }
+ }
+
+ iface=IfaceList;
+ while(iface)
+ {
+ struct Interface *next_iface = iface->next;
+ struct AdvPrefix *prefix;
+ struct AdvRoute *route;
+ struct AdvRDNSS *rdnss;
+
+ dlog(LOG_DEBUG, 4, "freeing interface %s", iface->Name);
+
+ prefix = iface->AdvPrefixList;
+ while (prefix)
+ {
+ struct AdvPrefix *next_prefix = prefix->next;
+
+ free(prefix);
+ prefix = next_prefix;
+ }
+
+ route = iface->AdvRouteList;
+ while (route)
+ {
+ struct AdvRoute *next_route = route->next;
+
+ free(route);
+ route = next_route;
+ }
+
+ rdnss = iface->AdvRDNSSList;
+ while (rdnss)
+ {
+ struct AdvRDNSS *next_rdnss = rdnss->next;
+
+ free(rdnss);
+ rdnss = next_rdnss;
+ }
+
+ free(iface);
+ iface = next_iface;
+ }
+
+ IfaceList = NULL;
+
+ /* reread config file */
+ if (readin_config(conf_file) < 0)
+ exit(1);
+
+ config_interface();
+ kickoff_adverts();
+
+ flog(LOG_INFO, "resuming normal operation");
+}
+
+void
+sighup_handler(int sig)
+{
+ /* Linux has "one-shot" signals, reinstall the signal handler */
+ signal(SIGHUP, sighup_handler);
+
+ dlog(LOG_DEBUG, 4, "sighup_handler called");
+
+ sighup_received = 1;
+}
+
+void
+sigterm_handler(int sig)
+{
+ /* Linux has "one-shot" signals, reinstall the signal handler */
+ signal(SIGTERM, sigterm_handler);
+
+ dlog(LOG_DEBUG, 4, "sigterm_handler called");
+
+ sigterm_received = 1;
+}
+
+void
+sigint_handler(int sig)
+{
+ /* Linux has "one-shot" signals, reinstall the signal handler */
+ signal(SIGINT, sigint_handler);
+
+ dlog(LOG_DEBUG, 4, "sigint_handler called");
+
+ sigint_received = 1;
+}
+
+int
+drop_root_privileges(const char *username)
+{
+ struct passwd *pw = NULL;
+ pw = getpwnam(username);
+ if (pw) {
+ if (initgroups(username, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) {
+ flog(LOG_ERR, "Couldn't change to '%.32s' uid=%d gid=%d\n",
+ username, pw->pw_uid, pw->pw_gid);
+ return (-1);
+ }
+ }
+ else {
+ flog(LOG_ERR, "Couldn't find user '%.32s'\n", username);
+ return (-1);
+ }
+ return 0;
+}
+
+int
+check_conffile_perm(const char *username, const char *conf_file)
+{
+ struct stat *st = NULL;
+ struct passwd *pw = NULL;
+ FILE *fp = fopen(conf_file, "r");
+
+ if (fp == NULL) {
+ flog(LOG_ERR, "can't open %s: %s", conf_file, strerror(errno));
+ return (-1);
+ }
+ fclose(fp);
+
+ st = malloc(sizeof(struct stat));
+ if (st == NULL)
+ goto errorout;
+
+ if (!username)
+ username = "root";
+
+ pw = getpwnam(username);
+
+ if (stat(conf_file, st) || pw == NULL)
+ goto errorout;
+
+ if (st->st_mode & S_IWOTH) {
+ flog(LOG_ERR, "Insecure file permissions (writable by others): %s", conf_file);
+ goto errorout;
+ }
+
+ /* for non-root: must not be writable by self/own group */
+ if (strncmp(username, "root", 5) != 0 &&
+ ((st->st_mode & S_IWGRP && pw->pw_gid == st->st_gid) ||
+ (st->st_mode & S_IWUSR && pw->pw_uid == st->st_uid))) {
+ flog(LOG_ERR, "Insecure file permissions (writable by self/group): %s", conf_file);
+ goto errorout;
+ }
+
+ free(st);
+ return 0;
+
+errorout:
+ if (st)
+ free(st);
+ return(-1);
+}
+
+int
+check_ip6_forwarding(void)
+{
+ int forw_sysctl[] = { SYSCTL_IP6_FORWARDING };
+ int value;
+ size_t size = sizeof(value);
+ FILE *fp = NULL;
+
+#ifdef __linux__
+ fp = fopen(PROC_SYS_IP6_FORWARDING, "r");
+ if (fp) {
+ fscanf(fp, "%d", &value);
+ fclose(fp);
+ }
+ else
+ flog(LOG_DEBUG, "Correct IPv6 forwarding procfs entry not found, "
+ "perhaps the procfs is disabled, "
+ "or the kernel interface has changed?");
+#endif /* __linux__ */
+
+ if (!fp && sysctl(forw_sysctl, sizeof(forw_sysctl)/sizeof(forw_sysctl[0]),
+ &value, &size, NULL, 0) < 0) {
+ flog(LOG_DEBUG, "Correct IPv6 forwarding sysctl branch not found, "
+ "perhaps the kernel interface has changed?");
+ return(0); /* this is of advisory value only */
+ }
+
+ if (value != 1) {
+ flog(LOG_DEBUG, "IPv6 forwarding setting is: %u, should be 1", value);
+ return(-1);
+ }
+
+ return(0);
+}
+
+int
+readin_config(char *fname)
+{
+ if ((yyin = fopen(fname, "r")) == NULL)
+ {
+ flog(LOG_ERR, "can't open %s: %s", fname, strerror(errno));
+ return (-1);
+ }
+
+ if (yyparse() != 0)
+ {
+ flog(LOG_ERR, "error parsing or activating the config file: %s", fname);
+ return (-1);
+ }
+
+ fclose(yyin);
+ return 0;
+}
+
+void
+version(void)
+{
+ fprintf(stderr, "Version: %s\n\n", VERSION);
+ fprintf(stderr, "Compiled in settings:\n");
+ fprintf(stderr, " default config file \"%s\"\n", PATH_RADVD_CONF);
+ fprintf(stderr, " default pidfile \"%s\"\n", PATH_RADVD_PID);
+ fprintf(stderr, " default logfile \"%s\"\n", PATH_RADVD_LOG);
+ fprintf(stderr, " default syslog facililty %d\n", LOG_FACILITY);
+ fprintf(stderr, "Please send bug reports or suggestions to %s.\n",
+ CONTACT_EMAIL);
+
+ exit(1);
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: %s %s\n", pname, usage_str);
+ exit(1);
+}
+
--- /dev/null
+.\"
+.\" $Id$
+.\"
+.\" Authors:
+.\" Lars Fenneberg <lf@elemental.net>
+.\" Marko Myllynen <myllynen@lut.fi>
+.\"
+.\" This software is Copyright 1996-2000 by the above mentioned author(s),
+.\" All Rights Reserved.
+.\"
+.\" The license which is distributed with this software in the file COPYRIGHT
+.\" applies to this software. If your distribution is missing this file, you
+.\" may request it from <pekkas@netcore.fi>.
+.\"
+.\"
+.\"
+.TH RADVD.CONF 5 "20 Aug 2004" "radvd @VERSION@" ""
+.SH NAME
+radvd.conf \- configuration file of the router advertisement daemon
+.B radvd
+.SH DESCRIPTION
+This file describes the information which is included in the router
+advertisement (RA) of a specific interface.
+.P
+The file contains one or more interface definitions of the form:
+
+.nf
+.BR "interface " "name " {
+ list of interface specific options
+ list of prefix definitions
+ list of route definitions
+ list of RDNSS definitions
+.B };
+.fi
+
+All the possible interface specific options are detailed below. Each
+option has to be terminated by a semicolon.
+
+Prefix definitions are of the form:
+
+.nf
+.BR "prefix " prefix / "length " {
+ list of prefix specific options
+.B };
+.fi
+
+Prefix can be network prefix or the address of the inferface.
+The address of interface should be used when using Mobile IPv6
+extensions.
+
+All the possible prefix specific options are described below. Each
+option has to be terminated by a semicolon.
+
+Decimal values are allowed only for MinDelayBetweenRAs,
+MaxRtrAdvInterval and MinRtrAdvInterval. Decimal values should
+be used only when using Mobile IPv6 extensions.
+
+Route definitions are of the form:
+
+.nf
+.BR "route " prefix / "length " {
+ list of route specific options
+.B };
+.fi
+
+The prefix of a route definition should be network prefix; it can be used to
+advertise more specific routes to the hosts.
+
+RDNSS (Recursive DNS server) definitions are of the form:
+
+.nf
+.BR "RDNSS " "ip [ip] [ip] " {
+ list of rdnss specific options
+.B };
+.fi
+
+.SH INTERFACE SPECIFIC OPTIONS
+
+.TP
+.BR IgnoreIfMissing " " on | off
+
+A flag indicating whether or not the interface is ignored
+if it does not exist at start-up. By default, radvd exits.
+
+This is useful for dynamic interfaces which are not active when radvd
+starts or which are dynamically disabled and re-enabled during the time
+radvd runs.
+
+Current versions of radvd automatically try to re-enable interfaces.
+
+Enabling IgnoreIfMissing also quenches certain warnings in log messages
+relating to missing interfaces.
+
+Default: off
+
+.TP
+.BR AdvSendAdvert " " on | off
+
+A flag indicating whether or not the router sends
+periodic router advertisements and responds to
+router solicitations.
+
+This option no longer has to be specified first, but it
+needs to be
+.B on
+to enable advertisement on this interface.
+
+Default: off
+
+.TP
+.BR UnicastOnly " " on | off
+
+Indicates that the interface link type only supports unicast.
+This will prevent unsolicited advertisements from being sent, and
+will cause solicited advertisements to be unicast to the
+soliciting node. This option is necessary for non-broadcast,
+multiple-access links, such as ISATAP.
+
+Default: off
+
+.TP
+.BR "MaxRtrAdvInterval " seconds
+
+The maximum time allowed between sending unsolicited multicast
+router advertisements from the interface, in seconds.
+
+Must be no less than 4 seconds and no greater than 1800 seconds.
+
+Minimum when using Mobile IPv6 extensions: 0.07.
+
+For values less than 0.2 seconds, 0.02 seconds is added to account for
+scheduling granularities as specified in RFC3775.
+
+Default: 600 seconds
+
+.TP
+.BR "MinRtrAdvInterval " seconds
+
+The minimum time allowed between sending unsolicited multicast
+router advertisements from the interface, in seconds.
+
+Must be no less than 3 seconds and no greater than 0.75 *
+MaxRtrAdvInterval.
+
+Minimum when using Mobile IPv6 extensions: 0.03.
+
+Default: 0.33 * MaxRtrAdvInterval
+
+.TP
+.BR "MinDelayBetweenRAs " seconds
+
+The minimum time allowed between sending multicast
+router advertisements from the interface, in seconds.
+
+This applies to solicited multicast RAs.
+This is defined as the protocol constant MIN_DELAY_BETWEEN_RAS in RFC2461.
+MIPv6 redefines this parameter to have a minimum of 0.03 seconds.
+
+Minimum when using Mobile IPv6 extensions: 0.03.
+
+Default: 3
+
+.TP
+.BR AdvManagedFlag " " on | off
+
+When set, hosts use the administered (stateful) protocol for address
+autoconfiguration in addition to any addresses autoconfigured using
+stateless address autoconfiguration. The use of this flag is
+described in RFC 2462.
+
+Default: off
+
+.TP
+.BR AdvOtherConfigFlag " " on | off
+
+When set, hosts use the administered (stateful) protocol for
+autoconfiguration of other (non-address) information. The use of
+this flag is described in RFC 2462.
+
+Default: off
+
+.TP
+.BR "AdvLinkMTU " integer
+
+The MTU option is used in router advertisement messages to insure
+that all nodes on a link use the same MTU value in those cases where
+the link MTU is not well known.
+
+If specified, i.e. not 0, must not be smaller than 1280 and not greater
+than the maximum MTU allowed for this link (e.g. ethernet has
+a maximum MTU of 1500. See RFC 2464).
+
+Default: 0
+
+.TP
+.BR "AdvReachableTime " milliseconds
+
+The time, in milliseconds, that a node assumes a neighbor is
+reachable after having received a reachability confirmation. Used
+by the Neighbor Unreachability Detection algorithm (see Section
+7.3 of RFC 2461). A value of zero means unspecified (by this router).
+
+Must be no greater than 3,600,000 milliseconds (1 hour).
+
+Default: 0
+
+.TP
+.BR "AdvRetransTimer " milliseconds
+
+The time, in milliseconds, between retransmitted Neighbor
+Solicitation messages. Used by address resolution and the Neighbor
+Unreachability Detection algorithm (see Sections 7.2 and 7.3 of RFC 2461).
+A value of zero means unspecified (by this router).
+
+Default: 0
+
+.TP
+.BR "AdvCurHopLimit " integer
+
+The default value that should be placed in the Hop Count field of
+the IP header for outgoing (unicast) IP packets. The value should
+be set to the current diameter of the Internet. The value zero
+means unspecified (by this router).
+
+Default: 64
+
+.TP
+.BR "AdvDefaultLifetime " seconds
+
+The lifetime associated with the default router in units of seconds.
+The maximum value corresponds to 18.2 hours. A lifetime of 0
+indicates that the router is not a default router and should not
+appear on the default router list. The router lifetime applies only
+to the router's usefulness as a default router; it does not apply to
+information contained in other message fields or options. Options
+that need time limits for their information include their own
+lifetime fields.
+
+Must be either zero or between MaxRtrAdvInterval and 9000 seconds.
+
+Default: 3 * MaxRtrAdvInterval (Minimum 1 second).
+
+.TP
+.BR AdvDefaultPreference " " low | medium | high
+
+The preference associated with the default router, as either "low",
+"medium", or "high".
+
+Default: medium
+
+.TP
+.BR AdvSourceLLAddress " " on | off
+
+When set, the link-layer address of the outgoing interface is
+included in the RA.
+
+Default: on
+
+.TP
+.BR AdvHomeAgentFlag " " on | off
+
+When set, indicates that sending router is able to serve as Mobile
+IPv6 Home Agent. When set, minimum limits specified by Mobile IPv6
+are used for MinRtrAdvInterval and MaxRtrAdvInterval.
+
+Default: off
+
+.TP
+.BR AdvHomeAgentInfo " " on | off
+
+When set, Home Agent Information Option (specified by Mobile IPv6)
+is included in Router Advertisements. AdvHomeAgentFlag must also
+be set when using this option.
+
+Default: off
+
+.TP
+.BR "HomeAgentLifetime " seconds
+
+The length of time in seconds (relative to the time the packet is
+sent) that the router is offering Mobile IPv6 Home Agent services.
+A value 0 must not be used. The maximum lifetime is 65520 seconds
+(18.2 hours). This option is ignored, if AdvHomeAgentInfo is not
+set.
+
+If both HomeAgentLifetime and HomeAgentPreference are set to their
+default values, Home Agent Information Option will not be sent.
+
+Default: AdvDefaultLifetime
+
+.TP
+.BR "HomeAgentPreference " integer
+
+The preference for the Home Agent sending this Router Advertisement.
+Values greater than 0 indicate more preferable Home Agent, values
+less than 0 indicate less preferable Home Agent. This option is
+ignored, if AdvHomeAgentInfo is not set.
+
+If both HomeAgentLifetime and HomeAgentPreference are set to their
+default values, Home Agent Information Option will not be sent.
+
+Default: 0
+
+.TP
+.BR AdvMobRtrSupportFlag " " on | off
+
+When set, the Home Agent signals it supports Mobile Router
+registrations (specified by NEMO Basic). AdvHomeAgentInfo must also
+be set when using this option.
+
+Default: off
+
+.TP
+.BR AdvIntervalOpt " " on | off
+
+When set, Advertisement Interval Option (specified by Mobile IPv6)
+is included in Router Advertisements. When set, minimum limits
+specified by Mobile IPv6 are used for MinRtrAdvInterval and
+MaxRtrAdvInterval.
+
+The advertisement interval is based on the configured MaxRtrAdvInterval
+parameter except where this is less than 200ms. In this case,
+the advertised interval is ( MaxRtrAdvInterval + 20ms ).
+
+Default: off
+
+.SH PREFIX SPECIFIC OPTIONS
+
+.TP
+.BR AdvOnLink " " on | off
+
+When set, indicates that this prefix can be used for on-link
+determination. When not set the advertisement makes no statement
+about on-link or off-link properties of the prefix. For instance,
+the prefix might be used for address configuration with some of the
+addresses belonging to the prefix being on-link and others being
+off-link.
+
+Default: on
+
+.TP
+.BR AdvAutonomous " " on | off
+
+When set, indicates that this prefix can be used for autonomous
+address configuration as specified in RFC 2462.
+
+Default: on
+
+.TP
+.BR AdvRouterAddr " " on | off
+
+When set, indicates that the address of interface is sent instead of
+network prefix, as is required by Mobile IPv6. When set, minimum
+limits specified by Mobile IPv6 are used for MinRtrAdvInterval and
+MaxRtrAdvInterval.
+
+Default: off
+
+.TP
+.BR "AdvValidLifetime " seconds "" | infinity
+
+The length of time in seconds (relative to the time the packet is
+sent) that the prefix is valid for the purpose of on-link
+determination. The symbolic value
+.B infinity
+represents infinity (i.e. a value of all one bits (0xffffffff)).
+The valid lifetime is also used by RFC 2462.
+
+Default: 2592000 seconds (30 days)
+
+.TP
+.BR "AdvPreferredLifetime " seconds "" | infinity
+
+The length of time in seconds (relative to the time the packet is
+sent) that addresses generated from the prefix via stateless address
+autoconfiguration remain preferred.
+The symbolic value
+.B infinity
+represents infinity (i.e. a value of all one bits (0xffffffff)).
+See RFC 2462.
+
+Default: 604800 seconds (7 days)
+
+.TP
+.BR "Base6to4Interface " name
+
+If this option is specified, this prefix will be combined with the
+IPv4 address of interface
+.B name
+to produce a valid 6to4 prefix. The first 16 bits of this prefix
+will be replaced by
+.B 2002
+and the next 32 bits of this prefix will be replaced by the IPv4
+address assigned to interface
+.B name
+at configuration time. The remaining 80 bits of the prefix (including
+the SLA ID) will be advertised as specified in the configuration file.
+See the next section for an example.
+
+If interface
+.B name
+is not available at configuration time, a warning will be written to
+the log and this prefix will be disabled until radvd is reconfigured.
+
+This option enables systems with dynamic IPv4 addresses to update their
+advertised 6to4 prefixes simply by restarting radvd or sending a SIGHUP
+signal to cause radvd to reconfigure itself.
+
+Note that 6to4 prefixes derived from dynamically-assigned IPv4 addresses
+should be advertised with a significantly shorter lifetime (see the
+.B AdvValidLifetime
+and
+.B AdvPreferredLifetime
+options).
+
+For more information on 6to4, see RFC 3056.
+
+Default: 6to4 is not used
+
+.SH ROUTE SPECIFIC OPTIONS
+
+.TP
+.BR "AdvRouteLifetime " seconds "" | infinity
+
+The lifetime associated with the route in units of seconds.
+The symbolic value
+.B infinity
+represents infinity (i.e. a value of all one bits (0xffffffff)).
+
+Default: 3 * MaxRtrAdvInterval
+
+.TP
+.BR AdvRoutePreference " " low | medium | high
+
+The preference associated with the default router, as either "low",
+"medium", or "high".
+
+Default: medium
+
+.SH RDNSS SPECIFIC OPTIONS
+
+.TP
+.BR "AdvRDNSSPreference " integer;
+
+The preference of the DNS server, compared to other DNS servers advertised and used.
+0 to 7 means less important than manually configured nameservers in resolv.conf, while 12 to 15 means more important.
+
+Default: 8
+
+.TP
+.BR "AdvRDNSSOpen " on | off;
+
+"Service Open" flag. When set, indicates that RDNSS continues to be available to hosts even if they moved to a different subnet.
+
+Default: off
+
+.TP
+.BR "AdvRDNSSLifetime " seconds | infinity;
+The maximum duration how long the RDNSS entries are used for name resolution. A value of 0 means the nameserver should no longer be used.
+The maximum duration how long the RDNSS entries are used for name resolution. A value of 0 means the nameserver should no longer be used.
+The value, if not 0, must be at least MaxRtrAdvInterval. To ensure stale
+RDNSS info gets removed in a timely fashion, this should not be greater than
+2*MaxRtrAdvInterval.
+
+Default: 2*MaxRtrAdvInterval
+
+.SH EXAMPLES
+
+.nf
+interface eth0
+{
+ AdvSendAdvert on;
+ prefix 2001:db8:0:1::/64
+ {
+ AdvOnLink on;
+ AdvAutonomous on;
+ };
+};
+.fi
+
+It says that router advertisement daemon should advertise
+(AdvSendAdvert on;) the prefix 2001:db8:0:1:: which has a lenght of 64
+on the interface eth0. Also the prefix should be marked as autonomous
+(AdvAutonomous on;) and as on-link (AdvOnLink on;). All the other
+options are left on their default values.
+
+To support movement detection of Mobile IPv6 Mobile Nodes, the
+address of interface should be used instead of network prefix:
+
+.nf
+interface eth0
+{
+ AdvSendAdvert on;
+ prefix 2001:db8:0:1::4/64
+ {
+ AdvOnLink on;
+ AdvAutonomous on;
+ AdvRouterAddr on;
+ };
+};
+.fi
+
+For 6to4 support, include the
+.B Base6to4Interface
+option in each prefix section. When using a dynamic IPv4 address, set
+small prefix lifetimes to prevent hosts from retaining unreachable
+prefixes after a new IPv4 address has been assigned. When advertising to on
+a dynamic interface (e.g., Bluetooth), skip the interface if it is not
+active yet.
+
+.nf
+interface bnep0
+{
+ IgnoreIfMissing on;
+ AdvSendAdvert on;
+
+ # Advertise at least every 30 seconds
+ MaxRtrAdvInterval 30;
+
+ prefix 0:0:0:5678::/64
+ {
+ AdvOnLink on;
+ AdvAutonomous on;
+ Base6to4Interface ppp0;
+
+ # Very short lifetimes for dynamic addresses
+ AdvValidLifetime 300;
+ AdvPreferredLifetime 120;
+ };
+};
+.fi
+
+Since 6to4 is enabled, the prefix will be advertised as
+2002:WWXX:YYZZ:5678::/64, where WW.XX.YY.ZZ is the IPv4 address of
+ppp0 at configuration time. (IPv6 addresses are written in hexadecimal
+whereas IPv4 addresses are written in decimal, so the IPv4 address
+WW.XX.YY.ZZ in the 6to4 prefix will be represented in hex.)
+
+In this specific case, the configuration scripts may send HUP signal to
+radvd when taking bnep0 up or down to notify about the status; in the
+current radvd releases, sending HUP is no longer mandatory when the link
+comes back up.
+
+.SH FILES
+
+.nf
+@sbindir@/radvd
+@PATH_RADVD_CONF@
+@PATH_RADVD_PID@
+@PATH_RADVD_LOG@
+.fi
+
+.SH CREDIT
+The description of the different flags and variables is in large
+parts taken from RFC 2461.
+
+.SH RFCS
+Narten, T., E. Nordmark, W. Simpson, "Neighbor Discovery for IP
+Version 6 (IPv6)", RFC 2461, December 1998
+.PP
+Thomson, S., and T. Narten, "IPv6 Stateless Address Autoconfiguration",
+RFC 2462, December 1998.
+.PP
+Deering, S., and R. Hinden, "IP Version 6 Addressing
+Architecture", RFC 3513, April 2003.
+.PP
+Conta, A., and S. Deering, "Internet Control Message Protocol (ICMPv6)
+for the Internet Protocol Version 6 (IPv6)", RFC 2463, December 1998.
+.PP
+Crawford, M., "Transmission of IPv6 Packets over Ethernet Networks",
+RFC 2464, December 1998.
+.PP
+Carpenter B., K. Moore, "Connection of IPv6 Domains via IPv4 Clouds",
+RFC 3056, February 2001. (6to4 specification)
+.PP
+Draves, R., D. Thaler, "Default Router Preferences and More-Specific Routes",
+RFC 4191, November 2005.
+.PP
+Johnson, D., Perkins, C., and J. Arkko, "Mobility Support in IPv6",
+RFC 3775, June 2004.
+.PP
+Devarapalli, V., Wakikawa, R., Petrescu, A., and P. Thubert "Network Mobility (NEMO) Basic Support Protocol",
+RFC 3963, January 2005.
+.PP
+J. Jeong, L. Beloeil, and S. Madanapalli, "IPv6 Router Advertisement Option for DNS Configuration",
+IETF Draft v08 (January 18, 2006).
+
+.SH "SEE ALSO"
+
+.BR radvd (8),
+.BR radvdump (8)
--- /dev/null
+#
+# NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
+# NOTE NOTE
+# NOTE This is an EXAMPLE, which serves only to demonstrate the NOTE
+# NOTE syntax of radvd.conf, and is not meant to be used for a NOTE
+# NOTE real radvd configuration. NOTE
+# NOTE NOTE
+# NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
+#
+
+interface eth0
+{
+ AdvSendAdvert on;
+
+# This may be needed on some interfaces which are not active when
+# radvd starts, but becomoe available later on; see man page for details.
+
+ # IgnoreIfMissing on;
+
+#
+# These settings cause advertisements to be sent every 3-10 seconds. This
+# range is good for 6to4 with a dynamic IPv4 address, but can be greatly
+# increased when not using 6to4 prefixes.
+#
+
+ MinRtrAdvInterval 3;
+ MaxRtrAdvInterval 10;
+
+#
+# You can use AdvDefaultPreference setting to advertise the preference of
+# the router for the purposes of default router determination.
+# NOTE: This feature is still being specified and is not widely supported!
+#
+ AdvDefaultPreference low;
+
+#
+# Disable Mobile IPv6 support
+#
+ AdvHomeAgentFlag off;
+
+#
+# example of a standard prefix
+#
+ prefix 2001:db8:1:0::/64
+ {
+ AdvOnLink on;
+ AdvAutonomous on;
+ AdvRouterAddr off;
+ };
+
+#
+# example of a 6to4 prefix
+#
+# Note that the first 48 bits are specified here as zeros. These will be
+# replaced with the appropriate 6to4 address when radvd starts or is
+# reconfigured. Be sure that the SLA ID (1234 in this case) is specified
+# here!
+#
+ prefix 0:0:0:1234::/64
+ {
+ AdvOnLink on;
+ AdvAutonomous on;
+ AdvRouterAddr off;
+
+#
+# This setting causes radvd to replace the first 48 bits of the prefix
+# with the 6to4 address generated from the specified interface. For example,
+# if the address of ppp0 is 192.0.2.25 when radvd configures itself, this
+# prefix will be advertised as 2002:C000:0219:1234::/64.
+#
+# If ppp0 is not available at configuration time, this prefix will not be
+# advertised, but other prefixes listed in the configuration will be
+# advertised as usual.
+#
+# When using the Base6to4Interface option, make sure radvd receives a
+# SIGHUP every time the ppp0 interface goes up, down, or is assigned a
+# new IPv4 address. The SIGHUP will cause radvd to recognize that the
+# ppp0 interface has changed and will adjust the advertisements
+# accordingly.
+#
+
+ Base6to4Interface ppp0;
+
+#
+# If the IP address of ppp0 is assigned dynamically, be sure to set the
+# lifetimes for this prefix to be small. Otherwise, hosts on your network
+# may continue to use a prefix that no longer corresponds to the address
+# on ppp0!
+#
+ AdvPreferredLifetime 120;
+ AdvValidLifetime 300;
+ };
+#
+# example of a more specific route
+# NOTE: This feature is still being specified and is not widely supported!
+#
+ route 2001:db0:fff::/48
+ {
+ AdvRoutePreference high;
+ AdvRouteLifetime 3600;
+ };
+
+#
+# RDNSS
+# NOTE: This feature is still a draft has no IANA number type for the moment
+#
+ RDNSS 2001:db8::1 2001:db8::2
+ {
+ AdvRDNSSPreference 8;
+ AdvRDNSSOpen off;
+ AdvRDNSSLifetime 30;
+ };
+
+
+};
+
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#ifndef RADV_H
+#define RADV_H
+
+#include <config.h>
+#include <includes.h>
+#include <defaults.h>
+
+#define CONTACT_EMAIL "Pekka Savola <pekkas@netcore.fi>"
+
+/* for log.c */
+#define L_NONE 0
+#define L_SYSLOG 1
+#define L_STDERR 2
+#define L_STDERR_SYSLOG 3
+#define L_LOGFILE 4
+
+#define LOG_TIME_FORMAT "%b %d %H:%M:%S"
+
+struct timer_lst {
+ struct timeval expires;
+ void (*handler)(void *);
+ void * data;
+ struct timer_lst *next;
+ struct timer_lst *prev;
+};
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+struct AdvPrefix;
+
+#define HWADDR_MAX 16
+
+struct Interface {
+ char Name[IFNAMSIZ]; /* interface name */
+
+ struct in6_addr if_addr;
+ unsigned int if_index;
+
+ uint8_t init_racount; /* Initial RAs */
+
+ uint8_t if_hwaddr[HWADDR_MAX];
+ int if_hwaddr_len;
+ int if_prefix_len;
+ int if_maxmtu;
+
+ int IgnoreIfMissing;
+ int AdvSendAdvert;
+ double MaxRtrAdvInterval;
+ double MinRtrAdvInterval;
+ double MinDelayBetweenRAs;
+ int AdvManagedFlag;
+ int AdvOtherConfigFlag;
+ uint32_t AdvLinkMTU;
+ uint32_t AdvReachableTime;
+ uint32_t AdvRetransTimer;
+ uint8_t AdvCurHopLimit;
+ int32_t AdvDefaultLifetime; /* XXX: really uint16_t but we need to use -1 */
+ int AdvDefaultPreference;
+ int AdvSourceLLAddress;
+ int UnicastOnly;
+
+ /* Mobile IPv6 extensions */
+ int AdvIntervalOpt;
+ int AdvHomeAgentInfo;
+ int AdvHomeAgentFlag;
+ uint16_t HomeAgentPreference;
+ int32_t HomeAgentLifetime; /* XXX: really uint16_t but we need to use -1 */
+
+ /* NEMO extensions */
+ int AdvMobRtrSupportFlag;
+
+ struct AdvPrefix *AdvPrefixList;
+ struct AdvRoute *AdvRouteList;
+ struct AdvRDNSS *AdvRDNSSList;
+ struct timer_lst tm;
+ time_t last_multicast_sec;
+ suseconds_t last_multicast_usec;
+
+ /* Info whether this interface has failed in the past (and may need to be reinitialized) */
+ int HasFailed;
+
+ struct Interface *next;
+};
+
+struct AdvPrefix {
+ struct in6_addr Prefix;
+ uint8_t PrefixLen;
+
+ int AdvOnLinkFlag;
+ int AdvAutonomousFlag;
+ uint32_t AdvValidLifetime;
+ uint32_t AdvPreferredLifetime;
+
+ /* Mobile IPv6 extensions */
+ int AdvRouterAddr;
+
+ /* 6to4 extensions */
+ char if6to4[IFNAMSIZ];
+ int enabled;
+
+ struct AdvPrefix *next;
+};
+
+/* More-Specific Routes extensions */
+
+struct AdvRoute {
+ struct in6_addr Prefix;
+ uint8_t PrefixLen;
+
+ int AdvRoutePreference;
+ uint32_t AdvRouteLifetime;
+
+ struct AdvRoute *next;
+};
+
+/* Option for DNS configuration */
+struct AdvRDNSS {
+ int AdvRDNSSNumber;
+ uint8_t AdvRDNSSPreference;
+ int AdvRDNSSOpenFlag;
+ uint32_t AdvRDNSSLifetime;
+ struct in6_addr AdvRDNSSAddr1;
+ struct in6_addr AdvRDNSSAddr2;
+ struct in6_addr AdvRDNSSAddr3;
+
+ struct AdvRDNSS *next;
+};
+
+/* Mobile IPv6 extensions */
+
+struct AdvInterval {
+ uint8_t type;
+ uint8_t length;
+ uint16_t reserved;
+ uint32_t adv_ival;
+};
+
+struct HomeAgentInfo {
+ uint8_t type;
+ uint8_t length;
+ uint16_t flags_reserved;
+ uint16_t preference;
+ uint16_t lifetime;
+};
+
+
+/* gram.y */
+int yyparse(void);
+
+/* scanner.l */
+int yylex(void);
+
+/* radvd.c */
+int check_ip6_forwarding(void);
+void reload_config(void);
+
+/* timer.c */
+void set_timer(struct timer_lst *tm, double);
+void clear_timer(struct timer_lst *tm);
+void init_timer(struct timer_lst *, void (*)(void *), void *);
+
+/* log.c */
+int log_open(int, char *, char*, int);
+void flog(int, char *, ...);
+void dlog(int, int, char *, ...);
+int log_close(void);
+int log_reopen(void);
+void set_debuglevel(int);
+int get_debuglevel(void);
+
+/* device.c */
+int setup_deviceinfo(int, struct Interface *);
+int check_device(int, struct Interface *);
+int setup_linklocal_addr(int, struct Interface *);
+int setup_allrouters_membership(int, struct Interface *);
+int check_allrouters_membership(int, struct Interface *);
+int get_v4addr(const char *, unsigned int *);
+int set_interface_linkmtu(const char *, uint32_t);
+int set_interface_curhlim(const char *, uint8_t);
+int set_interface_reachtime(const char *, uint32_t);
+int set_interface_retranstimer(const char *, uint32_t);
+
+/* interface.c */
+void iface_init_defaults(struct Interface *);
+void prefix_init_defaults(struct AdvPrefix *);
+void route_init_defaults(struct AdvRoute *, struct Interface *);
+void rdnss_init_defaults(struct AdvRDNSS *, struct Interface *);
+int check_iface(struct Interface *);
+
+/* socket.c */
+int open_icmpv6_socket(void);
+
+/* send.c */
+void send_ra(int, struct Interface *iface, struct in6_addr *dest);
+
+/* process.c */
+void process(int sock, struct Interface *, unsigned char *, int,
+ struct sockaddr_in6 *, struct in6_pktinfo *, int);
+
+/* recv.c */
+int recv_rs_ra(int, unsigned char *, struct sockaddr_in6 *, struct in6_pktinfo **, int *);
+
+/* util.c */
+void mdelay(double);
+double rand_between(double, double);
+void print_addr(struct in6_addr *, char *);
+int check_rdnss_presence(struct AdvRDNSS *, struct in6_addr *);
+
+#endif
--- /dev/null
+.\"
+.\" $Id$
+.\"
+.\" Authors:
+.\" Lars Fenneberg <lf@elemental.net>
+.\" Marko Myllynen <myllynen@lut.fi>
+.\"
+.\" This software is Copyright 1996 by the above mentioned author(s),
+.\" All Rights Reserved.
+.\"
+.\" The license which is distributed with this software in the file COPYRIGHT
+.\" applies to this software. If your distribution is missing this file, you
+.\" may request it from <pekkas@netcore.fi>.
+.\"
+.\"
+.\"
+.TH RADVDUMP 8 "29 Dec 2001" "radvd @VERSION@" ""
+.SH NAME
+radvdump \- dump router advertisements
+.SH SYNOPSIS
+.B radvdump
+.B "[ \-vhfe ]"
+.BI "[ \-d " debuglevel " ]"
+
+.SH DESCRIPTION
+.B radvdump
+prints out the contents of incoming router advertisements sent by
+.B radvd
+or some other software implementing (parts of)
+"Neighbor Discovery for IP Version 6 (IPv6)" (RFC 2461).
+
+.SH OPTIONS
+
+For every one character option there is also a long option, which
+is listed right next to the "short" option name:
+
+.TP
+.BR "\-v" , " \-\-version"
+Displays the version of
+.I radvdump
+and then aborts.
+.TP
+.BR "\-h" , " \-\-help"
+Displays a short usage description and then aborts.
+.TP
+.BR "\-f" , " \-\-file\-format"
+Output received router advertisements in the format of the
+.B radvd
+configuration file.
+Since radvd 0.9, this is the default and the switch is provided
+for backward compatibility only.
+.TP
+.BR "\-e" , " \-\-exclude-defaults"
+Exclude default valued options from configuration file format.
+This option is ignored if option
+.B "\-f"
+is not set.
+.TP
+.BR "\-d " debuglevel, " \-\-debug " debuglevel
+With this option you turn on debugging information. The debugging level is
+an integer in the range from 1 to 4, from quiet to very verbose. A
+debugging level of 0 completely turns off debugging.
+
+The default debugging level is 0.
+
+.SH FILES
+
+.nf
+@sbindir@/radvdump
+.fi
+.SH BUGS
+
+There certainly are some bugs. If you find them or have other
+suggestions please contact Pekka Savola <pekkas@netcore.fi>.
+
+.SH "SEE ALSO"
+
+.BR radvd (8),
+.BR radvd.conf (5)
+.SH AUTHORS
+
+.nf
+Lars Fenneberg <lf@elemental.net> - previous maintainer
+Nathan Lutchansky <lutchann@litech.org> - previous maintainer
+Pekka Savola <pekkas@netcore.fi> - current maintainer
+Marko Myllynen <myllynen@lut.fi> - Mobile IPv6 support
+.fi
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Lars Fenneberg <lf@elemental.net>
+ * Marko Myllynen <myllynen@lut.fi>
+ *
+ * This software is Copyright 1996-2000 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+
+char usage_str[] = "[-vhfe] [-d level]";
+
+#ifdef HAVE_GETOPT_LONG
+struct option prog_opt[] = {
+ {"debug", 1, 0, 'd'},
+ {"file-format", 0, 0, 'f'},
+ {"exclude-defaults", 0, 0, 'e'},
+ {"version", 0, 0, 'v'},
+ {"help", 0, 0, 'h'},
+ {NULL, 0, 0, 0}
+};
+#endif
+
+char *pname;
+int sock = -1;
+
+void version(void);
+void usage(void);
+void print_ff(unsigned char *, int, struct sockaddr_in6 *, int, unsigned int, int);
+void print_preferences(int);
+
+int
+main(int argc, char *argv[])
+{
+ unsigned char msg[MSG_SIZE];
+ int c, len, hoplimit;
+ int edefs = 0;
+ struct sockaddr_in6 rcv_addr;
+ struct in6_pktinfo *pkt_info = NULL;
+#ifdef HAVE_GETOPT_LONG
+ int opt_idx;
+#endif
+
+ pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0];
+
+ /* parse args */
+#ifdef HAVE_GETOPT_LONG
+ while ((c = getopt_long(argc, argv, "d:fehv", prog_opt, &opt_idx)) > 0)
+#else
+ while ((c = getopt(argc, argv, "d:fehv")) > 0)
+#endif
+ {
+ switch (c) {
+ case 'd':
+ set_debuglevel(atoi(optarg));
+ break;
+ case 'f':
+ break;
+ case 'e':
+ edefs = 1;
+ break;
+ case 'v':
+ version();
+ break;
+ case 'h':
+ usage();
+#ifdef HAVE_GETOPT_LONG
+ case ':':
+ fprintf(stderr, "%s: option %s: parameter expected\n", pname,
+ prog_opt[opt_idx].name);
+ exit(1);
+#endif
+ case '?':
+ exit(1);
+ }
+ }
+
+ if (log_open(L_STDERR, pname, NULL, 0) < 0)
+ exit(1);
+
+ /* get a raw socket for sending and receiving ICMPv6 messages */
+ sock = open_icmpv6_socket();
+ if (sock < 0)
+ exit(1);
+
+ for(;;)
+ {
+ len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit);
+ if (len > 0)
+ {
+ struct icmp6_hdr *icmph;
+
+ /*
+ * can this happen?
+ */
+
+ if (len < sizeof(struct icmp6_hdr))
+ {
+ flog(LOG_WARNING, "received icmpv6 packet with invalid length: %d",
+ len);
+ exit(1);
+ }
+
+ icmph = (struct icmp6_hdr *) msg;
+
+ if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
+ icmph->icmp6_type != ND_ROUTER_ADVERT)
+ {
+ /*
+ * We just want to listen to RSs and RAs
+ */
+
+ flog(LOG_ERR, "icmpv6 filter failed");
+ exit(1);
+ }
+
+ dlog(LOG_DEBUG, 4, "receiver if_index: %u", pkt_info->ipi6_ifindex);
+
+ if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
+ {
+ /* not yet */
+ }
+ else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
+ print_ff(msg, len, &rcv_addr, hoplimit, (unsigned int)pkt_info->ipi6_ifindex, edefs);
+ }
+ else if (len == 0)
+ {
+ flog(LOG_ERR, "received zero lenght packet");
+ exit(1);
+ }
+ else
+ {
+ flog(LOG_ERR, "recv_rs_ra: %s", strerror(errno));
+ exit(1);
+ }
+ }
+
+ exit(0);
+}
+
+void
+print_ff(unsigned char *msg, int len, struct sockaddr_in6 *addr, int hoplimit, unsigned int if_index, int edefs)
+{
+ /* XXX: hoplimit not being used for anything here.. */
+ struct nd_router_advert *radvert;
+ char addr_str[INET6_ADDRSTRLEN];
+ uint8_t *opt_str;
+ int orig_len = len;
+ char if_name[IFNAMSIZ] = "";
+
+ print_addr(&addr->sin6_addr, addr_str);
+ printf("#\n# radvd configuration generated by radvdump %s\n", VERSION);
+ printf("# based on Router Advertisement from %s\n", addr_str);
+ if_indextoname(if_index, if_name);
+ printf("# received by interface %s\n", if_name);
+ printf("#\n\ninterface %s\n{\n\tAdvSendAdvert on;\n", if_name);
+
+ printf("\t# Note: {Min,Max}RtrAdvInterval cannot be obtained with radvdump\n");
+
+ radvert = (struct nd_router_advert *) msg;
+
+ if (!edefs || DFLT_AdvManagedFlag != (ND_RA_FLAG_MANAGED == (radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)))
+ printf("\tAdvManagedFlag %s;\n",
+ (radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)?"on":"off");
+
+ if (!edefs || DFLT_AdvOtherConfigFlag != (ND_RA_FLAG_OTHER == (radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)))
+ printf("\tAdvOtherConfigFlag %s;\n",
+ (radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)?"on":"off");
+
+ if (!edefs || DFLT_AdvReachableTime != ntohl(radvert->nd_ra_reachable))
+ printf("\tAdvReachableTime %u;\n", ntohl(radvert->nd_ra_reachable));
+
+ if (!edefs || DFLT_AdvRetransTimer != ntohl(radvert->nd_ra_retransmit))
+ printf("\tAdvRetransTimer %u;\n", ntohl(radvert->nd_ra_retransmit));
+
+ if (!edefs || DFLT_AdvCurHopLimit != radvert->nd_ra_curhoplimit)
+ printf("\tAdvCurHopLimit %u;\n", radvert->nd_ra_curhoplimit);
+
+ /* Mobile IPv6 ext */
+ if (!edefs || DFLT_AdvHomeAgentFlag != (ND_RA_FLAG_HOME_AGENT == (radvert->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)))
+ printf("\tAdvHomeAgentFlag %s;\n",
+ (radvert->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)?"on":"off");
+
+ /* Route Preferences and more specific routes */
+ /* XXX two middlemost bits from 8 bit field */
+ if (!edefs || (((radvert->nd_ra_flags_reserved & 0x18) >> 3) & 0xff) != DFLT_AdvDefaultPreference) {
+ printf("\tAdvDefaultPreference ");
+ print_preferences(((radvert->nd_ra_flags_reserved & 0x18) >> 3) & 0xff);
+ printf(";\n");
+ }
+
+ len -= sizeof(struct nd_router_advert);
+
+ if (len == 0)
+ return;
+
+ opt_str = (uint8_t *)(msg + sizeof(struct nd_router_advert));
+
+ while (len > 0)
+ {
+ int optlen;
+ struct nd_opt_mtu *mtu;
+ struct HomeAgentInfo *ha_info;
+
+ if (len < 2)
+ {
+ flog(LOG_ERR, "trailing garbage in RA from %s",
+ addr_str);
+ break;
+ }
+
+ optlen = (opt_str[1] << 3);
+
+ if (optlen == 0)
+ {
+ flog(LOG_ERR, "zero length option in RA");
+ break;
+ }
+ else if (optlen > len)
+ {
+ flog(LOG_ERR, "option length greater than total"
+ " length in RA (type %d, optlen %d, len %d)",
+ (int)*opt_str, optlen, len);
+ break;
+ }
+
+ switch (*opt_str)
+ {
+ case ND_OPT_MTU:
+ mtu = (struct nd_opt_mtu *)opt_str;
+
+ if (!edefs || DFLT_AdvLinkMTU != ntohl(mtu->nd_opt_mtu_mtu))
+ printf("\tAdvLinkMTU %u;\n", ntohl(mtu->nd_opt_mtu_mtu));
+ break;
+ case ND_OPT_SOURCE_LINKADDR:
+ /* XXX: !DFLT depends on current DFLT_ value */
+ if (!edefs || !DFLT_AdvSourceLLAddress)
+ printf("\tAdvSourceLLAddress on;\n");
+ break;
+ /* Mobile IPv6 ext */
+ case ND_OPT_RTR_ADV_INTERVAL:
+ /* XXX: !DFLT depends on current DFLT_ value */
+ if (!edefs || !DFLT_AdvIntervalOpt)
+ printf("\tAdvIntervalOpt on;\n");
+ break;
+ /* Mobile IPv6 ext */
+ case ND_OPT_HOME_AGENT_INFO:
+ ha_info = (struct HomeAgentInfo *)opt_str;
+
+ /* XXX: we check DFLT_HomeAgentInfo by interface, and it's outside
+ of context here, so we always need to print it out.. */
+ printf("\tAdvHomeAgentInfo on;\n");
+
+ /* NEMO ext */
+ if (!edefs || DFLT_AdvMobRtrSupportFlag != (ha_info->flags_reserved & ND_OPT_HAI_FLAG_SUPPORT_MR))
+ printf("\tAdvMobRtrSupportFlag %s;\n", (ha_info->flags_reserved & ND_OPT_HAI_FLAG_SUPPORT_MR)?"on":"off");
+
+ if (!edefs || DFLT_HomeAgentPreference != ntohs(ha_info->preference))
+ printf("\tHomeAgentPreference %hu;\n", ntohs(ha_info->preference));
+ /* Hum.. */
+ if (!edefs || (3*DFLT_MaxRtrAdvInterval) != ntohs(ha_info->lifetime))
+ printf("\tHomeAgentLifetime %hu;\n", ntohs(ha_info->lifetime));
+ break;
+ case ND_OPT_TARGET_LINKADDR:
+ case ND_OPT_REDIRECTED_HEADER:
+ flog(LOG_ERR, "invalid option %d in RA", (int)*opt_str);
+ break;
+ case ND_OPT_PREFIX_INFORMATION:
+ break;
+ case ND_OPT_ROUTE_INFORMATION:
+ break;
+ case ND_OPT_RDNSS_INFORMATION:
+ break;
+ default:
+ dlog(LOG_DEBUG, 1, "unknown option %d in RA",
+ (int)*opt_str);
+ break;
+ }
+
+ len -= optlen;
+ opt_str += optlen;
+ }
+
+ orig_len -= sizeof(struct nd_router_advert);
+
+ if (orig_len == 0)
+ return;
+
+ opt_str = (uint8_t *)(msg + sizeof(struct nd_router_advert));
+
+ while (orig_len > 0)
+ {
+ int optlen;
+ struct nd_opt_prefix_info *pinfo;
+ struct nd_opt_route_info_local *rinfo;
+ struct nd_opt_rdnss_info_local *rdnss_info;
+ char prefix_str[INET6_ADDRSTRLEN];
+
+ if (orig_len < 2)
+ {
+ flog(LOG_ERR, "trailing garbage in RA from %s",
+ addr_str);
+ break;
+ }
+
+ optlen = (opt_str[1] << 3);
+
+ if (optlen == 0)
+ {
+ flog(LOG_ERR, "zero length option in RA");
+ break;
+ }
+ else if (optlen > orig_len)
+ {
+ flog(LOG_ERR, "option length greater than total"
+ " length in RA (type %d, optlen %d, len %d)",
+ (int)*opt_str, optlen, orig_len);
+ break;
+ }
+
+ switch (*opt_str)
+ {
+ case ND_OPT_PREFIX_INFORMATION:
+ pinfo = (struct nd_opt_prefix_info *) opt_str;
+
+ print_addr(&pinfo->nd_opt_pi_prefix, prefix_str);
+
+ printf("\n\tprefix %s/%d\n\t{\n", prefix_str, pinfo->nd_opt_pi_prefix_len);
+
+ if (ntohl(pinfo->nd_opt_pi_valid_time) == 0xffffffff)
+ {
+ if (!edefs || DFLT_AdvValidLifetime != 0xffffffff)
+ printf("\t\tAdvValidLifetime infinity; # (0xffffffff)\n");
+ }
+ else
+ {
+ if (!edefs || DFLT_AdvValidLifetime != ntohl(pinfo->nd_opt_pi_valid_time))
+ printf("\t\tAdvValidLifetime %u;\n", ntohl(pinfo->nd_opt_pi_valid_time));
+ }
+ if (ntohl(pinfo->nd_opt_pi_preferred_time) == 0xffffffff)
+ {
+ if (!edefs || DFLT_AdvPreferredLifetime != 0xffffffff)
+ printf("\t\tAdvPreferredLifetime infinity; # (0xffffffff)\n");
+ }
+ else
+ {
+ if (!edefs || DFLT_AdvPreferredLifetime != ntohl(pinfo->nd_opt_pi_preferred_time))
+ printf("\t\tAdvPreferredLifetime %u;\n", ntohl(pinfo->nd_opt_pi_preferred_time));
+ }
+
+ if (!edefs || DFLT_AdvOnLinkFlag != (ND_OPT_PI_FLAG_ONLINK == (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)))
+ printf("\t\tAdvOnLink %s;\n",
+ (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)?"on":"off");
+
+ if (!edefs || DFLT_AdvAutonomousFlag != (ND_OPT_PI_FLAG_AUTO == (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)))
+ printf("\t\tAdvAutonomous %s;\n",
+ (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)?"on":"off");
+
+ /* Mobile IPv6 ext */
+ if (!edefs || DFLT_AdvRouterAddr != (ND_OPT_PI_FLAG_RADDR == (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_RADDR)))
+ printf("\t\tAdvRouterAddr %s;\n",
+ (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_RADDR)?"on":"off");
+
+ printf("\t}; # End of prefix definition\n\n");
+ break;
+ case ND_OPT_ROUTE_INFORMATION:
+ rinfo = (struct nd_opt_route_info_local *) opt_str;
+
+ print_addr(&rinfo->nd_opt_ri_prefix, prefix_str);
+
+ printf("\n\troute %s/%d\n\t{\n", prefix_str, rinfo->nd_opt_ri_prefix_len);
+
+ if (!edefs || (((radvert->nd_ra_flags_reserved & 0x18) >> 3) & 0xff) != DFLT_AdvRoutePreference) {
+ printf("\t\tAdvRoutePreference ");
+ print_preferences(((rinfo->nd_opt_ri_flags_reserved & 0x18) >> 3) & 0xff);
+ printf(";\n");
+ }
+
+ /* XXX: we check DFLT_AdvRouteLifetime by interface, and it's outside of context here */
+ if (ntohl(rinfo->nd_opt_ri_lifetime) == 0xffffffff)
+ printf("\t\tAdvRouteLifetime infinity; # (0xffffffff)\n");
+ else
+ printf("\t\tAdvRouteLifetime %u;\n", ntohl(rinfo->nd_opt_ri_lifetime));
+
+ printf("\t}; # End of route definition\n\n");
+ break;
+ case ND_OPT_RDNSS_INFORMATION:
+ rdnss_info = (struct nd_opt_rdnss_info_local *) opt_str;
+
+ printf("\n\tRDNSS");
+
+ print_addr(&rdnss_info->nd_opt_rdnssi_addr1, prefix_str);
+ printf(" %s", prefix_str);
+
+ if (rdnss_info->nd_opt_rdnssi_len >= 5) {
+ print_addr(&rdnss_info->nd_opt_rdnssi_addr2, prefix_str);
+ printf(" %s", prefix_str);
+ }
+ if (rdnss_info->nd_opt_rdnssi_len >= 7) {
+ print_addr(&rdnss_info->nd_opt_rdnssi_addr3, prefix_str);
+ printf(" %s", prefix_str);
+ }
+
+ printf("\n\t{\n");
+ if (!edefs
+ || ((rdnss_info->nd_opt_rdnssi_pref_flag_reserved & ND_OPT_RDNSSI_PREF_MASK) >> ND_OPT_RDNSSI_PREF_SHIFT) != DFLT_AdvRDNSSPreference)
+ printf("\t\tAdvRDNSSPreference %d;\n",
+ (rdnss_info->nd_opt_rdnssi_pref_flag_reserved & ND_OPT_RDNSSI_PREF_MASK) >> ND_OPT_RDNSSI_PREF_SHIFT);
+
+ if (!edefs
+ || ((rdnss_info->nd_opt_rdnssi_pref_flag_reserved & ND_OPT_RDNSSI_FLAG_S) == 0 ) == DFLT_AdvRDNSSOpenFlag)
+ printf("\t\tAdvRDNSSOpen %s;\n", rdnss_info->nd_opt_rdnssi_pref_flag_reserved & ND_OPT_RDNSSI_FLAG_S ? "on" : "off");
+
+ /* as AdvRDNSSLifetime may depend on MaxRtrAdvInterval, it could change */
+ if (ntohl(rdnss_info->nd_opt_rdnssi_lifetime) == 0xffffffff)
+ printf("\t\tAdvRDNSSLifetime infinity; # (0xffffffff)\n");
+ else
+ printf("\t\tAdvRDNSSLifetime %u;\n", ntohl(rdnss_info->nd_opt_rdnssi_lifetime));
+
+ printf("\t}; # End of RDNSS definition\n\n");
+ break;
+ default:
+ break;
+ }
+ orig_len -= optlen;
+ opt_str += optlen;
+ }
+
+ printf("}; # End of interface definition\n");
+
+ fflush(stdout);
+}
+
+void
+print_preferences(int p)
+{
+ switch (p) {
+ case 0:
+ printf("medium");
+ break;
+ case 1:
+ printf("high");
+ break;
+ case 2:
+ /* reserved, ignore */
+ break;
+ case 3:
+ printf("low");
+ break;
+ }
+}
+
+void
+version(void)
+{
+ fprintf(stderr,"Version: %s\n\n", VERSION);
+ fprintf(stderr,"Please send bug reports and suggestions to %s\n",
+ CONTACT_EMAIL);
+ exit(1);
+}
+
+void
+usage(void)
+{
+ fprintf(stderr,"usage: %s %s\n", pname, usage_str);
+ exit(1);
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+
+int
+recv_rs_ra(int sock, unsigned char *msg, struct sockaddr_in6 *addr,
+ struct in6_pktinfo **pkt_info, int *hoplimit)
+{
+ struct msghdr mhdr;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ static unsigned char *chdr = NULL;
+ static unsigned int chdrlen = 0;
+ int len;
+ fd_set rfds;
+
+ if( ! chdr )
+ {
+ chdrlen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ if ((chdr = malloc(chdrlen)) == NULL) {
+ flog(LOG_ERR, "recv_rs_ra: malloc: %s", strerror(errno));
+ return -1;
+ }
+ }
+
+ FD_ZERO( &rfds );
+ FD_SET( sock, &rfds );
+
+ if( select( sock+1, &rfds, NULL, NULL, NULL ) < 0 )
+ {
+ if (errno != EINTR)
+ flog(LOG_ERR, "select: %s", strerror(errno));
+
+ return -1;
+ }
+
+ iov.iov_len = MSG_SIZE;
+ iov.iov_base = (caddr_t) msg;
+
+ memset(&mhdr, 0, sizeof(mhdr));
+ mhdr.msg_name = (caddr_t)addr;
+ mhdr.msg_namelen = sizeof(*addr);
+ mhdr.msg_iov = &iov;
+ mhdr.msg_iovlen = 1;
+ mhdr.msg_control = (void *)chdr;
+ mhdr.msg_controllen = chdrlen;
+
+ len = recvmsg(sock, &mhdr, 0);
+
+ if (len < 0)
+ {
+ if (errno != EINTR)
+ flog(LOG_ERR, "recvmsg: %s", strerror(errno));
+
+ return len;
+ }
+
+ *hoplimit = 255;
+
+ for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&mhdr, cmsg))
+ {
+ if (cmsg->cmsg_level != IPPROTO_IPV6)
+ continue;
+
+ switch(cmsg->cmsg_type)
+ {
+#ifdef IPV6_HOPLIMIT
+ case IPV6_HOPLIMIT:
+ if ((cmsg->cmsg_len == CMSG_LEN(sizeof(int))) &&
+ (*(int *)CMSG_DATA(cmsg) >= 0) &&
+ (*(int *)CMSG_DATA(cmsg) < 256))
+ {
+ *hoplimit = *(int *)CMSG_DATA(cmsg);
+ }
+ else
+ {
+ flog(LOG_ERR, "received a bogus IPV6_HOPLIMIT from the kernel! len=%d, data=%d",
+ cmsg->cmsg_len, *(int *)CMSG_DATA(cmsg));
+ return (-1);
+ }
+ break;
+#endif /* IPV6_HOPLIMIT */
+ case IPV6_PKTINFO:
+ if ((cmsg->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) &&
+ ((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_ifindex)
+ {
+ *pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+ }
+ else
+ {
+ flog(LOG_ERR, "received a bogus IPV6_PKTINFO from the kernel! len=%d, index=%d",
+ cmsg->cmsg_len, ((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_ifindex);
+ return (-1);
+ }
+ break;
+ }
+ }
+
+ dlog(LOG_DEBUG, 4, "recvmsg len=%d", len);
+
+ return len;
+}
--- /dev/null
+
+#line 3 "lex.yy.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 33
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
+void yy_delete_buffer (YY_BUFFER_STATE b );
+void yy_flush_buffer (YY_BUFFER_STATE b );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 53
+#define YY_END_OF_BUFFER 54
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[514] =
+ { 0,
+ 0, 0, 54, 52, 3, 2, 52, 52, 51, 41,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 3, 0,
+ 1, 42, 0, 41, 0, 0, 40, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 50, 0, 50, 50,
+ 50, 50, 50, 50, 45, 50, 50, 43, 41, 0,
+ 0, 40, 0, 0, 0, 0, 0, 0, 0, 0,
+ 50, 50, 50, 50, 50, 50, 47, 50, 46, 50,
+ 50, 41, 0, 0, 0, 40, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 50, 50, 49, 50,
+ 50, 50, 50, 50, 41, 0, 0, 40, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 7, 0, 50, 50, 50, 50, 50, 6,
+ 0, 0, 0, 40, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 50,
+ 50, 50, 48, 5, 0, 0, 40, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 50, 50, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 44, 50, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 21, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 4, 0, 0, 0, 0,
+ 0, 0, 0, 0, 14, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 29, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 36, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 22, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 25,
+ 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 17, 0, 0, 0, 0, 27, 12,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 16, 0, 0, 0, 0, 0, 0, 0, 8, 0,
+ 0, 0, 0, 40, 0, 0, 0, 26, 28, 0,
+ 0, 0, 37, 0, 15, 34, 0, 0, 23, 0,
+ 0, 0, 0, 0, 0, 40, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 30, 32, 0, 10, 0,
+ 11, 40, 0, 18, 0, 0, 13, 0, 35, 33,
+
+ 20, 0, 38, 0, 0, 0, 0, 31, 0, 19,
+ 39, 24, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 1, 4, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 5, 6, 7, 8, 8, 8,
+ 8, 9, 8, 10, 8, 8, 8, 11, 12, 1,
+ 1, 1, 1, 1, 13, 14, 15, 16, 17, 18,
+ 1, 19, 20, 1, 1, 21, 22, 23, 24, 25,
+ 1, 26, 27, 28, 29, 30, 1, 1, 1, 1,
+ 1, 1, 1, 1, 31, 1, 32, 33, 34, 35,
+
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 47, 41, 48, 49, 50, 51, 52, 53, 54,
+ 55, 41, 56, 1, 57, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[58] =
+ { 0,
+ 1, 1, 1, 1, 1, 2, 1, 3, 3, 3,
+ 4, 1, 5, 5, 5, 5, 5, 5, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 6, 3, 3, 3, 3, 3, 3, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[555] =
+ { 0,
+ 0, 0, 884, 885, 881, 885, 879, 50, 885, 55,
+ 870, 56, 62, 63, 834, 841, 38, 862, 832, 89,
+ 65, 69, 66, 73, 76, 139, 104, 102, 874, 872,
+ 885, 80, 108, 145, 863, 75, 885, 151, 152, 829,
+ 827, 817, 825, 846, 828, 151, 196, 156, 90, 162,
+ 171, 163, 164, 180, 172, 179, 183, 171, 187, 181,
+ 856, 0, 222, 830, 829, 818, 837, 67, 835, 827,
+ 210, 245, 214, 234, 196, 258, 245, 259, 260, 261,
+ 277, 281, 849, 848, 847, 846, 805, 804, 818, 807,
+ 807, 811, 254, 251, 802, 259, 238, 817, 838, 834,
+
+ 798, 795, 808, 793, 815, 809, 291, 298, 304, 305,
+ 306, 307, 308, 315, 314, 829, 828, 827, 0, 787,
+ 788, 798, 790, 783, 787, 786, 797, 808, 789, 791,
+ 803, 207, 774, 779, 772, 779, 771, 782, 783, 770,
+ 774, 768, 885, 766, 320, 326, 327, 328, 329, 330,
+ 803, 802, 801, 800, 764, 790, 776, 771, 770, 763,
+ 772, 777, 762, 765, 763, 772, 764, 749, 746, 760,
+ 746, 753, 746, 755, 770, 776, 756, 774, 736, 334,
+ 341, 349, 350, 351, 774, 773, 772, 737, 735, 729,
+ 766, 730, 755, 738, 725, 729, 725, 736, 744, 731,
+
+ 737, 732, 754, 732, 730, 755, 718, 725, 726, 705,
+ 724, 734, 357, 359, 746, 745, 744, 708, 706, 709,
+ 713, 698, 721, 712, 699, 704, 730, 696, 350, 711,
+ 697, 328, 706, 704, 718, 718, 687, 714, 683, 720,
+ 681, 687, 367, 371, 720, 719, 685, 707, 677, 690,
+ 693, 695, 688, 695, 885, 675, 672, 679, 671, 669,
+ 683, 666, 674, 665, 699, 659, 689, 669, 663, 359,
+ 667, 686, 669, 684, 660, 379, 691, 690, 689, 653,
+ 658, 367, 652, 653, 885, 677, 643, 648, 656, 654,
+ 654, 653, 645, 659, 649, 649, 649, 647, 661, 644,
+
+ 630, 639, 630, 628, 631, 625, 629, 618, 661, 660,
+ 619, 625, 628, 619, 616, 641, 621, 616, 625, 626,
+ 624, 614, 621, 621, 616, 619, 617, 618, 604, 638,
+ 614, 613, 611, 611, 597, 595, 591, 593, 885, 631,
+ 630, 629, 590, 598, 600, 600, 129, 588, 602, 586,
+ 592, 610, 580, 885, 593, 600, 583, 576, 589, 576,
+ 573, 587, 571, 572, 583, 581, 577, 580, 579, 578,
+ 602, 601, 885, 561, 574, 572, 565, 562, 556, 567,
+ 558, 565, 562, 561, 552, 559, 562, 557, 548, 885,
+ 885, 560, 554, 556, 542, 555, 545, 541, 552, 539,
+
+ 575, 574, 573, 885, 533, 546, 549, 543, 885, 885,
+ 531, 560, 540, 532, 539, 530, 525, 528, 535, 522,
+ 525, 536, 527, 518, 527, 512, 518, 510, 550, 549,
+ 519, 510, 519, 510, 505, 511, 517, 516, 506, 514,
+ 885, 513, 503, 511, 510, 511, 500, 407, 885, 394,
+ 385, 378, 398, 397, 395, 361, 368, 885, 885, 385,
+ 370, 351, 885, 366, 885, 885, 365, 349, 885, 361,
+ 360, 350, 351, 376, 344, 375, 368, 333, 322, 316,
+ 308, 285, 268, 267, 244, 885, 885, 251, 885, 227,
+ 885, 257, 239, 885, 193, 194, 885, 144, 885, 885,
+
+ 885, 136, 885, 160, 110, 76, 56, 885, 74, 885,
+ 885, 885, 885, 412, 417, 421, 426, 429, 433, 436,
+ 439, 442, 445, 448, 451, 454, 457, 460, 463, 466,
+ 469, 472, 475, 478, 481, 484, 487, 490, 493, 496,
+ 499, 502, 505, 508, 511, 514, 517, 520, 523, 526,
+ 529, 532, 535, 538
+ } ;
+
+static yyconst flex_int16_t yy_def[555] =
+ { 0,
+ 513, 1, 513, 513, 513, 513, 514, 513, 513, 515,
+ 513, 515, 515, 515, 513, 513, 513, 513, 513, 513,
+ 516, 516, 516, 516, 516, 516, 516, 516, 513, 514,
+ 513, 513, 513, 517, 518, 517, 513, 517, 517, 513,
+ 513, 513, 513, 513, 513, 513, 20, 518, 516, 516,
+ 516, 516, 516, 516, 516, 516, 516, 513, 519, 519,
+ 520, 521, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 20, 520, 516, 516, 516, 516, 516, 516, 516,
+ 516, 513, 513, 522, 523, 524, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+
+ 513, 513, 513, 513, 513, 513, 516, 522, 516, 516,
+ 516, 516, 516, 516, 513, 525, 526, 527, 521, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 525, 516, 516, 516, 516, 516,
+ 513, 528, 529, 530, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 516, 516, 516, 516, 531, 532, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 516, 516, 513, 533, 534, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 516, 516, 535, 536, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 516, 513, 537, 538, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+
+ 513, 513, 513, 513, 513, 513, 513, 513, 539, 540,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 541, 542, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 543, 544, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+
+ 513, 545, 546, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 547, 548,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 549, 550, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 551, 552, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 553, 513, 513, 513, 513, 513, 513, 513,
+
+ 513, 513, 513, 554, 513, 513, 513, 513, 513, 513,
+ 513, 513, 0, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513
+ } ;
+
+static yyconst flex_int16_t yy_nxt[943] =
+ { 0,
+ 4, 5, 6, 7, 8, 4, 9, 10, 10, 10,
+ 11, 9, 12, 13, 14, 14, 14, 14, 15, 16,
+ 4, 17, 4, 4, 4, 18, 4, 4, 19, 4,
+ 4, 20, 20, 20, 20, 20, 20, 21, 22, 23,
+ 21, 21, 24, 25, 21, 26, 27, 28, 21, 21,
+ 21, 21, 21, 21, 21, 9, 9, 32, 32, 32,
+ 33, 513, 34, 34, 34, 35, 35, 513, 513, 42,
+ 46, 46, 35, 35, 46, 46, 46, 43, 46, 46,
+ 513, 46, 103, 46, 455, 35, 46, 32, 32, 32,
+ 38, 512, 104, 39, 46, 46, 47, 47, 47, 48,
+
+ 46, 36, 36, 36, 36, 36, 36, 46, 50, 46,
+ 51, 53, 46, 511, 46, 58, 58, 58, 52, 49,
+ 47, 47, 47, 47, 47, 47, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 46, 510, 377, 57, 378, 46,
+ 33, 56, 59, 59, 59, 35, 513, 513, 71, 71,
+ 71, 35, 35, 73, 73, 73, 62, 46, 46, 46,
+ 455, 508, 46, 46, 46, 54, 46, 46, 58, 58,
+ 58, 46, 46, 55, 46, 46, 513, 507, 46, 46,
+ 46, 35, 33, 46, 82, 82, 82, 35, 78, 74,
+
+ 64, 46, 63, 72, 72, 72, 46, 75, 60, 60,
+ 60, 60, 60, 60, 80, 77, 79, 71, 71, 71,
+ 76, 108, 108, 108, 85, 506, 505, 72, 72, 72,
+ 72, 72, 72, 81, 87, 110, 88, 89, 167, 46,
+ 90, 91, 92, 93, 46, 94, 95, 96, 97, 455,
+ 46, 98, 107, 107, 107, 46, 168, 83, 83, 83,
+ 83, 83, 83, 46, 46, 46, 46, 455, 46, 46,
+ 46, 46, 109, 134, 131, 503, 107, 107, 107, 107,
+ 107, 107, 46, 135, 502, 126, 33, 46, 115, 115,
+ 115, 35, 501, 111, 132, 128, 46, 113, 112, 127,
+
+ 129, 48, 500, 499, 133, 145, 145, 145, 85, 46,
+ 46, 46, 46, 46, 46, 46, 46, 46, 46, 33,
+ 46, 115, 115, 115, 498, 46, 114, 180, 180, 180,
+ 85, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 71, 71, 71, 85, 497, 46, 149, 263, 146,
+ 150, 46, 264, 147, 46, 46, 46, 148, 496, 46,
+ 46, 46, 46, 182, 46, 181, 495, 46, 494, 46,
+ 258, 183, 46, 259, 260, 265, 46, 46, 455, 302,
+ 214, 46, 184, 303, 46, 455, 491, 313, 490, 46,
+ 213, 314, 244, 489, 488, 487, 486, 485, 484, 483,
+
+ 482, 481, 480, 479, 478, 62, 276, 455, 403, 475,
+ 474, 243, 30, 30, 30, 30, 30, 30, 36, 36,
+ 36, 36, 49, 49, 49, 473, 49, 60, 60, 60,
+ 60, 61, 61, 61, 83, 83, 83, 83, 84, 84,
+ 84, 86, 472, 86, 116, 116, 116, 117, 117, 117,
+ 118, 118, 118, 151, 151, 151, 152, 152, 152, 154,
+ 154, 154, 185, 185, 185, 186, 186, 186, 187, 187,
+ 187, 215, 215, 215, 216, 216, 216, 245, 245, 245,
+ 246, 246, 246, 277, 277, 277, 278, 278, 278, 309,
+ 309, 309, 310, 310, 310, 340, 340, 340, 341, 341,
+
+ 341, 371, 371, 371, 372, 372, 372, 401, 401, 401,
+ 402, 402, 402, 429, 429, 429, 430, 430, 430, 453,
+ 453, 453, 454, 454, 454, 476, 476, 476, 477, 477,
+ 477, 492, 492, 492, 493, 493, 493, 504, 504, 504,
+ 509, 509, 509, 471, 470, 469, 468, 467, 466, 465,
+ 464, 463, 462, 461, 460, 459, 458, 457, 456, 455,
+ 403, 452, 451, 450, 449, 448, 447, 446, 445, 444,
+ 443, 442, 441, 440, 439, 438, 437, 436, 435, 434,
+ 433, 432, 431, 62, 403, 342, 428, 427, 426, 425,
+ 424, 423, 422, 421, 420, 419, 418, 417, 416, 415,
+
+ 414, 413, 412, 411, 410, 409, 408, 407, 406, 405,
+ 404, 403, 342, 400, 399, 398, 397, 396, 395, 394,
+ 393, 392, 391, 390, 389, 388, 387, 386, 385, 384,
+ 383, 382, 381, 380, 379, 376, 375, 374, 373, 62,
+ 342, 279, 370, 369, 368, 367, 366, 365, 364, 363,
+ 362, 361, 360, 359, 358, 357, 356, 355, 354, 353,
+ 352, 351, 350, 349, 348, 347, 346, 345, 344, 343,
+ 342, 279, 339, 338, 337, 336, 335, 334, 333, 332,
+ 331, 330, 329, 328, 327, 326, 325, 324, 323, 322,
+ 321, 320, 319, 318, 317, 316, 315, 312, 311, 62,
+
+ 279, 217, 308, 307, 306, 305, 304, 301, 300, 299,
+ 298, 297, 296, 295, 294, 293, 292, 291, 290, 289,
+ 288, 287, 286, 285, 284, 283, 282, 281, 280, 279,
+ 217, 275, 274, 273, 272, 271, 270, 269, 268, 267,
+ 266, 262, 261, 257, 256, 255, 254, 253, 252, 251,
+ 250, 249, 248, 247, 62, 217, 153, 242, 241, 240,
+ 239, 238, 237, 236, 235, 234, 233, 232, 231, 230,
+ 229, 228, 227, 226, 225, 224, 223, 222, 221, 220,
+ 219, 218, 119, 217, 153, 212, 211, 210, 209, 208,
+ 207, 206, 205, 204, 203, 202, 201, 200, 199, 198,
+
+ 197, 196, 195, 194, 193, 192, 191, 190, 189, 188,
+ 119, 62, 153, 85, 179, 178, 177, 176, 175, 174,
+ 173, 172, 171, 170, 169, 166, 165, 164, 163, 162,
+ 161, 160, 159, 158, 157, 156, 155, 119, 153, 85,
+ 144, 143, 142, 141, 140, 139, 138, 137, 136, 130,
+ 125, 124, 123, 122, 121, 120, 119, 62, 85, 35,
+ 106, 105, 102, 101, 100, 99, 85, 70, 69, 68,
+ 67, 66, 65, 62, 31, 29, 45, 44, 41, 40,
+ 37, 31, 29, 513, 3, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513
+ } ;
+
+static yyconst flex_int16_t yy_chk[943] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 8, 8, 8,
+ 10, 12, 10, 10, 10, 10, 12, 13, 14, 17,
+ 21, 23, 13, 14, 22, 21, 23, 17, 24, 22,
+ 36, 25, 68, 24, 509, 36, 25, 32, 32, 32,
+ 12, 507, 68, 13, 20, 49, 20, 20, 20, 20,
+
+ 49, 20, 20, 20, 20, 20, 20, 28, 22, 27,
+ 23, 25, 28, 506, 27, 33, 33, 33, 24, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 26, 505, 347, 28, 347, 26,
+ 34, 27, 34, 34, 34, 34, 38, 39, 46, 46,
+ 46, 38, 39, 48, 48, 48, 48, 50, 52, 53,
+ 504, 502, 50, 52, 53, 26, 51, 55, 58, 58,
+ 58, 51, 55, 26, 56, 54, 60, 498, 57, 56,
+ 54, 60, 59, 57, 59, 59, 59, 59, 53, 50,
+
+ 39, 75, 38, 47, 47, 47, 75, 51, 47, 47,
+ 47, 47, 47, 47, 56, 52, 54, 71, 71, 71,
+ 51, 73, 73, 73, 73, 496, 495, 47, 47, 47,
+ 47, 47, 47, 57, 63, 75, 63, 63, 132, 74,
+ 63, 63, 63, 63, 74, 63, 63, 63, 63, 493,
+ 77, 63, 72, 72, 72, 77, 132, 72, 72, 72,
+ 72, 72, 72, 76, 78, 79, 80, 492, 76, 78,
+ 79, 80, 74, 97, 96, 490, 72, 72, 72, 72,
+ 72, 72, 81, 97, 488, 93, 82, 81, 82, 82,
+ 82, 82, 485, 76, 96, 94, 107, 80, 78, 93,
+
+ 94, 107, 484, 483, 96, 108, 108, 108, 108, 109,
+ 110, 111, 112, 113, 109, 110, 111, 112, 113, 115,
+ 114, 115, 115, 115, 482, 114, 81, 145, 145, 145,
+ 145, 146, 147, 148, 149, 150, 146, 147, 148, 149,
+ 150, 180, 180, 180, 180, 481, 181, 113, 232, 110,
+ 114, 181, 232, 111, 182, 183, 184, 112, 480, 182,
+ 183, 184, 213, 147, 214, 146, 479, 213, 478, 214,
+ 229, 148, 243, 229, 229, 232, 244, 243, 477, 270,
+ 182, 244, 149, 270, 276, 476, 475, 282, 474, 276,
+ 181, 282, 214, 473, 472, 471, 470, 468, 467, 464,
+
+ 462, 461, 460, 457, 456, 455, 244, 454, 453, 452,
+ 451, 213, 514, 514, 514, 514, 514, 514, 515, 515,
+ 515, 515, 516, 516, 516, 450, 516, 517, 517, 517,
+ 517, 518, 518, 518, 519, 519, 519, 519, 520, 520,
+ 520, 521, 448, 521, 522, 522, 522, 523, 523, 523,
+ 524, 524, 524, 525, 525, 525, 526, 526, 526, 527,
+ 527, 527, 528, 528, 528, 529, 529, 529, 530, 530,
+ 530, 531, 531, 531, 532, 532, 532, 533, 533, 533,
+ 534, 534, 534, 535, 535, 535, 536, 536, 536, 537,
+ 537, 537, 538, 538, 538, 539, 539, 539, 540, 540,
+
+ 540, 541, 541, 541, 542, 542, 542, 543, 543, 543,
+ 544, 544, 544, 545, 545, 545, 546, 546, 546, 547,
+ 547, 547, 548, 548, 548, 549, 549, 549, 550, 550,
+ 550, 551, 551, 551, 552, 552, 552, 553, 553, 553,
+ 554, 554, 554, 447, 446, 445, 444, 443, 442, 440,
+ 439, 438, 437, 436, 435, 434, 433, 432, 431, 430,
+ 429, 428, 427, 426, 425, 424, 423, 422, 421, 420,
+ 419, 418, 417, 416, 415, 414, 413, 412, 411, 408,
+ 407, 406, 405, 403, 402, 401, 400, 399, 398, 397,
+ 396, 395, 394, 393, 392, 389, 388, 387, 386, 385,
+
+ 384, 383, 382, 381, 380, 379, 378, 377, 376, 375,
+ 374, 372, 371, 370, 369, 368, 367, 366, 365, 364,
+ 363, 362, 361, 360, 359, 358, 357, 356, 355, 353,
+ 352, 351, 350, 349, 348, 346, 345, 344, 343, 342,
+ 341, 340, 338, 337, 336, 335, 334, 333, 332, 331,
+ 330, 329, 328, 327, 326, 325, 324, 323, 322, 321,
+ 320, 319, 318, 317, 316, 315, 314, 313, 312, 311,
+ 310, 309, 308, 307, 306, 305, 304, 303, 302, 301,
+ 300, 299, 298, 297, 296, 295, 294, 293, 292, 291,
+ 290, 289, 288, 287, 286, 284, 283, 281, 280, 279,
+
+ 278, 277, 275, 274, 273, 272, 271, 269, 268, 267,
+ 266, 265, 264, 263, 262, 261, 260, 259, 258, 257,
+ 256, 254, 253, 252, 251, 250, 249, 248, 247, 246,
+ 245, 242, 241, 240, 239, 238, 237, 236, 235, 234,
+ 233, 231, 230, 228, 227, 226, 225, 224, 223, 222,
+ 221, 220, 219, 218, 217, 216, 215, 212, 211, 210,
+ 209, 208, 207, 206, 205, 204, 203, 202, 201, 200,
+ 199, 198, 197, 196, 195, 194, 193, 192, 191, 190,
+ 189, 188, 187, 186, 185, 179, 178, 177, 176, 175,
+ 174, 173, 172, 171, 170, 169, 168, 167, 166, 165,
+
+ 164, 163, 162, 161, 160, 159, 158, 157, 156, 155,
+ 154, 153, 152, 151, 144, 142, 141, 140, 139, 138,
+ 137, 136, 135, 134, 133, 131, 130, 129, 128, 127,
+ 126, 125, 124, 123, 122, 121, 120, 118, 117, 116,
+ 106, 105, 104, 103, 102, 101, 100, 99, 98, 95,
+ 92, 91, 90, 89, 88, 87, 86, 85, 84, 83,
+ 70, 69, 67, 66, 65, 64, 61, 45, 44, 43,
+ 42, 41, 40, 35, 30, 29, 19, 18, 16, 15,
+ 11, 7, 5, 3, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+ 513, 513
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "scanner.l"
+/*
+ * $Id$
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996-2000 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+#line 17 "scanner.l"
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+#include <gram.h>
+
+extern char *conf_file;
+
+int num_lines = 1;
+#line 864 "lex.yy.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr );
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 38 "scanner.l"
+
+
+#line 1020 "lex.yy.c"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 514 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 885 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 40 "scanner.l"
+{/* ignore comments */}
+ YY_BREAK
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 41 "scanner.l"
+{num_lines++;}
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 42 "scanner.l"
+{}
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 44 "scanner.l"
+{ return T_INTERFACE; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 45 "scanner.l"
+{ return T_PREFIX; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 46 "scanner.l"
+{ return T_ROUTE; }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 47 "scanner.l"
+{ return T_RDNSS; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 49 "scanner.l"
+{ return T_IgnoreIfMissing; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 50 "scanner.l"
+{ return T_AdvSendAdvert; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 51 "scanner.l"
+{ return T_MaxRtrAdvInterval; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 52 "scanner.l"
+{ return T_MinRtrAdvInterval; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 53 "scanner.l"
+{ return T_AdvManagedFlag; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 54 "scanner.l"
+{ return T_AdvOtherConfigFlag; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 55 "scanner.l"
+{ return T_AdvLinkMTU; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 56 "scanner.l"
+{ return T_AdvReachableTime; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 57 "scanner.l"
+{ return T_AdvRetransTimer; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 58 "scanner.l"
+{ return T_AdvCurHopLimit; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 59 "scanner.l"
+{ return T_AdvDefaultLifetime; }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 60 "scanner.l"
+{ return T_AdvDefaultPreference; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 61 "scanner.l"
+{ return T_AdvSourceLLAddress; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 63 "scanner.l"
+{ return T_AdvOnLink; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 64 "scanner.l"
+{ return T_AdvAutonomous; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 65 "scanner.l"
+{ return T_AdvValidLifetime; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 66 "scanner.l"
+{ return T_AdvPreferredLifetime; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 68 "scanner.l"
+{ return T_AdvRouterAddr; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 69 "scanner.l"
+{ return T_AdvHomeAgentFlag; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 70 "scanner.l"
+{ return T_AdvIntervalOpt; }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 71 "scanner.l"
+{ return T_AdvHomeAgentInfo; }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 72 "scanner.l"
+{ return T_UnicastOnly; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 74 "scanner.l"
+{ return T_Base6to4Interface; }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 76 "scanner.l"
+{ return T_HomeAgentPreference; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 77 "scanner.l"
+{ return T_HomeAgentLifetime; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 79 "scanner.l"
+{ return T_AdvRoutePreference; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 80 "scanner.l"
+{ return T_AdvRouteLifetime; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 82 "scanner.l"
+{ return T_AdvRDNSSPreference; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 83 "scanner.l"
+{ return T_AdvRDNSSOpenFlag; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 84 "scanner.l"
+{ return T_AdvRDNSSLifetime; }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 86 "scanner.l"
+{ return T_MinDelayBetweenRAs; }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 88 "scanner.l"
+{ return T_AdvMobRtrSupportFlag; }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 90 "scanner.l"
+{
+ static struct in6_addr addr;
+ int i;
+
+ i = inet_pton(AF_INET6, yytext, &addr);
+
+ dlog(LOG_DEBUG, 4, "inet_pton returned %d", i);
+
+ /* BSD API draft and NRL's code don't aggree on
+ * this. the draft specifies a return value of 1 on
+ * success, NRL's code returns the address length in
+ * bytes on success (16 for an IPv6 address)
+ */
+ if (i < 1) {
+ flog(LOG_ERR, "invalid address in %s, line %d", conf_file,
+ num_lines);
+ return T_BAD_TOKEN;
+ }
+
+ yylval.addr = &addr;
+ return IPV6ADDR;
+ }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 113 "scanner.l"
+{
+ unsigned long lnum;
+ char *endp;
+ lnum = strtoul(yytext, &endp, 10);
+ if (*yytext == '\0' || *endp != '\0')
+ return T_BAD_TOKEN;
+ if (lnum > 0xFFFFFFFFUL)
+ return T_BAD_TOKEN; /* XXX */
+ yylval.num = lnum;
+ return NUMBER;
+ }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 125 "scanner.l"
+{ yylval.snum = atoi(yytext); return SIGNEDNUMBER; }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 127 "scanner.l"
+{ yylval.dec = atof(yytext); return DECIMAL; }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 129 "scanner.l"
+{ return INFINITY; }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 131 "scanner.l"
+{ yylval.bool = 1; return SWITCH; }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 133 "scanner.l"
+{ yylval.bool = 0; return SWITCH; }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 135 "scanner.l"
+{ yylval.snum = -1; return SIGNEDNUMBER; }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 137 "scanner.l"
+{ yylval.snum = 0; return SIGNEDNUMBER; }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 139 "scanner.l"
+{ yylval.snum = 1; return SIGNEDNUMBER; }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 141 "scanner.l"
+{
+ static char name[IFNAMSIZ];
+
+ strncpy(name, yytext, IFNAMSIZ-1);
+ name[IFNAMSIZ-1] = '\0';
+ yylval.str = name;
+ return STRING;
+ }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 150 "scanner.l"
+{ return *yytext; }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 152 "scanner.l"
+{ return T_BAD_TOKEN; }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 153 "scanner.l"
+ECHO;
+ YY_BREAK
+#line 1410 "lex.yy.c"
+case YY_STATE_EOF(INITIAL):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 514 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 514 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 513);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp )
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up yytext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = (yy_n_chars) + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ (yytext_ptr) = yy_bp;
+ (yy_hold_char) = *yy_cp;
+ (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ yyfree((void *) b );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+
+ return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void yyset_lineno (int line_number )
+{
+
+ yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str )
+{
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str )
+{
+ yyout = out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug )
+{
+ yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 153 "scanner.l"
+
+
+
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996-2000 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+%{
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+#include <gram.h>
+
+extern char *conf_file;
+
+int num_lines = 1;
+%}
+
+digit [0-9]
+number ({digit})+
+snum -?({digit})+
+decimal ({number}"."{number})
+hexdigit ([a-f]|[A-F]|[0-9])
+addr1 {hexdigit}{1,4}":"({hexdigit}{1,4}":")*(":"{hexdigit}{1,4})+
+addr2 {hexdigit}{1,4}(":"{hexdigit}{1,4})*"::"
+addr3 ({hexdigit}{1,4}":"){7}{hexdigit}{1,4}
+addr ({addr1}|{addr2}|{addr3}|"::")
+whitespace ([ \t])+
+string [a-z]([a-z]|{digit}|_)*([:.]{digit}+)?
+%%
+
+#.*$ {/* ignore comments */}
+\n {num_lines++;}
+{whitespace} {}
+
+interface { return T_INTERFACE; }
+prefix { return T_PREFIX; }
+route { return T_ROUTE; }
+RDNSS { return T_RDNSS; }
+
+IgnoreIfMissing { return T_IgnoreIfMissing; }
+AdvSendAdvert { return T_AdvSendAdvert; }
+MaxRtrAdvInterval { return T_MaxRtrAdvInterval; }
+MinRtrAdvInterval { return T_MinRtrAdvInterval; }
+AdvManagedFlag { return T_AdvManagedFlag; }
+AdvOtherConfigFlag { return T_AdvOtherConfigFlag; }
+AdvLinkMTU { return T_AdvLinkMTU; }
+AdvReachableTime { return T_AdvReachableTime; }
+AdvRetransTimer { return T_AdvRetransTimer; }
+AdvCurHopLimit { return T_AdvCurHopLimit; }
+AdvDefaultLifetime { return T_AdvDefaultLifetime; }
+AdvDefaultPreference { return T_AdvDefaultPreference; }
+AdvSourceLLAddress { return T_AdvSourceLLAddress; }
+
+AdvOnLink { return T_AdvOnLink; }
+AdvAutonomous { return T_AdvAutonomous; }
+AdvValidLifetime { return T_AdvValidLifetime; }
+AdvPreferredLifetime { return T_AdvPreferredLifetime; }
+
+AdvRouterAddr { return T_AdvRouterAddr; }
+AdvHomeAgentFlag { return T_AdvHomeAgentFlag; }
+AdvIntervalOpt { return T_AdvIntervalOpt; }
+AdvHomeAgentInfo { return T_AdvHomeAgentInfo; }
+UnicastOnly { return T_UnicastOnly; }
+
+Base6to4Interface { return T_Base6to4Interface; }
+
+HomeAgentPreference { return T_HomeAgentPreference; }
+HomeAgentLifetime { return T_HomeAgentLifetime; }
+
+AdvRoutePreference { return T_AdvRoutePreference; }
+AdvRouteLifetime { return T_AdvRouteLifetime; }
+
+AdvRDNSSPreference { return T_AdvRDNSSPreference; }
+AdvRDNSSOpen { return T_AdvRDNSSOpenFlag; }
+AdvRDNSSLifetime { return T_AdvRDNSSLifetime; }
+
+MinDelayBetweenRAs { return T_MinDelayBetweenRAs; }
+
+AdvMobRtrSupportFlag { return T_AdvMobRtrSupportFlag; }
+
+{addr} {
+ static struct in6_addr addr;
+ int i;
+
+ i = inet_pton(AF_INET6, yytext, &addr);
+
+ dlog(LOG_DEBUG, 4, "inet_pton returned %d", i);
+
+ /* BSD API draft and NRL's code don't aggree on
+ * this. the draft specifies a return value of 1 on
+ * success, NRL's code returns the address length in
+ * bytes on success (16 for an IPv6 address)
+ */
+ if (i < 1) {
+ flog(LOG_ERR, "invalid address in %s, line %d", conf_file,
+ num_lines);
+ return T_BAD_TOKEN;
+ }
+
+ yylval.addr = &addr;
+ return IPV6ADDR;
+ }
+
+{number} {
+ unsigned long lnum;
+ char *endp;
+ lnum = strtoul(yytext, &endp, 10);
+ if (*yytext == '\0' || *endp != '\0')
+ return T_BAD_TOKEN;
+ if (lnum > 0xFFFFFFFFUL)
+ return T_BAD_TOKEN; /* XXX */
+ yylval.num = lnum;
+ return NUMBER;
+ }
+
+{snum} { yylval.snum = atoi(yytext); return SIGNEDNUMBER; }
+
+{decimal} { yylval.dec = atof(yytext); return DECIMAL; }
+
+infinity { return INFINITY; }
+
+on { yylval.bool = 1; return SWITCH; }
+
+off { yylval.bool = 0; return SWITCH; }
+
+low { yylval.snum = -1; return SIGNEDNUMBER; }
+
+medium { yylval.snum = 0; return SIGNEDNUMBER; }
+
+high { yylval.snum = 1; return SIGNEDNUMBER; }
+
+{string} {
+ static char name[IFNAMSIZ];
+
+ strncpy(name, yytext, IFNAMSIZ-1);
+ name[IFNAMSIZ-1] = '\0';
+ yylval.str = name;
+ return STRING;
+ }
+
+"{"|"}"|";"|"/" { return *yytext; }
+
+. { return T_BAD_TOKEN; }
+%%
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+
+void
+send_ra(int sock, struct Interface *iface, struct in6_addr *dest)
+{
+ uint8_t all_hosts_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+ struct sockaddr_in6 addr;
+ struct in6_pktinfo *pkt_info;
+ struct msghdr mhdr;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ char chdr[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+ struct nd_router_advert *radvert;
+ struct AdvPrefix *prefix;
+ struct AdvRoute *route;
+ struct AdvRDNSS *rdnss;
+ /* XXX: we don't keep track if buff gets overflowed. In theory the sysadmin could
+ do that with e.g., too many advertised prefixes or routes, but buff is just so
+ large that this should never happen and if it does, it's admin's fault :-) */
+ unsigned char buff[MSG_SIZE];
+ int len = 0;
+ int err;
+
+ /* First we need to check that the interface hasn't been removed or deactivated */
+ if(check_device(sock, iface) < 0) {
+ if (iface->IgnoreIfMissing) /* a bit more quiet warning message.. */
+ dlog(LOG_DEBUG, 4, "interface %s does not exist, ignoring the interface", iface->Name);
+ else {
+ flog(LOG_WARNING, "interface %s does not exist, ignoring the interface", iface->Name);
+ }
+ iface->HasFailed = 1;
+ } else {
+ /* check_device was successful, act if it has failed previously */
+ if (iface->HasFailed == 1) {
+ flog(LOG_WARNING, "interface %s seems to have come back up, trying to reinitialize", iface->Name);
+ iface->HasFailed = 0;
+ /* XXX: reinitializes 'iface', so this probably isn't going to work until next send_ra().. */
+ /* SDH : don't do this since we're not doing config the same way */
+ /* reload_config(); */
+ }
+ }
+
+ /* Make sure that we've joined the all-routers multicast group */
+ if (check_allrouters_membership(sock, iface) < 0)
+ flog(LOG_WARNING, "problem checking all-routers membership on %s", iface->Name);
+
+ dlog(LOG_DEBUG, 3, "sending RA on %s", iface->Name);
+
+ if (dest == NULL)
+ {
+ struct timeval tv;
+
+ dest = (struct in6_addr *)all_hosts_addr;
+ gettimeofday(&tv, NULL);
+
+ iface->last_multicast_sec = tv.tv_sec;
+ iface->last_multicast_usec = tv.tv_usec;
+ }
+
+ memset((void *)&addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons(IPPROTO_ICMPV6);
+ memcpy(&addr.sin6_addr, dest, sizeof(struct in6_addr));
+
+ memset(&buff, 0, sizeof(buff));
+ radvert = (struct nd_router_advert *) buff;
+
+ radvert->nd_ra_type = ND_ROUTER_ADVERT;
+ radvert->nd_ra_code = 0;
+ radvert->nd_ra_cksum = 0;
+
+ radvert->nd_ra_curhoplimit = iface->AdvCurHopLimit;
+ radvert->nd_ra_flags_reserved =
+ (iface->AdvManagedFlag)?ND_RA_FLAG_MANAGED:0;
+ radvert->nd_ra_flags_reserved |=
+ (iface->AdvOtherConfigFlag)?ND_RA_FLAG_OTHER:0;
+ /* Mobile IPv6 ext */
+ radvert->nd_ra_flags_reserved |=
+ (iface->AdvHomeAgentFlag)?ND_RA_FLAG_HOME_AGENT:0;
+
+ /* if forwarding is disabled, send zero router lifetime */
+ /* SDH : disable this check too */
+ /* radvert->nd_ra_router_lifetime = !check_ip6_forwarding() ? htons(iface->AdvDefaultLifetime) : 0; */
+ radvert->nd_ra_flags_reserved |=
+ (iface->AdvDefaultPreference << ND_OPT_RI_PRF_SHIFT) & ND_OPT_RI_PRF_MASK;
+
+ radvert->nd_ra_reachable = htonl(iface->AdvReachableTime);
+ radvert->nd_ra_retransmit = htonl(iface->AdvRetransTimer);
+
+ len = sizeof(struct nd_router_advert);
+
+ prefix = iface->AdvPrefixList;
+
+ /*
+ * add prefix options
+ */
+
+ while(prefix)
+ {
+ if( prefix->enabled )
+ {
+ struct nd_opt_prefix_info *pinfo;
+
+ pinfo = (struct nd_opt_prefix_info *) (buff + len);
+
+ pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
+ pinfo->nd_opt_pi_len = 4;
+ pinfo->nd_opt_pi_prefix_len = prefix->PrefixLen;
+
+ pinfo->nd_opt_pi_flags_reserved =
+ (prefix->AdvOnLinkFlag)?ND_OPT_PI_FLAG_ONLINK:0;
+ pinfo->nd_opt_pi_flags_reserved |=
+ (prefix->AdvAutonomousFlag)?ND_OPT_PI_FLAG_AUTO:0;
+ /* Mobile IPv6 ext */
+ pinfo->nd_opt_pi_flags_reserved |=
+ (prefix->AdvRouterAddr)?ND_OPT_PI_FLAG_RADDR:0;
+
+ pinfo->nd_opt_pi_valid_time = htonl(prefix->AdvValidLifetime);
+ pinfo->nd_opt_pi_preferred_time = htonl(prefix->AdvPreferredLifetime);
+ pinfo->nd_opt_pi_reserved2 = 0;
+
+ memcpy(&pinfo->nd_opt_pi_prefix, &prefix->Prefix,
+ sizeof(struct in6_addr));
+
+ len += sizeof(*pinfo);
+ }
+
+ prefix = prefix->next;
+ }
+
+ route = iface->AdvRouteList;
+
+ /*
+ * add route options
+ */
+
+ while(route)
+ {
+ struct nd_opt_route_info_local *rinfo;
+
+ rinfo = (struct nd_opt_route_info_local *) (buff + len);
+
+ rinfo->nd_opt_ri_type = ND_OPT_ROUTE_INFORMATION;
+ /* XXX: the prefixes are allowed to be sent in smaller chunks as well */
+ rinfo->nd_opt_ri_len = 3;
+ rinfo->nd_opt_ri_prefix_len = route->PrefixLen;
+
+ rinfo->nd_opt_ri_flags_reserved =
+ (route->AdvRoutePreference << ND_OPT_RI_PRF_SHIFT) & ND_OPT_RI_PRF_MASK;
+ rinfo->nd_opt_ri_lifetime = htonl(route->AdvRouteLifetime);
+
+ memcpy(&rinfo->nd_opt_ri_prefix, &route->Prefix,
+ sizeof(struct in6_addr));
+ len += sizeof(*rinfo);
+
+ route = route->next;
+ }
+
+ rdnss = iface->AdvRDNSSList;
+
+ /*
+ * add rdnss options
+ */
+
+ while(rdnss)
+ {
+ struct nd_opt_rdnss_info_local *rdnssinfo;
+
+ rdnssinfo = (struct nd_opt_rdnss_info_local *) (buff + len);
+
+ rdnssinfo->nd_opt_rdnssi_type = ND_OPT_RDNSS_INFORMATION;
+ rdnssinfo->nd_opt_rdnssi_len = 1 + 2*rdnss->AdvRDNSSNumber;
+ rdnssinfo->nd_opt_rdnssi_pref_flag_reserved =
+ ((rdnss->AdvRDNSSPreference << ND_OPT_RDNSSI_PREF_SHIFT) & ND_OPT_RDNSSI_PREF_MASK);
+ rdnssinfo->nd_opt_rdnssi_pref_flag_reserved |=
+ ((rdnss->AdvRDNSSOpenFlag)?ND_OPT_RDNSSI_FLAG_S:0);
+
+ rdnssinfo->nd_opt_rdnssi_lifetime = htonl(rdnss->AdvRDNSSLifetime);
+
+ memcpy(&rdnssinfo->nd_opt_rdnssi_addr1, &rdnss->AdvRDNSSAddr1,
+ sizeof(struct in6_addr));
+ memcpy(&rdnssinfo->nd_opt_rdnssi_addr2, &rdnss->AdvRDNSSAddr2,
+ sizeof(struct in6_addr));
+ memcpy(&rdnssinfo->nd_opt_rdnssi_addr3, &rdnss->AdvRDNSSAddr3,
+ sizeof(struct in6_addr));
+ len += sizeof(*rdnssinfo) - (3-rdnss->AdvRDNSSNumber)*sizeof(struct in6_addr);
+
+ rdnss = rdnss->next;
+ }
+
+ /*
+ * add MTU option
+ */
+
+ if (iface->AdvLinkMTU != 0) {
+ struct nd_opt_mtu *mtu;
+
+ mtu = (struct nd_opt_mtu *) (buff + len);
+
+ mtu->nd_opt_mtu_type = ND_OPT_MTU;
+ mtu->nd_opt_mtu_len = 1;
+ mtu->nd_opt_mtu_reserved = 0;
+ mtu->nd_opt_mtu_mtu = htonl(iface->AdvLinkMTU);
+
+ len += sizeof(*mtu);
+ }
+
+ /*
+ * add Source Link-layer Address option
+ */
+
+ if (iface->AdvSourceLLAddress && iface->if_hwaddr_len != -1)
+ {
+ uint8_t *ucp;
+ unsigned int i;
+
+ ucp = (uint8_t *) (buff + len);
+
+ *ucp++ = ND_OPT_SOURCE_LINKADDR;
+ *ucp++ = (uint8_t) ((iface->if_hwaddr_len + 16 + 63) >> 6);
+
+ len += 2 * sizeof(uint8_t);
+
+ i = (iface->if_hwaddr_len + 7) >> 3;
+ memcpy(buff + len, iface->if_hwaddr, i);
+ len += i;
+ }
+
+ /*
+ * Mobile IPv6 ext: Advertisement Interval Option to support
+ * movement detection of mobile nodes
+ */
+
+ if(iface->AdvIntervalOpt)
+ {
+ struct AdvInterval a_ival;
+ uint32_t ival;
+ if(iface->MaxRtrAdvInterval < Cautious_MaxRtrAdvInterval){
+ ival = ((iface->MaxRtrAdvInterval +
+ Cautious_MaxRtrAdvInterval_Leeway ) * 1000);
+
+ }
+ else {
+ ival = (iface->MaxRtrAdvInterval * 1000);
+ }
+ a_ival.type = ND_OPT_RTR_ADV_INTERVAL;
+ a_ival.length = 1;
+ a_ival.reserved = 0;
+ a_ival.adv_ival = htonl(ival);
+
+ memcpy(buff + len, &a_ival, sizeof(a_ival));
+ len += sizeof(a_ival);
+ }
+
+ /*
+ * Mobile IPv6 ext: Home Agent Information Option to support
+ * Dynamic Home Agent Address Discovery
+ */
+
+ if(iface->AdvHomeAgentInfo &&
+ (iface->AdvMobRtrSupportFlag || iface->HomeAgentPreference != 0 ||
+ iface->HomeAgentLifetime != iface->AdvDefaultLifetime))
+
+ {
+ struct HomeAgentInfo ha_info;
+ ha_info.type = ND_OPT_HOME_AGENT_INFO;
+ ha_info.length = 1;
+ ha_info.flags_reserved =
+ (iface->AdvMobRtrSupportFlag)?ND_OPT_HAI_FLAG_SUPPORT_MR:0;
+ ha_info.preference = htons(iface->HomeAgentPreference);
+ ha_info.lifetime = htons(iface->HomeAgentLifetime);
+
+ memcpy(buff + len, &ha_info, sizeof(ha_info));
+ len += sizeof(ha_info);
+ }
+
+ iov.iov_len = len;
+ iov.iov_base = (caddr_t) buff;
+
+ memset(chdr, 0, sizeof(chdr));
+ cmsg = (struct cmsghdr *) chdr;
+
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+
+ pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+ pkt_info->ipi6_ifindex = iface->if_index;
+ memcpy(&pkt_info->ipi6_addr, &iface->if_addr, sizeof(struct in6_addr));
+
+#ifdef HAVE_SIN6_SCOPE_ID
+ if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6_addr))
+ addr.sin6_scope_id = iface->if_index;
+#endif
+
+ memset(&mhdr, 0, sizeof(mhdr));
+ mhdr.msg_name = (caddr_t)&addr;
+ mhdr.msg_namelen = sizeof(struct sockaddr_in6);
+ mhdr.msg_iov = &iov;
+ mhdr.msg_iovlen = 1;
+ mhdr.msg_control = (void *) cmsg;
+ mhdr.msg_controllen = sizeof(chdr);
+
+ err = sendmsg(sock, &mhdr, 0);
+
+ if (err < 0) {
+ if (!iface->IgnoreIfMissing || !(errno == EINVAL || errno == ENODEV))
+ flog(LOG_WARNING, "sendmsg: %s", strerror(errno));
+ else
+ dlog(LOG_DEBUG, 3, "sendmsg: %s", strerror(errno));
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+
+/* Note: these are applicable to receiving sockopts only */
+#if defined IPV6_HOPLIMIT && !defined IPV6_RECVHOPLIMIT
+# define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
+#endif
+
+#if defined IPV6_PKTINFO && !defined IPV6_RECVPKTINFO
+# define IPV6_RECVPKTINFO IPV6_PKTINFO
+#endif
+
+int
+open_icmpv6_socket(void)
+{
+ int sock;
+ struct icmp6_filter filter;
+ int err, val;
+
+ sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+ if (sock < 0)
+ {
+ flog(LOG_ERR, "can't create socket(AF_INET6): %s", strerror(errno));
+ return (-1);
+ }
+
+ val = 1;
+ err = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
+ if (err < 0)
+ {
+ flog(LOG_ERR, "setsockopt(IPV6_RECVPKTINFO): %s", strerror(errno));
+ return (-1);
+ }
+
+ val = 2;
+#ifdef __linux__
+ err = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
+#else
+ err = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
+#endif
+ if (err < 0)
+ {
+ flog(LOG_ERR, "setsockopt(IPV6_CHECKSUM): %s", strerror(errno));
+ return (-1);
+ }
+
+ val = 255;
+ err = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
+ if (err < 0)
+ {
+ flog(LOG_ERR, "setsockopt(IPV6_UNICAST_HOPS): %s", strerror(errno));
+ return (-1);
+ }
+
+ val = 255;
+ err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val));
+ if (err < 0)
+ {
+ flog(LOG_ERR, "setsockopt(IPV6_MULTICAST_HOPS): %s", strerror(errno));
+ return (-1);
+ }
+
+#ifdef IPV6_RECVHOPLIMIT
+ val = 1;
+ err = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val));
+ if (err < 0)
+ {
+ flog(LOG_ERR, "setsockopt(IPV6_RECVHOPLIMIT): %s", strerror(errno));
+ return (-1);
+ }
+#endif
+
+ /*
+ * setup ICMP filter
+ */
+
+ ICMP6_FILTER_SETBLOCKALL(&filter);
+ ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
+ ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
+
+ err = setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
+ sizeof(filter));
+ if (err < 0)
+ {
+ flog(LOG_ERR, "setsockopt(ICMPV6_FILTER): %s", strerror(errno));
+ return (-1);
+ }
+
+ return sock;
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996-2000 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+
+static struct timer_lst timers_head = {
+ {LONG_MAX, LONG_MAX},
+ NULL, NULL,
+ &timers_head, &timers_head
+};
+
+static void alarm_handler(int sig);
+int inline check_time_diff(struct timer_lst *tm, struct timeval tv);
+
+static void
+schedule_timer(void)
+{
+ struct timer_lst *tm = timers_head.next;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ if (tm != &timers_head)
+ {
+ struct itimerval next;
+
+ memset(&next, 0, sizeof(next));
+
+ timersub(&tm->expires, &tv, &next.it_value);
+
+ signal(SIGALRM, alarm_handler);
+
+ if ((next.it_value.tv_sec > 0) ||
+ ((next.it_value.tv_sec == 0) && (next.it_value.tv_usec > 0)))
+ {
+ dlog(LOG_DEBUG, 4, "calling alarm: %ld secs, %ld usecs",
+ next.it_value.tv_sec, next.it_value.tv_usec);
+
+ if(setitimer(ITIMER_REAL, &next, NULL))
+ flog(LOG_WARNING, "schedule_timer setitimer for %ld.%ld failed: %s",
+ next.it_value.tv_sec, next.it_value.tv_usec, strerror(errno));
+ }
+ else
+ {
+ dlog(LOG_DEBUG, 4, "next timer has already expired, queueing signal");
+ kill(getpid(), SIGALRM);
+ }
+ }
+}
+
+void
+set_timer(struct timer_lst *tm, double secs)
+{
+ struct timeval tv;
+ struct timer_lst *lst;
+ sigset_t bmask, oldmask;
+ struct timeval firein;
+
+ dlog(LOG_DEBUG, 3, "setting timer: %.2f secs", secs);
+
+ firein.tv_sec = (long)secs;
+ firein.tv_usec = (long)((secs - (double)firein.tv_sec) * 1000000);
+
+ dlog(LOG_DEBUG, 5, "setting timer: %ld secs %ld usecs", firein.tv_sec, firein.tv_usec);
+
+ gettimeofday(&tv, NULL);
+ timeradd(&tv, &firein, &tm->expires);
+
+ sigemptyset(&bmask);
+ sigaddset(&bmask, SIGALRM);
+ sigprocmask(SIG_BLOCK, &bmask, &oldmask);
+
+ lst = &timers_head;
+
+ /* the timers are in the list in the order they expire, the soonest first */
+ do {
+ lst = lst->next;
+ } while ((tm->expires.tv_sec > lst->expires.tv_sec) ||
+ ((tm->expires.tv_sec == lst->expires.tv_sec) &&
+ (tm->expires.tv_usec > lst->expires.tv_usec)));
+
+ tm->next = lst;
+ tm->prev = lst->prev;
+ lst->prev = tm;
+ tm->prev->next = tm;
+
+ dlog(LOG_DEBUG, 5, "calling schedule_timer from set_timer context");
+ schedule_timer();
+
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+}
+
+void
+clear_timer(struct timer_lst *tm)
+{
+ sigset_t bmask, oldmask;
+
+ sigemptyset(&bmask);
+ sigaddset(&bmask, SIGALRM);
+ sigprocmask(SIG_BLOCK, &bmask, &oldmask);
+
+ tm->prev->next = tm->next;
+ tm->next->prev = tm->prev;
+
+ tm->prev = tm->next = NULL;
+
+ dlog(LOG_DEBUG, 5, "calling schedule_timer from clear_timer context");
+ schedule_timer();
+
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+}
+
+static void
+alarm_handler(int sig)
+{
+ struct timer_lst *tm, *back;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ tm = timers_head.next;
+
+ /*
+ * This handler is called when the alarm goes off, so at least one of
+ * the interfaces' timers should satisfy the while condition.
+ *
+ * Sadly, this is not always the case, at least on Linux kernels:
+ * see http://lkml.org/lkml/2005/4/29/163. :-(. It seems some
+ * versions of timers are not accurate and get called up to a couple of
+ * hundred microseconds before they expire.
+ *
+ * Therefore we allow some inaccuracy here; it's sufficient for us
+ * that a timer should go off in a millisecond.
+ */
+
+ /* unused timers are initialized to LONG_MAX so we skip them */
+ while (tm->expires.tv_sec != LONG_MAX && check_time_diff(tm, tv))
+ {
+ tm->prev->next = tm->next;
+ tm->next->prev = tm->prev;
+
+ back = tm;
+ tm = tm->next;
+ back->prev = back->next = NULL;
+
+ (*back->handler)(back->data);
+ }
+
+ dlog(LOG_DEBUG, 5, "calling schedule_timer from alarm_handler context");
+ schedule_timer();
+}
+
+
+void
+init_timer(struct timer_lst *tm, void (*handler)(void *), void *data)
+{
+ memset(tm, 0, sizeof(struct timer_lst));
+ tm->handler = handler;
+ tm->data = data;
+}
+
+int inline
+check_time_diff(struct timer_lst *tm, struct timeval tv)
+{
+ struct itimerval diff;
+ memset(&diff, 0, sizeof(diff));
+
+ #define ALLOW_CLOCK_USEC 1000
+
+ timersub(&tm->expires, &tv, &diff.it_value);
+ dlog(LOG_DEBUG, 5, "check_time_diff, difference: %ld sec + %ld usec",
+ diff.it_value.tv_sec, diff.it_value.tv_usec);
+
+ if (diff.it_value.tv_sec <= 0) {
+ /* already gone, this is the "good" case */
+ if (diff.it_value.tv_sec < 0)
+ return 1;
+#ifdef __linux__ /* we haven't seen this on other OSes */
+ /* still OK if the expiry time is not too much in the future */
+ else if (diff.it_value.tv_usec > 0 &&
+ diff.it_value.tv_usec <= ALLOW_CLOCK_USEC) {
+ dlog(LOG_DEBUG, 4, "alarm_handler clock was probably off by %ld usec, allowing %u",
+ tm->expires.tv_usec-tv.tv_usec, ALLOW_CLOCK_USEC);
+ return 2;
+ }
+#endif /* __linux__ */
+ else /* scheduled intentionally in the future? */
+ return 0;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Authors:
+ * Lars Fenneberg <lf@elemental.net>
+ *
+ * This software is Copyright 1996,1997 by the above mentioned author(s),
+ * All Rights Reserved.
+ *
+ * The license which is distributed with this software in the file COPYRIGHT
+ * applies to this software. If your distribution is missing this file, you
+ * may request it from <pekkas@netcore.fi>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+
+void
+mdelay(double msecs)
+{
+ struct timeval tv;
+
+ tv.tv_sec = (time_t)(msecs / 1000.0);
+ tv.tv_usec = (suseconds_t)((msecs - tv.tv_sec * 1000.0) * 1000.0);
+
+ select(0,(fd_set *)NULL,(fd_set *)NULL,(fd_set *)NULL, &tv);
+}
+
+double
+rand_between(double lower, double upper)
+{
+ return ((upper - lower) / (RAND_MAX + 1.0) * rand() + lower);
+}
+
+void
+print_addr(struct in6_addr *addr, char *str)
+{
+ const char *res;
+
+ /* XXX: overflows 'str' if it isn't big enough */
+ res = inet_ntop(AF_INET6, (void *)addr, str, INET6_ADDRSTRLEN);
+
+ if (res == NULL)
+ {
+ flog(LOG_ERR, "print_addr: inet_ntop: %s", strerror(errno));
+ strcpy(str, "[invalid address]");
+ }
+}
+
+/* Check if an in6_addr exists in the rdnss list */
+int
+check_rdnss_presence(struct AdvRDNSS *rdnss, struct in6_addr *addr)
+{
+ while (rdnss) {
+ if ( !memcmp(&rdnss->AdvRDNSSAddr1, addr, sizeof(struct in6_addr))
+ || !memcmp(&rdnss->AdvRDNSSAddr2, addr, sizeof(struct in6_addr))
+ || !memcmp(&rdnss->AdvRDNSSAddr3, addr, sizeof(struct in6_addr)) )
+ break; /* rdnss address found in the list */
+ else
+ rdnss = rdnss->next; /* no match */
+ }
+ return (rdnss != NULL);
+}
--- /dev/null
+/*
+ * radvd-wrapper.c
+ * author: Stephen Dawson-Haggerty <stevedh@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;
+}
--- /dev/null
+/*
+ * "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"; */
+
+}
--- /dev/null
+/*
+ * "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
--- /dev/null
+/*
+ * "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
+ *
+ * Copyright (c) 2008 Stephen Dawson-Haggerty
+ * Extensivly modified to use lib6lowpan / b6lowpan.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <termios.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "tun_dev.h"
+#include "serialsource.h"
+#include "serialpacket.h"
+#include "serialprotocol.h"
+#include "sfsource.h"
+
+#include "6lowpan.h"
+#include "ip.h"
+#include "lib6lowpan.h"
+#include "IEEE154.h"
+#include "routing.h"
+#include "devconf.h"
+#include "logging.h"
+#include "config.h"
+#include "nwstate.h"
+
+#define min(a,b) ( (a>b) ? b : a )
+#define max(a,b) ( (a>b) ? a : b )
+
+int tun_fd, radvd_fd = -1;
+int radvd_init(char *ifname, struct config *c);
+void radvd_process();
+
+#ifndef SIM
+serial_source ser_src;
+#define write_pan_packet(DATA, LEN) write_serial_packet(ser_src, DATA, LEN)
+#define read_pan_packet(LENP) read_serial_packet(ser_src, LENP)
+#else
+int sf_fd;
+#define write_pan_packet(DATA, LEN) write_sf_packet(sf_fd, DATA, LEN)
+#define read_pan_packet(LENP) read_sf_packet(sf_fd, LENP)
+#endif
+
+enum {
+ N_RECONSTRUCTIONS = 10,
+};
+
+/*
+ * This is not the right way to detect we're on that platform, but I
+ * can't find a better macro.
+ */
+#ifdef __TARGET_mips__
+char *def_configfile = "/etc/lowpan/serial_tun.conf";
+#else
+char *def_configfile = "serial_tun.conf";
+#endif
+
+#ifdef DBG_TRACK_FLOWS
+FILE *dbg_file;
+#endif
+
+
+extern struct in6_addr __my_address;
+uint16_t local_seqno = 0;
+
+volatile sig_atomic_t config_success = 0;
+struct config driver_config;
+char dev[IFNAMSIZ];
+struct {
+ time_t boot_time;
+ unsigned long tx_pkts;
+ unsigned long tx_frags;
+ unsigned long tx_bytes;
+ unsigned long rx_pkts;
+ unsigned long rx_frags;
+ unsigned long rx_bytes;
+ unsigned long fw_pkts;
+} stats = {0, 0, 0, 0, 0, 0, 0, 0};
+
+
+/* ------------------------------------------------------------------------- */
+
+void stderr_msg(serial_source_msg problem)
+{
+ // fprintf(stderr, "Note: %s\n", msgs[problem]);
+}
+
+
+void print_ip_packet(struct split_ip_msg *msg) {
+ int i;
+ struct generic_header *g_hdr;
+ if (log_getlevel() > LOGLVL_DEBUG) return;
+
+ printf(" nxthdr: 0x%x hlim: 0x%x\n", msg->hdr.nxt_hdr, msg->hdr.hlim);
+ printf(" src: ");
+ for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.ip6_src.s6_addr[i]);
+ printf("\n");
+ printf(" dst: ");
+ for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.ip6_dst.s6_addr[i]);
+ printf("\n");
+
+ g_hdr = msg->headers;
+ while (g_hdr != NULL) {
+ printf("header [%i]: ", g_hdr->len);
+ for (i = 0; i < g_hdr->len; i++)
+ printf("0x%x ", g_hdr->hdr.data[i]);
+ printf("\n");
+ g_hdr = g_hdr->next;
+ }
+
+ printf("data [%i]:\n\t", msg->data_len);
+ for (i = 0; i < msg->data_len; i++) {
+ if (i == 0x40) {
+ printf (" ...\n");
+ break;
+ }
+ printf("0x%x ", msg->data[i]);
+ if (i % 16 == 15) printf("\n\t");
+ if (i % 16 == 7) printf (" ");
+ }
+ printf("\n");
+}
+
+/*
+ * frees the linked list structs, and their payloads if we have
+ * malloc'ed them at some other point.
+ *
+ * does not free the payload buffer or the actual split_ip_msg struct,
+ * since those are malloc'ed seperatly in this implementation.
+ */
+void free_split_msg(struct split_ip_msg *msg) {
+ struct generic_header *cur, *next;
+ cur = msg->headers;
+ while (cur != NULL) {
+ next = cur->next;
+ if (cur->payload_malloced)
+ free(cur->hdr.data);
+ free(cur);
+ cur = next;
+ }
+}
+
+void configure_timeout() {
+ if (config_success == 0) {
+ fatal("configuring interface failed! aborting!\n");
+ exit(2);
+ } else {
+ signal(SIGALRM, SIG_DFL);
+ }
+}
+
+void configure_reboot() {
+ uint8_t buf[sizeof(config_cmd_t) + 1];
+ config_cmd_t *cmd = (config_cmd_t *)(&buf[1]);
+ memset(buf, 0, sizeof(config_cmd_t) + 1);
+ buf[0] = TOS_SERIAL_DEVCONF;
+ cmd->cmd = CONFIG_REBOOT;
+
+ signal(SIGALRM, configure_timeout);
+ write_pan_packet(buf, CONFIGURE_MSG_SIZE + 1);
+ alarm(5);
+}
+
+void configure_setparms(struct config *c) {
+ uint8_t buf[sizeof(config_cmd_t) + 1];
+ config_cmd_t *cmd = (config_cmd_t *)(&buf[1]);
+ memset(buf, 0, sizeof(config_cmd_t) + 1);
+ buf[0] = TOS_SERIAL_DEVCONF;
+ cmd->cmd = CONFIG_SET_PARM;
+ cmd->rf.addr = c->router_addr.s6_addr16[7]; // is network byte-order
+ cmd->rf.channel = c->channel;
+ cmd->retx.retries = htons(10);
+ cmd->retx.delay = htons(30);
+
+ write_pan_packet(buf, CONFIGURE_MSG_SIZE + 1);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/*
+ * the first byte the TOS serial stack sends is a dispatch byte. One
+ * dispatch value is for forwarded 802;.15.4 packets; we use a few
+ * others to talk directly to the attached IPBaseStation.
+ */
+void handle_other_pkt(uint8_t *data, int len) {
+ config_reply_t *rep;
+ switch (data[0]) {
+ case TOS_SERIAL_DEVCONF:
+ rep = (config_reply_t *)(&data[1]);
+ debug("interface configured (0x%x) addr: 0x%x\n", rep->error, ntohs(rep->addr));
+ switch (rep->error) {
+ case CONFIG_ERROR_BOOTED:
+ configure_setparms(&driver_config);
+ break;
+ default:
+ info("interface device successfully initialized\n");
+ config_success = 1;
+
+ /* put this here because we already use SIGALRM for the
+ configure timeout, and radvd needs it for its own timer. */
+ if ((radvd_fd = radvd_init(dev, &driver_config)) < 0) {
+ fatal("radvd init failed!\n");
+ exit(1);
+ }
+ }
+ break;
+ default:
+ warn("received serial packet with unknown dispatch 0x%x\n",data[0]);
+ log_dump_serial_packet(data, len);
+ }
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* handling of data arriving on the tun interface */
+void write_radio_header(uint8_t *serial, hw_addr_t dest, uint16_t payload_len) {
+#ifndef SIM
+ IEEE154_header_t *radioPacket = (IEEE154_header_t *)(serial + 1);
+ radioPacket->length = payload_len + MAC_HEADER_SIZE + MAC_FOOTER_SIZE
+#ifdef DBG_TRACK_FLOWS
+ + sizeof(struct flow_id);
+#else
+ ;
+#endif
+ // don't include the length byte
+ radioPacket->fcf = htons(0x4188);
+ // dsn will get set on mote
+ radioPacket->destpan = 0;
+ radioPacket->dest = htole16(dest);
+ // src will get set on mote
+
+ serial[0] = SERIAL_TOS_SERIAL_802_15_4_ID;
+#else
+ serial_header_t *serialHeader = (serial_header_t *)(serial + 1);
+ serialHeader->length = payload_len
+#ifdef DBG_TRACK_FLOWS
+ + sizeof(struct flow_id);
+#else
+ ;
+#endif
+ serialHeader->dest = htons(dest);
+ serialHeader->type = 0;
+
+ serial[0] = 0;
+#endif
+}
+
+void send_fragments (struct split_ip_msg *msg, hw_addr_t dest) {
+ int result;
+ uint16_t frag_len;
+ fragment_t progress;
+ uint8_t serial[LOWPAN_LINK_MTU + 1];
+#ifndef SIM
+ IEEE154_header_t *radioPacket = (IEEE154_header_t *)(serial + 1);
+#define PKTLEN(X) ((X)->length + 2)
+#else
+ serial_header_t *radioPacket = (serial_header_t *)(serial + 1);
+#define PKTLEN(X) ((X)->length + sizeof(serial_header_t) + 1)
+#endif
+
+ uint8_t *lowpan = (uint8_t *)(radioPacket + 1);
+
+#ifdef DBG_TRACK_FLOWS
+#define LOWPAN_PAYLOAD_LENGTH (LOWPAN_LINK_MTU - MAC_HEADER_SIZE \
+ - MAC_FOOTER_SIZE - sizeof(struct flow_id))
+ lowpan += sizeof(struct flow_id);
+#else
+#define LOWPAN_PAYLOAD_LENGTH (LOWPAN_LINK_MTU - MAC_HEADER_SIZE \
+ - MAC_FOOTER_SIZE)
+#endif
+
+ progress.offset = 0;
+
+ // and IEEE 802.15.4 header
+ // write_radio_header(serial, dest, frag_len);
+#ifdef DBG_TRACK_FLOWS
+#ifndef SIM
+ ip_memcpy(serial + 1 + sizeof(IEEE154_header_t), &msg->id, sizeof(struct flow_id));
+#else
+ ip_memcpy(serial + 1 + sizeof(serial_header_t), &msg->id, sizeof(struct flow_id));
+#endif
+ if (dest != 0xffff) {
+ fprintf(dbg_file, "DEBUG (%i): %i\t%i\t%i\t%i\t%i\t%i\t%i\n",
+ 100, msg->id.src, msg->id.dst, msg->id.id, msg->id.seq,
+ msg->id.nxt_hdr, 100, dest);
+ fflush(dbg_file);
+ }
+#endif
+
+ while ((frag_len = getNextFrag(msg, &progress, lowpan,
+ LOWPAN_PAYLOAD_LENGTH)) > 0) {
+
+ //debug("frag len: 0x%x offset: 0x%x plen: 0x%x\n", frag_len, progress.offset * 8, ntohs(ip_header->plen));
+
+ write_radio_header(serial, dest, frag_len);
+
+ // if this is sent too fast, the base station can't keep up. The effect of this is
+ // we send incomplete fragment. 25ms seems to work pretty well.
+ // usleep(30000);
+ // 6-9-08 : SDH : this is a bad fix that does not address the
+ // problem.
+ // at the very least, the serial ack's seem to be
+ // working, so we should be retrying if the ack is failing
+ // because the hardware cannot keep up.
+#ifdef __TARGET_mips__
+ usleep(50000);
+#endif
+
+ log_dump_serial_packet(serial, PKTLEN(radioPacket));
+ result = write_pan_packet(serial, PKTLEN(radioPacket));
+ if (result != 0)
+ result = write_pan_packet(serial, PKTLEN(radioPacket));
+
+ debug("send_fragments: result: 0x%x len: 0x%x\n", result, frag_len);
+ log_dump_serial_packet(serial, PKTLEN(radioPacket));
+ stats.tx_frags++;
+ stats.tx_bytes += PKTLEN(radioPacket);
+ }
+ stats.tx_pkts++;
+}
+
+void icmp_unreachable(struct split_ip_msg *msg) {
+
+}
+
+/*
+ * this function takes a complete IP packet, and sends it out to a
+ * destination in the PAN. It will insert source routing headers and
+ * recompute L4 checksums as necessary.
+ *
+ */
+uint8_t ip_to_pan(struct split_ip_msg *msg) {
+ uint16_t dest;
+
+ debug("ip_to_pan\n");
+ print_ip_packet(msg);
+
+ // if this packet has a source route (rinstall header, or prexisting
+ // source header, we don't want to mess with it
+ switch (routing_is_onehop(msg)) {
+ case ROUTE_MHOP:
+ debug("Multihop packet");
+ if (routing_insert_route(msg)) goto fail;
+ break;
+
+ case ROUTE_NO_ROUTE:
+ info("destination unreachable: 0x%x: dropping\n", ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
+ return 0;
+ }
+
+
+ dest = routing_get_nexthop(msg);
+ debug("next hop: 0x%x\n", dest);
+ send_fragments(msg, dest);
+ return 0;
+ fail:
+ error("ip_to_pan: no route to host\n");
+ return 1;
+}
+
+void upd_source_route(struct source_header *sh, hw_addr_t addr) {
+ if (sh->current < SH_NENTRIES(sh)) {
+ sh->hops[sh->current] = leton16(addr);
+ sh->current++;
+ }
+}
+
+int remove_sourceroute(struct split_ip_msg *msg) {
+ struct source_header *sh;
+ struct rinstall_header *rih;
+ struct generic_header *g_hdr;
+ uint8_t removeSource = 1;
+ if (msg->hdr.nxt_hdr == NXTHDR_SOURCE) {
+ sh = msg->headers->hdr.sh;
+ upd_source_route(sh, msg->metadata.sender);
+
+ // Our thinking here is that if something is source_routed
+ // from inside the network and it is not destined to us
+ // then its either a rinstall being forwarded, or a path
+ // that's been set up, so we shouldn't strip it away
+ if (cmpPfx(msg->hdr.ip6_dst.s6_addr, __my_address.s6_addr) &&
+ msg->hdr.ip6_dst.s6_addr16[7] != __my_address.s6_addr16[7]) {
+/* ((msg->hdr.ip6_dst.s6_addr[14] != __my_address[14] || */
+/* msg->hdr.ip6_dst.s6_addr[15] != __my_address[15]))) { */
+ info("Packet with source header not destined for me\n");
+
+ if ((sh->dispatch & IP_EXT_SOURCE_INVAL) != IP_EXT_SOURCE_INVAL) {
+ debug("Removing invalid source header\n");
+ removeSource = 0;
+ }
+
+ if ((sh->dispatch & IP_EXT_SOURCE_CONTROLLER) == IP_EXT_SOURCE_CONTROLLER) {
+ debug("WE sent this packet! dropping...\n");
+ return 1;
+ }
+
+
+ // If this is an rinstall header moving through, we need to
+ // updated the current position of the path, similar to
+ // what we do for source headers.
+ if (sh->nxt_hdr == NXTHDR_INSTALL) {
+ rih = msg->headers->next->hdr.rih;
+ rih->current++;
+ info("Incrementing current of rih to 0x%x\n", rih->current);
+ }
+ }
+ if (removeSource) {
+ msg->hdr.nxt_hdr = sh->nxt_hdr;
+ msg->hdr.plen = htons(ntohs(msg->hdr.plen) - sh->len);
+ g_hdr = msg->headers;
+ msg->headers = msg->headers->next;
+ free(g_hdr);
+ }
+ }
+ return 0;
+}
+
+
+void handle_serial_packet(struct split_ip_msg *msg) {
+ path_t* tPath;
+ path_t* i;
+#ifdef DBG_TRACK_FLOWS
+ uint8_t flags = 0x00;
+#endif
+ if (ntohs(msg->hdr.plen) > INET_MTU - sizeof(struct ip6_hdr)) {
+ warn("handle_ip_packet: too long: 0x%x\n", ntohs(msg->hdr.plen));
+ return;
+ }
+
+ // print_ip_packet(msg);
+ // if this packet has a source route that we inserted, we need to
+ // drop it to prevent loops.
+ if (remove_sourceroute(msg))
+ return;
+ routing_proc_msg(msg);
+ remove_sourceroute(msg);
+
+ if (cmpPfx(msg->hdr.ip6_dst.s6_addr, __my_address.s6_addr) &&
+ msg->hdr.ip6_dst.s6_addr16[7] != __my_address.s6_addr16[7]) {
+/* ((msg->hdr.ip6_dst.s6_addr[14] != __my_address[14] || */
+/* msg->hdr.ip6_dst.s6_addr[15] != __my_address[15]))) { */
+ info("Received packet destined to 0x%x\n", msg->hdr.ip6_dst.s6_addr[15]);
+
+ // If this packet is not source routed, check to see if we're on the best path before
+ // issuing a route install
+ if (msg->hdr.nxt_hdr != NXTHDR_SOURCE) {
+ tPath = nw_get_route(ntohs(msg->hdr.ip6_src.s6_addr16[7]), ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
+ for (i = tPath; i != NULL; i = i->next) {
+ if (i->node == ntohs(__my_address.s6_addr16[7])) {
+ info("Not installing route for packet from 0x%x to 0x%x (on best path)\n",
+ ntohs(msg->hdr.ip6_src.s6_addr16[7]), ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
+ nw_free_path(tPath);
+ ip_to_pan(msg);
+ return;
+ }
+ }
+ nw_free_path(tPath);
+ }
+
+ // We send the route installation packet before forwarding the actual
+ // packet, with the thinking being that the route can be set up, in
+ // case acks are issued by the destination on the packet
+ //
+ // We have to first select the flags that we want:
+
+ // At this point, if it's not source routed, then this packet
+ // shouldn't be coming through us so we install a route
+ if (msg->hdr.nxt_hdr != NXTHDR_SOURCE) {
+ info("installing route for packet from 0x%x to 0x%x\n",
+ ntohs(msg->hdr.ip6_src.s6_addr16[7]), ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
+ } else {
+ info("Packet had a source header so no route install\n");
+ }
+ stats.fw_pkts++;
+ ip_to_pan(msg);
+ // do routing
+ } else {
+ // give it to linux
+ // need to remove route info here.
+ stats.rx_pkts++;
+ tun_write(tun_fd, msg);
+ debug("tun_write: wrote 0x%x bytes\n", sizeof(struct ip6_hdr) + ntohs(msg->hdr.plen));
+ }
+}
+
+void add_header_list(struct split_ip_msg *msg) {
+ uint8_t nxt_hdr;
+ struct generic_header *g_hdr, **g_list;
+ struct ip6_ext *ext = (struct ip6_ext *)msg->next;
+ uint16_t hdr_len = 0;
+ debug("add_header_list for message destined to 0x%x\n", ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
+ nxt_hdr = msg->hdr.nxt_hdr;
+ msg->headers = NULL;
+ g_list = &(msg->headers);
+ while (KNOWN_HEADER(nxt_hdr)) {
+ g_hdr = (struct generic_header *)malloc(sizeof(struct generic_header));
+ g_hdr->payload_malloced = 0;
+ g_hdr->hdr.ext = ext;
+ g_hdr->next = NULL;
+ *g_list = g_hdr;
+ g_list = &g_hdr->next;
+
+ switch(nxt_hdr) {
+ case IANA_UDP:
+ // a UDP header terminates a chain of headers we can compress...
+ g_hdr->len = sizeof(struct udp_hdr);
+ ext = (struct ip6_ext *)(((uint8_t *)ext) + sizeof(struct udp_hdr));
+ nxt_hdr = NXTHDR_UNKNOWN;
+ break;
+ // XXX : SDH : these are all "ip extension" headers and so can be treated genericlly.
+ case NXTHDR_INSTALL:
+ info("inserted NXTHDR_INSTALL\n");
+ case NXTHDR_TOPO:
+ case NXTHDR_SOURCE:
+ g_hdr->len = ext->len;
+
+ nxt_hdr = ext->nxt_hdr;
+ ext = (struct ip6_ext *)(((uint8_t *)ext) + ext->len);
+ break;
+ default:
+ // TODO : SDH : discard the packet here since we can get in a
+ // bad place with invalid header types. this isn't all that
+ // likely, but you never know.
+ break;
+ }
+ hdr_len += g_hdr->len;
+ }
+ msg->data = (uint8_t *)ext;
+ msg->data_len = ntohs(msg->hdr.plen) - hdr_len;
+}
+
+/*
+ * read data from the tun device and send it to the serial port
+ * does also fragmentation
+ */
+int tun_input()
+{
+ uint8_t buf[sizeof(struct split_ip_msg) + INET_MTU];
+ struct split_ip_msg *msg = (struct split_ip_msg *)buf;
+ int len;
+
+ len = tun_read(tun_fd, (void *)(&msg->pi), INET_MTU + sizeof(struct ip6_hdr));
+
+ if (len <= 0) {
+ return 0;
+ }
+ debug("tun_read: read 0x%x bytes\n", len);
+
+ if ((msg->hdr.vlfc[0] >> 4) != IPV6_VERSION) {
+ warn("tun_read: discarding non-ip packet\n");
+ goto fail;
+ }
+ if (ntohs(msg->hdr.plen) > INET_MTU - sizeof(struct ip6_hdr)) {
+ debug("tun_input: dropping packet due to length: 0x%x\n", ntohs(msg->hdr.plen));
+ goto fail;
+ }
+ if (msg->hdr.nxt_hdr == 0) {
+ debug("tun_input: dropping packet with IPv6 options\n");
+ goto fail;
+ }
+
+ add_header_list(msg);
+#ifdef DBG_TRACK_FLOWS
+ msg->id.src = 100;
+ msg->id.dst = ntohs(msg->hdr.ip6_dst.s6_addr16[7]); //l2fromIP(msg->hdr.dst_addr);
+ msg->id.id = local_seqno++;
+ msg->id.seq = 0;
+ msg->id.nxt_hdr = msg->hdr.nxt_hdr;
+#endif
+
+ ip_to_pan(msg);
+
+ free_split_msg(msg);
+
+ return 1;
+ fail:
+ /* error("Invalid packet or version received\n"); */
+ return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+/* handling of data arriving on the serial port */
+
+reconstruct_t reconstructions [N_RECONSTRUCTIONS];
+
+void age_reconstructions() {
+ int i;
+ for (i = 0; i < N_RECONSTRUCTIONS; i++) {
+ // switch "active" buffers to "zombie"
+ if (reconstructions[i].timeout == T_ACTIVE) {
+ reconstructions[i].timeout = T_ZOMBIE;
+ } else if (reconstructions[i].timeout == T_ZOMBIE) {
+ reconstructions[i].timeout = T_UNUSED;
+ free(reconstructions[i].buf);
+ reconstructions[i].buf = NULL;
+ }
+ }
+}
+
+
+reconstruct_t *getReassembly(packed_lowmsg_t *lowmsg) {
+ int i, free_spot = N_RECONSTRUCTIONS + 1;
+ uint16_t mytag, size;
+ if (getFragDgramTag(lowmsg, &mytag)) return NULL;
+ if (getFragDgramSize(lowmsg, &size)) return NULL;
+
+ for (i = 0; i < N_RECONSTRUCTIONS; i++) {
+ if (reconstructions[i].timeout > T_UNUSED && reconstructions[i].tag == mytag) {
+ reconstructions[i].timeout = T_ACTIVE;
+ return &(reconstructions[i]);
+ }
+ if (reconstructions[i].timeout == T_UNUSED) free_spot = i;
+ }
+ // allocate a new struct for doing reassembly.
+ if (free_spot != N_RECONSTRUCTIONS + 1) {
+ // if we don't get the packet with the protocol in it first, we
+ // don't know who to ask for a buffer, and so give up.
+
+ reconstructions[free_spot].tag = mytag;
+
+ reconstructions[free_spot].size = size;
+ reconstructions[free_spot].buf = malloc(size + offsetof(struct split_ip_msg, hdr));
+ reconstructions[free_spot].bytes_rcvd = 0;
+ reconstructions[free_spot].timeout = T_ACTIVE;
+
+ debug("checking buffer size 0x%x\n", reconstructions[free_spot].size);
+ if (reconstructions[free_spot].buf == NULL) {
+ reconstructions[free_spot].timeout = T_UNUSED;
+ return NULL;
+ }
+ return &(reconstructions[free_spot]);
+ }
+ return NULL;
+}
+
+/*
+ * read data on serial port and send it to the tun interface
+ * does fragment reassembly
+ */
+int serial_input() {
+ packed_lowmsg_t pkt;
+ reconstruct_t *recon;
+ struct split_ip_msg *msg;
+#ifndef SIM
+ IEEE154_header_t *mac_hdr;
+#else
+ serial_header_t *mac_hdr;
+#endif
+
+ uint8_t *ser_data = NULL; /* data read from serial port */
+ int ser_len = 0; /* length of data read from serial port */
+ uint8_t shortMsg[INET_MTU];
+ uint8_t *payload;
+#ifdef DBG_TRACK_FLOWS
+ struct flow_id *fl_id;
+#endif
+
+ int rv = 1;
+
+ /* read data from serial port */
+ ser_data = (uint8_t *)read_pan_packet(&ser_len);
+
+ /* process the packet we have received */
+ if (ser_len && ser_data) {
+#ifndef SIM
+ if (ser_data[0] != TOS_SERIAL_802_15_4_ID) {
+ handle_other_pkt(ser_data, ser_len);
+ goto discard_packet;
+ }
+ mac_hdr = (IEEE154_header_t *)(ser_data + 1);
+
+#ifdef DBG_TRACK_FLOWS
+ fl_id = (struct flow_id *)(ser_data + 1 + sizeof(IEEE154_header_t));
+
+ // size is one for the length byte, minus two for the checksum
+ pkt.len = mac_hdr->length - MAC_HEADER_SIZE - MAC_FOOTER_SIZE - sizeof(struct flow_id);
+ // add one for the dispatch byte.
+ pkt.data = ser_data + 1 + sizeof(IEEE154_header_t) + sizeof(struct flow_id);
+#else
+ // size is one for the length byte, minus two for the checksum
+ pkt.len = mac_hdr->length - MAC_HEADER_SIZE - MAC_FOOTER_SIZE;
+ // add one for the dispatch byte.
+ pkt.data = ser_data + 1 + sizeof(IEEE154_header_t);
+#endif // DBG_TRACK_FLOWS
+
+ // for some reason these are little endian so we don't do any conversion.
+ pkt.src = mac_hdr->src;
+ pkt.dst = mac_hdr->dest;
+#else
+ mac_hdr = (serial_header_t *)(ser_data + 1);
+
+ if (mac_hdr->type != 0) {
+ goto discard_packet;
+ }
+
+#ifdef DBG_TRACK_FLOWS
+ fl_id = (struct flow_id *)(ser_data + 1 + sizeof(serial_header_t));
+ pkt.len = mac_hdr->length - sizeof(struct flow_id);
+ pkt.data = ser_data + 1 + sizeof(serial_header_t) + sizeof(struct flow_id);
+#else
+ pkt.len = mac_hdr->length;;
+ pkt.data = ser_data + 1 + sizeof(serial_header_t);
+#endif // DBG_TRACK_FLOWS
+
+ // except in serial packets, they __are__ little endian...
+ pkt.src = ntohs(mac_hdr->src);
+ pkt.dst = ntohs(mac_hdr->dest);
+#endif
+
+ debug("serial_input: read 0x%x bytes\n", ser_len);
+
+ pkt.headers = getHeaderBitmap(&pkt);
+ if (pkt.headers == LOWPAN_NALP_PATTERN) goto discard_packet;
+
+ stats.rx_frags++;
+ stats.rx_bytes += ser_len - 1;
+ if (hasFrag1Header(&pkt) || hasFragNHeader(&pkt)) {
+ unpack_info_t u_info;
+ uint8_t amount_here;
+
+ recon = getReassembly(&pkt);
+ if (recon == NULL || recon->buf == NULL) goto discard_packet;
+ msg = (struct split_ip_msg *)recon->buf;
+
+ if (hasFrag1Header(&pkt)) {
+ if (unpackHeaders(&pkt, &u_info,
+ (uint8_t *)&msg->hdr, recon->size) == NULL) goto discard_packet;
+ amount_here = pkt.len - (u_info.payload_start - pkt.data);
+ ip_memcpy(u_info.header_end, u_info.payload_start, amount_here);
+ recon->bytes_rcvd = sizeof(struct ip6_hdr) + u_info.payload_offset + amount_here;
+ } else {
+ uint8_t offset_cmpr;
+ uint16_t offset;
+ if (getFragDgramOffset(&pkt, &offset_cmpr)) goto discard_packet;
+ offset = offset_cmpr * 8;
+ payload = getLowpanPayload(&pkt);
+ amount_here = pkt.len - (payload - pkt.data);
+
+ if (offset + amount_here > recon->size) goto discard_packet;
+ ip_memcpy(((uint8_t *)&msg->hdr) + offset, payload, amount_here);
+ recon->bytes_rcvd += amount_here;
+
+ if (recon->size == recon->bytes_rcvd) {
+ // got all the fragments...
+ debug ("serial: reconstruction finished\n");
+ add_header_list(msg);
+
+ msg->metadata.sender = pkt.src;
+
+ handle_serial_packet(msg);
+
+ recon->timeout = T_UNUSED;
+ free_split_msg(msg);
+ free(recon->buf);
+ }
+ }
+
+ } else {
+ unpack_info_t u_info;
+ u_info.rih = NULL;
+ msg = (struct split_ip_msg *)shortMsg;
+ if (unpackHeaders(&pkt, &u_info,
+ (uint8_t *)&msg->hdr, INET_MTU) == NULL) goto discard_packet;
+ if (ntohs(msg->hdr.plen) > INET_MTU - sizeof(struct ip6_hdr)) goto discard_packet;
+
+ msg->metadata.sender = pkt.src;
+ if (u_info.rih != NULL)
+ info("Has a rinstall_header for src 0x%x with match: 0x%x\n",
+ pkt.src, ntohs(u_info.rih->match.dest));;
+
+ ip_memcpy(u_info.header_end, u_info.payload_start, ntohs(msg->hdr.plen));
+#ifdef DBG_TRACK_FLOWS
+ ip_memcpy(&msg->id, fl_id, sizeof(struct flow_id));
+#endif
+
+ add_header_list(msg);
+
+ handle_serial_packet(msg);
+ free_split_msg(msg);
+ }
+ } else {
+ //printf("no data on serial port, but FD triggered select\n");
+ rv = 0;
+ }
+ discard_packet:
+ // debug("serial_input: discard packet\n");
+ free(ser_data);
+ return rv;
+}
+
+void print_stats() {
+ printf("Up since %s", ctime(&stats.boot_time));
+ printf(" receive packets: %lu fragments: %lu bytes: %lu\n",
+ stats.tx_pkts, stats.tx_frags, stats.tx_bytes);
+ printf(" transmit packets: %lu fragments: %lu bytes: %lu\n",
+ stats.rx_pkts, stats.rx_frags, stats.rx_bytes);
+ printf(" forward packets: %lu\n", stats.fw_pkts);
+}
+
+int eval_cmd(char *cmd) {
+ char arg[1024];
+ int int_arg;
+ switch (cmd[0]) {
+ case 'c':
+ config_print(&driver_config);
+ return 0;
+ case 'd':
+ if (sscanf(cmd, "d %s\n", arg) == 1) {
+ nw_print_dotfile(arg);
+ } else {
+ printf("error: include a filename!\n");
+ }
+ return 0;
+ case 'i':
+ if (sscanf(cmd, "i %i\n", &int_arg) == 1) {
+ info("invalidating node 0x%x\n", int_arg);
+ nw_inval_node(int_arg);
+ }
+ return 0;
+ case 'l':
+ nw_print_links();
+ return 0;
+ case 'p':
+ nw_print_routes();
+ return 0;
+ case 's':
+ print_stats();
+ return 0;
+ case 't':
+ nw_test_routes();
+ return 0;
+ case 'v':
+ if (sscanf(cmd, "v %s\n", arg) == 1) {
+ int i;
+ for (i = 0; i < 5; i++) {
+ if (strcmp(log_names[i], arg) == 0) {
+ printf("setting verbosity to %s\n", log_names[i]);
+ log_setlevel(i);
+ }
+ }
+ }
+ return 0;
+ case 'h':
+ default:
+ printf("ip-driver console\n");
+ printf(" c: print configuration info\n");
+ printf(" d <dotfile>: print dot-file of topology\n");
+ printf(" i <nodeid>: invalidate a router\n");
+ printf(" l: print link detail\n");
+ printf(" p: print routes\n");
+ printf(" t: recalculate routes\n");
+ printf(" v {DEBUG INFO WARN ERROR FATAL}: set verbosity\n");
+ printf(" s: print statistics\n");
+ printf("\n");
+ printf(" h: print this help\n");
+ }
+
+ return 0;
+}
+
+/* shifts data between the serial port and the tun interface */
+int serial_tunnel(int tun_fd) {
+ char cmd_buf[2][1024], *cmd_cur;
+ int cur_buf = 0;
+ fd_set fs;
+ int maxfd = 0;
+ time_t last_aging, current_time;
+ time(&last_aging);
+#ifndef SIM
+ int pan_fd = serial_source_fd(ser_src);
+#else
+ int pan_fd = sf_fd;
+#endif
+ cmd_cur = cmd_buf[0];
+
+ /* disable input buffering on stdin since we're going to accumulate
+ the input outselves, and don't want to block */
+ if (isatty(fileno(stdin))) {
+ struct termios tio;
+ /* disable it on the fd */
+ if (tcgetattr(fileno(stdin), &tio))
+ return -1;
+ tio.c_lflag &= ~ICANON;
+ if (tcsetattr(fileno(stdin), TCSANOW, &tio))
+ return -1;
+ /* and also in libc */
+ setbuf(stdin, NULL);
+ }
+
+ while (1) {
+ FD_ZERO(&fs);
+ FD_SET(tun_fd, &fs);
+ FD_SET(pan_fd, &fs);
+
+ maxfd = max(tun_fd, pan_fd);
+ if (isatty(fileno(stdin))) {
+ FD_SET(fileno(stdin), &fs);
+ maxfd = max(fileno(stdin), maxfd);
+ }
+ if (radvd_fd >= 0) {
+ FD_SET(radvd_fd, &fs);
+ maxfd = max(radvd_fd, maxfd);
+ }
+
+ if (select(maxfd + 1, &fs, NULL, NULL, NULL) < 0)
+ continue;
+
+
+ /* data available on tunnel device */
+ if (FD_ISSET(tun_fd, &fs))
+ while(tun_input());
+
+ if (FD_ISSET(pan_fd, &fs))
+ while(serial_input());
+
+ if (FD_ISSET(fileno(stdin), &fs)) {
+ *cmd_cur++ = getc(stdin);
+ if (*(cmd_cur - 1) == '\n' ||
+ cmd_cur - cmd_buf[cur_buf] == 1024) {
+ *cmd_cur = '\0';
+ if (cmd_cur == cmd_buf[cur_buf] + 1) {
+ eval_cmd(cmd_buf[(cur_buf + 1) % 2]);
+ } else {
+ eval_cmd(cmd_buf[cur_buf]);
+ cur_buf = (cur_buf + 1) % 2;
+ }
+ cmd_cur = cmd_buf[cur_buf];
+ }
+ }
+
+ if (radvd_fd >= 0 && FD_ISSET(radvd_fd, &fs)) {
+ radvd_process();
+ }
+
+#ifndef SIM
+/* if (tcdrain(pan_fd) < 0) { */
+/* fatal("tcdrain error: %i\n", errno); */
+/* exit(3); */
+/* } */
+#endif
+
+ /* end of data available */
+ time(¤t_time);
+ if (current_time > last_aging + (FRAG_EXPIRE_TIME / 1024)) {
+ last_aging = current_time;
+ age_reconstructions();
+ }
+ }
+
+ return 0;
+}
+
+#ifdef DBG_TRACK_FLOWS
+void truncate_dbg() {
+ ftruncate(fileno(dbg_file), 0);
+}
+#endif
+
+int main(int argc, char **argv) {
+ int i, c;
+
+ time(&stats.boot_time);
+
+ log_init();
+ while ((c = getopt(argc, argv, "c:")) != -1) {
+ switch (c) {
+ case 'c':
+ def_configfile = optarg;
+ break;
+ default:
+ fatal("Invalid command line argument.\n");
+ exit(1);
+ }
+ }
+
+ if (argc - optind != 2) {
+#ifndef SIM
+ fatal("usage: %s [-c config] <device> <rate>\n", argv[0]);
+#else
+ fatal("usage: %s [-c config] <host> <port>\n", argv[0]);
+#endif
+ exit(2);
+ }
+
+#ifdef DBG_TRACK_FLOWS
+ dbg_file = fopen("dbg.txt", "w");
+ if (dbg_file == NULL) {
+ perror("main: opening dbg file:");
+ exit(1);
+ }
+ signal(SIGUSR2, truncate_dbg);
+#endif
+
+ if (config_parse(def_configfile, &driver_config) != 0) {
+ fatal ("config parse of %s failed!\n", def_configfile);
+ exit(1);
+ }
+ globalPrefix = 1;
+ memcpy(&__my_address, &driver_config.router_addr, sizeof(struct in6_addr));
+
+ /* create the tunnel device */
+ dev[0] = 0;
+ tun_fd = tun_open(dev);
+ if (tun_fd < 1) {
+ fatal("Could not create tunnel device. Fatal.\n");
+ return 1;
+ } else {
+ info("created tun device: %s\n", dev);
+ }
+ if (tun_setup(dev, &__my_address) < 0) {
+ fatal("configuring the tun failed; aborting\n");
+ perror("tun_setup");
+ return 1;
+ }
+
+
+ for (i = 0; i < N_RECONSTRUCTIONS; i++) {
+ reconstructions[i].timeout = T_UNUSED;
+ }
+
+ /* open the serial port */
+#ifndef SIM
+ ser_src = open_serial_source(argv[optind], platform_baud_rate(argv[optind + 1]),
+ 1, stderr_msg);
+ if (!ser_src) {
+ fatal("Couldn't open serial port at %s:%s\n", argv[optind], argv[optind + 1]);
+ exit(1);
+ }
+#else
+ sf_fd = open_sf_source(argv[optind], atoi(argv[optind + 1]));
+ if (sf_fd < 0) {
+ fatal("Couldn't connect to serial forwarder sf@%s:%s\n", argv[optind], argv[optind + 1]);
+ 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;
+}
--- /dev/null
+/*
+ * "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);
+}
--- /dev/null
+/*
+ * "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
--- /dev/null
+/*
+ * "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;
+}
--- /dev/null
+/*
+ * "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."
+ *
+ */
+
+
+/*
+ * Header file for the 6lowpan/IPv6 stack.
+ *
+ * @author Stephen Dawson-Haggerty
+ *
+ */
+
+#ifndef __6LOWPAN_H__
+#define __6LOWPAN_H__
+
+#include <stdint.h>
+/*
+ * Typedefs and static library data.
+ */
+typedef uint8_t ip6_addr_t [16];
+typedef uint16_t cmpr_ip6_addr_t;
+#ifdef PC
+typedef uint16_t hw_addr_t;
+typedef uint16_t hw_pan_t;
+enum {
+ HW_BROADCAST_ADDR = 0xffff,
+};
+#else
+#include <IEEE802154.h>
+#endif
+
+/*
+ * shared variables which contain addressing information for 6lowpan
+ * devices
+ */
+extern uint8_t globalPrefix;
+extern uint8_t multicast_prefix[8];
+extern uint8_t linklocal_prefix[8];
+
+uint8_t cmpPfx(ip6_addr_t a, uint8_t *pfx);
+
+void ip_memclr(uint8_t *buf, uint16_t len);
+void *ip_memcpy(void *dst0, const void *src0, uint16_t len);
+
+/*
+ * A packed 6lowpan packet.
+ *
+ * The data buffer points at the start of 6lowpan packed data. We
+ * included a few other fields from L2 with this information so that
+ * we are able to infer things like source and destination IP from it.
+ *
+ */
+typedef struct packed_lowmsg {
+ uint8_t headers;
+ uint8_t len;
+ // we preprocess the headers bitmap for easy processing.
+ hw_addr_t src;
+ hw_addr_t dst;
+ uint8_t *data;
+} packed_lowmsg_t;
+
+/*
+ * bit fields we use to keep track of which optional header fields are
+ * present in a message
+ */
+enum {
+ LOWMSG_MESH_HDR = (1 << 0),
+ LOWMSG_BCAST_HDR = (1 << 1),
+ LOWMSG_FRAG1_HDR = (1 << 2),
+ LOWMSG_FRAGN_HDR = (1 << 3),
+ LOWMSG_NALP = (1 << 4),
+ LOWMSG_IPNH_HDR = (1 << 5),
+};
+
+/*
+ * lengths of different lowpan headers
+ */
+enum {
+ LOWMSG_MESH_LEN = 5,
+ LOWMSG_BCAST_LEN = 2,
+ LOWMSG_FRAG1_LEN = 4,
+ LOWMSG_FRAGN_LEN = 5,
+};
+
+enum {
+ LOWPAN_LINK_MTU = 110,
+ INET_MTU = 1280,
+ LIB6LOWPAN_MAX_LEN = LOWPAN_LINK_MTU,
+};
+
+/*
+ * magic numbers from rfc4944; some of them shifted: mostly dispatch values.
+ */
+enum {
+ LOWPAN_NALP_PATTERN = 0x0,
+ LOWPAN_MESH_PATTERN = 0x2,
+ LOWPAN_FRAG1_PATTERN = 0x18,
+ LOWPAN_FRAGN_PATTERN = 0x1c,
+ LOWPAN_BCAST_PATTERN = 0x50,
+ LOWPAN_HC1_PATTERN = 0x42,
+ LOWPAN_HC_LOCAL_PATTERN = 0x3,
+ LOWPAN_HC_CRP_PATTERN = 0x4,
+};
+
+enum {
+ LOWPAN_MESH_V_MASK = 0x20,
+ LOWPAN_MESH_F_MASK = 0x10,
+ LOWPAN_MESH_HOPS_MASK = 0x0f,
+};
+
+/*
+ * IP protocol numbers
+ */
+enum {
+ IANA_ICMP = 58,
+ IANA_UDP = 17,
+ IANA_TCP = 6,
+
+ NXTHDR_SOURCE = 0,
+ NXTHDR_INSTALL = 253, // Use for experimentation and testing(IANA.org)
+ NXTHDR_TOPO = 252,
+ NXTHDR_UNKNOWN = 0xff,
+};
+
+#define KNOWN_HEADER(X) ((X) == NXTHDR_SOURCE || (X) == IANA_UDP || (X) == NXTHDR_INSTALL || (X) == NXTHDR_TOPO)
+
+/*
+ * constants to unpack HC-packed headers
+ */
+enum {
+ LOWPAN_IPHC_VTF_MASK = 0x80,
+ LOWPAN_IPHC_VTF_INLINE = 0,
+ LOWPAN_IPHC_NH_MASK = 0x40,
+ LOWPAN_IPHC_NH_INLINE = 0,
+ LOWPAN_IPHC_HLIM_MASK = 0x20,
+ LOWPAN_IPHC_HLIM_INLINE = 0,
+
+ LOWPAN_IPHC_SC_OFFSET = 3,
+ LOWPAN_IPHC_DST_OFFSET = 1,
+ LOWPAN_IPHC_ADDRFLAGS_MASK = 0x3,
+
+ LOWPAN_IPHC_ADDR_128 = 0x0,
+ LOWPAN_IPHC_ADDR_64 = 0x1,
+ LOWPAN_IPHC_ADDR_16 = 0x2,
+ LOWPAN_IPHC_ADDR_0 = 0x3,
+
+ LOWPAN_IPHC_SHORT_MASK = 0x80,
+ LOWPAN_IPHC_SHORT_LONG_MASK= 0xe0,
+
+ LOWPAN_IPHC_HC1_MCAST = 0x80,
+ LOWPAN_IPHC_HC_MCAST = 0xa0,
+
+ LOWPAN_HC_MCAST_SCOPE_MASK = 0x1e,
+ LOWPAN_HC_MCAST_SCOPE_OFFSET = 1,
+
+ LOWPAN_UDP_PORT_BASE_MASK = 0xfff0,
+ LOWPAN_UDP_PORT_BASE = 0xf0b0,
+ LOWPAN_UDP_DISPATCH = 0x80,
+
+ LOWPAN_UDP_S_MASK = 0x40,
+ LOWPAN_UDP_D_MASK = 0x20,
+ LOWPAN_UDP_C_MASK = 0x10,
+};
+
+
+/*
+ * nonstandard source routing header fields
+ */
+enum {
+ IP_EXT_SOURCE_DISPATCH = 0x40,
+ IP_EXT_SOURCE_MASK = 0xc0,
+
+ // dispatch values
+ IP_EXT_SOURCE_RECORD = 0x01,
+ IP_EXT_SOURCE_RECORD_MASK = 0x01,
+ IP_EXT_SOURCE_INVAL = 0x02,
+ IP_EXT_SOURCE_INVAL_MASK = 0x02,
+ IP_EXT_SOURCE_CONTROLLER = 0x04,
+
+ // dispatch values for route installation if this flag is set, the
+ // source_header must be immediately followed by a
+ // source_install_opt struct.
+ IP_EXT_SOURCE_INSTALL = 0x10,
+ IP_EXT_SOURCE_INSTALL_MASK= 0x10,
+
+ // indicates weather the forward and reverse paths should be
+ // installed. Are these needed? the only case when we don't want
+ // to install the reverse path is when the destination is a
+ // multicast?
+ IP_EXT_SOURCE_INST_SRC = 0x20,
+ IP_EXT_SOURCE_INST_DST = 0x40,
+};
+
+#define SH_NENTRIES(SH) ((sh->len - (sizeof(struct source_header))) / (sizeof(uint16_t)))
+
+struct source_header {
+ uint8_t nxt_hdr;
+ uint8_t len;
+ // the equalivent of the "routing type" field
+ uint8_t dispatch;
+ uint8_t current;
+ uint16_t hops[0];
+};
+
+// AT: These are really 16 bit values, but after a certain point the numbers
+// beyond 255 aren't important to us, or rather no different than 255
+struct topology_entry {
+ uint8_t etx;
+ uint8_t conf;
+ hw_addr_t hwaddr;
+};
+struct topology_header {
+ uint8_t nxt_hdr;
+ uint8_t len;
+ struct topology_entry topo[0];
+};
+
+enum {
+ IP_NUMBER_FRAGMENTS = 12,
+};
+
+#endif
--- /dev/null
+/*
+ * "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 _IEEE154_H_
+#define _IEEE154_H_
+
+typedef struct IEEE154_header {
+ uint8_t length;
+ uint16_t fcf;
+ uint8_t dsn;
+ uint16_t destpan;
+ uint16_t dest;
+ uint16_t src;
+} __attribute__((packed)) IEEE154_header_t;
+
+typedef struct serial_header {
+ uint16_t dest;
+ uint16_t src;
+ uint8_t length;
+ uint8_t group;
+ uint8_t type;
+} __attribute__((packed)) serial_header_t;
+
+enum {
+ // size of the header not including the length byte
+ MAC_HEADER_SIZE = sizeof( IEEE154_header_t ) - 1,
+ // size of the footer (FCS field)
+ MAC_FOOTER_SIZE = sizeof( uint16_t ),
+};
+
+#endif
--- /dev/null
+/*
+ * "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 _CONFIGURE_H_
+#define _CONFIGURE_H_
+
+#include "6lowpan.h"
+
+enum {
+ CONFIG_ECHO = 0, // ping the device for status information
+ CONFIG_SET_PARM = 1, // instruct the device to set its hardware addr
+ CONFIG_REBOOT = 2,
+};
+
+enum {
+ CONFIG_ERROR_OK,
+ CONFIG_ERROR_FAIL,
+ CONFIG_ERROR_BOOTED,
+};
+
+#ifndef PC
+
+
+typedef nx_struct config_cmd {
+ nx_uint8_t cmd;
+ nx_struct {
+ nx_uint16_t retries;
+ nx_uint16_t delay;
+ } retx;
+ nx_struct {
+ nx_uint16_t addr;
+ nx_uint8_t channel;
+ } rf;
+} config_cmd_t;
+
+
+typedef nx_struct {
+ nx_uint8_t error;
+ nx_uint16_t addr;
+ nx_uint16_t serial_read;
+ nx_uint16_t radio_read;
+ nx_uint16_t serial_fail;
+ nx_uint16_t radio_fail;
+} config_reply_t;
+
+#else
+
+enum {
+ CONFIGURE_MSG_SIZE = 8,
+};
+typedef struct config_cmd {
+ uint8_t cmd;
+ struct {
+ uint16_t retries;
+ uint16_t delay;
+ } retx;
+ struct {
+ hw_addr_t addr;
+ uint8_t channel;
+ } rf;
+} __attribute__((packed)) config_cmd_t;
+
+
+
+typedef struct {
+ uint8_t error;
+ hw_addr_t addr;
+ uint16_t serial_read;
+ uint16_t radio_read;
+ uint16_t serial_fail;
+ uint16_t radio_fail;
+} __attribute__((packed)) config_reply_t;
+
+enum {
+ TOS_SERIAL_802_15_4_ID = 2,
+ TOS_SERIAL_DEVCONF = 3,
+};
+
+#endif
+
+#endif
+
--- /dev/null
+/*
+ * "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 _IN_CKSUM_H_
+#define _IN_CKSUM_H_
+
+/* in_cksum.h
+ * Declaration of Internet checksum routine.
+ *
+ * $Id$
+ */
+
+#include <stdint.h>
+#include "ip.h"
+
+typedef struct {
+ const uint8_t *ptr;
+ int len;
+} vec_t;
+
+extern int in_cksum(const vec_t *vec, int veclen);
+
+// extern uint16_t in_cksum(const vec_t *vec, int veclen);
+
+extern uint16_t msg_cksum(struct split_ip_msg *msg, uint8_t nxt_hdr);
+
+#endif
--- /dev/null
+/*
+ * "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 _IP_H_
+#define _IP_H_
+
+/*
+ * define message structures for internet communication
+ *
+ */
+
+#ifdef PC
+#include <linux/if_tun.h>
+#include <netinet/in.h>
+#endif
+
+#include "6lowpan.h"
+
+enum {
+ /*
+ * The time, in binary milliseconds, after which we stop waiting for
+ * fragments and report a failed receive. We
+ */
+ FRAG_EXPIRE_TIME = 4096,
+};
+
+
+#ifndef PC
+// update to use netinet/in definition of an IPv6 address; this is a
+// lot more elegent.
+struct in6_addr
+ {
+ union
+ {
+ uint8_t u6_addr8[16];
+ uint16_t u6_addr16[8];
+ uint32_t u6_addr32[4];
+ } in6_u;
+#define s6_addr in6_u.u6_addr8
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+ };
+
+struct sockaddr_in6 {
+ uint16_t sin6_port;
+ struct in6_addr sin6_addr;
+};
+#endif
+
+/*
+ * Definition for internet protocol version 6.
+ * RFC 2460
+ */
+struct ip6_hdr {
+ uint8_t vlfc[4];
+ uint16_t plen; /* payload length */
+ uint8_t nxt_hdr; /* next header */
+ uint8_t hlim; /* hop limit */
+ struct in6_addr ip6_src; /* source address */
+ struct in6_addr ip6_dst; /* destination address */
+} __attribute__((packed));
+
+#define IPV6_VERSION 0x6
+#define IPV6_VERSION_MASK 0xf0
+
+
+/*
+ * Extension Headers
+ */
+
+struct ip6_ext {
+ uint8_t nxt_hdr;
+ uint8_t len;
+ uint8_t data[0];
+};
+
+/*
+ * icmp
+ */
+struct icmp6_hdr {
+ uint8_t type; /* type field */
+ uint8_t code; /* code field */
+ uint16_t cksum; /* checksum field */
+};
+
+enum {
+ ICMP_TYPE_ECHO_DEST_UNREACH = 1,
+ ICMP_TYPE_ECHO_PKT_TOO_BIG = 2,
+ ICMP_TYPE_ECHO_TIME_EXCEEDED = 3,
+ ICMP_TYPE_ECHO_PARAM_PROBLEM = 4,
+ ICMP_TYPE_ECHO_REQUEST = 128,
+ ICMP_TYPE_ECHO_REPLY = 129,
+ ICMP_TYPE_ROUTER_SOL = 133,
+ ICMP_TYPE_ROUTER_ADV = 134,
+ ICMP_TYPE_NEIGHBOR_SOL = 135,
+ ICMP_TYPE_NEIGHBOR_ADV = 136,
+ ICMP_NEIGHBOR_HOPLIMIT = 255,
+
+ ICMP_CODE_HOPLIMIT_EXCEEDED = 0,
+ ICMP_CODE_ASSEMBLY_EXCEEDED = 1,
+};
+
+/*
+ * UDP protocol header.
+ */
+struct udp_hdr {
+ uint16_t srcport; /* source port */
+ uint16_t dstport; /* destination port */
+ uint16_t len; /* udp length */
+ uint16_t chksum; /* udp checksum */
+};
+
+/*
+ * TCP transport headers and flags
+ */
+enum {
+ TCP_FLAG_FIN = 0x1,
+ TCP_FLAG_SYN = 0x2,
+ TCP_FLAG_RST = 0x4,
+ TCP_FLAG_PSH = 0x8,
+ TCP_FLAG_ACK = 0x10,
+ TCP_FLAG_URG = 0x20,
+ TCP_FLAG_ECE = 0x40,
+ TCP_FLAG_CWR = 0x80,
+};
+
+struct tcp_hdr {
+ uint16_t srcport;
+ uint16_t dstport;
+ uint32_t seqno;
+ uint32_t ackno;
+ uint8_t offset;
+ uint8_t flags;
+ uint16_t window;
+ uint16_t chksum;
+ uint16_t urgent;
+};
+
+/*
+ * IP metadata and routing structures
+ */
+struct ip_metadata {
+ hw_addr_t sender;
+ uint8_t lqi;
+ uint8_t padding[1];
+};
+
+struct flow_match {
+ cmpr_ip6_addr_t src;
+ cmpr_ip6_addr_t dest; // Need to make this more extensible at some point
+ cmpr_ip6_addr_t prev_hop;
+};
+
+struct rinstall_header {
+ struct ip6_ext ext;
+ uint16_t flags;
+ struct flow_match match;
+ uint8_t path_len;
+ uint8_t current;
+ cmpr_ip6_addr_t path[0];
+};
+
+enum {
+ R_SRC_FULL_PATH_INSTALL_MASK = 0x01,
+ R_DEST_FULL_PATH_INSTALL_MASK = 0x02,
+ R_HOP_BY_HOP_PATH_INSTALL_MASK = 0x04,
+ R_REVERSE_PATH_INSTALL_MASK = 0x08,
+ R_SRC_FULL_PATH_UNINSTALL_MASK = 0x10,
+ R_DEST_FULL_PATH_UNINSTALL_MASK = 0x20,
+ R_HOP_BY_HOP_PATH_UNINSTALL_MASK = 0x40,
+ R_REVERSE_PATH_UNINSTALL_MASK = 0x80,
+};
+
+#define IS_FULL_SRC_INSTALL(r) (((r)->flags & R_SRC_FULL_PATH_INSTALL_MASK) == R_SRC_FULL_PATH_INSTALL_MASK)
+#define IS_FULL_DST_INSTALL(r) (((r)->flags & R_DEST_FULL_PATH_INSTALL_MASK) == R_DEST_FULL_PATH_INSTALL_MASK)
+#define IS_HOP_INSTALL(r) (((r)->flags & R_HOP_BY_HOP_PATH_INSTALL_MASK) == R_HOP_BY_HOP_PATH_INSTALL_MASK)
+#define IS_REV_INSTALL(r) (((r)->flags & R_REVERSE_PATH_INSTALL_MASK) == R_REVERSE_PATH_INSTALL_MASK)
+#define IS_FULL_SRC_UNINSTALL(r) (((r)->flags & R_SRC_FULL_PATH_UNINSTALL_MASK) == R_SRC_FULL_PATH_UNINSTALL_MASK)
+#define IS_FULL_DST_UNINSTALL(r) (((r)->flags & R_DEST_FULL_PATH_UNINSTALL_MASK) == R_DEST_FULL_PATH_UNINSTALL_MASK)
+#define IS_HOP_UNINSTALL(r) (((r)->flags & R_HOP_BY_HOP_PATH_UNINSTALL_MASK) == R_HOP_BY_HOP_PATH_UNINSTALL_MASK)
+#define IS_REV_UNINSTALL(r) (((r)->flags & R_REVERSE_PATH_UNINSTALL_MASK) == R_REVERSE_PATH_UNINSTALL_MASK)
+
+enum {
+ T_INVAL_NEIGH = 0xef,
+ T_SET_NEIGH = 0xee,
+};
+
+struct flow_id {
+ uint16_t src;
+ uint16_t dst;
+ uint16_t id;
+ uint16_t seq;
+ uint16_t nxt_hdr;
+};
+
+
+/*
+ * These are data structures to hold IP messages. We used a linked
+ * list of headers so that we can easily add extra headers with no
+ * copy; similar to the linux iovec's or BSD mbuf structs.
+ * Every split_ip_msg contains a full IPv6 header (40 bytes), but it
+ * is placed at the end of the struct so that we can read() a message
+ * straight into one of these structs, and then just set up the header
+ * chain.
+ *
+ * Due to the way fragmentation is currently implemented, the total
+ * length of the data referenced from this chain must not be longer
+ * then what can fit into a single fragment. This is a limitation of
+ * the current fragmentation code, but is perfectly usable in most
+ * cases.
+ */
+struct generic_header {
+#ifdef PC
+ int payload_malloced:1;
+#endif
+ uint8_t len;
+ union {
+ // this could be an eumeration of all the valid headers we can have here.
+ struct ip6_ext *ext;
+ struct source_header *sh;
+ struct udp_hdr *udp;
+ struct tcp_hdr *tcp;
+ struct rinstall_header *rih;
+ struct topology_header *th;
+ uint8_t *data;
+ } hdr;
+ struct generic_header *next;
+};
+
+struct split_ip_msg {
+ struct generic_header *headers;
+ uint16_t data_len;
+ uint8_t *data;
+#ifdef PC
+ struct ip_metadata metadata;
+#ifdef DBG_TRACK_FLOWS
+ struct flow_id id;
+#endif
+ // this must be last so we can read() straight into the end of the buffer.
+ struct tun_pi pi;
+#endif
+ struct ip6_hdr hdr;
+ uint8_t next[0];
+};
+
+/*
+ * parse a string representation of an IPv6 address
+ */
+void inet_pton6(char *addr, struct in6_addr *dest);
+
+#endif
--- /dev/null
+#ifndef NO_IP_MALLOC
+#ifndef IP_MALLOC_H_
+#define IP_MALLOC_H_
+
+#include <stdint.h>
+
+// align on this number of byte boundarie#s
+#define IP_MALLOC_ALIGN 2
+#define IP_MALLOC_LEN 0x0fff
+#define IP_MALLOC_FLAGS 0x7000
+#define IP_MALLOC_INUSE 0x8000
+#define IP_MALLOC_HEAP_SIZE 1500
+
+extern uint8_t heap[IP_MALLOC_HEAP_SIZE];
+typedef uint16_t bndrt_t;
+
+void ip_malloc_init();
+void *ip_malloc(uint16_t sz);
+void ip_free(void *ptr);
+uint16_t ip_malloc_freespace();
+
+#ifndef PC
+#define malloc(X) ip_malloc(X)
+#define free(X) ip_free(X)
+#endif
+
+#endif
+#endif
--- /dev/null
+/*
+ * "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 _LIB6LOWPAN_H_
+#define _LIB6LOWPAN_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "6lowpan.h"
+#include "ip.h"
+
+#ifdef __TARGET_mips__
+// #warning "Using big endian byte order"
+#define ntoh16(X) (X)
+#define hton16(X) (X)
+#define ntoh32(X) (X)
+#define hton32(X) (X)
+#define leton16(X) (((((uint16_t)(X)) << 8) | ((uint16_t)(X) >> 8)) & 0xffff)
+#define htole16(X) leton16(X)
+#else
+// #warning "Using little endian byte order"
+#define ntoh16(X) (((((uint16_t)(X)) >> 8) | ((uint16_t)(X) << 8)) & 0xffff)
+#define hton16(X) (((((uint16_t)(X)) << 8) | ((uint16_t)(X) >> 8)) & 0xffff)
+#define leton16(X) hton16(X)
+#define htole16(X) (X)
+#define ntoh32(X) ((((uint32_t)(X) >> 24) & 0x000000ff)| \
+ ((((uint32_t)(X) >> 8)) & 0x0000ff00) | \
+ ((((uint32_t)(X) << 8)) & 0x00ff0000) | \
+ ((((uint32_t)(X) << 24)) & 0xff000000))
+
+#define hton32(X) ((((uint32_t)(X) << 24) & 0xff000000)| \
+ ((((uint32_t)(X) << 8)) & 0x00ff0000) | \
+ ((((uint32_t)(X) >> 8)) & 0x0000ff00) | \
+ ((((uint32_t)(X) >> 24)) & 0x000000ff))
+#endif
+
+
+#define ntohs(X) ntoh16(X)
+#define htons(X) hton16(X)
+
+#define ntohl(X) ntoh32(X)
+#define htonl(X) hton32(X)
+
+
+#ifdef DEF_MEMCPY
+#define memcpy(X,Y,Z) ip_memcpy(X,Y,Z)
+#endif
+
+/*
+ * This interface implements the 6loWPAN header structures. Support
+ * for the HC1 and HC2 compressed IP and UDP headers is also
+ * available, and the interface is presented in lib6lowpanIP.h.
+ *
+ */
+
+// only 16-bit address handling modes
+#define __6LOWPAN_16BIT_ADDRESS
+
+/*
+ * Library implementation of packing of 6lowpan packets.
+ *
+ * This should allow uniform code treatment between pc and mote code;
+ * the goal is to write ANSI C here... This means no nx_ types,
+ * unfortunately.
+ */
+
+/*
+ * 6lowpan header functions
+ */
+
+uint16_t getHeaderBitmap(packed_lowmsg_t *lowmsg);
+/*
+ * Return the length of the buffer required to pack lowmsg
+ * into a buffer.
+ */
+
+uint8_t *getLowpanPayload(packed_lowmsg_t *lowmsg);
+
+/*
+ * Initialize the header bitmap in 'packed' so that
+ * we know how long the headers are.
+ *
+ * @return FAIL if the buffer is not long enough.
+ */
+uint8_t setupHeaders(packed_lowmsg_t *packed, uint16_t headers);
+
+/*
+ * Test if various protocol features are enabled
+ */
+uint8_t hasMeshHeader(packed_lowmsg_t *msg);
+uint8_t hasBcastHeader(packed_lowmsg_t *msg);
+uint8_t hasFrag1Header(packed_lowmsg_t *msg);
+uint8_t hasFragNHeader(packed_lowmsg_t *msg);
+
+/*
+ * Mesh header fields
+ *
+ * return FAIL if the message doesn't have a mesh header
+ */
+uint8_t getMeshHopsLeft(packed_lowmsg_t *msg, uint8_t *hops);
+uint8_t getMeshOriginAddr(packed_lowmsg_t *msg, hw_addr_t *origin);
+uint8_t getMeshFinalAddr(packed_lowmsg_t *msg, hw_addr_t *final);
+
+uint8_t setMeshHopsLeft(packed_lowmsg_t *msg, uint8_t hops);
+uint8_t setMeshOriginAddr(packed_lowmsg_t *msg, hw_addr_t origin);
+uint8_t setMeshFinalAddr(packed_lowmsg_t *msg, hw_addr_t final);
+
+/*
+ * Broadcast header fields
+ */
+uint8_t getBcastSeqno(packed_lowmsg_t *msg, uint8_t *seqno);
+
+uint8_t setBcastSeqno(packed_lowmsg_t *msg, uint8_t seqno);
+
+/*
+ * Fragmentation header fields
+ */
+uint8_t getFragDgramSize(packed_lowmsg_t *msg, uint16_t *size);
+uint8_t getFragDgramTag(packed_lowmsg_t *msg, uint16_t *tag);
+uint8_t getFragDgramOffset(packed_lowmsg_t *msg, uint8_t *size);
+
+uint8_t setFragDgramSize(packed_lowmsg_t *msg, uint16_t size);
+uint8_t setFragDgramTag(packed_lowmsg_t *msg, uint16_t tag);
+uint8_t setFragDgramOffset(packed_lowmsg_t *msg, uint8_t size);
+
+/*
+ * IP header compression functions
+ *
+ */
+int getCompressedLen(packed_lowmsg_t *pkt);
+
+/*
+ * Pack the header fields of msg into buffer 'buf'.
+ * it returns the number of bytes written to 'buf', or zero if it encountered a problem.
+ *
+ * it will pack the IP header and all headers in the header chain of
+ * msg into the buffer; the only thing it will not pack is the
+ * payload.
+ */
+uint8_t packHeaders(struct split_ip_msg *msg,
+ uint8_t *buf, uint8_t len);
+/*
+ * Unpack the packed data from pkt into dest.
+ *
+ * It turns out that we need to keep track of a lot of different
+ * locations in order to be able to unpack and forward efficiently.
+ * If we don't save these during the unpack, we end up reconstructing
+ * them in various places so it's less error-prone to compute them
+ * while we're parsing the packed fields.
+ */
+typedef struct {
+ // the final header in the header chain; should be the transport header
+ uint8_t nxt_hdr;
+ // a pointer to the point in the source where we stopped unpacking
+ uint8_t *payload_start;
+ // a pointer to the point in the destination right after all headers
+ uint8_t *header_end;
+ // the total, uncompressed length of the headers which were unpacked
+ uint8_t payload_offset;
+ // points to the hop limit field of the packet message
+ uint8_t *hlim;
+ // points to the tranport header in the destination region,
+ // if it was within the unpacked region header.
+ // if it was not, it is the same as header_end
+ uint8_t *transport_ptr;
+ // points to the source header within the packed fields, IF it contains one.
+ struct source_header *sh;
+ struct rinstall_header *rih;
+} unpack_info_t;
+
+uint8_t *unpackHeaders(packed_lowmsg_t *pkt, unpack_info_t *u_info,
+ uint8_t *dest, uint16_t len);
+
+/*
+ * Fragmentation routines.
+ */
+
+extern uint16_t lib6lowpan_frag_tag;
+
+typedef struct {
+ uint16_t tag; /* datagram label */
+ uint16_t size; /* the size of the packet we are reconstructing */
+ void *buf; /* the reconstruction location */
+ uint16_t bytes_rcvd; /* how many bytes from the packet we have
+ received so far */
+ uint8_t timeout;
+ uint8_t *transport_hdr;
+ struct ip_metadata metadata;
+} reconstruct_t;
+
+typedef struct {
+ uint16_t tag; /* the label of the datagram */
+ uint16_t offset; /* how far into the packet we have sent, in bytes */
+} fragment_t;
+
+
+/*
+ * this function writes the next fragment which needs to be sent into
+ * the buffer passed in. It updates the structures in process to
+ * reflect how much of the packet has been sent so far.
+ *
+ * if the packet does not require fragmentation, this function will
+ * not insert a fragmentation header and will merely compress the
+ * headers into the packet.
+ *
+ */
+uint8_t getNextFrag(struct split_ip_msg *msg, fragment_t *progress,
+ uint8_t *buf, uint16_t len);
+
+
+enum {
+ T_FAILED1 = 0,
+ T_FAILED2 = 1,
+ T_UNUSED = 2,
+ T_ACTIVE = 3,
+ T_ZOMBIE = 4,
+};
+
+uint8_t* getLinkLocalPrefix();
+#endif
--- /dev/null
+
+SOURCES=lib6lowpan.c lib6lowpanIP.c lib6lowpanFrag.c
+INCLUDE=../include/
+
+###############
+##
+## Use these for PC
+ifndef GCC
+GCC=gcc
+endif
+ifndef AR
+AR=ar
+endif
+
+CFLAGS=-DPC -g -I$(INCLUDE)
+TEST=testhc.c
+
+###############
+##
+## These for msp430
+# GCC=msp430-gcc
+# AR=msp430-ar
+# TEST=msp_test.c
+# CFLAGS=-DMSP
+
+LIB=lib6lowpan.a
+OBJS=$(SOURCES:.c=.o)
+
+$(LIB): $(OBJS)
+ $(AR) crv $(LIB) $(OBJS)
+
+test: $(SOURCES) $(TEST) $(LIB)
+ $(GCC) -o $@ $(TEST) $(CFLAGS) $(LIB) printpacket.c
+
+%.o: %.c
+ $(GCC) -o $@ $< $(CFLAGS) -c
+
+clean:
+ rm -f test $(OBJS) $(LIB)
+
+lib6lowpan.o: lib6lowpan.c ip-hdrs
+lib6lowpanIP.o: lib6lowpanIP.c ip-hdrs
+lib6lowpanFrag.o: lib6lowpanFrag.c ip-hdrs
+
+ip-hdrs: $(INCLUDE)/6lowpan.h $(INCLUDE)/ip.h $(INCLUDE)/lib6lowpan.h
\ No newline at end of file
--- /dev/null
+/*
+ * "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."
+ *
+ */
+/* in_cksum.c
+ * 4.4-Lite-2 Internet checksum routine, modified to take a vector of
+ * pointers/lengths giving the pieces to be checksummed.
+ *
+ * $Id$
+ */
+
+/*
+ * Copyright (c) 1988, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93
+ */
+
+#include <stdlib.h>
+#include "in_cksum.h"
+#include "lib6lowpan.h"
+
+
+#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
+#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
+
+int
+in_cksum(const vec_t *vec, int veclen) {
+
+ uint32_t sum = 0;
+ uint16_t res = 0;
+ uint16_t cur = 0;
+ int i;
+
+
+ uint8_t *w;
+
+ for (; veclen != 0; vec++, veclen--) {
+ if (vec->len == 0)
+ continue;
+
+ w = (uint8_t *)vec->ptr;
+ for (i = 0; i < vec->len; i++) {
+ if (i % 2 == 0) {
+ cur |= ((uint16_t)w[i]) << 8;
+ if (i + 1 == vec->len) {
+ goto finish;
+ }
+ } else {
+ cur |= w[i];
+ finish:
+ sum += cur;
+ res = (sum & 0xffff) + (sum >> 16);
+ cur = 0;
+ }
+ }
+ }
+ return ~res ;
+#if 0
+ register const uint16_t *w;
+ register uint32_t sum = 0;
+ register uint32_t mlen = 0;
+ int byte_swapped = 0;
+
+ union {
+ uint8_t c[2];
+ uint16_t s;
+ } s_util;
+ union {
+ uint16_t s[2];
+ uint32_t l;
+ } l_util;
+
+ for (; veclen != 0; vec++, veclen--) {
+ if (vec->len == 0)
+ continue;
+ w = (const uint16_t *)vec->ptr;
+ if (mlen == -1) {
+ /*
+ * The first byte of this chunk is the continuation
+ * of a word spanning between this chunk and the
+ * last chunk.
+ *
+ * s_util.c[0] is already saved when scanning previous
+ * chunk.
+ */
+ s_util.c[1] = *(const uint8_t *)w;
+ sum += s_util.s;
+ w = (const uint16_t *)((const uint8_t *)w + 1);
+ mlen = vec->len - 1;
+ } else
+ mlen = vec->len;
+ /*
+ * Force to even boundary.
+ */
+ if ((1 & (int) w) && (mlen > 0)) {
+ REDUCE;
+ sum <<= 8;
+ s_util.c[0] = *(const uint8_t *)w;
+ w = (const uint16_t *)((const uint8_t *)w + 1);
+ mlen--;
+ byte_swapped = 1;
+ }
+ /*
+ * Unroll the loop to make overhead from
+ * branches &c small.
+ */
+ while ((mlen -= 32) >= 0) {
+ sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+ sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
+ sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
+ sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
+ w += 16;
+ }
+ mlen += 32;
+ while ((mlen -= 8) >= 0) {
+ sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+ w += 4;
+ }
+ mlen += 8;
+ if (mlen == 0 && byte_swapped == 0)
+ continue;
+ REDUCE;
+ while ((mlen -= 2) >= 0) {
+ sum += *w++;
+ }
+ if (byte_swapped) {
+ REDUCE;
+ sum <<= 8;
+ byte_swapped = 0;
+ if (mlen == -1) {
+ s_util.c[1] = *(const uint8_t *)w;
+ sum += s_util.s;
+ mlen = 0;
+ } else
+ mlen = -1;
+ } else if (mlen == -1)
+ s_util.c[0] = *(const uint8_t *)w;
+ }
+ if (mlen == -1) {
+ /* The last mbuf has odd # of bytes. Follow the
+ standard (the odd byte may be shifted left by 8 bits
+ or not as determined by endian-ness of the machine) */
+ s_util.c[1] = 0;
+ sum += s_util.s;
+ }
+ REDUCE;
+ return (~sum & 0xffff);
+#endif
+}
+
+/* SDH : Added to allow for friendly message checksumming */
+uint16_t msg_cksum(struct split_ip_msg *msg, uint8_t nxt_hdr) {
+ struct generic_header *cur;
+ int n_headers = 4;
+ vec_t cksum_vec[7];
+ uint32_t hdr[2];
+
+ cksum_vec[0].ptr = (uint8_t *)(msg->hdr.ip6_src.s6_addr);
+ cksum_vec[0].len = 16;
+ cksum_vec[1].ptr = (uint8_t *)(msg->hdr.ip6_dst.s6_addr);
+ cksum_vec[1].len = 16;
+ cksum_vec[2].ptr = (uint8_t *)hdr;
+ cksum_vec[2].len = 8;
+ hdr[0] = msg->data_len;
+ hdr[1] = htonl(nxt_hdr);
+ cksum_vec[3].ptr = msg->data;
+ cksum_vec[3].len = msg->data_len;
+
+ cur = msg->headers;
+ while (cur != NULL) {
+ cksum_vec[n_headers].ptr = cur->hdr.data;
+ cksum_vec[n_headers].len = cur->len;
+ hdr[0] += cur->len;
+ n_headers++;
+ cur = cur->next;
+ }
+ hdr[0] = htonl(hdr[0]);
+
+ return in_cksum(cksum_vec, n_headers);
+}
--- /dev/null
+#ifndef NO_IP_MALLOC
+#include <stdint.h>
+#include <stdio.h>
+#include "ip_malloc.h"
+
+uint8_t heap[IP_MALLOC_HEAP_SIZE];
+
+void ip_malloc_init() {
+ bndrt_t *b = (bndrt_t *)heap;
+ *b = IP_MALLOC_HEAP_SIZE & IP_MALLOC_LEN;
+}
+
+void *ip_malloc(uint16_t sz) {
+ bndrt_t *cur = (bndrt_t *)heap;
+ sz += sizeof(bndrt_t) * 2;
+ sz += (sz % IP_MALLOC_ALIGN);
+
+ while (((*cur & IP_MALLOC_LEN) < sz || (*cur & IP_MALLOC_INUSE) != 0)
+ && (uint8_t *)cur - heap < IP_MALLOC_HEAP_SIZE) {
+ cur = (bndrt_t *)(((uint8_t *)cur) + ((*cur) & IP_MALLOC_LEN));
+ }
+
+ if ((uint8_t *)cur < heap + IP_MALLOC_HEAP_SIZE) {
+ uint16_t oldsize = *cur & IP_MALLOC_LEN;
+ bndrt_t *next;
+ sz -= sizeof(bndrt_t);
+ next = ((bndrt_t *)(((uint8_t *)cur) + sz));
+
+ *cur = (sz & IP_MALLOC_LEN) | IP_MALLOC_INUSE;
+ *next = (oldsize - sz) & IP_MALLOC_LEN;
+
+ return cur + 1;
+ } else return NULL;
+}
+
+void ip_free(void *ptr) {
+ bndrt_t *prev = NULL, *cur, *next = NULL;
+ cur = (bndrt_t *)heap;
+
+ while (cur + 1 != ptr && (uint8_t *)cur - heap < IP_MALLOC_HEAP_SIZE) {
+ prev = cur;
+ cur = (bndrt_t *)(((uint8_t *)cur) + ((*cur) & IP_MALLOC_LEN));
+ }
+ if (cur + 1 == ptr) {
+ next = (bndrt_t *)((*cur & IP_MALLOC_LEN) + ((uint8_t *)cur));
+
+ *cur &= ~IP_MALLOC_INUSE;
+ if ((((uint8_t *)next) - heap) < IP_MALLOC_HEAP_SIZE &&
+ (*next & IP_MALLOC_INUSE) == 0) {
+ *cur = (*cur & IP_MALLOC_LEN) + (*next & IP_MALLOC_LEN);
+ }
+ if (prev != NULL && (*prev & IP_MALLOC_INUSE) == 0) {
+ *prev = (*prev & IP_MALLOC_LEN) + (*cur & IP_MALLOC_LEN);
+ }
+ }
+}
+
+uint16_t ip_malloc_freespace() {
+ uint16_t ret = 0;
+ bndrt_t *cur = (bndrt_t *)heap;
+
+ while ((uint8_t *)cur - heap < IP_MALLOC_HEAP_SIZE) {
+ if ((*cur & IP_MALLOC_INUSE) == 0)
+ ret += *cur & IP_MALLOC_LEN;
+ cur = (bndrt_t *)(((uint8_t *)cur) + ((*cur) & IP_MALLOC_LEN));
+ }
+ return ret;
+}
+
+#ifdef PC
+void dump_heap() {
+ int i;
+ for (i = 0; i < IP_MALLOC_HEAP_SIZE; i++) {
+ printf("0x%x ", heap[i]);
+ if (i % 8 == 7) printf(" ");
+ if (i % 16 == 15) printf ("\n");
+ if (i > 64) break;
+ }
+ printf("\n");
+}
+
+void ip_print_heap() {
+ bndrt_t *cur = (bndrt_t *)heap;
+ while (((uint8_t *)cur) - heap < IP_MALLOC_HEAP_SIZE) {
+ printf ("heap region start: 0x%x length: %i used: %i\n",
+ cur, (*cur & IP_MALLOC_LEN), (*cur & IP_MALLOC_INUSE) >> 15);
+ if ((*cur & IP_MALLOC_LEN) == 0) {
+ printf("ERROR: zero length cell detected!\n");
+ dump_heap();
+ exit(1);
+ }
+ cur = (bndrt_t *)(((uint8_t *)cur) + ((*cur) & IP_MALLOC_LEN));
+
+ }
+}
+#endif
+#endif
--- /dev/null
+/*
+ * "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 "6lowpan.h"
+#include "ip.h"
+#include "lib6lowpan.h"
+
+
+#ifndef __6LOWPAN_16BIT_ADDRESS
+#error "Only 16-bit short addresses are supported"
+#endif
+
+/*
+ * Library implementation of packing of 6lowpan packets.
+ *
+ * This should allow uniform code treatment between pc and mote code;
+ * the goal is to write ANSI C here... This means no nx_ types,
+ * unfortunately.
+ *
+ * Accessing fields programtically is probably a little less
+ * efficient, but that can be improved. By precomputing the packet
+ * headers present, we can make the overhead not too bad. The #1
+ * goal of this library is portability and readability.
+ *
+ * The broadcast and mesh headers may or may not be useful, and are
+ * off by default to reduce code size. Removing them reduces the
+ * library size by about 600 bytes.
+ */
+
+
+/*
+ * Return the length (in bytes) of the buffer required to pack lowmsg
+ * into a buffer.
+ */
+uint8_t *getLowpanPayload(packed_lowmsg_t *lowmsg) {
+ uint8_t len = 0;
+#if LIB6LOWPAN_FULL
+ if (lowmsg->headers & LOWMSG_MESH_HDR)
+ len += LOWMSG_MESH_LEN;
+ if (lowmsg->headers & LOWMSG_BCAST_HDR)
+ len += LOWMSG_BCAST_LEN;
+#endif
+ if (lowmsg->headers & LOWMSG_FRAG1_HDR)
+ len += LOWMSG_FRAG1_LEN;
+ if (lowmsg->headers & LOWMSG_FRAGN_HDR)
+ len += LOWMSG_FRAGN_LEN;
+ return lowmsg->data + len;
+}
+
+/*
+ * Return a bitmap indicating which lowpan headers are
+ * present in the message pointed to by lowmsg.
+ *
+ */
+uint16_t getHeaderBitmap(packed_lowmsg_t *lowmsg) {
+ uint16_t headers = 0;
+ uint8_t *buf = lowmsg->data;
+ uint16_t len = lowmsg->len;
+ if (buf == NULL) return headers;
+
+ if (len > 0 && ((*buf) >> 6) == LOWPAN_NALP_PATTERN) {
+ return LOWMSG_NALP;
+ }
+
+#if LIB6LOWPAN_FULL
+ if (len > 0 && ((*buf) >> 6) == LOWPAN_MESH_PATTERN) {
+ if (!(*buf & LOWPAN_MESH_V_MASK) ||
+ !(*buf & LOWPAN_MESH_F_MASK)) {
+ // we will not parse a packet with 64-bit addressing.
+ return LOWMSG_NALP;
+ }
+ headers |= LOWMSG_MESH_HDR;
+ buf += LOWMSG_MESH_LEN;
+ len -= LOWMSG_MESH_LEN;
+ }
+ if (len > 0 && (*buf) == LOWPAN_BCAST_PATTERN) {
+ headers |= LOWMSG_BCAST_HDR;
+ buf += LOWMSG_BCAST_LEN;
+ len -= LOWMSG_BCAST_LEN;
+ }
+#endif
+
+ if (len > 0 && ((*buf) >> 3) == LOWPAN_FRAG1_PATTERN) {
+ headers |= LOWMSG_FRAG1_HDR;
+ buf += LOWMSG_FRAG1_LEN;
+ len -= LOWMSG_FRAG1_LEN;
+ }
+ if (len > 0 && ((*buf) >> 3) == LOWPAN_FRAGN_PATTERN) {
+ headers |= LOWMSG_FRAGN_HDR;
+ buf += LOWMSG_FRAGN_LEN;
+ len -= LOWMSG_FRAGN_LEN;
+ }
+ return headers;
+}
+
+/*
+ * Fill in dispatch values
+ */
+uint8_t setupHeaders(packed_lowmsg_t *packed, uint16_t headers) {
+ uint8_t *buf = packed->data;
+ uint16_t len = packed->len;
+ if (packed == NULL) return 1;
+ if (buf == NULL) return 1;
+ packed->headers = 0;
+#if LIB6LOWPAN_FULL
+ if (headers & LOWMSG_MESH_HDR) {
+ if (len < LOWMSG_MESH_LEN) return 1;
+ packed->headers |= LOWMSG_MESH_HDR;
+ *buf = LOWPAN_MESH_PATTERN << 6 | LOWPAN_MESH_V_MASK | LOWPAN_MESH_F_MASK;
+ buf += LOWMSG_MESH_LEN;
+ len -= LOWMSG_MESH_LEN;
+ }
+ if (headers & LOWMSG_BCAST_HDR) {
+ if (len < LOWMSG_BCAST_LEN) return 1;
+ packed->headers |= LOWMSG_BCAST_HDR;
+ *buf = LOWPAN_BCAST_PATTERN;
+ buf += LOWMSG_BCAST_LEN;
+ len -= LOWMSG_BCAST_LEN;
+ }
+#endif
+ if (headers & LOWMSG_FRAG1_HDR) {
+ if (len < LOWMSG_FRAG1_HDR) return 1;
+ packed->headers |= LOWMSG_FRAG1_HDR;
+ *buf = LOWPAN_FRAG1_PATTERN << 3;
+ buf += LOWMSG_FRAG1_LEN;
+ len -= LOWMSG_FRAG1_LEN;
+ }
+ if (headers & LOWMSG_FRAGN_HDR) {
+ if (len < LOWMSG_FRAGN_HDR) return 1;
+ packed->headers |= LOWMSG_FRAGN_HDR;
+ *buf = LOWPAN_FRAGN_PATTERN << 3;
+ }
+ return 0;
+
+}
+
+/*
+ * Test if various headers are present are enabled
+ */
+#ifdef LIB6LOWPAN_FULL
+inline uint8_t hasMeshHeader(packed_lowmsg_t *msg) {
+ return (msg->headers & LOWMSG_MESH_HDR);
+}
+inline uint8_t hasBcastHeader(packed_lowmsg_t *msg) {
+ return (msg->headers & LOWMSG_BCAST_HDR);
+}
+#endif
+inline uint8_t hasFrag1Header(packed_lowmsg_t *msg) {
+ return (msg->headers & LOWMSG_FRAG1_HDR);
+}
+inline uint8_t hasFragNHeader(packed_lowmsg_t *msg) {
+ return (msg->headers & LOWMSG_FRAGN_HDR);
+}
+#ifdef LIB6LOWPAN_FULL
+/*
+ * Mesh header fields
+ *
+ * return FAIL if the message doesn't have a mesh header
+ */
+inline uint8_t getMeshHopsLeft(packed_lowmsg_t *msg, uint8_t *hops) {
+ uint8_t *buf = msg->data;
+ if (!hasMeshHeader(msg) || msg->data == NULL || hops == NULL) return 1;
+ *hops = (*buf) & LOWPAN_MESH_HOPS_MASK;
+ return 0;
+}
+inline uint8_t getMeshOriginAddr(packed_lowmsg_t *msg, hw_addr_t *origin) {
+ uint8_t *buf = msg->data;
+ if (!hasMeshHeader(msg) || msg->data == NULL || origin == NULL) return 1;
+ // skip 64-bit addresses
+ if (!(*buf & LOWPAN_MESH_V_MASK)) return 1;
+ buf += 1;
+ *origin = ntoh16(*((uint16_t *)buf));
+ return 0;
+}
+inline uint8_t getMeshFinalAddr(packed_lowmsg_t *msg, hw_addr_t *final) {
+ uint8_t *buf = msg->data;
+ if (!hasMeshHeader(msg) || msg->data == NULL || final == NULL) return 1;
+ // skip 64-bit addresses
+ if (!(*buf & LOWPAN_MESH_F_MASK)) return 1;
+ buf += 3;
+ *final = ntoh16(*((uint16_t *)buf));
+ return 0;
+}
+
+
+inline uint8_t setMeshHopsLeft(packed_lowmsg_t *msg, uint8_t hops) {
+ uint8_t *buf = msg->data;
+ if (!hasMeshHeader(msg) || msg->data == NULL) return 1;
+
+ *buf = 0xb0;
+ *buf |= hops & LOWPAN_MESH_HOPS_MASK;
+ return 0;
+}
+inline uint8_t setMeshOriginAddr(packed_lowmsg_t *msg, hw_addr_t origin) {
+ uint8_t *buf = msg->data;
+ if (!hasMeshHeader(msg) || msg->data == NULL) return 1;
+ // skip 64-bit addresses
+ if (!(*buf & LOWPAN_MESH_V_MASK)) return 1;
+ buf += 1;
+ *((uint16_t *)buf) = hton16(origin);
+ return 0;
+}
+inline uint8_t setMeshFinalAddr(packed_lowmsg_t *msg, hw_addr_t final) {
+ uint8_t *buf = msg->data;
+ if (!hasMeshHeader(msg) || msg->data == NULL) return 1;
+ // skip 64-bit addresses
+ if (!(*buf & LOWPAN_MESH_F_MASK)) return 1;
+ buf += 3;
+ *((uint16_t *)buf) = hton16(final);
+ return 0;
+}
+
+/*
+ * Broadcast header fields
+ */
+inline uint8_t getBcastSeqno(packed_lowmsg_t *msg, uint8_t *seqno) {
+ uint8_t *buf = msg->data;
+ if (buf == NULL || seqno == NULL || !hasBcastHeader(msg)) return 1;
+ if (hasMeshHeader(msg)) buf += LOWMSG_MESH_LEN;
+ if (*buf != LOWPAN_BCAST_PATTERN) return 2;
+ buf += 1;
+ *seqno = *buf;
+ return 0;
+}
+
+inline uint8_t setBcastSeqno(packed_lowmsg_t *msg, uint8_t seqno) {
+ uint8_t *buf = msg->data;
+ if (buf == NULL || !hasBcastHeader(msg)) return 1;
+ if (hasMeshHeader(msg)) buf += LOWMSG_MESH_LEN;
+ if (*buf != LOWPAN_BCAST_PATTERN) return 2;
+ buf += 1;
+ *buf = seqno;
+ return 0;
+}
+#endif
+
+/*
+ * Fragmentation header fields
+ */
+inline uint8_t getFragDgramSize(packed_lowmsg_t *msg, uint16_t *size) {
+ uint8_t *buf = msg->data;
+ uint8_t s[2];
+ if (buf == NULL || size == NULL) return 1;
+#ifdef LIB6LOWPAN_FULL
+ if (hasMeshHeader(msg)) buf += LOWMSG_MESH_LEN;
+ if (hasBcastHeader(msg)) buf += LOWMSG_BCAST_LEN;
+#endif
+ if ((*buf >> 3) != LOWPAN_FRAG1_PATTERN &&
+ (*buf >> 3) != LOWPAN_FRAGN_PATTERN) return 1;
+
+ s[0] = *buf & 0x7;
+ buf++;
+ s[1] = *buf;
+ *size = ntoh16 ( *(uint16_t *)s);
+ return 0;
+}
+inline uint8_t getFragDgramTag(packed_lowmsg_t *msg, uint16_t *tag) {
+ uint8_t *buf = msg->data;
+ if (buf == NULL || tag == NULL) return 1;
+#ifdef LIB6LOWPAN_FULL
+ if (hasMeshHeader(msg)) buf += LOWMSG_MESH_LEN;
+ if (hasBcastHeader(msg)) buf += LOWMSG_BCAST_LEN;
+#endif
+ if ((*buf >> 3) != LOWPAN_FRAG1_PATTERN &&
+ (*buf >> 3) != LOWPAN_FRAGN_PATTERN) return 1;
+ buf += 2;
+ //*tag = (*buf << 8) | *(buf + 1); ;
+ *tag = ntoh16( *(uint16_t *)buf);
+ return 0;
+}
+inline uint8_t getFragDgramOffset(packed_lowmsg_t *msg, uint8_t *size) {
+ uint8_t *buf = msg->data;
+ if (buf == NULL || size == NULL) return 1;
+#ifdef LIB6LOWPAN_FULL
+ if (hasMeshHeader(msg)) buf += LOWMSG_MESH_LEN;
+ if (hasBcastHeader(msg)) buf += LOWMSG_BCAST_LEN;
+#endif
+ if ((*buf >> 3) != LOWPAN_FRAGN_PATTERN) return 1;
+ buf += 4;
+ *size = *buf;
+ return 0;
+
+}
+
+
+inline uint8_t setFragDgramSize(packed_lowmsg_t *msg, uint16_t size) {
+ uint8_t *buf = msg->data;
+ if (buf == NULL) return 1;
+#ifdef LIB6LOWPAN_FULL
+ if (hasMeshHeader(msg)) buf += LOWMSG_MESH_LEN;
+ if (hasBcastHeader(msg)) buf += LOWMSG_BCAST_LEN;
+#endif
+ if ((*buf >> 3) != LOWPAN_FRAG1_PATTERN &&
+ (*buf >> 3) != LOWPAN_FRAGN_PATTERN) return 1;
+ // zero out the dgram size first.
+ *buf &= 0xf8;
+ *(buf + 1) = 0;
+ *((uint16_t *)buf) |= hton16(size & 0x7ff);
+ return 0;
+}
+
+inline uint8_t setFragDgramTag(packed_lowmsg_t *msg, uint16_t tag) {
+ uint8_t *buf = msg->data;
+ if (buf == NULL) return 1;
+#ifdef LIB6LOWPAN_FULL
+ if (hasMeshHeader(msg)) buf += LOWMSG_MESH_LEN;
+ if (hasBcastHeader(msg)) buf += LOWMSG_BCAST_LEN;
+#endif
+
+ if ((*buf >> 3) != LOWPAN_FRAG1_PATTERN &&
+ (*buf >> 3) != LOWPAN_FRAGN_PATTERN) return 1;
+ buf += 2;
+ *(uint16_t *)buf = ntoh16(tag);
+ return 0;
+}
+inline uint8_t setFragDgramOffset(packed_lowmsg_t *msg, uint8_t size) {
+ uint8_t *buf = msg->data;
+ if (buf == NULL) return 1;
+#ifdef LIB6LOWPAN_FULL
+ if (hasMeshHeader(msg)) buf += LOWMSG_MESH_LEN;
+ if (hasBcastHeader(msg)) buf += LOWMSG_BCAST_LEN;
+#endif
+
+ if ((*buf >> 3) != LOWPAN_FRAGN_PATTERN) return 1;
+ buf += 4;
+ *buf = size;
+ return 0;
+}
--- /dev/null
+/*
+ * "Copyright (c) 2008 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+/*
+ * @author Stephen Dawson-Haggerty <stevedh@cs.berkeley.edu>
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "ip.h"
+#include "ip_malloc.h"
+#include "6lowpan.h"
+#include "lib6lowpan.h"
+
+#define min(a,b) ( ((a)>(b)) ? (b) : (a) )
+#define max(a,b) ( ((a)<(b)) ? (b) : (a) )
+
+uint16_t lib6lowpan_frag_tag = 0;
+
+void ip_memclr(uint8_t *buf, uint16_t len) {
+ for (; len > 0; len--)
+ *buf++ = 0;
+
+}
+
+void *ip_memcpy(void *dst0, const void *src0, uint16_t len) {
+ uint8_t *dst = (uint8_t *) dst0;
+ uint8_t *src = (uint8_t *) src0;
+ void *ret = dst0;
+
+ for (; len > 0; len--)
+ *dst++ = *src++;
+
+ return ret;
+}
+
+/*
+ * this function writes the next fragment which needs to be sent into
+ * the buffer passed in. It updates the structures in process to
+ * reflect how much of the packet has been sent so far.
+ *
+ * if the packet does not require fragmentation, this function will
+ * not insert a fragmentation header and will merely compress the
+ * headers into the packet.
+ *
+ * returns the number of bytes used in buf, or zero if there was no
+ * fragment to be sent.
+ *
+ */
+uint8_t getNextFrag(struct split_ip_msg *msg, fragment_t *progress,
+ uint8_t *buf, uint16_t len) {
+ if (msg == NULL || progress == NULL || buf == NULL) return 0;
+ packed_lowmsg_t pkt;
+ uint16_t frag_length = 0;
+ pkt.headers = 0;
+ pkt.data = buf;
+ pkt.len = len;
+
+ // if this is the first fragment, we will compress the headers in
+ // the ip message, and only insert a fragmentation header if
+ // necessary to pack it into buffer
+ if (progress->offset == 0) {
+ uint8_t *compressed_headers;
+ uint8_t lowpan_len = 0;
+ uint8_t cmpr_header_len = 0, header_length = 0;
+
+ compressed_headers = malloc(LIB6LOWPAN_MAX_LEN);
+ if (compressed_headers == NULL) return 0;
+
+ // pack the headers into a temporary buffer
+ cmpr_header_len = packHeaders(msg, compressed_headers, LIB6LOWPAN_MAX_LEN);
+
+ {
+ struct generic_header *cur = msg->headers;
+ while (cur != NULL) {
+ header_length += cur->len;
+ cur = cur->next;
+ }
+ }
+
+ // printBuf(compressed_headers, compressed_len);
+ // printf("payload: %p\n", payload);
+
+ // maybe add a fragmentation header
+ if (cmpr_header_len + msg->data_len > len) {
+ pkt.headers |= LOWMSG_FRAG1_HDR;
+ if (setupHeaders(&pkt, pkt.headers)) goto free_fail;
+ if (setFragDgramTag(&pkt, ++lib6lowpan_frag_tag)) goto free_fail;
+ if (setFragDgramSize(&pkt, ntoh16(msg->hdr.plen) + sizeof(struct ip6_hdr))) goto free_fail;
+ lowpan_len += LOWMSG_FRAG1_LEN;
+ } else {
+ if (setupHeaders(&pkt, pkt.headers)) goto free_fail;
+ }
+ ip_memcpy(getLowpanPayload(&pkt), compressed_headers, cmpr_header_len);
+
+ /*
+ * calculate how much to put into this fragment
+ *
+ * if the whole packet fits in the buffer, this is easy; it's the
+ * compressed headers plus the payload length.
+ *
+ * given fragmentation, we need to do a little more work.
+ */
+ if (pkt.headers & LOWMSG_FRAG1_HDR) {
+ frag_length = len - cmpr_header_len - LOWMSG_FRAG1_LEN + sizeof(struct ip6_hdr) + header_length;
+ frag_length -= (frag_length % 8);
+ frag_length -= (sizeof(struct ip6_hdr) + header_length);
+ } else {
+ frag_length = ntoh16(msg->hdr.plen) - header_length;
+ }
+ // frag_length contains the number of bytes in uncompressed headers.
+
+ ip_memcpy(getLowpanPayload(&pkt) + cmpr_header_len,
+ msg->data, frag_length);
+
+ progress->tag = lib6lowpan_frag_tag;
+ progress->offset = frag_length + sizeof(struct ip6_hdr) + header_length;
+
+ // printfUART("frag: 0x%x 0x%x 0x%x\n", header_len, frag_length, compressed_len);
+
+ // return the length we wrote, which comes in three pieces;
+ free(compressed_headers);
+ return lowpan_len + cmpr_header_len + frag_length;
+ free_fail:
+ free(compressed_headers);
+ goto fail;
+ } else {
+ /*
+ * we've already sent the first fragment; we only need to send a
+ * subsequent one or return zero if we're at the end of the buffer;
+ *
+ */
+ //printf("offset: 0x%x plen: 0x%x\n", progress->offset, ntoh16(ip->plen) + sizeof(struct ip6_hdr));
+
+ // NOTE : this should be a >= to detect runaway lengths. However,
+ // it is useful for debugging to require equality.
+ if (progress->offset == ntoh16(msg->hdr.plen) + sizeof(struct ip6_hdr)) return 0;
+ // the only headers we need now is the fragn header.
+
+ pkt.headers |= LOWMSG_FRAGN_HDR;
+
+ // send out the fragments some frasgments.
+ //printf ("--- sending fragment\n");
+ // now we're pointing at the start of the 6loWPAN frame in the packet.
+ pkt.data = buf;
+ pkt.len = len;
+ // setup the fragmentation headers
+ if (setupHeaders(&pkt, pkt.headers)) goto fail;
+ if (setFragDgramTag(&pkt, progress->tag)) goto fail;
+
+ //printf ("frag dgram size 0x%x progress: 0x%x\n", ntoh16(ip->plen) + sizeof(struct ip6_hdr),
+/* progress->offset); */
+
+ if (setFragDgramSize(&pkt, ntoh16(msg->hdr.plen) + sizeof(struct ip6_hdr))) goto fail;
+ if (setFragDgramOffset(&pkt, (progress->offset) / 8)) goto fail;
+
+ frag_length = min(len - LOWMSG_FRAGN_LEN,
+ ntoh16(msg->hdr.plen) + sizeof(struct ip6_hdr) - progress->offset);
+
+
+
+ // unless this is the last fragment, we must sent a multiple of 8 bytes;
+ if (frag_length + progress->offset != ntoh16(msg->hdr.plen) + sizeof(struct ip6_hdr))
+ frag_length -= (frag_length % 8);
+
+ pkt.len = frag_length + LOWMSG_FRAGN_LEN;
+
+ {
+ uint8_t header_length = sizeof(struct ip6_hdr);
+ struct generic_header *cur = msg->headers;
+ while (cur != NULL) {
+ header_length += cur->len;
+ cur = cur->next;
+ }
+ ip_memcpy(buf + LOWMSG_FRAGN_LEN, msg->data + progress->offset - header_length, frag_length);
+ }
+ progress->offset += frag_length;
+ //printf("frag length is: 0x%x offset: 0x%x max: 0x%x\n", frag_length, progress->offset, LOWPAN_MTU);
+
+ return frag_length + LOWMSG_FRAGN_LEN;
+ }
+ fail:
+ return 0;
+}
--- /dev/null
+/*l
+ * "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 <string.h>
+#include "lib6lowpan.h"
+/*
+ * This file presents an interface for parsing IP and UDP headers in a
+ * 6loWPAN packet.
+ *
+ * @author Stephen Dawson-Haggerty <stevedh@cs.berkeley.edu>
+ */
+
+uint8_t linklocal_prefix [] = {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+uint8_t multicast_prefix [] = {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+struct in6_addr __my_address = {{{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65}}};
+uint8_t globalPrefix = 0;
+
+uint8_t *getLinkLocalPrefix() {
+ return &linklocal_prefix[0];
+}
+
+uint8_t cmpPfx(ip6_addr_t a, uint8_t *pfx) {
+ return (a[0] == pfx[0] &&
+ a[1] == pfx[1] &&
+ a[2] == pfx[2] &&
+ a[3] == pfx[3] &&
+ a[4] == pfx[4] &&
+ a[5] == pfx[5] &&
+ a[6] == pfx[6] &&
+ a[7] == pfx[7]);
+}
+
+int ipv6_addr_suffix_is_long(const ip6_addr_t addr) {
+ return (!(addr[8] == 0 &&
+ addr[9] == 0 &&
+ addr[10] == 0 &&
+ addr[11] == 0 &&
+ addr[12] == 0 &&
+ addr[13] == 0));
+}
+
+/*
+ * return the length of the compressed fields in buf
+ */
+int getCompressedLen(packed_lowmsg_t *pkt) {
+ // min lenght is DISPATCH + ENCODING
+ uint8_t encoding, len = 2;
+ uint8_t *buf = getLowpanPayload(pkt);
+
+ if (!(*buf == LOWPAN_HC_LOCAL_PATTERN || *buf == LOWPAN_HC_CRP_PATTERN))
+ return 0;
+
+ encoding = *(buf + 1);
+ if ((encoding & LOWPAN_IPHC_VTF_MASK) == LOWPAN_IPHC_VTF_INLINE)
+ len += 4;
+ if ((encoding & LOWPAN_IPHC_NH_MASK) == LOWPAN_IPHC_NH_INLINE)
+ len += 1;
+ if ((encoding &LOWPAN_IPHC_HLIM_MASK) == LOWPAN_IPHC_HLIM_INLINE)
+ len += 1;
+
+ switch ((encoding >> LOWPAN_IPHC_SC_OFFSET) & LOWPAN_IPHC_ADDRFLAGS_MASK) {
+ case LOWPAN_IPHC_ADDR_128: len += 16; break;
+ case LOWPAN_IPHC_ADDR_64: len += 8; break;
+ case LOWPAN_IPHC_ADDR_16: len += 2; break;
+ case LOWPAN_IPHC_ADDR_0: len += 0; break;
+ }
+ switch ((encoding >> LOWPAN_IPHC_DST_OFFSET) & LOWPAN_IPHC_ADDRFLAGS_MASK) {
+ case LOWPAN_IPHC_ADDR_128: len += 16; break;
+ case LOWPAN_IPHC_ADDR_64: len += 8; break;
+ case LOWPAN_IPHC_ADDR_16: len += 2; break;
+ case LOWPAN_IPHC_ADDR_0: len += 0; break;
+ }
+
+ if ((encoding & LOWPAN_IPHC_NH_MASK) != LOWPAN_IPHC_NH_INLINE) {
+ // figure out how long the next header encoding is
+ uint8_t *nh = buf + len;
+ if ((*nh & LOWPAN_UDP_DISPATCH) == LOWPAN_UDP_DISPATCH) {
+ // are at a udp packet
+ len += 1; // add LOWPAN_HCNH
+ uint8_t udp_enc = *nh;
+ //printf("udp_enc: 0x%x\n", udp_enc);
+ if ((udp_enc & LOWPAN_UDP_S_MASK) && (udp_enc & LOWPAN_UDP_D_MASK))
+ len += 1;
+ else if ((udp_enc & LOWPAN_UDP_S_MASK) || (udp_enc & LOWPAN_UDP_D_MASK))
+ len += 3;
+ else
+ len += 4;
+ if ((udp_enc & LOWPAN_UDP_C_MASK) == 0)
+ len += 2;
+ }
+ }
+
+ len += (buf - pkt->data);
+ return len;
+}
+
+int decompressShortAddress(uint8_t dispatch, uint8_t *s_addr, uint8_t *dest) {
+ if ((*s_addr & LOWPAN_IPHC_SHORT_MASK) == 0) {
+ // simplest case, just use the appropriate prefix.
+ if (dispatch == LOWPAN_HC_LOCAL_PATTERN)
+ ip_memcpy(dest, linklocal_prefix, 8);
+ else
+ ip_memcpy(dest, __my_address.s6_addr, 8);
+ ip_memclr(dest + 8, 8);
+ dest[14] = (*s_addr) & ~LOWPAN_IPHC_SHORT_MASK;
+ dest[15] = *(s_addr + 1);
+ return 0;
+ }
+ // otherwise we either have an invalid compression, or else it's a
+ // multicast address
+ ip_memcpy(dest, multicast_prefix, 8);
+ ip_memclr(dest + 8, 8);
+ switch (*s_addr & LOWPAN_IPHC_SHORT_LONG_MASK) {
+ case LOWPAN_IPHC_HC1_MCAST:
+ dest[14] = (*s_addr) & ~LOWPAN_IPHC_SHORT_LONG_MASK;
+ dest[15] = *(s_addr + 1);
+ break;
+ case LOWPAN_IPHC_HC_MCAST:
+ dest[1] = ((*s_addr) & LOWPAN_HC_MCAST_SCOPE_MASK) >> LOWPAN_HC_MCAST_SCOPE_OFFSET;
+
+ // we'll just direct map the bottom 9 bits in for the moment,
+ // since HC doesn't specify anything that would break this. In
+ // the future, a more complicated mapping is likely.
+ dest[14] = (*s_addr) & 0x1;
+ dest[15] = *(s_addr + 1);
+ break;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+int decompressAddress(uint8_t dispatch, uint16_t src, uint8_t addr_flags,
+ uint8_t **buf, uint8_t *dest) {
+ uint8_t *prefix;
+ uint16_t tmp;
+ int rc = 0;
+ if (dispatch == LOWPAN_HC_LOCAL_PATTERN)
+ prefix = linklocal_prefix;
+ else
+ prefix = __my_address.s6_addr;
+
+ switch (addr_flags) {
+ case LOWPAN_IPHC_ADDR_128:
+ ip_memcpy(dest, *buf, 16);
+ *buf += 16;
+ break;
+ case LOWPAN_IPHC_ADDR_64:
+ ip_memcpy(dest, prefix, 8);
+ ip_memcpy(dest + 8, *buf, 8);
+ *buf += 8;
+ break;
+ case LOWPAN_IPHC_ADDR_16:
+ rc = decompressShortAddress(dispatch, *buf, dest);
+ *buf += 2;
+ break;
+ case LOWPAN_IPHC_ADDR_0:
+ ip_memcpy(dest, prefix, 8);
+ ip_memclr(dest + 8, 6);
+ tmp = hton16(src);
+ ip_memcpy(dest + 14, (uint8_t *)&tmp, 2);
+ break;
+ }
+ return rc;
+}
+
+/*
+ * Unpacks all headers, including any compressed transport headers if
+ * there is a compression scheme defined for them.
+ *
+ * @pkt - the wrapped struct pointing to the compressed headers
+ * @dest - buffer to unpack the headers into
+ * @len - the len of 'dest'
+ * @return the number of bytes written to dest, or zero if decompression failed.
+ * should be >= sizeof(struct ip6_hdr)
+ */
+uint8_t *unpackHeaders(packed_lowmsg_t *pkt, unpack_info_t *u_info,
+ uint8_t *dest, uint16_t len) {
+ uint8_t dispatch, encoding;
+ uint16_t size, extra_header_length = 0;
+ uint8_t *buf = (uint8_t *)getLowpanPayload(pkt);
+
+ // pointers to fields we may come back to fill in later
+ uint8_t *plen, *prot_len, *nxt_hdr;
+
+ u_info->payload_offset = 0;
+ u_info->rih = NULL;
+ u_info->sh = NULL;
+ u_info->transport_ptr = NULL;
+
+ // a buffer we can write addresses prefixes and suffexes into.
+ // now we don't need to check sizes until we get to next headers
+ if (buf == NULL || len < sizeof(struct ip6_hdr)) return NULL;
+ len -= sizeof(struct ip6_hdr);
+
+ dispatch = *buf; buf++;
+ encoding = *buf; buf++;
+
+ if (dispatch != LOWPAN_HC_LOCAL_PATTERN && dispatch != LOWPAN_HC_CRP_PATTERN)
+ return NULL;
+
+ if ((encoding & LOWPAN_IPHC_VTF_MASK) == LOWPAN_IPHC_VTF_INLINE) {
+ // copy the inline 4 bytes of fields.
+ ip_memcpy(dest, buf, 4);
+ buf += 4;
+ } else {
+ // cler the traffic class and flow label fields, and write the version.
+ ip_memclr(dest, 4);
+ *dest = IPV6_VERSION << 4;
+ }
+ dest += 4;
+
+ plen = dest;
+ prot_len = dest;
+ // payload length field requires some computation...
+ dest += 2;
+
+ if ((encoding & LOWPAN_IPHC_NH_MASK) == LOWPAN_IPHC_NH_INLINE) {
+ *dest = *buf;
+ buf++;
+ }
+ nxt_hdr = dest;
+
+ dest += 1;
+ // otherwise, decompress IPNH compression once we reach the end of
+ // the packed data.
+
+ u_info->hlim = NULL;
+ if ((encoding & LOWPAN_IPHC_HLIM_MASK) == LOWPAN_IPHC_HLIM_INLINE) {
+ *dest = *buf;
+ u_info->hlim = buf;
+ buf++;
+ }
+ dest += 1;
+ // otherwise, follow instructions for reconstructing hop limit once
+ // destination address is known.
+
+
+ // dest points at the start of the source address IP header field.
+ decompressAddress(dispatch, pkt->src,
+ (encoding >> LOWPAN_IPHC_SC_OFFSET) & LOWPAN_IPHC_ADDRFLAGS_MASK,
+ &buf, dest);
+ dest += 16;
+
+ decompressAddress(dispatch, pkt->src,
+ (encoding >> LOWPAN_IPHC_DST_OFFSET) & LOWPAN_IPHC_ADDRFLAGS_MASK,
+ &buf, dest);
+ dest += 16;
+
+ // we're done with the IP headers; time to decompress any compressed
+ // headers which follow... We need to re-check that there's enough
+ // buffer to do this.
+
+
+ if ((encoding & LOWPAN_IPHC_NH_MASK) != LOWPAN_IPHC_NH_INLINE) {
+ // time to decode some next header fields
+ // we ought to be pointing at the HCNH encoding byte now.
+ if ((*buf & LOWPAN_UDP_DISPATCH) == LOWPAN_UDP_DISPATCH) {
+ pkt->headers |= LOWMSG_IPNH_HDR;
+ if (len < sizeof(struct udp_hdr)) return NULL;
+ len -= sizeof(struct udp_hdr);
+ struct udp_hdr *udp = (struct udp_hdr *)dest;
+ uint8_t udp_enc = *buf;
+ uint8_t dst_shift = 4;
+
+ extra_header_length = sizeof(struct udp_hdr);
+ buf += 1;
+ // UDP
+ *nxt_hdr = IANA_UDP;
+ if (udp_enc & LOWPAN_UDP_S_MASK) {
+ // recover from 4 bit packing
+ udp->srcport = hton16((*buf >> 4) + LOWPAN_UDP_PORT_BASE);
+ dst_shift = 0;
+ } else {
+ ip_memcpy((uint8_t *)&udp->srcport, buf, 2);
+ buf += 2;
+ }
+
+ if (udp_enc & LOWPAN_UDP_D_MASK) {
+ udp->dstport = hton16((((*buf >> dst_shift)) & 0x0f) + LOWPAN_UDP_PORT_BASE);
+ buf += 1;
+ } else {
+ if (dst_shift == 0) buf += 1;
+ ip_memcpy((uint8_t *)&udp->dstport, buf, 2);
+ buf += 2;
+ }
+
+ if (udp_enc & LOWPAN_UDP_C_MASK) {
+ // we elided the checksum and so are supposed to recompute it here.
+ // however, we won't do this.
+ } else {
+ ip_memcpy((uint8_t *)&udp->chksum, buf, 2);
+ buf += 2;
+ }
+
+ // still must fill in the length field, but we must first
+ // recompute the IP length, which we couldn't do until now.
+ // lamers...
+ prot_len = (uint8_t *)&udp->len;
+ dest += sizeof(struct udp_hdr);
+
+ u_info->nxt_hdr = IANA_UDP;
+ u_info->payload_offset += sizeof(struct udp_hdr);
+ u_info->transport_ptr = (uint8_t *)udp;
+
+ } else {
+ // otherwise who knows what's here... it's an error because the
+ // NH bit said we were inline but when we got here, we didn't
+ // recognize the NH encoding.
+ return NULL;
+ }
+ } else {
+ // there was no IPNH field, but there might be uncompressed fields
+ // we want to copy out for consistency (since we always unpack all
+ // headers not part of the payload).
+ uint8_t nhdr = *nxt_hdr;
+ uint8_t nhdr_len = 0;
+ struct ip6_ext *hdr;
+ u_info->nxt_hdr = nhdr;
+ while (KNOWN_HEADER(nhdr)) {
+ hdr = (struct ip6_ext *)buf;
+ u_info->nxt_hdr = nhdr;
+ switch (nhdr) {
+ case IANA_UDP:
+ nhdr = NXTHDR_UNKNOWN;
+ nhdr_len = sizeof(struct udp_hdr);
+ u_info->transport_ptr = dest;
+ break;
+ case NXTHDR_SOURCE:
+ u_info->sh = (struct source_header *)buf;
+ nhdr = hdr->nxt_hdr;
+ nhdr_len = hdr->len;
+ u_info->nxt_hdr = nhdr;
+ break;
+ case NXTHDR_INSTALL:
+ // this is how to handle all ipv6 options headers: should we
+ // use "default" here?
+ u_info->rih = (struct rinstall_header *)buf;
+ default:
+ nhdr = hdr->nxt_hdr;
+ nhdr_len = hdr->len;
+ u_info->nxt_hdr = nhdr;
+ }
+ if (len < nhdr_len) return NULL;
+ ip_memcpy(dest, buf, nhdr_len);
+ dest += nhdr_len;
+ buf += nhdr_len;
+
+ u_info->payload_offset += nhdr_len;
+ extra_header_length += nhdr_len;
+ }
+ }
+
+ u_info->payload_start = buf;
+ u_info->header_end = dest;
+ if (u_info->transport_ptr == NULL)
+ u_info->transport_ptr = dest;
+
+ // we can go back and figure out the payload length now that we know
+ // how long the compressed headers were
+ if (hasFrag1Header(pkt) || hasFragNHeader(pkt)) {
+ getFragDgramSize(pkt, &size);
+ size -= sizeof(struct ip6_hdr);
+ } else {
+ // it's a one fragment packet
+ size = pkt->len - (buf - pkt->data);
+ size += extra_header_length;
+ size -= getLowpanPayload(pkt) - pkt->data;
+ }
+
+ *plen = size >> 8;
+ *(plen + 1) = size & 0xff;
+
+ // finally fill in the udp length field that we finally can recompute
+ switch (*nxt_hdr) {
+ case IANA_UDP:
+ *prot_len = size >> 8;
+ *(prot_len + 1) = size & 0xff;
+ }
+
+
+ return buf;
+}
+
+/* packs addr into *buf, and updates the pointer relative to the length
+ * that was needed.
+ * @returns the bit flags indicating which length was used
+ */
+uint8_t packAddress(uint8_t dispatch, uint8_t **buf, ip6_addr_t addr) {
+
+ if ((dispatch == LOWPAN_HC_CRP_PATTERN && globalPrefix &&
+ cmpPfx(addr, __my_address.s6_addr)) ||
+ (dispatch == LOWPAN_HC_LOCAL_PATTERN &&
+ cmpPfx(addr, linklocal_prefix))) {
+ // only choice here are 64-bit and 16-bit addresses
+ if (ipv6_addr_suffix_is_long(addr)) {
+ // use the 64-bit compression
+ ip_memcpy(*buf, &addr[8], 8);
+ *buf += 8;
+ return LOWPAN_IPHC_ADDR_64;
+ } else {
+ // down to 16 bits: we never use the 0-bit compression
+ // (althought we could for link local).
+ ip_memcpy(*buf, &addr[14], 2);
+ *buf += 2;
+ return LOWPAN_IPHC_ADDR_16;
+ }
+ } else if (addr[0] == 0xff && // is multicast
+ addr[1] < 0x0f) { // the scope is small enough
+ // XXX : SDH : Need to check that the group is small enough
+ **buf = LOWPAN_IPHC_HC_MCAST; // set the encoding bits
+ **buf |= (addr[1] << LOWPAN_HC_MCAST_SCOPE_OFFSET); // scope
+
+ // direct mapped group id
+ **buf |= addr[14] & 0x1;
+ *(*buf + 1) = addr[15];
+ *buf += 2;
+ return LOWPAN_IPHC_ADDR_16;
+ } else {
+ // fuck it, send the whole thing
+ ip_memcpy(*buf, addr, 16);
+ *buf += 16;
+ return LOWPAN_IPHC_ADDR_128;
+ }
+}
+
+/*
+ * pack the headers of msg into the buffer pointed to by buf.
+ *
+ * @returns a pointer to where we stopped writing
+ */
+uint8_t packHeaders(struct split_ip_msg *msg,
+ uint8_t *buf, uint8_t len) {
+ uint8_t *dispatch, *encoding, addr_enc, nxt_hdr;
+ struct ip6_hdr *hdr = &msg->hdr;
+ dispatch = buf;
+ buf += 1;
+ encoding = buf;
+ buf += 1;
+ *encoding = 0;
+
+ if (!(hdr->vlfc[0] == (IPV6_VERSION << 4) &&
+ hdr->vlfc[1] == 0 &&
+ hdr->vlfc[2] == 0 &&
+ hdr->vlfc[3] == 0)) {
+ ip_memcpy(buf, &hdr->vlfc, 4);
+ buf += 4;
+ } else {
+ *encoding |= LOWPAN_IPHC_VTF_MASK;
+ }
+
+ nxt_hdr = hdr->nxt_hdr;
+ if (hdr->nxt_hdr == IANA_UDP /* or other compressed values... */) {
+ // we will add the HCNH encoding at the end of the header
+ *encoding |= LOWPAN_IPHC_NH_MASK;
+ } else {
+ *buf = hdr->nxt_hdr;
+ buf += 1;
+ }
+
+ // always carry hop limit
+ *buf = hdr->hlim;
+ buf += 1;
+
+ if (globalPrefix && cmpPfx(hdr->ip6_src.s6_addr, __my_address.s6_addr)) {
+ *dispatch = LOWPAN_HC_CRP_PATTERN;
+ } else if (globalPrefix && cmpPfx(hdr->ip6_dst.s6_addr, __my_address.s6_addr)) {
+ *dispatch = LOWPAN_HC_CRP_PATTERN;
+ } else if (cmpPfx(hdr->ip6_src.s6_addr, linklocal_prefix)) {
+ *dispatch = LOWPAN_HC_LOCAL_PATTERN;
+ } else {
+ *dispatch = LOWPAN_HC_LOCAL_PATTERN;
+ }
+
+ addr_enc = packAddress(*dispatch, &buf, hdr->ip6_src.s6_addr);
+ *encoding |= addr_enc << LOWPAN_IPHC_SC_OFFSET;
+
+ addr_enc = packAddress(*dispatch, &buf, hdr->ip6_dst.s6_addr);
+ *encoding |= addr_enc << LOWPAN_IPHC_DST_OFFSET;
+
+ len -= (buf - dispatch);
+ // now come the compressions for special next header values.
+ // we pack all the headers in the split message into this fragment, and fail if we cannot;
+ {
+ int i = 0;
+ struct generic_header *cur = msg->headers;
+ while (cur != NULL) {
+ if (nxt_hdr == IANA_UDP && i == 0) {
+ struct udp_hdr *udp = cur->hdr.udp;
+
+ uint8_t *udp_enc = buf;
+ uint8_t *cmpr_port = NULL;
+ // do the LOWPAN_UDP coding
+
+ if (len < sizeof(struct udp_hdr)) return (buf - dispatch);
+
+ *udp_enc = LOWPAN_UDP_DISPATCH;;
+ buf += 1;
+
+
+ if ((ntoh16(udp->srcport) & LOWPAN_UDP_PORT_BASE_MASK) ==
+ LOWPAN_UDP_PORT_BASE) {
+ //printf("compr to 4b\n");
+ cmpr_port = buf;
+ *cmpr_port = (ntoh16(udp->srcport) & ~LOWPAN_UDP_PORT_BASE_MASK) << 4;
+ *udp_enc |= LOWPAN_UDP_S_MASK;
+ buf += 1;
+ } else {
+ ip_memcpy(buf, (uint8_t *)&udp->srcport, 2);
+ buf += 2;
+ }
+
+ if ((ntoh16(udp->dstport) & LOWPAN_UDP_PORT_BASE_MASK) ==
+ LOWPAN_UDP_PORT_BASE) {
+ if (cmpr_port == NULL) {
+ // the source port must not have been compressed, so
+ // allocate a new byte for this guy
+ *buf = ((ntoh16(udp->dstport) & ~LOWPAN_UDP_PORT_BASE_MASK) << 4);
+ buf += 1;
+ } else {
+ // already in the middle of a byte for the port compression,
+ // so fill in the rest of the byte
+ *cmpr_port = *cmpr_port | ((ntoh16(udp->dstport) & ~LOWPAN_UDP_PORT_BASE_MASK));
+ }
+ *udp_enc |= LOWPAN_UDP_D_MASK;
+ } else {
+ ip_memcpy(buf, (uint8_t *)&udp->dstport, 2);
+ buf += 2;
+ }
+
+ // we never elide the checksum
+ ip_memcpy(buf, (uint8_t *)&udp->chksum, 2);
+ buf += 2;
+ } else {
+ // otherwise we just need to copy the extension header
+ if (len < cur->len) return 0;
+ ip_memcpy(buf, (uint8_t *)cur->hdr.ext, cur->len);
+ len -= cur->len;
+ buf += cur->len;
+ }
+ cur = cur->next;
+ i++;
+ }
+ }
+ // I think we're done here...
+ return buf - dispatch;
+}
+
+/*
+ * indicates how much of the packet after the IP header we will pack
+ *
+ */
+/* int packs_header(struct split_ip_msg *msg) { */
+/* switch (hdr->nxt_hdr) { */
+/* case IANA_UDP: */
+/* return sizeof(struct udp_hdr); */
+/* default: */
+/* return 0; */
+/* } */
+/* } */
+
+
+#define CHAR_VAL(X) (((X) >= '0' && (X) <= '9') ? ((X) - '0') : \
+ (((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : ((X) - 'a' + 10)))
+
+
+void inet_pton6(char *addr, struct in6_addr *dest) {
+ uint16_t cur = 0;
+ char *p = addr;
+ uint8_t block = 0, shift = 0;
+ if (addr == NULL || dest == NULL) return;
+ ip_memclr(dest->s6_addr, 16);
+
+ // first fill in from the front
+ while (*p != '\0') {
+ if (*p != ':') {
+ cur <<= 4;
+ cur |= CHAR_VAL(*p);
+ } else {
+ dest->s6_addr16[block++] = hton16(cur);
+ cur = 0;
+ }
+ p++;
+ if (*p == '\0')
+ return;
+ if (*(p - 1) == ':' && *p == ':') {
+ break;
+ }
+ }
+ // we must have hit a "::" which means we need to start filling in from the end.
+ block = 7;
+ cur = 0;
+ while (*p != '\0') p++;
+ p--;
+ // now pointing at the end of the address string
+ while (p > addr) {
+ if (*p != ':') {
+ cur |= (CHAR_VAL(*p) << shift);
+ shift += 4;
+ } else {
+ dest->s6_addr16[block--] = hton16(cur);
+ cur = 0; shift = 0;
+ }
+ p --;
+ if (*(p + 1) == ':' && *p == ':') break;
+ }
+}
--- /dev/null
+/*
+ * "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 <arpa/inet.h>
+#include "6lowpan.h"
+#include "lib6lowpan.h"
+#include "lib6lowpanIP.h"
+
+
+void printBuf(uint8_t *buf, uint16_t len) {
+ int i;
+ for (i = 1; i <= len; i++) {
+ printf(" 0x%02x", buf[i-1]);
+ if (i % 16 == 0) printf("\n");
+
+ }
+ printf("\n\n");
+}
+
+
+void printPacket(uint8_t *buf, int len) {
+ uint8_t val;
+ uint16_t origin, final;
+ packed_lowmsg_t pkt;
+
+ // used for autoconfiguration; would be provided by lower layers.
+ pkt.src = 0xaa;
+ pkt.dst = 0xbb;
+
+ printBuf(buf, len);
+
+ pkt.data = buf;
+ pkt.len = len;
+ pkt.headers = getHeaderBitmap(&pkt);
+ printf("6loWPAN Packet (headers: 0x%x)\n", pkt.headers);
+ if (hasBcastHeader(&pkt)) {
+ getBcastSeqno(&pkt, &val);
+ printf(" BCast seqno: 0x%x\n", val);
+ }
+ if (hasMeshHeader(&pkt)) {
+ getMeshHopsLeft(&pkt, &val);
+ getMeshOriginAddr(&pkt, &origin);
+ getMeshFinalAddr(&pkt, &final);
+ printf(" Mesh hops: 0x%x origin: 0x%x final: 0x%x\n", val, origin, final);
+ }
+ if (hasFrag1Header(&pkt) || hasFragNHeader(&pkt)) {
+ getFragDgramSize(&pkt, &origin);
+ getFragDgramTag(&pkt, &final);
+ printf(" Frag size: 0x%x tag: 0x%x\n", origin, final);
+ }
+ if (hasFragNHeader(&pkt)) {
+ getFragDgramOffset(&pkt, &val);
+ printf(" Frag offset: 0x%x\n", val);
+ }
+
+
+ uint8_t data[100];
+ struct ip6_hdr *h = (struct ip6_hdr *)data;
+ unpackHeaders(&pkt, (uint8_t *)h, 100);
+
+ printf(" ip first bytes: 0x%x\n", ntohl(*((uint32_t *)h->vlfc)));
+ printf(" plen: 0x%x next: 0x%x hlim: 0x%x\n", ntohs(h->plen), h->nxt_hdr, h->hlim);
+ printf(" src: ");
+ for (val = 0; val < 16; val++)
+ printf("0x%x ", h->src_addr[val]);
+ printf("\n dst: ");
+ for (val = 0; val < 16; val++)
+ printf("0x%x ", h->dst_addr[val]);
+ printf("\n");
+
+ if (h->nxt_hdr == IANA_UDP) {
+ struct udp_hdr *udp = (struct udp_hdr *)&data[sizeof(struct ip6_hdr)];
+ printf("udp src: 0x%x dst: 0x%x len: 0x%x cksum: 0x%x\n",
+ ntoh16(udp->srcport), ntoh16(udp->dstport),
+ ntoh16(udp->len), ntoh16(udp->chksum));
+ }
+
+
+ printf("\n\n");
+}
--- /dev/null
+
+GCC=gcc
+CFLAGS=-I../include -I../driver/ -DPC -g
+
+
+all: test_client test_server
+
+test_circ: test_circ.c circ.c
+ $(GCC) -o $@ $^
+
+test_client: test_client.c tcplib.h tcplib.c circ.c
+ $(GCC) -o $@ $< tcplib.c circ.c ../driver/tun_dev.c ../lib6lowpan/ip_malloc.c ../lib6lowpan/in_cksum.c $(CFLAGS)
+
+test_server: test_server.c tcplib.h tcplib.c circ.c
+ $(GCC) -o $@ $< tcplib.c circ.c ../driver/tun_dev.c ../lib6lowpan/ip_malloc.c ../lib6lowpan/in_cksum.c $(CFLAGS)
+
+clean:
+ rm -rf test_server test_circ
\ No newline at end of file
--- /dev/null
+
+#include <stdio.h>
+#include <stdint.h>
+// #include <assert.h>
+#include <string.h>
+
+#include "tcplib.h"
+
+struct circ_buf {
+ uint8_t *map;
+ uint16_t map_len;
+ uint8_t *data_start;
+ uint8_t *data_head;
+ uint16_t data_len;
+ uint32_t head_seqno;
+};
+
+int circ_buf_init(void *data, int len, uint32_t seqno, int incl_map) {
+ struct circ_buf *b = (struct circ_buf *)data;
+ int bitmap_len = ((len - sizeof(struct circ_buf)) / 9);
+ // int data_len = bitmap_len * 8;
+
+ // printf("circ_buf_init: len: %i data_len: %i bitmap_len: %i\n", len, data_len, bitmap_len);
+ // assert(bitmap_len + data_len + sizeof(struct circ_buf) <= len);
+
+ if (len < sizeof(struct circ_buf))
+ return -1;
+
+ if (incl_map) {
+ b->map = (uint8_t *)(b + 1);
+ b->map_len = bitmap_len;
+ b->data_start = b->map + bitmap_len;
+ b->data_len= bitmap_len * 8;
+ memset(b->map, 0, bitmap_len * 9);
+ } else {
+ b->map = NULL;
+ b->map_len = 0;
+ b->data_start = (uint8_t *)(b + 1);
+ b->data_len = len - sizeof(struct circ_buf);
+ memset(b->data_start, 0, b->data_len);
+ }
+ b->data_head = b->data_start;
+ b->head_seqno = seqno;
+
+ // printf("circ_buf_init: buf: %p data_start: %p data_head: %p data_len: %i\n",
+ // b, b->data_start, b->data_head, b->data_len);
+
+ return 0;
+}
+
+#define BIT_SET(off,map) map[(off)/8] |= (1 << (7 - ((off) % 8)))
+#define BIT_UNSET(off,map) map[(off)/8] &= ~(1 << (7 - ((off) % 8)))
+#define BIT_ISSET(off, map) map[(off)/8] & 1 << (7 - (off) % 8)
+
+static void bitmap_mark(struct circ_buf *b, uint8_t *data, int len) {
+ int offset = data - b->data_start;
+ if (b->map_len == 0) return;
+ while (len-- > 0) {
+ BIT_SET(offset, b->map);
+ offset = (offset + 1) % b->data_len;
+ }
+}
+
+/* return the sequence number of the first byte of data in the buffer;
+ this is what the stack can ACK. */
+uint32_t circ_get_seqno(void *buf) {
+ struct circ_buf *b = (struct circ_buf *)buf;
+ return b->head_seqno;
+}
+
+void circ_set_seqno(void *buf, uint32_t seqno) {
+ struct circ_buf *b = (struct circ_buf *)buf;
+ b->head_seqno = seqno;
+}
+
+uint16_t circ_get_window(void *buf) {
+ struct circ_buf *b = (struct circ_buf *)buf;
+ return b->data_len;
+}
+
+/* read as many contiguous bytes from the head of the buffer as
+ * possible, and update the internal data structures to shorten the
+ * buffer
+ *
+ * buf: the circular buffer
+ * data: a pointer which will be updated with the location of the data
+ * return: the number of bytes available
+ */
+int circ_buf_read_head(void *buf, char **data) {
+ struct circ_buf *b = (struct circ_buf *)buf;
+ int off = b->data_head - b->data_start;
+ int rlen = 0;
+ *data = b->data_head;
+ while (BIT_ISSET(off, b->map) && off < b->data_len) {
+ BIT_UNSET(off, b->map);
+ rlen++;
+ b->head_seqno++;
+ b->data_head ++;
+ if (b->data_head == b->data_start + b->data_len)
+ b->data_head = b->data_start;
+ off++;
+ }
+ return rlen;
+}
+
+
+static void get_ptr_off_1(struct circ_buf *b, uint32_t sseqno, int len,
+ uint8_t **writeptr, int *w_len) {
+ uint8_t *endptr = b->data_start + b->data_len;
+ int offset;
+
+ *writeptr = NULL;
+ *w_len = 0;
+
+ /* write up to either the end of the buffer */
+ offset = sseqno - b->head_seqno;
+ if (b->data_head + offset < endptr) {
+ *w_len = len;
+ *writeptr = b->data_head + offset;
+ if (*writeptr + *w_len > endptr) {
+ *w_len = endptr - *writeptr;
+ }
+ }
+}
+
+int circ_shorten_head(void *buf, uint32_t seqno) {
+ struct circ_buf *b = (struct circ_buf *)buf;
+ int offset = seqno - b->head_seqno;
+
+ b->head_seqno = seqno;
+
+ b->data_head += offset;
+ while (b->data_head > b->data_start + b->data_len)
+ b->data_head -= b->data_len;
+
+ return 0;
+}
+
+int circ_buf_read(void *buf, uint32_t sseqno,
+ uint8_t *data, int len) {
+ struct circ_buf *b = (struct circ_buf *)buf;
+ uint8_t *readptr;
+ int r_len, rc = 0;
+
+ get_ptr_off_1(b, sseqno, len, &readptr, &r_len);
+ memcpy(data, readptr, r_len);
+ data += r_len;
+ rc += r_len;
+
+ if (r_len != len) {
+ readptr = b->data_start;
+ r_len = min(len - r_len, b->data_head - b->data_start);
+ memcpy(data, readptr, r_len);
+ rc += r_len;
+ }
+ return rc;
+}
+
+int circ_buf_write(void *buf, uint32_t sseqno,
+ uint8_t *data, int len) {
+ struct circ_buf *b = (struct circ_buf *)buf;
+ uint8_t *writeptr;
+ int w_len;
+
+ /* we can't write any bytes since we're trying to write too far
+ ahead */
+ // printf("circ_buf_write: sseqno: %i head_seqno: %i len: %i\n",
+ // sseqno, b->head_seqno, len);
+
+ if (sseqno > b->head_seqno + b->data_len)
+ return -1;
+
+ if (sseqno < b->head_seqno) {
+ /* old data, but already received */
+ if (sseqno < b->head_seqno - len) return -1;
+ /* a segment which overlaps with data we've already received */
+ data += (b->head_seqno - sseqno);
+ len -= (b->head_seqno - sseqno);
+ sseqno = b->head_seqno;
+ }
+ if (len == 0) return 0;
+
+ // printf("circ_buf_write: buf: %p data_start: %p data_head: %p data_len: %i\n",
+ // b, b->data_start, b->data_head, b->data_len);
+ get_ptr_off_1(b, sseqno, len, &writeptr, &w_len);
+ memcpy(writeptr, data, w_len);
+ data += w_len;
+ bitmap_mark(b, writeptr, w_len);
+
+ if (w_len != len) {
+ writeptr = b->data_start;
+ w_len = min(len - w_len, b->data_head - b->data_start);
+ memcpy(writeptr, data, w_len);
+ bitmap_mark(b, writeptr, w_len);
+ // printf("circ_buf_write (2): write: %p len: %i\n", writeptr, w_len);
+ }
+ return 0;
+}
+
+#ifdef PC
+void circ_buf_dump(void *buf) {
+ struct circ_buf *b = (struct circ_buf *)buf;
+ int i;
+/* printf("circ buf: %p\n\tmap: %p\n\tmap_len: %i\n\tdata_start: %p\n\t" */
+/* "data_head: %p\n\tdata_len: %i\n\thead_seqno: %i\n", */
+/* b, b->map, */
+/* b->map_len, b->data_start, b->data_head, b->data_len, b->head_seqno); */
+
+ for (i = 1; i <= b->data_len; i++) {
+ if (BIT_ISSET(i-1, b->map))
+ putc('x',stdout);
+ else
+ putc('_',stdout);
+ if (i % 80 == 0 || i == b->data_len) {
+ putc('\n',stdout);
+ }
+ }
+}
+#endif
--- /dev/null
+#ifndef __CIRC_H_
+#define __CIRC_H_
+
+#include <stdint.h>
+
+int circ_buf_init(void *data, int len, uint32_t seqno, int inc_map);
+
+
+int circ_buf_write(void *buf, uint32_t sseqno,
+ uint8_t *data, int len);
+
+
+int circ_buf_read(void *buf, uint32_t sseqno,
+ uint8_t *data, int len);
+
+
+int circ_shorten_head(void *buf, uint32_t seqno);
+
+/* read from the head of the buffer, moving the data pointer forward */
+int circ_buf_read_head(void *buf, char **data);
+
+void circ_buf_dump(void *buf);
+
+void circ_set_seqno(void *buf, uint32_t seqno);
+
+#endif
--- /dev/null
+
+/* A nonblocking library-based implementation of TCP
+ *
+ * There are some things like timers which need to be handled
+ * externally with callbacks.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "ip_malloc.h"
+#include "in_cksum.h"
+#include "6lowpan.h"
+#include "ip.h"
+#include "tcplib.h"
+#include "circ.h"
+
+static struct tcplib_sock *conns = NULL;
+
+#define ONE_SEGMENT(X) ((X)->mss)
+
+uint16_t alloc_local_port() {
+ return 32012;
+}
+
+static inline void conn_add_once(struct tcplib_sock *sock) {
+ struct tcplib_sock *iter;
+
+ for (iter = conns; iter != NULL; iter = iter->next) {
+ if (iter == sock) break;
+ }
+ if (iter == NULL) {
+ sock->next = conns;
+ conns = sock;
+ }
+
+}
+static int isInaddrAny(struct in6_addr *addr) {
+ int i;
+ for (i = 0; i < 8; i++)
+ if (addr->s6_addr16[i] != 0) break;
+ if (i != 8) return 0;
+ return 1;
+}
+
+static struct tcplib_sock *conn_lookup(struct ip6_hdr *iph,
+ struct tcp_hdr *tcph) {
+ struct tcplib_sock *iter;
+ printfUART("looking up conns...\n");
+ for (iter = conns; iter != NULL; iter = iter->next) {
+ printf("conn lport: %i\n", ntohs(iter->l_ep.sin6_port));
+ if (((memcmp(iph->ip6_dst.s6_addr, iter->l_ep.sin6_addr.s6_addr, 16) == 0) ||
+ isInaddrAny(&iter->l_ep.sin6_addr)) &&
+ tcph->dstport == iter->l_ep.sin6_port &&
+ (iter->r_ep.sin6_port == 0 ||
+ (memcmp(&iph->ip6_src, &iter->r_ep.sin6_addr, 16) == 0 &&
+ tcph->srcport == iter->r_ep.sin6_port)))
+ return iter;
+ }
+ return NULL;
+}
+
+static int conn_checkport(uint16_t port) {
+ struct tcplib_sock *iter;
+
+ for (iter = conns; iter != NULL; iter = iter->next) {
+ if (iter->l_ep.sin6_port == port)
+ return -1;
+ }
+ return 0;
+}
+
+struct tcp_hdr *find_tcp_hdr(struct split_ip_msg *msg) {
+ if (msg->hdr.nxt_hdr == IANA_TCP) {
+ return (struct tcp_hdr *)((msg->headers == NULL) ? msg->data :
+ msg->headers->hdr.data);
+ }
+}
+
+static struct split_ip_msg *get_ipmsg(int plen) {
+ struct split_ip_msg *msg =
+ (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg) + sizeof(struct tcp_hdr) + plen);
+ if (msg == NULL) return NULL;
+ memset(msg, 0, sizeof(struct split_ip_msg) + sizeof(struct tcp_hdr));
+ msg->hdr.nxt_hdr = IANA_TCP;
+ msg->hdr.plen = htons(sizeof(struct tcp_hdr) + plen);
+
+ msg->headers = NULL;
+ msg->data = (void *)(msg + 1);
+ msg->data_len = sizeof(struct tcp_hdr) + plen;
+
+ return msg;
+}
+
+static void __tcplib_send(struct tcplib_sock *sock,
+ struct split_ip_msg *msg) {
+ struct tcp_hdr *tcph = find_tcp_hdr(msg);
+ memcpy(&msg->hdr.ip6_dst, &sock->r_ep.sin6_addr, 16);
+
+ sock->flags &= ~TCP_ACKPENDING;
+
+ // sock->ackno = ntohl(tcph->ackno);
+
+ tcph->srcport = sock->l_ep.sin6_port;
+ tcph->dstport = sock->r_ep.sin6_port;
+ tcph->offset = sizeof(struct tcp_hdr) * 4;
+ tcph->window = htons(circ_get_window(sock->rx_buf));
+ tcph->chksum = 0;
+ tcph->urgent = 0;
+
+ tcplib_send_out(msg, tcph);
+}
+
+static void tcplib_send_ack(struct tcplib_sock *sock, int fin_seqno, uint8_t flags) {
+ struct split_ip_msg *msg = get_ipmsg(0);
+
+ if (msg != NULL) {
+ struct tcp_hdr *tcp_rep = (struct tcp_hdr *)(msg + 1);
+ tcp_rep->flags = flags;
+
+ tcp_rep->seqno = htonl(sock->seqno);
+ tcp_rep->ackno = htonl(circ_get_seqno(sock->rx_buf) +
+ (fin_seqno ? 1 : 0));
+ __tcplib_send(sock, msg);
+ ip_free(msg);
+ }
+}
+
+static void tcplib_send_rst(struct ip6_hdr *iph, struct tcp_hdr *tcph) {
+ struct split_ip_msg *msg = get_ipmsg(0);
+
+ if (msg != NULL) {
+ struct tcp_hdr *tcp_rep = (struct tcp_hdr *)(msg + 1);
+
+ memcpy(&msg->hdr.ip6_dst, &iph->ip6_src, 16);
+
+ tcp_rep->flags = TCP_FLAG_RST;
+
+ tcp_rep->ackno = tcph->seqno + 1;
+ tcp_rep->seqno = tcph->ackno;;
+
+ tcp_rep->srcport = tcph->dstport;
+ tcp_rep->dstport = tcph->srcport;
+ tcp_rep->offset = sizeof(struct tcp_hdr) * 4;
+ tcp_rep->window = 0;
+ tcp_rep->chksum = 0;
+ tcp_rep->urgent = 0;
+
+ tcplib_send_out(msg, tcp_rep);
+
+ ip_free(msg);
+
+ }
+}
+
+/* send all the data in the tx buffer, starting at sseqno */
+static int tcplib_output(struct tcplib_sock *sock, uint32_t sseqno) {
+ // the output size is the minimum of the advertised window and the
+ // conjestion window. of course, if we have less data we send even
+ // less.
+ int seg_size = min(sock->seqno - sseqno, sock->r_wind);
+ seg_size = min(seg_size, sock->cwnd);
+ while (seg_size > 0 && sock->seqno > sseqno) {
+ // printf("sending seg_size: %i\n", seg_size);
+ struct split_ip_msg *msg = get_ipmsg(seg_size);
+ struct tcp_hdr *tcph;
+ uint8_t *data;
+ if (msg == NULL) return -1;
+ tcph = (struct tcp_hdr *)(msg + 1);
+ data = (uint8_t *)(tcph + 1);
+
+ tcph->flags = TCP_FLAG_ACK;
+ tcph->seqno = htonl(sseqno);
+ tcph->ackno = htonl(circ_get_seqno(sock->rx_buf));
+
+ circ_buf_read(sock->tx_buf, sseqno, data, seg_size);
+ __tcplib_send(sock, msg);
+ ip_free(msg);
+
+ sseqno += seg_size;
+ seg_size = min(sock->seqno - sseqno, sock->mss);
+ }
+ return 0;
+}
+
+int tcplib_init_sock(struct tcplib_sock *sock) {
+ memset(sock, 0, sizeof(struct tcplib_sock) - sizeof(struct tcplib_sock *));
+ sock->mss = 100;
+ sock->cwnd = ONE_SEGMENT(sock);
+ sock->ssthresh = 0xffff;
+ conn_add_once(sock);
+ return 0;
+}
+
+/* called when a new segment arrives. */
+/* deliver as much data to the app as possible, and update the ack
+ * number of the socket to reflect how much was delivered
+ */
+static void add_data(struct tcplib_sock *sock, struct tcp_hdr *tcph, int len) {
+ char *ptr;
+ int payload_len;
+ ptr = ((uint8_t *)tcph) + (tcph->offset / 4);
+ payload_len = len - (tcph->offset / 4);
+ // TODO : SDH : optimize out the extra copy for in-sequence data
+ circ_buf_write(sock->rx_buf, ntohl(tcph->seqno),
+ ptr, payload_len);
+ // now try to deliver any data ahead of the ack pointer that's in
+ // the buffer
+
+ /* if we wrapped around the buffer, we'll actually recieve twice. */
+ while ((payload_len = circ_buf_read_head(sock->rx_buf, &ptr)) > 0) {
+ sock->ops.recvfrom(sock, ptr, payload_len);
+ }
+}
+
+static void reset_ssthresh(struct tcplib_sock *conn) {
+ uint16_t new_ssthresh = min(conn->cwnd, conn->r_wind) / 2;
+ if (new_ssthresh < 2 * ONE_SEGMENT(conn))
+ new_ssthresh = 2 * ONE_SEGMENT(conn);
+ conn->ssthresh = new_ssthresh;
+}
+
+int tcplib_process(struct ip6_hdr *iph, void *payload) {
+ int rc = 0;
+ struct tcp_hdr *tcph;
+ struct tcplib_sock *this_conn;
+ // uint8_t *ptr;
+ int payload_len;
+ int len = ntohs(iph->plen) + sizeof(struct ip6_hdr);;
+ tcph = (struct tcp_hdr *)payload;
+
+ // printf("tcplib_process\n");
+
+ /* malformed ip packet? could happen I supppose... */
+/* if (len < sizeof(struct ip6_hdr) || */
+/* len != ntohs(iph->plen) + sizeof(struct ip6_hdr)) { */
+/* fprintf(stderr, "tcplib_process: warn: length mismatch\n"); */
+/* return -1; */
+/* } */
+
+ /* if there's no local */
+ this_conn = conn_lookup(iph, tcph);
+ if (this_conn != NULL) {
+ if (tcph->flags & TCP_FLAG_RST) {
+ /* Really hose this connection if we get a RST packet.
+ * still TODO: RST generation for unbound ports */
+ printf("connection reset by peer\n");
+
+ if (this_conn->ops.closed)
+ this_conn->ops.close_done(this_conn);
+ tcplib_init_sock(this_conn);
+ return 0;
+ }
+ // always get window updates from new segments
+ // TODO : this should be after we detect out-of-sequence ACK
+ // numbers!
+ this_conn->r_wind = ntohs(tcph->window);
+
+ switch (this_conn->state) {
+ case TCP_LAST_ACK:
+ if (tcph->flags & TCP_FLAG_ACK &&
+ ntohl(tcph->ackno) == this_conn->seqno + 1) {
+ // printf("closing connection\n");
+ this_conn->state = TCP_CLOSED;
+ this_conn->ops.close_done(this_conn);
+ break;
+ }
+
+ case TCP_SYN_SENT:
+ if (tcph->flags & (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
+ // got a syn-ack
+ // send the ACK
+ this_conn->state = TCP_ESTABLISHED;
+ circ_set_seqno(this_conn->rx_buf, ntohl(tcph->seqno) + 1);
+ // skip the LISTEN processing
+ // this will also generate an ACK
+ goto ESTABLISHED;
+ } else if (this_conn->flags & TCP_FLAG_SYN) {
+ // otherwise the state machine says we're in a simultaneous open, so continue doen
+ this_conn->state = TCP_SYN_RCVD;
+ } else {
+ printf("sending RST on bad data in state SYN_SENT\n");
+ tcplib_send_rst(iph, tcph);
+ break;
+ }
+ case TCP_SYN_RCVD:
+ case TCP_LISTEN:
+ /* not connected. */
+ if (tcph->flags & TCP_FLAG_SYN) {
+ struct tcplib_sock *new_sock;
+
+ if (this_conn->state == TCP_LISTEN) {
+ memcpy(&this_conn->r_ep.sin6_addr, &iph->ip6_src, 16);
+ this_conn->r_ep.sin6_port = tcph->srcport;
+ new_sock = tcplib_accept(this_conn, &this_conn->r_ep);
+ if (new_sock != this_conn) {
+ memset(this_conn->r_ep.sin6_addr.s6_addr, 0, 16);
+ this_conn->r_ep.sin6_port = 0;
+ if (new_sock != NULL) {
+ memcpy(&new_sock->r_ep.sin6_addr, &iph->ip6_src, 16);
+ new_sock->r_ep.sin6_port = tcph->srcport;
+ conn_add_once(new_sock);
+ }
+ }
+ if (new_sock == NULL) {
+ tcplib_send_rst(iph, tcph);
+ break;
+ }
+ memcpy(&new_sock->l_ep.sin6_addr, &iph->ip6_dst, 16);
+ new_sock->l_ep.sin6_port = tcph->dstport;
+
+ circ_buf_init(new_sock->rx_buf, new_sock->rx_buf_len,
+ ntohl(tcph->seqno) + 1, 1);
+ circ_buf_init(new_sock->tx_buf, new_sock->tx_buf_len,
+ 0xcafebabe + 1, 0);
+ } else {
+ /* recieved a SYN retransmission. */
+ new_sock = this_conn;
+ }
+
+ if (new_sock != NULL) {
+ new_sock->seqno = 0xcafebabe + 1;
+ new_sock->state = TCP_SYN_RCVD;
+ tcplib_send_ack(new_sock, 0, TCP_FLAG_ACK | TCP_FLAG_SYN);
+ new_sock->seqno++;
+ } else {
+ memset(&this_conn->r_ep, 0, sizeof(struct sockaddr_in6));
+ }
+ } else if (this_conn->state == TCP_LISTEN) {
+ printf("sending RST on out-of-sequence data\n");
+ tcplib_send_rst(iph, tcph);
+ break;
+ }
+ /* this is SYN_RECVd */
+ if (tcph->flags & TCP_FLAG_ACK) {
+ // printf("recv ack, in state TCP_SYN_RCVD\n");
+ this_conn->state = TCP_ESTABLISHED;
+ }
+ /* fall through to handle any data. */
+
+ case TCP_CLOSE_WAIT:
+ case TCP_ESTABLISHED:
+ ESTABLISHED:
+ // ptr = ((uint8_t *)(iph + 1)) + (tcph->offset / 4);
+ payload_len = len - sizeof(struct ip6_hdr) - (tcph->offset / 4);
+ // printf("recv data len: %i\n", payload_len);
+
+ /* ack any data in this packet */
+ if (this_conn->state == TCP_ESTABLISHED) {
+ if (payload_len > 0)
+ this_conn->flags ++;
+
+
+ // receive side sequence check and add data
+ // printf("seqno: %i ackno: %i\n", ntohl(tcph->seqno), ntohl(tcph->ackno));
+
+
+ // send side recieve sequence check and congestion window updates.
+ if (ntohl(tcph->ackno) > circ_get_seqno(this_conn->tx_buf)) {
+ // new data is being ACKed
+ // or we haven't sent anything new
+ if (this_conn->cwnd <= this_conn->ssthresh) {
+ // in slow start; increase the cwnd by one segment
+ this_conn->cwnd += ONE_SEGMENT(this_conn);
+ // printf("in slow start\n");
+ } else {
+ // in congestion avoidance
+ this_conn->cwnd += (ONE_SEGMENT(this_conn) * ONE_SEGMENT(this_conn)) / this_conn->cwnd;
+ // printf("in congestion avoidence\n");
+ }
+ // printf("ACK new data: cwnd: %i ssthresh: %i\n", this_conn->cwnd, this_conn->ssthresh);
+ // reset the duplicate ack counter
+ UNSET_ACK_COUNT(this_conn->flags);
+ // truncates the ack buffer
+ circ_shorten_head(this_conn->tx_buf, ntohl(tcph->ackno));
+ // printf("ack_count: %i\n", GET_ACK_COUNT(this_conn->flags));
+ } else if (this_conn->seqno > circ_get_seqno(this_conn->tx_buf)) {
+ // this is a duplicate ACK
+ // - increase the counter of the number of duplicate ACKs
+ // - if we get to three duplicate ACK's, start resending at
+ // the ACK number because this probably means we lost a segment
+
+ INCR_ACK_COUNT(this_conn->flags);
+ // printf("ack_count: %i\n", GET_ACK_COUNT(this_conn->flags));
+ // printf("dup ack count: %i\n", GET_ACK_COUNT(this_conn->flags));
+ // a "dup ack count" of 2 is really 3 total acks because we start with zero
+ if (GET_ACK_COUNT(this_conn->flags) == 2) {
+ UNSET_ACK_COUNT(this_conn->flags);
+ printf("detected multiple duplicate ACKs-- doing fast retransmit [%u, %u]\n",
+ circ_get_seqno(this_conn->tx_buf),
+ this_conn->seqno);
+
+ // this is our detection of a "duplicate ack" event.
+ // we are going to reset ssthresh and retransmit the data.
+ reset_ssthresh(this_conn);
+ tcplib_output(this_conn, circ_get_seqno(this_conn->tx_buf));
+ this_conn->timer.retx = 6;
+
+ }
+ } else if (ntohl(tcph->seqno) != circ_get_seqno(this_conn->rx_buf)) {
+ printf("==> received out-of-sequence data!\n");
+ tcplib_send_ack(this_conn, 0, TCP_FLAG_ACK);
+ }
+ add_data(this_conn, tcph, len - sizeof(struct ip6_hdr));
+
+
+ // printf("tx seqno: %i ackno: %i\n", circ_get_seqno(this_conn->tx_buf),
+ // ntohl(tcph->ackno));
+
+
+ // reset the retransmission timer
+ if (this_conn->timer.retx == 0)
+ this_conn->timer.retx = 6;
+ }
+ if ((payload_len > 0 && (this_conn->flags & TCP_ACKPENDING) >= 2)
+ || tcph->flags & TCP_FLAG_FIN) {
+ ///|| ntohl(tcph->seqno) != circ_get_seqno(this_conn->rx_buf)) {
+ tcplib_send_ack(this_conn, (payload_len == 0 && tcph->flags & TCP_FLAG_FIN), TCP_FLAG_ACK);
+ /* only close the connection if we've gotten all the data */
+ if (this_conn->state == TCP_ESTABLISHED
+ && tcph->flags & TCP_FLAG_FIN
+ && ntohl(tcph->seqno) == circ_get_seqno(this_conn->rx_buf)) {
+ this_conn->state = TCP_CLOSE_WAIT;
+ this_conn->ops.closed(this_conn);
+ }
+ }
+ break;
+ case TCP_CLOSED:
+ default:
+ rc = -1;
+ // printf("sending RST\n");
+ // tcplib_send_ack(this_conn, 0, TCP_FLAG_ACK | TCP_FLAG_RST);
+ }
+ } else {
+ /* this_conn was NULL */
+ /* TODO : SDH : send ICMP error */
+ }
+ return rc;
+}
+
+
+/* bind the socket to a local address */
+int tcplib_bind(struct tcplib_sock *sock,
+ struct sockaddr_in6 *addr) {
+ /* not using an already-bound port */
+ /* TODO : SDH : check local address */
+ if (conn_checkport(addr->sin6_port))
+ return -1;
+
+ memcpy(&sock->l_ep, addr, sizeof(struct sockaddr_in6));
+ /* passive open */
+ sock->state = TCP_LISTEN;
+}
+
+/* connect the socket to a remote endpoint */
+int tcplib_connect(struct tcplib_sock *sock,
+ struct sockaddr_in6 *serv_addr) {
+ if (sock->rx_buf == NULL || sock->tx_buf == NULL)
+ return -1;
+
+ switch (sock->state) {
+ case TCP_CLOSED:
+ // passive open; need to set up the local endpoint.
+ memset(&sock->l_ep, 0, sizeof(struct sockaddr_in6));
+ sock->l_ep.sin6_port = htons(alloc_local_port());
+ break;
+ case TCP_LISTEN:
+ // we got here by calling bind, so we're cool.
+ break;
+ default:
+ return -1;
+ }
+ circ_buf_init(sock->rx_buf, sock->rx_buf_len,
+ 0, 1);
+ circ_buf_init(sock->tx_buf, sock->tx_buf_len,
+ 0xcafebabe + 1, 0);
+
+ sock->seqno = 0xcafebabe;
+ memcpy(&sock->r_ep, serv_addr, sizeof(struct sockaddr_in6));
+ tcplib_send_ack(sock, 0, TCP_FLAG_SYN);
+ sock->state = TCP_SYN_SENT;
+ sock->seqno++;
+ return 0;
+}
+
+
+int tcplib_send(struct tcplib_sock *sock, void *data, int len) {
+ /* have enough tx buffer left? */
+ if (sock->state != TCP_ESTABLISHED)
+ return -1;
+ if (sock->seqno - circ_get_seqno(sock->tx_buf) + len > circ_get_window(sock->tx_buf))
+ return -1;
+
+ circ_buf_write(sock->tx_buf, sock->seqno, data, len);
+
+ sock->seqno += len;
+ // printf("tcplib_output from send\n");
+ tcplib_output(sock, sock->seqno - len);
+
+ // 3 seconds
+ if (sock->timer.retx == 0)
+ sock->timer.retx = 6;
+
+ return 0;
+}
+
+void tcplib_retx_expire(struct tcplib_sock *sock) {
+ // printf("retransmission timer expired!\n");
+ if (sock->state == TCP_ESTABLISHED &&
+ circ_get_seqno(sock->tx_buf) != sock->seqno) {
+ printf("retransmitting [%u, %u]\n", circ_get_seqno(sock->tx_buf),
+ sock->seqno);
+ reset_ssthresh(sock);
+ // restart slow start
+ sock->cwnd = ONE_SEGMENT(sock);
+ // printf("tcplib_output from timer\n");
+ tcplib_output(sock, circ_get_seqno(sock->tx_buf));
+ sock->timer.retx = 6;
+ } else if (sock->state == TCP_LAST_ACK) {
+ // printf("resending FIN\n");
+ tcplib_send_ack(sock, 1, TCP_FLAG_ACK | TCP_FLAG_FIN);
+ sock->timer.retx = 6;
+ }
+}
+
+int tcplib_close(struct tcplib_sock *sock) {
+ int rc = -1;
+
+ switch (sock->state) {
+ /* passive close */
+ case TCP_CLOSE_WAIT:
+ tcplib_send_ack(sock, 1, TCP_FLAG_ACK | TCP_FLAG_FIN);
+ sock->timer.retx = 6;
+ sock->state = TCP_LAST_ACK;
+ break;
+ /* active close */
+ case TCP_ESTABLISHED:
+ // kick off the close
+
+ break;
+ case TCP_SYN_SENT:
+ sock->state = TCP_CLOSED;
+ break;
+ default:
+ /* this is meaningless in other states */
+ rc = -1;
+ }
+ return rc;
+}
+
+int tcplib_timer_process() {
+ struct tcplib_sock *iter;
+ for (iter = conns; iter != NULL; iter = iter->next) {
+ if (iter->timer.retx > 0 && (--iter->timer.retx) == 0)
+ tcplib_retx_expire(iter);
+ if (iter->flags & TCP_ACKPENDING) {
+ // printf("sending delayed ACK\n");
+ tcplib_send_ack(iter, 0, TCP_FLAG_ACK);
+ }
+ }
+ return 0;
+}
--- /dev/null
+#ifndef TCPLIB_H_
+#define TCPLIB_H_
+
+// #include <netinet/in.h>
+#include "ip.h"
+
+#define min(X,Y) (((X) > (Y)) ? (Y) : (X))
+#ifndef PC
+#define printf(X, args ...) dbg("stdout", X, ## args)
+#define fprintf(X, Y, args ...) dbg("fprintf", Y, ## args)
+#endif
+
+typedef enum {
+ TCP_CLOSED = 0,
+ TCP_LISTEN,
+ TCP_SYN_RCVD,
+ TCP_SYN_SENT,
+ TCP_ESTABLISHED,
+ TCP_CLOSE_WAIT,
+ TCP_LAST_ACK,
+ TCP_FIN_WAIT_1,
+ TCP_FIN_WAIT_2,
+ TCP_CLOSING,
+ TCP_TIME_WAIT,
+} tcplib_sock_state_t;
+
+enum {
+ TCP_ACKPENDING = 0x3,
+ TCP_DUPACKS = 0x3c,
+ TCP_DUPACKS_OFF = 2,
+};
+
+#define GET_ACK_COUNT(X) (((X) & TCP_DUPACKS) >> TCP_DUPACKS_OFF)
+#define UNSET_ACK_COUNT(X) ((X) &= ~TCP_DUPACKS)
+#define INCR_ACK_COUNT(X) ((X) += 1 << TCP_DUPACKS_OFF)
+#define ACK_COUNT_IS_3(X) (((X) & TCP_DUPACKS) == TCP_DUPACKS)
+
+struct tcplib_sock {
+ uint8_t flags;
+
+ /* local and remote endpoints */
+ struct sockaddr_in6 l_ep;
+ struct sockaddr_in6 r_ep;
+
+ /* current connection state */
+ tcplib_sock_state_t state;
+
+ /* a buffer allocated for data on this connection */
+ void *rx_buf;
+ uint16_t rx_buf_len;
+
+ void *tx_buf;
+ uint16_t tx_buf_len;
+
+ /* max segment size, or default if
+ we didn't bother to pull it out
+ of the options field */
+ uint16_t mss;
+ /* the window the other end is
+ reporting */
+ uint16_t r_wind;
+ uint16_t cwnd;
+ uint16_t ssthresh;
+
+ // the current next sequence number for ourgoing data.
+ // the ack number is stored in the receive buffer.
+ uint32_t seqno;
+ // uint32_t ackno;
+
+ struct {
+ int8_t retx;
+ } timer;
+
+ /* callbacks for this connection */
+ struct {
+ /* a previous connection request has finished */
+ void (*connect_done)(struct tcplib_sock *sock, int error);
+
+ /* a callback to signal new data is ready */
+ void (*recvfrom)(struct tcplib_sock *sock, void *data, int len);
+
+ /* the connection was closed by the other party */
+ void (*closed)(struct tcplib_sock *sock);
+
+ /* you called close(); we've finished closing the socket. */
+ void (*close_done)(struct tcplib_sock *sock);
+ } ops;
+
+ /* this needs to be at the end so
+ we can call init() on a socket
+ without blowing away the linked
+ list */
+ struct tcplib_sock *next;
+};
+
+/* EVENTS
+ * ------------------------------------------------------------
+ *
+ * calls generated by tcplib that must be dealt with elsewhere in the
+ * program.
+ */
+
+
+/* called when a new connection request is recieved on a socket which
+ * is LISTENing.
+ *
+ *
+ * return 0 if it wants to accept the connection and allocated a
+ * buffer for it; -1 otherwise.
+ */
+struct tcplib_sock *tcplib_accept(struct tcplib_sock *conn,
+ struct sockaddr_in6 *from);
+
+/* a call-out point for tcplib to send a message */
+void tcplib_send_out(struct split_ip_msg *msg, struct tcp_hdr *tcph);
+
+/* upcall for new data; may be dispatched all the way out to a
+ * handler.
+ *
+ * Returns: 0 on success,
+ * -1 otherwise. The error may be safely ignored.
+ */
+int tcplib_process(struct ip6_hdr *ip_packet, void *payload);
+
+/*
+ * should be called every 500ms to increment all the tcp timers
+ */
+int tcplib_timer_process();
+
+/* Just fill in the fields of the socket.
+ *
+ * If you perform a send on a socket in this state, an ephemeral port
+ * will be allocated to it.
+ *
+ * This must be called once on any socket that might be sent on, or
+ * might have bind() called.
+ */
+int tcplib_init_sock(struct tcplib_sock *sock);
+
+/* bind the socket to a local address */
+int tcplib_bind(struct tcplib_sock *sock,
+ struct sockaddr_in6 *addr);
+
+/* connect the socket to a remote endpoint */
+int tcplib_connect(struct tcplib_sock *sock,
+ struct sockaddr_in6 *serv_addr);
+
+
+/* send data on an open socket.
+ *
+ * returns: 0 on success
+ * other errors
+ * - no local buffer is available,
+ *
+ */
+int tcplib_send(struct tcplib_sock *sock,
+ void *data, int len);
+
+int tcplib_close(struct tcplib_sock *sock);
+
+
+#endif
--- /dev/null
+
+#include <stdio.h>
+#include "circ.h"
+
+void do_head_read(void *buf) {
+ char *read_data;
+ int i, data_len;
+ data_len = circ_buf_read_head(buf, (void **)&read_data);
+ printf("buf_read_head: %i\n", data_len);
+ for (i = 0; i < data_len; i++)
+ putc(((char *)read_data)[i], stdout);
+ putc('\n', stdout);
+}
+
+void do_read(void *buf, uint32_t sseqno) {
+ char data[20];
+ int data_len, i;
+ data_len = circ_buf_read(buf, sseqno, data, 20);
+
+ printf("buf_read: %i\n", data_len);
+ for (i = 0; i < data_len; i++)
+ putc(((char *)data)[i], stdout);
+ putc('\n', stdout);
+
+}
+
+int main(int argc, char **argv) {
+ char buf[200];
+ char data[20], readbuf[30];
+ int i = 20, data_len;
+ char *read_data;
+ if (circ_buf_init(buf, 200, 0, 1) < 0)
+ printf("cir_buf_init: error\n");
+
+ for (i=0;i<20;i++)
+ data[i] = 'a' + i;
+
+ if (circ_buf_write(buf, 0, data, 20) < 0)
+ printf("circ_buf_write: error\n");
+
+ if (circ_buf_write(buf, 10, data, 20) < 0)
+ printf("circ_buf_write: error\n");
+
+
+ if (circ_buf_write(buf, 50, data, 20) < 0)
+ printf("circ_buf_write: error\n");
+
+ circ_buf_dump(buf);
+
+ do_head_read(buf);
+ circ_buf_dump(buf);
+
+ if (circ_buf_write(buf, 30, data, 20) < 0)
+ printf("circ_buf_write: error\n");
+
+ circ_buf_dump(buf);
+
+ if (circ_buf_write(buf, 70, data, 20) < 0)
+ printf("circ_buf_write: error\n");
+
+ circ_buf_dump(buf);
+
+ do_read(buf, 50);
+/* do_head_read(buf); */
+/* circ_buf_dump(buf); */
+
+/* if (circ_buf_write(buf, 90, data, 20) < 0) */
+/* printf("circ_buf_write: error\n"); */
+/* if (circ_buf_write(buf, 110, data, 20) < 0) */
+/* printf("circ_buf_write: error\n"); */
+/* if (circ_buf_write(buf, 130, data, 20) < 0) */
+/* printf("circ_buf_write: error\n"); */
+
+/* circ_buf_dump(buf); */
+/* do_head_read(buf); */
+/* do_head_read(buf); */
+/* circ_buf_dump(buf); */
+}
--- /dev/null
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <signal.h>
+#include <string.h>
+
+
+#include "ip.h"
+#include "tcplib.h"
+#include "tun_dev.h"
+#include "ip_malloc.h"
+
+
+#define BUFSZ 1024
+#define LOSS_RATE_RECPR 100
+
+int sock = 0;
+uint8_t iface_addr[16] = {0x20, 0x01, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+struct sockaddr_in6 laddr;
+
+
+void printBuf(uint8_t *buf, uint16_t len) {
+ int i;
+ // print("len: %i: ", len);
+ for (i = 1; i <= len; i++) {
+ printf(" 0x%02x", buf[i-1]);
+ // if (i % 16 == 0) printf("\n");
+ }
+ printf("\n");
+}
+
+void print_split_msg(struct split_ip_msg *msg) {
+ int i;
+ printf("src_addr: ");
+ for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.src_addr[i]);
+ printf("\ndst_addr: ");
+ for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.dst_addr[i]);
+ printf("\nplen: %i hlim: %i\n", ntohs(msg->hdr.plen), msg->hdr.hlim);
+
+ printBuf(msg->data, msg->data_len);
+}
+
+void rx(struct tcplib_sock *sock, void *data, int len) {
+ // printBuf(data, len);
+ if (tcplib_send(sock, data, len) < 0)
+ printf("tcplib_send: fail\n");
+}
+
+void cl(struct tcplib_sock *sock) {
+ printf("remote conn closed\n");
+ tcplib_close(sock);
+}
+
+void cd(struct tcplib_sock *sock) {
+ printf("local close done\n");
+ free(sock->rx_buf);
+ free(sock->tx_buf);
+ tcplib_init_sock(sock);
+/* printf("rebinding...\n"); */
+}
+
+/* called when a new connection request is received: not
+ *
+ * return: a tcplib_struc, with the ops table filled in and send and
+ * receive buffers allocated.
+ */
+
+struct tcplib_sock *tcplib_accept(struct tcplib_sock *conn,
+ struct sockaddr_in6 *from) {
+ printf("tcplib_accept\n");
+ conn->rx_buf = malloc(BUFSZ);
+ conn->rx_buf_len = BUFSZ;
+
+ conn->tx_buf = malloc(BUFSZ);
+ conn->tx_buf_len = BUFSZ;
+
+ conn->ops.recvfrom = rx;
+ conn->ops.closed = cl;
+ conn->ops.close_done = cd;
+
+ return conn;
+}
+
+void tcplib_send_out(struct split_ip_msg *msg, struct tcp_hdr *tcph) {
+ uint8_t buf[8192];
+ if (sock <= 0) return;
+
+ memcpy(msg->hdr.src_addr, iface_addr, 16);
+ msg->hdr.src_addr[15] = 2;
+ msg->hdr.hlim = 64;
+
+ memset(msg->hdr.vlfc, 0, 4);
+ msg->hdr.vlfc[0] = 6 << 4;
+
+ tcph->chksum = msg_cksum(msg, IANA_TCP);
+
+ // print_split_msg(msg);
+ if (rand() % LOSS_RATE_RECPR == 0) {
+ printf("dropping packet on write\n");
+ } else {
+ tun_write(sock, msg);
+ }
+}
+
+/* practice accepting connections and transfering data */
+int main(int argg, char **argv) {
+ char buf[8192], dev[IFNAMSIZ];
+ uint8_t *payload;
+ int len, i, flags;
+
+ ip_malloc_init();
+
+ payload = buf + sizeof(struct tun_pi);
+ dev[0] = 0;
+ if ((sock = tun_open(dev)) < 0)
+ exit(1);
+
+ if (tun_setup(dev, iface_addr) < 0)
+ exit(1);
+
+ /* tun_setup turns on non-blocking IO. Turn it off. */
+ flags = fcntl(sock, F_GETFL);
+ flags &= ~O_NONBLOCK;
+ fcntl(sock,F_SETFL, flags);
+
+ struct tcplib_sock srv_sock;
+ tcplib_init_sock(&srv_sock);
+ memcpy(laddr.sin6_addr.s6_addr, iface_addr, 16);
+ laddr.sin6_addr.s6_addr[15] = 2;
+ laddr.sin6_port = htons(atoi(argv[1]));
+
+ tcplib_bind(&srv_sock, &laddr);
+
+ fd_set fds;
+ struct timeval timeout;
+ FD_ZERO(&fds);
+ FD_SET(sock, &fds);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 500000;
+
+ while (select(sock + 1, &fds, NULL, NULL, &timeout) >= 0) {
+ if (FD_ISSET(sock, &fds)) {
+ if ((len = read(sock, buf, 8192)) <= 0) break;
+ struct ip6_hdr *iph = (struct ip6_hdr *)payload;
+ if (iph->nxt_hdr == IANA_TCP) {
+ if (rand() % LOSS_RATE_RECPR == 0) {
+ printf("dropping packet on rx\n");
+ } else {
+ if (tcplib_process(payload, len - sizeof(struct tun_pi)))
+ printf("TCPLIB_PROCESS: ERROR!\n");
+ }
+ }
+ } else {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 500000;
+ tcplib_timer_process();
+ }
+ if (srv_sock.state == TCP_CLOSED) {
+ tcplib_bind(&srv_sock, &laddr);
+ }
+
+ FD_ZERO(&fds);
+ FD_SET(sock, &fds);
+ }
+ tun_close(sock, dev);
+}
--- /dev/null
+
+# Before you can run the adaptation layer and router, you must
+# configure the address your router will advertise to the subnet, and
+# which network interface to proxy neighbor advertisements on.
+#
+
+# set the debug level of the output
+# choices are DEBUG, INFO, WARN, ERROR, and FATAL
+# log DEBUG
+
+# set the address of the router's 802.15.4 interface. The interface
+# ID must be a 16-bit short identifier.
+addr 2001:470:1f04:56d::64
+
+# the router can proxy neighbor IPv6 neighbor discovery on another
+# interface so that other machines on the subnet can discover hosts
+# routing through this router. This specifies which interface to proxy
+# the NDP on.
+proxy eth1
+
+# which 802.15.4 channel to operate on. valid choices are 11-26.
+channel 15
#endif
BUFSIZE = 256,
MTU = 256,
- ACK_TIMEOUT = 1000000, /* in us */
+ ACK_TIMEOUT = 100000, /* in us */
SYNC_BYTE = SERIAL_HDLC_FLAG_BYTE,
ESCAPE_BYTE = SERIAL_HDLC_CTLESC_BYTE,
--- /dev/null
+/*
+ * "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 _ICMP_H_
+#define _ICMP_H_
+
+enum {
+ ICMP_EXT_TYPE_PREFIX = 3,
+ ICMP_EXT_TYPE_BEACON = 17,
+};
+
+enum {
+ // jitter start requests by 10 seconds
+ TRICKLE_JITTER = 10240,
+ // have a trickle timer with a period of 4
+ TRICKLE_PERIOD = 4096,
+
+ // send a maximum of three trickle messages
+ TRICKLE_MAX = (TRICKLE_PERIOD << 5),
+
+};
+
+typedef nx_struct icmp6_echo_hdr {
+ nx_uint8_t type; /* type field */
+ nx_uint8_t code; /* code field */
+ nx_uint16_t cksum; /* checksum field */
+ nx_uint16_t ident;
+ nx_uint16_t seqno;
+} icmp_echo_hdr_t;
+
+typedef nx_struct radv {
+ nx_uint8_t type;
+ nx_uint8_t code;
+ nx_uint16_t cksum;
+ nx_uint8_t hlim;
+ nx_uint8_t flags;
+ nx_uint16_t lifetime;
+ nx_uint32_t reachable_time;
+ nx_uint32_t retrans_time;
+ nx_uint8_t options[0];
+} radv_t;
+
+typedef nx_struct rsol {
+ nx_uint8_t type;
+ nx_uint8_t code;
+ nx_uint16_t cksum;
+ nx_uint32_t reserved;
+} rsol_t;
+
+typedef nx_struct rpfx {
+ nx_uint8_t type;
+ nx_uint8_t length;
+ nx_uint8_t pfx_len;
+ nx_uint8_t flags;
+ nx_uint32_t valid_lifetime;
+ nx_uint32_t preferred_lifetime;
+ nx_uint32_t reserved;
+ nx_uint8_t prefix[16];
+} pfx_t;
+
+typedef nx_struct {
+ nx_uint8_t type;
+ nx_uint8_t length;
+ nx_uint16_t metric;
+} rqual_t;
+
+struct icmp_stats {
+ uint16_t seq;
+ uint8_t ttl;
+ uint32_t rtt;
+};
+
+#endif
--- /dev/null
+/*
+ * "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 <6lowpan.h>
+
+configuration ICMPResponderC {
+ provides interface ICMP;
+ provides interface ICMPPing[uint16_t client];
+ provides interface Statistics<icmp_statistics_t>;
+} implementation {
+ components NoLedsC as LedsC;
+ components IPDispatchC, IPRoutingP, ICMPResponderP, IPAddressC;
+
+ ICMP = ICMPResponderP;
+ ICMPPing = ICMPResponderP;
+ Statistics = ICMPResponderP;
+
+ ICMPResponderP.Leds -> LedsC;
+
+ ICMPResponderP.IP -> IPDispatchC.IP[IANA_ICMP];
+
+ ICMPResponderP.IPAddress -> IPAddressC;
+
+ ICMPResponderP.IPRouting -> IPRoutingP;
+
+ components RandomC;
+ ICMPResponderP.Random -> RandomC;
+
+ components new TimerMilliC() as STimer,
+ new TimerMilliC() as ATimer,
+ new TimerMilliC() as PTimer;
+ ICMPResponderP.Solicitation -> STimer;
+ ICMPResponderP.Advertisement -> ATimer;
+ ICMPResponderP.PingTimer -> PTimer;
+
+ components HilTimerMilliC;
+ ICMPResponderP.LocalTime -> HilTimerMilliC;
+}
--- /dev/null
+/*
+ * "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 <lib6lowpan.h>
+#include <6lowpan.h>
+#include <ip_malloc.h>
+#include "in_cksum.h"
+#include "PrintfUART.h"
+#include "ICMP.h"
+
+extern uint8_t multicast_prefix[8];
+
+module ICMPResponderP {
+ provides interface ICMP;
+ provides interface ICMPPing[uint16_t client];
+ provides interface Statistics<icmp_statistics_t>;
+
+ uses interface IP;
+ uses interface IPAddress;
+
+ uses interface Leds;
+
+ uses interface Timer<TMilli> as Solicitation;
+ uses interface Timer<TMilli> as Advertisement;
+ uses interface Timer<TMilli> as PingTimer;
+ uses interface LocalTime<TMilli>;
+ uses interface Random;
+
+ uses interface IPRouting;
+
+} implementation {
+
+ icmp_statistics_t stats;
+ uint32_t solicitation_period;
+ uint32_t advertisement_period;
+
+ uint16_t ping_seq, ping_n, ping_rcv, ping_ident;
+ struct in6_addr ping_dest;
+
+#ifndef SIM
+#define CHECK_NODE_ID
+#else
+#define CHECK_NODE_ID if (TOS_NODE_ID == BASESTATION_ID) return
+#endif
+
+ command uint16_t ICMP.cksum(struct split_ip_msg *msg, uint8_t nxt_hdr) {
+ return msg_cksum(msg, nxt_hdr);
+ }
+
+
+ command void ICMP.sendSolicitations() {
+ uint16_t jitter = (call Random.rand16()) % TRICKLE_JITTER;
+ CHECK_NODE_ID;
+ if (call Solicitation.isRunning()) return;
+ solicitation_period = TRICKLE_PERIOD;
+ call Solicitation.startOneShot(jitter);
+ }
+
+ command void ICMP.sendAdvertisements() {
+ uint16_t jitter = (call Random.rand16()) % TRICKLE_JITTER;
+ CHECK_NODE_ID;
+ if (call Advertisement.isRunning()) return;
+ advertisement_period = TRICKLE_PERIOD;
+ call Advertisement.startOneShot(jitter);
+ }
+
+ command void ICMP.sendTimeExceeded(struct ip6_hdr *hdr, unpack_info_t *u_info, uint16_t amount_here) {
+ uint8_t i_hdr_buf[sizeof(struct icmp6_hdr) + 4];
+ struct split_ip_msg *msg = (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg));
+ struct generic_header g_hdr[3];
+ struct icmp6_hdr *i_hdr = (struct icmp6_hdr *)i_hdr_buf;
+
+ if (msg == NULL) return;
+
+ dbg("ICMPResponder", "send time exceeded\n");
+
+ msg->headers = NULL;
+ msg->data = u_info->payload_start;
+ msg->data_len = amount_here;
+
+ // make sure to include the udp header if necessary
+ if (u_info->nxt_hdr == IANA_UDP) {
+ g_hdr[2].hdr.udp = (struct udp_hdr *)u_info->transport_ptr;
+ g_hdr[2].len = sizeof(struct udp_hdr);
+ g_hdr[2].next = NULL;
+
+ // since the udp headers are included in the offset we need to
+ // add that length so the payload length in the encapsulated
+ // packet will be correct.
+ hdr->plen = htons(ntohs(hdr->plen) + sizeof(struct udp_hdr));
+ msg->headers = &g_hdr[2];
+ }
+ // the fields in the packed packet is not necessarily the same as
+ // the fields in canonical packet which was packed. This is due
+ // to the insertion of transient routing headers.
+ hdr->nxt_hdr = u_info->nxt_hdr;
+ hdr->plen = htons(ntohs(hdr->plen) - u_info->payload_offset);
+
+ // the IP header is part of the payload
+ g_hdr[1].hdr.data = (void *)hdr;
+ g_hdr[1].len = sizeof(struct ip6_hdr);
+ g_hdr[1].next = msg->headers;
+ msg->headers = &g_hdr[1];
+
+ // and is preceeded by the icmp time exceeded message
+ g_hdr[0].hdr.data = (void *)i_hdr;
+ g_hdr[0].len = sizeof(struct icmp6_hdr) + 4;
+ g_hdr[0].next = msg->headers;
+ msg->headers = &g_hdr[0];
+
+ ip_memcpy(&msg->hdr.ip6_dst, &hdr->ip6_src, 16);
+ call IPAddress.getIPAddr(&msg->hdr.ip6_src);
+
+ i_hdr->type = ICMP_TYPE_ECHO_TIME_EXCEEDED;
+ i_hdr->code = ICMP_CODE_HOPLIMIT_EXCEEDED;
+ i_hdr->cksum = 0;
+ ip_memclr((void *)(i_hdr + 1), 4);
+
+ msg->hdr.nxt_hdr = IANA_ICMP;
+
+ i_hdr->cksum = call ICMP.cksum(msg, IANA_ICMP);
+
+ call IP.send(msg);
+
+ ip_free(msg);
+ }
+ /*
+ * Solicitations
+ */
+ void sendSolicitation() {
+ struct split_ip_msg *ipmsg = (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg) + sizeof(rsol_t));
+ rsol_t *msg = (rsol_t *)(ipmsg + 1);
+
+ if (ipmsg == NULL) return;
+
+ dbg("ICMPResponder", "Solicitation\n");
+ //stats.sol_tx++;
+
+ msg->type = ICMP_TYPE_ROUTER_SOL;
+ msg->code = 0;
+ msg->cksum = 0;
+ msg->reserved = 0;
+
+ ipmsg->headers = NULL;
+ ipmsg->data = (void *)msg;
+ ipmsg->data_len = sizeof(rsol_t);
+
+ // this is required for solicitation messages
+ ipmsg->hdr.hlim = 0xff;
+
+
+ call IPAddress.getLLAddr(&ipmsg->hdr.ip6_src);
+ inet_pton6("ff02::2", &ipmsg->hdr.ip6_dst);
+
+ msg->cksum = call ICMP.cksum(ipmsg, IANA_ICMP);
+
+ call IP.send(ipmsg);
+
+ ip_free(ipmsg);
+ }
+
+ void sendPing(struct in6_addr *dest, uint16_t seqno) {
+ struct split_ip_msg *ipmsg = (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg) +
+ sizeof(icmp_echo_hdr_t) +
+ sizeof(nx_uint32_t));
+ icmp_echo_hdr_t *e_hdr = (icmp_echo_hdr_t *)ipmsg->next;
+ nx_uint32_t *sendTime = (nx_uint32_t *)(e_hdr + 1);
+
+ if (ipmsg == NULL) return;
+ ipmsg->headers = NULL;
+ ipmsg->data = (void *)e_hdr;
+ ipmsg->data_len = sizeof(icmp_echo_hdr_t) + sizeof(nx_uint32_t);
+
+ e_hdr->type = ICMP_TYPE_ECHO_REQUEST;
+ e_hdr->code = 0;
+ e_hdr->cksum = 0;
+ e_hdr->ident = ping_ident;
+ e_hdr->seqno = seqno;
+ *sendTime = call LocalTime.get();
+
+ memcpy(&ipmsg->hdr.ip6_dst, dest->s6_addr, 16);
+ call IPAddress.getIPAddr(&ipmsg->hdr.ip6_src);
+
+ e_hdr->cksum = call ICMP.cksum(ipmsg,IANA_ICMP);
+
+ call IP.send(ipmsg);
+ ip_free(ipmsg);
+ }
+
+ /*
+ * Router advertisements
+ */
+ void handleRouterAdv(void *payload, uint16_t len, struct ip_metadata *meta) {
+
+ radv_t *r = (radv_t *)payload;
+ pfx_t *pfx = (pfx_t *)(r->options);
+ uint16_t cost = 0;
+ rqual_t *beacon = (rqual_t *)(pfx + 1);
+
+ if (len > sizeof(radv_t) + sizeof(pfx_t) &&
+ beacon->type == ICMP_EXT_TYPE_BEACON) {
+ cost = beacon->metric;
+ dbg("ICMPResponder", " * beacon cost: 0x%x\n", cost);
+ } else
+ dbg("ICMPResponder", " * no beacon cost\n");
+
+ call IPRouting.reportAdvertisement(meta->sender, r->hlim,
+ meta->lqi, cost);
+
+ if (pfx->type != ICMP_EXT_TYPE_PREFIX) return;
+
+ call IPAddress.setPrefix((uint8_t *)pfx->prefix);
+
+ // TODO : get short address here...
+ }
+
+ void sendAdvertisement() {
+ struct split_ip_msg *ipmsg = (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg) +
+ sizeof(radv_t) +
+ sizeof(pfx_t) +
+ sizeof(rqual_t));
+ uint16_t len = sizeof(radv_t);
+ radv_t *r = (radv_t *)(ipmsg + 1);
+ pfx_t *p = (pfx_t *)r->options;
+ rqual_t *q = (rqual_t *)(p + 1);
+
+ if (ipmsg == NULL) return;
+ // don't sent the advertisement if we don't have a valid route
+ if (!call IPRouting.hasRoute()) {
+ ip_free(ipmsg);
+ return;
+ }
+
+ r->type = ICMP_TYPE_ROUTER_ADV;
+ r->code = 0;
+ r->hlim = call IPRouting.getHopLimit();
+ r->flags = 0;
+ r->lifetime = 1;
+ r->reachable_time = 0;
+ r->retrans_time = 0;
+
+ ipmsg->hdr.hlim = 0xff;
+
+ if (globalPrefix) {
+ len += sizeof(pfx_t);
+ p->type = ICMP_EXT_TYPE_PREFIX;
+ p->length = 8;
+ memcpy(p->prefix, call IPAddress.getPublicAddr(), 8);
+ }
+
+ len += sizeof(rqual_t);
+ q->type = ICMP_EXT_TYPE_BEACON;
+ q->length = 2;
+ q->metric = call IPRouting.getQuality();
+
+ call IPAddress.getLLAddr(&ipmsg->hdr.ip6_src);
+ inet_pton6("ff02::1", &ipmsg->hdr.ip6_dst);
+
+ //dbg("ICMPResponder", "My Address: [0x%x] [0x%x] [0x%x] [0x%x]\n", ipmsg->hdr.src_addr[12], ipmsg->hdr.src_addr[13], ipmsg->hdr.src_addr[14], ipmsg->hdr.src_addr[15]);
+ dbg("ICMPResponder", "adv hop limit: 0x%x\n", r->hlim);
+
+ if (r->hlim >= 0xf0) {
+ ip_free(ipmsg);
+ return;
+ }
+
+ ipmsg->data = (void *)r;
+ ipmsg->data_len = len;
+ ipmsg->headers = NULL;
+
+ r->cksum = 0;
+ r->cksum = call ICMP.cksum(ipmsg, IANA_ICMP);
+
+ call IP.send(ipmsg);
+ ip_free(ipmsg);
+ }
+
+
+ event void IP.recv(struct ip6_hdr *iph,
+ void *payload,
+ struct ip_metadata *meta) {
+ icmp_echo_hdr_t *req = (icmp_echo_hdr_t *)payload;
+ uint16_t len = ntohs(iph->plen);
+ stats.rx++;
+
+ // for checksum calculation
+ printfUART ("icmp type: 0x%x code: 0x%x cksum: 0x%x ident: 0x%x seqno: 0x%x len: 0x%x\n",
+ req->type, req->code, req->cksum, req->ident, req->seqno, len);
+
+ switch (req->type) {
+ case ICMP_TYPE_ROUTER_ADV:
+ handleRouterAdv(payload, len, meta);
+ //stats.adv_rx++;
+ break;
+ case ICMP_TYPE_ROUTER_SOL:
+ // only reply to solicitations if we have established a default route.
+ if (call IPRouting.hasRoute()) {
+ call ICMP.sendAdvertisements();
+ }
+ break;
+ case ICMP_TYPE_ECHO_REPLY:
+ {
+ nx_uint32_t *sendTime = (nx_uint32_t *)(req + 1);
+ struct icmp_stats p_stat;
+ p_stat.seq = req->seqno;
+ p_stat.ttl = 0;// buf->hdr.hlim;
+ p_stat.rtt = (call LocalTime.get()) - (*sendTime);
+ signal ICMPPing.pingReply[req->ident](&iph->ip6_src, &p_stat);
+ ping_rcv++;
+ }
+ break;
+ case ICMP_TYPE_ECHO_REQUEST:
+ {
+ // send a ping reply.
+ struct split_ip_msg msg;
+ msg.headers = NULL;
+ msg.data = payload;
+ msg.data_len = len;
+ call IPAddress.getIPAddr(&msg.hdr.ip6_src);
+ memcpy(&msg.hdr.ip6_dst, &iph->ip6_src, 16);
+
+ req->type = ICMP_TYPE_ECHO_REPLY;
+ req->code = 0;
+ req->cksum = 0;
+ req->cksum = call ICMP.cksum(&msg, IANA_ICMP);
+
+ // remember, this can't really fail in a way we care about
+ call IP.send(&msg);
+ break;
+ }
+ }
+ }
+
+
+ event void Solicitation.fired() {
+ sendSolicitation();
+ dbg("ICMPResponder", "solicitation period: 0x%x max: 0x%x\n", solicitation_period, TRICKLE_MAX);
+ solicitation_period <<= 1;
+ if (solicitation_period < TRICKLE_MAX) {
+ call Solicitation.startOneShot(solicitation_period);
+ } else {
+ signal ICMP.solicitationDone();
+ }
+ }
+
+ event void Advertisement.fired() {
+ dbg("ICMPResponder", "==> Sending router advertisement\n");
+ sendAdvertisement();
+ advertisement_period <<= 1;
+ if (advertisement_period < TRICKLE_MAX) {
+ call Advertisement.startOneShot(advertisement_period);
+ }
+ }
+
+
+
+ command error_t ICMPPing.ping[uint16_t client](struct in6_addr *target, uint16_t period, uint16_t n) {
+ if (call PingTimer.isRunning()) return ERETRY;
+ call PingTimer.startPeriodic(period);
+
+ memcpy(&ping_dest, target, 16);
+ ping_n = n;
+ ping_seq = 0;
+ ping_rcv = 0;
+ ping_ident = client;
+ return SUCCESS;
+ }
+
+ event void PingTimer.fired() {
+ // send a ping request
+ if (ping_seq == ping_n) {
+ signal ICMPPing.pingDone[ping_ident](ping_rcv, ping_n);
+ call PingTimer.stop();
+ return;
+ }
+ sendPing(&ping_dest, ping_seq);
+ ping_seq++;
+ }
+
+
+
+ command void Statistics.get(icmp_statistics_t *statistics) {
+ statistics = &stats;
+ }
+
+ command void Statistics.clear() {
+ ip_memclr((uint8_t *)&stats, sizeof(icmp_statistics_t));
+ }
+
+ default event void ICMPPing.pingReply[uint16_t client](struct in6_addr *source,
+ struct icmp_stats *ping_stats) {
+ }
+
+ default event void ICMPPing.pingDone[uint16_t client](uint16_t n, uint16_t m) {
+
+ }
+
+}
--- /dev/null
+/*
+ * "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."
+ *
+ */
+
+
+configuration IPAddressC {
+ provides interface IPAddress;
+
+} implementation {
+ components IPAddressP, ActiveMessageAddressC;
+
+ IPAddress = IPAddressP;
+
+#ifndef SIM
+ IPAddressP.ActiveMessageAddress -> ActiveMessageAddressC;
+#else
+ IPAddressP.setAmAddress -> ActiveMessageAddressC;
+#endif
+}
--- /dev/null
+/*
+ * "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 <6lowpan.h>
+
+// defined in lib6lowpan
+extern struct in6_addr __my_address;
+extern uint8_t globalPrefix;
+
+module IPAddressP {
+ provides interface IPAddress;
+
+#ifndef SIM
+ uses interface ActiveMessageAddress;
+#else
+ uses async command void setAmAddress(am_addr_t a);
+#endif
+} implementation {
+
+
+ command hw_addr_t IPAddress.getShortAddr() {
+ return TOS_NODE_ID;
+ }
+
+ command void IPAddress.setShortAddr(hw_addr_t newAddr) {
+ TOS_NODE_ID = newAddr;
+#ifndef SIM
+ call ActiveMessageAddress.setAddress(call ActiveMessageAddress.amGroup(), newAddr);
+#else
+ call setAmAddress(newAddr);
+#endif
+ }
+
+ command void IPAddress.getLLAddr(struct in6_addr *addr) {
+ memcpy(addr->s6_addr, linklocal_prefix, 8);
+ memcpy(&addr->s6_addr[8], &__my_address.s6_addr[8], 8);
+ }
+
+ command void IPAddress.getIPAddr(struct in6_addr *addr) {
+ __my_address.s6_addr16[7] = htons(TOS_NODE_ID);
+ memcpy(addr, &__my_address, 16);
+ }
+
+ command struct in6_addr *IPAddress.getPublicAddr() {
+ __my_address.s6_addr16[7] = htons(TOS_NODE_ID);
+ return &__my_address;
+ }
+
+ command void IPAddress.setPrefix(uint8_t *pfx) {
+ ip_memclr(__my_address.s6_addr, sizeof(struct in6_addr));
+ ip_memcpy(__my_address.s6_addr, pfx, 8);
+ globalPrefix = 1;
+ }
+
+ command bool IPAddress.haveAddress() {
+ return globalPrefix;
+ }
+
+#ifndef SIM
+ async event void ActiveMessageAddress.changed() {
+
+ }
+#endif
+
+}
--- /dev/null
+/*
+ * "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 _IPDISPATCH_H_
+#define _IPDISPATCH_H_
+
+#include <message.h>
+#include <lib6lowpan.h>
+
+enum {
+ N_PARENTS = 3,
+ N_EPOCHS = 2,
+ N_EPOCHS_COUNTED = 1,
+ N_RECONSTRUCTIONS = 2,
+ N_FORWARD_ENT = IP_NUMBER_FRAGMENTS,
+};
+
+enum {
+ CONF_EVICT_THRESHOLD = 5, // Neighbor is 'mature'
+ CONF_PROM_THRESHOLD = 5, // Acceptable threshold for promotion
+ MAX_CONSEC_FAILURES = 40, // Max Failures before reroute is attempted
+ PATH_COST_DIFF_THRESH = 10, // Threshold for 'similar' path costs
+ LQI_DIFF_THRESH = 10, // Threshold for 'similar' LQI's
+ LINK_EVICT_THRESH = 50, // ETX * 10
+ LQI_ADMIT_THRESH = 0x200,
+ RSSI_ADMIT_THRESH = 0,
+ RANDOM_ROUTE = 20, //Percentage of time to select random default route
+};
+
+enum {
+ WITHIN_THRESH = 1,
+ ABOVE_THRESH = 2,
+ BELOW_THRESH = 3,
+};
+
+enum {
+ TGEN_BASE_TIME = 512,
+ TGEN_MAX_INTERVAL = 60L * 1024L * 5L,
+};
+
+struct epoch_stats {
+ uint16_t success;
+ uint16_t total;
+ uint16_t receptions;
+};
+
+struct report_stats {
+ uint8_t messages;
+ uint8_t transmissions;
+ uint8_t successes;
+};
+
+enum {
+ T_PIN_OFFSET = 0,
+ T_PIN_MASK = 1 << T_PIN_OFFSET,
+ T_VALID_OFFSET = 2,
+ T_VALID_MASK = 1 << T_VALID_OFFSET,
+ T_MARKED_OFFSET = 3,
+ T_MARKED_MASK = 1 << T_MARKED_OFFSET,
+ T_MATURE_OFFSET = 4,
+ T_MATURE_MASK = 1 << T_MATURE_OFFSET,
+ T_EVICT_OFFSET = 5,
+ T_EVICT_MASK = 1 << T_EVICT_OFFSET,
+};
+
+enum {
+ // store the top-k neighbors. This could be a poor topology
+ // formation critera is very dense networks. we may be able to
+ // really use the fact that the "base" has infinite memory.
+ N_NEIGH = 8,
+ N_LOW_NEIGH = 2,
+ N_FREE_NEIGH = (N_NEIGH - N_LOW_NEIGH),
+ N_FLOW_ENT = 6,
+ N_FLOW_CHOICES = 2,
+ N_PARENT_CHOICES = 3,
+ T_DEF_PARENT = 0xfffd,
+ T_DEF_PARENT_SLOT = 0,
+};
+
+typedef struct {
+ // The extra 2 is because one dest could be from source route, other
+ // from the dest being a direct neighbor
+ hw_addr_t dest[N_FLOW_CHOICES + N_PARENT_CHOICES + 2];
+ uint8_t current:4;
+ uint8_t nchoices:4;
+ uint8_t retries;
+ uint8_t actRetries;
+ uint8_t delay;
+} send_policy_t;
+
+typedef struct {
+ send_policy_t policy;
+ uint8_t frags_sent;
+ bool failed;
+ uint8_t refcount;
+} send_info_t;
+
+typedef struct {
+ send_info_t *info;
+ message_t *msg;
+} send_entry_t;
+
+typedef struct {
+ uint8_t timeout;
+ hw_addr_t l2_src;
+ uint16_t old_tag;
+ uint16_t new_tag;
+ send_info_t *s_info;
+} forward_entry_t;
+
+/* typedef struct { */
+/* /\* how to dispatch this packet *\/ */
+/* union { */
+/* struct sockaddr_in6 sock; */
+/* ip6_addr_t src; */
+/* } address; */
+/* /\* packet metadata *\/ */
+/* union { */
+/* uint16_t udp_port; */
+/* } dispatch; */
+/* struct ip_metadata metadata; */
+
+/* /\* the lib6lowpan reconstruct structure *\/ */
+/* reconstruct_t recon; */
+/* } ip_recon_t; */
+
+enum {
+ F_VALID_MASK = 0x01,
+ //F_TOTAL_VALID_ENTRY_MASK = 0x80, // For entire entry (not just specific choice)
+ F_FULL_PATH_OFFSET = 1,
+ F_FULL_PATH_MASK = 0x02,
+
+ MAX_PATH_LENGTH = 10,
+ N_FULL_PATH_ENTRIES = (N_FLOW_CHOICES * N_FLOW_ENT),
+};
+
+struct flow_path {
+ uint8_t path_len;
+ cmpr_ip6_addr_t path[MAX_PATH_LENGTH];
+};
+
+struct f_entry {
+ uint8_t flags;
+ union {
+ struct flow_path *pathE;
+ cmpr_ip6_addr_t nextHop;
+ };
+};
+
+// Need to add another entry to avoid useless padding
+// Or can make sure that the flow_table has an even
+// number of entries.
+struct flow_entry {
+ uint8_t flags;
+ uint8_t count;
+ struct flow_match match;
+ struct f_entry entries[N_FLOW_CHOICES];
+};
+
+//#define IS_VALID_SLOT(f) (((f)->entries[0].flags & F_TOTAL_VALID_ENTRY_MASK) == F_TOTAL_VALID_ENTRY_MASK)
+#define IS_VALID_SLOT(f) (((f)->flags & F_VALID_MASK) == F_VALID_MASK)
+//#define SET_VALID_SLOT(f) (f)->entries[0].flags |= F_TOTAL_VALID_ENTRY_MASK
+#define SET_VALID_SLOT(f) (f)->flags |= F_VALID_MASK
+//#define SET_INVALID_SLOT(f) (f)->entries[0].flags &= ~F_TOTAL_VALID_ENTRY_MASK
+#define SET_INVALID_SLOT(f) (f)->flags &= ~F_VALID_MASK
+#define IS_VALID_ENTRY(e) (((e).flags & F_VALID_MASK) == F_VALID_MASK)
+#define SET_VALID_ENTRY(e) (e).flags |= F_VALID_MASK
+#define SET_INVALID_ENTRY(e) (e).flags &= ~F_VALID_MASK
+#define IS_FULL_TYPE(e) (((e).flags & F_FULL_PATH_MASK) == F_FULL_PATH_MASK)
+#define IS_HOP_TYPE(e) !IS_FULL_TYPE(e)
+#define SET_FULL_TYPE(e) ((e).flags |= F_FULL_PATH_MASK)
+#define SET_HOP_TYPE(e) ((e).flags &= ~F_FULL_PATH_MASK)
+
+
+struct neigh_entry {
+ uint8_t flags;
+ uint8_t hops; // Put this before neighbor to remove potential padding issues
+ hw_addr_t neighbor;
+ uint16_t costEstimate;
+ uint16_t linkEstimate;
+ struct epoch_stats stats[N_EPOCHS];
+}
+#ifdef MIG
+ __attribute__((packed));
+#else
+;
+#endif
+
+#define IS_NEIGH_VALID(e) (((e)->flags & T_VALID_MASK) == T_VALID_MASK)
+#define SET_NEIGH_VALID(e) ((e)->flags |= T_VALID_MASK)
+#define SET_NEIGH_INVALID(e) ((e)->flags &= ~T_VALID_MASK)
+#define PINNED(e) (((e)->flags & T_PIN_MASK) == T_PIN_MASK)
+#define REMOVABLE(e) (((e)->refCount == 0) && !(PINNED(e)))
+#define SET_PIN(e) (((e)->flags |= T_PIN_MASK))
+#define UNSET_PIN(e) (((e)->flags &= ~T_PIN_MASK))
+#define IS_MARKED(e) (((e)->flags & T_MARKED_MASK) == T_MARKED_MASK)
+#define SET_MARK(e) (((e)->flags |= T_MARKED_MASK))
+#define UNSET_MARK(e) (((e)->flags &= ~T_MARKED_MASK))
+#define IS_MATURE(e) (((e)->flags & T_MATURE_MASK) == T_MATURE_MASK)
+#define SET_MATURE(e) ((e)->flags |= T_MATURE_MASK)
+#define SET_EVICT(e) ((e).flags |= T_EVICT_MASK)
+#define UNSET_EVICT(e) ((e).flags &= ~T_EVICT_MASK)
+#define SHOULD_EVICT(e) ((e).flags & T_EVICT_MASK)
+
+
+typedef enum {
+ S_FORWARD,
+ S_REQ,
+} send_type_t;
+
+
+typedef nx_struct {
+ nx_uint16_t sent;
+ nx_uint16_t forwarded;
+ nx_uint8_t rx_drop;
+ nx_uint8_t tx_drop;
+ nx_uint8_t fw_drop;
+ nx_uint8_t rx_total;
+ nx_uint8_t real_drop;
+ nx_uint8_t hlim_drop;
+ nx_uint8_t senddone_el;
+ nx_uint8_t fragpool;
+ nx_uint8_t sendinfo;
+ nx_uint8_t sendentry;
+ nx_uint8_t sndqueue;
+ nx_uint8_t encfail;
+ nx_uint16_t heapfree;
+} ip_statistics_t;
+
+
+typedef nx_struct {
+ nx_uint8_t hop_limit;
+ nx_uint16_t parent;
+ nx_uint16_t parent_metric;
+ nx_uint16_t parent_etx;
+} route_statistics_t;
+
+typedef nx_struct {
+/* nx_uint8_t sol_rx; */
+/* nx_uint8_t sol_tx; */
+/* nx_uint8_t adv_rx; */
+/* nx_uint8_t adv_tx; */
+/* nx_uint8_t unk_rx; */
+ nx_uint16_t rx;
+} icmp_statistics_t;
+
+typedef nx_struct {
+ nx_uint16_t total;
+ nx_uint16_t failed;
+ nx_uint16_t seqno;
+ nx_uint16_t sender;
+} udp_statistics_t;
+
+#endif
--- /dev/null
+/*
+ * "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."
+ *
+ */
+
+/*
+ * Provides message dispatch based on the next header field of IP packets.
+ *
+ */
+#include "IPDispatch.h"
+
+configuration IPDispatchC {
+ provides {
+ interface SplitControl;
+ interface IPAddress;
+ interface IP[uint8_t nxt_hdr];
+
+ interface Statistics<ip_statistics_t> as IPStats;
+ interface Statistics<route_statistics_t> as RouteStats;
+ interface Statistics<icmp_statistics_t> as ICMPStats;
+
+ }
+} implementation {
+
+#ifndef SIM
+ components CC2420ActiveMessageC as MessageC;
+#else
+ components ActiveMessageC as MessageC;
+#endif
+ components MainC, IPDispatchP, IPAddressC, IPRoutingP;
+ components NoLedsC as LedsC;
+ components RandomC;
+
+ SplitControl = IPDispatchP.SplitControl;
+ IPAddress = IPAddressC;
+ IP = IPDispatchP;
+
+ IPDispatchP.Boot -> MainC;
+
+#ifndef SIM
+ IPDispatchP.IEEE154Send -> MessageC;
+ IPDispatchP.IEEE154Receive -> MessageC;
+#else
+ IPDispatchP.IEEE154Send -> MessageC.AMSend[0];
+ IPDispatchP.IEEE154Receive -> MessageC.Receive[0];
+#endif
+ IPDispatchP.Packet -> MessageC.SubAMPacket;
+#ifdef LOW_POWER_LISTENING
+ IPDispatchP.LowPowerListening -> MessageC;
+#endif
+
+
+ IPDispatchP.IEEE154Packet -> MessageC;
+ IPDispatchP.PacketLink -> MessageC;
+ IPDispatchP.CC2420Packet -> MessageC;
+
+#ifdef DBG_TRACK_FLOWS
+ IPDispatchP.getFlowID -> MessageC;
+#endif
+
+
+ IPDispatchP.Leds -> LedsC;
+
+ IPDispatchP.IPAddress -> IPAddressC;
+
+ components new TimerMilliC();
+ IPDispatchP.ExpireTimer -> TimerMilliC;
+
+ components new PoolC(message_t, IP_NUMBER_FRAGMENTS) as FragPool;
+
+ components new PoolC(send_entry_t, IP_NUMBER_FRAGMENTS) as SendEntryPool;
+ components new QueueC(send_entry_t *, IP_NUMBER_FRAGMENTS);
+
+ components new PoolC(send_info_t, N_FORWARD_ENT) as SendInfoPool;
+
+ IPDispatchP.FragPool -> FragPool;
+ IPDispatchP.SendEntryPool -> SendEntryPool;
+ IPDispatchP.SendInfoPool -> SendInfoPool;
+ IPDispatchP.SendQueue -> QueueC;
+
+ components ICMPResponderC;
+ components new TimerMilliC() as TGenTimer;
+ IPDispatchP.ICMP -> ICMPResponderC;
+ IPRoutingP.ICMP -> ICMPResponderC;
+ IPDispatchP.RadioControl -> MessageC;
+
+ IPDispatchP.IPRouting -> IPRoutingP;
+ IPRoutingP.Boot -> MainC;
+ IPRoutingP.Leds -> LedsC;
+ IPRoutingP.IPAddress -> IPAddressC;
+ IPRoutingP.Random -> RandomC;
+ IPRoutingP.TrafficGenTimer -> TGenTimer;
+ IPRoutingP.TGenSend -> IPDispatchP.IP[NXTHDR_UNKNOWN];
+
+ IPStats = IPDispatchP;
+ RouteStats = IPRoutingP;
+ ICMPStats = ICMPResponderC;
+
+ components new TimerMilliC() as RouteTimer;
+ IPRoutingP.SortTimer -> RouteTimer;
+
+#ifdef DELUGE
+ components NWProgC;
+#endif
+
+}
--- /dev/null
+/*
+ * "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."
+ *
+ */
+
+/*
+ * This file has the potential to be rather confusing, here are a few
+ * notes about what is happening. There are several state machines in
+ * this file. Together, they take care of packet forwarding and
+ * sending (which is accomplished by injecting new packets into the
+ * outgoing queue.)
+ *
+ * Messages enter from two places: either from the bottom (from the
+ * radio), or from the top (from the application). Messages also
+ * leave from two places: either out over the radio, or up to an
+ * application.
+ *
+ *
+ * IP.send ---- - ---> IP.recvfrom
+ * \ /
+ * X
+ * / \
+ * IEEE154.receive ---- - ---> IEEE154.send
+ *
+ *
+ * All of the queueing is done on the output; when each message
+ * arrives, it is dispatched all the way to an output queue.
+ *
+ * There are four paths through the system, so here they are:
+ *
+ * IP.send -> IP.recvfrom : local delivery: not implemented
+ * IP.send -> IEEE154.send : enqueue fragments on radio queue
+ * IEEE154.receive -> IP.recv : deliver to this mote : reassemble and deliver
+ * IEEE154.receive -> IEEE154.send : forwarding : enqueue fragments
+ *
+ * the IP receive queue
+ * data structures:
+ * recon_cache: holds state about packets which are to be consumed
+ * by this mote, and have fragments pending.
+ *
+ * radio send queue
+ * data structures:
+ * send_info_t: packet metadata for a single packet flow through
+ * the mote (could either come from a forwarded stream
+ * or a local send.
+ * send_entry_t: the actual queue items, pointing to a fragment
+ * and the packet metadata (send_info_t)
+ *
+ * extra forwarding structures:
+ * forward_cache: used to match up incoming fragments with their flow metadata,
+ * stored in a send_info_t.
+ * fragment pool:
+ */
+#include <6lowpan.h>
+#include <lib6lowpan.h>
+#include <ip.h>
+#include <in_cksum.h>
+#include <ip_malloc.h>
+#include "IPDispatch.h"
+#include "table.h"
+#include "PrintfUART.h"
+#ifdef PRINTF_LIBRARY
+#include "printf.h"
+#endif
+
+/*
+ * Provides IP layer reception to applications on motes.
+ *
+ * @author Stephen Dawson-Haggerty <stevedh@cs.berkeley.edu>
+ */
+
+module IPDispatchP {
+ provides {
+ interface SplitControl;
+ // interface for protocols not requiring special hand-holding
+ interface IP[uint8_t nxt_hdr];
+ interface Statistics<ip_statistics_t>;
+ }
+ uses {
+ interface Boot;
+ interface SplitControl as RadioControl;
+
+ interface CC2420Packet;
+ interface Packet;
+
+#ifndef SIM
+ interface IEEE154Send;
+ interface IEEE154Packet;
+#else
+ interface AMSend as IEEE154Send;
+ interface AMPacket as IEEE154Packet;
+#endif
+ interface Receive as IEEE154Receive;
+
+ interface PacketLink;
+
+ // outgoing fragments
+ interface Pool<message_t> as FragPool;
+ interface Pool<send_info_t> as SendInfoPool;
+ interface Pool<send_entry_t> as SendEntryPool;
+ interface Queue<send_entry_t *> as SendQueue;
+
+ interface Timer<TMilli> as ExpireTimer;
+
+ interface IPRouting;
+ interface ICMP;
+
+ interface LowPowerListening;
+
+ interface Leds;
+
+ interface IPAddress;
+
+#ifdef DBG_TRACK_FLOWS
+ command flow_id_t *getFlowID(message_t *);
+#endif
+
+ }
+} implementation {
+
+ enum {
+ S_RUNNING,
+ S_STOPPED,
+ S_STOPPING,
+ };
+ uint8_t state = S_STOPPED;
+ bool radioBusy;
+ ip_statistics_t stats;
+
+ // this in theory could be arbitrarily large; however, it needs to
+ // be large enough to hold all active reconstructions, and any tags
+ // which we are dropping. It's important to keep dropped tags
+ // around for a while, or else there are pathological situations
+ // where you continually allocate buffers for packets which will
+ // never complete.
+
+ ////////////////////////////////////////
+ //
+ //
+
+ table_t recon_cache, forward_cache;
+
+
+ // table of packets we are currently receiving fragments from, that
+ // are destined to us
+ reconstruct_t recon_data[N_RECONSTRUCTIONS];
+
+ // table of fragmented flows who are going through us, so we must
+ // remember the next hop.
+ forward_entry_t forward_data[N_FORWARD_ENT];
+
+ //
+ //
+ ////////////////////////////////////////
+
+#ifdef DBG_TRACK_FLOWS
+ uint16_t dbg_flowid = 0;
+#endif
+
+#ifndef SIM
+#define CHECK_NODE_ID if (0) return
+#else
+#define CHECK_NODE_ID if (TOS_NODE_ID == BASESTATION_ID) return
+#endif
+
+ task void sendTask();
+
+ void reconstruct_clear(void *ent) {
+ reconstruct_t *recon = (reconstruct_t *)ent;
+ ip_memclr((uint8_t *)&recon->metadata, sizeof(struct ip_metadata));
+ recon->timeout = T_UNUSED;
+ recon->buf = NULL;
+ }
+
+ void forward_clear(void *ent) {
+ forward_entry_t *fwd = (forward_entry_t *)ent;
+ fwd->timeout = T_UNUSED;
+ }
+
+ int forward_unused(void *ent) {
+ forward_entry_t *fwd = (forward_entry_t *)ent;
+ if (fwd->timeout == T_UNUSED)
+ return 1;
+ return 0;
+ }
+
+ uint16_t forward_lookup_tag;
+ uint16_t forward_lookup_src;
+ int forward_lookup(void *ent) {
+ forward_entry_t *fwd = (forward_entry_t *)ent;
+ if (fwd->timeout > T_UNUSED &&
+ fwd->l2_src == forward_lookup_src &&
+ fwd->old_tag == forward_lookup_tag) {
+ fwd->timeout = T_ACTIVE;
+ return 1;
+ }
+ return 0;
+ }
+
+
+ send_info_t *getSendInfo() {
+ send_info_t *ret = call SendInfoPool.get();
+ if (ret == NULL) return ret;
+ ret->refcount = 1;
+ ret->failed = FALSE;
+ ret->frags_sent = 0;
+ return ret;
+ }
+#define SENDINFO_INCR(X) ((X)->refcount)++
+#define SENDINFO_DECR(X) if (--((X)->refcount) == 0) call SendInfoPool.put(X)
+
+ command error_t SplitControl.start() {
+ CHECK_NODE_ID FAIL;
+ return call RadioControl.start();
+ }
+
+ command error_t SplitControl.stop() {
+ if (!radioBusy) {
+ state = S_STOPPED;
+ return call RadioControl.stop();
+ } else {
+ // if there's a packet in the radio, wait for it to exit before
+ // stopping
+ state = S_STOPPING;
+ return SUCCESS;
+ }
+ }
+
+ event void RadioControl.startDone(error_t error) {
+#ifdef LPL_SLEEP_INTERVAL
+ call LowPowerListening.setLocalSleepInterval(LPL_SLEEP_INTERVAL);
+#endif
+ if (error == SUCCESS) {
+ call ICMP.sendSolicitations();
+ state = S_RUNNING;
+ }
+ signal SplitControl.startDone(error);
+ }
+
+ event void RadioControl.stopDone(error_t error) {
+ signal SplitControl.stopDone(error);
+ }
+
+ event void Boot.booted() {
+ CHECK_NODE_ID;
+ call Statistics.clear();
+
+ ip_malloc_init();
+
+ table_init(&recon_cache, recon_data, sizeof(reconstruct_t), N_RECONSTRUCTIONS);
+ table_init(&forward_cache, forward_data, sizeof(forward_entry_t), N_FORWARD_ENT);
+
+ table_map(&recon_cache, reconstruct_clear);
+ table_map(&forward_cache, forward_clear);
+
+ radioBusy = FALSE;
+
+ call ExpireTimer.startPeriodic(FRAG_EXPIRE_TIME);
+
+ call SplitControl.start();
+ return;
+ }
+
+ /*
+ * Receive-side code.
+ */
+
+ /*
+ * Logic which must process every received IP datagram.
+ *
+ * Each IP packet may be consumed and/or forwarded.
+ */
+ void signalDone(reconstruct_t *recon) {
+ struct ip6_hdr *iph = (struct ip6_hdr *)recon->buf;
+ signal IP.recv[iph->nxt_hdr](iph, recon->transport_hdr, &recon->metadata);
+ ip_free(recon->buf);
+ recon->timeout = T_UNUSED;
+ recon->buf = NULL;
+ }
+
+ /*
+ * Bulletproof recovery logic is very important to make sure we
+ * don't get wedged with no free buffers.
+ *
+ * The table is managed as follows:
+ * - unused entries are marked T_UNUSED
+ * - entries which
+ * o have a buffer allocated
+ * o have had a fragment reception before we fired
+ * are marked T_ACTIVE
+ * - entries which have not had a fragment reception during the last timer period
+ * and were active are marked T_ZOMBIE
+ * - zombie receptions are deleted: their buffer is freed and table entry marked unused.
+ * - when a fragment is dropped, it is entered into the table as T_FAILED1.
+ * no buffer is allocated
+ * - when the timer fires, T_FAILED1 entries are aged to T_FAILED2.
+ * - T_FAILED2 entries are deleted. Incomming fragments with tags
+ * that are marked either FAILED1 or FAILED2 are dropped; this
+ * prevents us from allocating a buffer for a packet which we
+ * have already dropped fragments from.
+ *
+ */
+ void reconstruct_age(void *elt) {
+ reconstruct_t *recon = (reconstruct_t *)elt;
+ switch (recon->timeout) {
+ case T_ACTIVE:
+ recon->timeout = T_ZOMBIE; break; // age existing receptions
+ case T_FAILED1:
+ recon->timeout = T_FAILED2; break; // age existing receptions
+ case T_ZOMBIE:
+ case T_FAILED2:
+ // deallocate the space for reconstruction
+ if (recon->buf != NULL) {
+ ip_free(recon->buf);
+ }
+ recon->timeout = T_UNUSED;
+ recon->buf = NULL;
+ break;
+ }
+ }
+
+ void forward_age(void *elt) {
+ forward_entry_t *fwd = (forward_entry_t *)elt;
+ switch (fwd->timeout) {
+ case T_ACTIVE:
+ fwd->timeout = T_ZOMBIE; break; // age existing receptions
+ case T_FAILED1:
+ fwd->timeout = T_FAILED2; break; // age existing receptions
+ case T_ZOMBIE:
+ case T_FAILED2:
+ fwd->s_info->failed = TRUE;
+ SENDINFO_DECR(fwd->s_info);
+ fwd->timeout = T_UNUSED;
+ break;
+ }
+ }
+
+ void ip_print_heap() {
+#ifdef PRINTFUART_ENABLED
+ bndrt_t *cur = (bndrt_t *)heap;
+ while (((uint8_t *)cur) - heap < IP_MALLOC_HEAP_SIZE) {
+ //printfUART ("heap region start: 0x%x length: %i used: %i\n",
+ //cur, (*cur & IP_MALLOC_LEN), (*cur & IP_MALLOC_INUSE) >> 15);
+ cur = (bndrt_t *)(((uint8_t *)cur) + ((*cur) & IP_MALLOC_LEN));
+ }
+#endif
+ }
+
+ event void ExpireTimer.fired() {
+ CHECK_NODE_ID;
+ table_map(&recon_cache, reconstruct_age);
+ table_map(&forward_cache, forward_age);
+
+ /*
+ printfUART("Frag pool size: %i\n", call FragPool.size());
+ printfUART("SendInfo pool size: %i\n", call SendInfoPool.size());
+ printfUART("SendEntry pool size: %i\n", call SendEntryPool.size());
+ printfUART("Forward queue length: %i\n", call SendQueue.size());
+ */
+ ip_print_heap();
+ }
+
+ /*
+ * allocate a structure for recording information about incomming fragments.
+ */
+
+ reconstruct_t *get_reconstruct(hw_addr_t src, uint16_t tag) {
+ reconstruct_t *ret = NULL;
+ int i;
+ for (i = 0; i < N_RECONSTRUCTIONS; i++) {
+ reconstruct_t *recon = (reconstruct_t *)&recon_data[i];
+ dbg("IPDispatch", " 0x%x 0x%x 0x%x\n", recon->timeout, recon->metadata.sender, recon->tag);
+
+ if (recon->tag == tag &&
+ recon->metadata.sender == src) {
+
+ if (recon->timeout > T_UNUSED) {
+
+ recon->timeout = T_ACTIVE;
+ return recon;
+
+ } else if (recon->timeout < T_UNUSED) {
+ // if we have already tried and failed to get a buffer, we
+ // need to drop remaining fragments.
+ return NULL;
+ }
+ }
+ if (recon->timeout == T_UNUSED)
+ ret = recon;
+ }
+ return ret;
+ }
+
+ /*
+ * This is called before a receive on packets with a source routing header.
+ *
+ * it updates the path stored in the header to remove our address
+ * and include our predicessor.
+ *
+ * However, if this is not a source record path and we are not in the current
+ * spot, this means we are along the default path and so should invalidate this
+ * source header.
+ */
+ void updateSourceRoute(hw_addr_t prev_hop, struct source_header *sh) {
+ uint16_t my_address = call IPAddress.getShortAddr();
+ if ((sh->dispatch & IP_EXT_SOURCE_INVAL) == IP_EXT_SOURCE_INVAL) return;
+ if (((sh->dispatch & IP_EXT_SOURCE_RECORD) != IP_EXT_SOURCE_RECORD) &&
+ (ntohs(sh->hops[sh->current]) != my_address)) {
+ sh->dispatch |= IP_EXT_SOURCE_INVAL;
+ dbg("IPDispatch", "Invalidating source route!\n");
+ return;
+ }
+ if (sh->current == SH_NENTRIES(sh)) return;
+ sh->hops[sh->current] = htons(prev_hop);
+ sh->current++;
+ }
+
+
+
+
+ message_t *handle1stFrag(message_t *msg, packed_lowmsg_t *lowmsg) {
+ uint8_t *unpack_buf;
+ struct ip6_hdr *ip;
+
+ // uint16_t real_payload_length, real_offset = sizeof(struct ip6_hdr);
+
+ unpack_info_t u_info;
+
+ unpack_buf = ip_malloc(LIB6LOWPAN_MAX_LEN + LOWPAN_LINK_MTU);
+ if (unpack_buf == NULL) return msg;
+
+ // unpack all the compressed headers. this means the IP headers,
+ // and possibly also the UDP ones if there are no hop-by-hop
+ // options.
+ ip_memclr(unpack_buf, LIB6LOWPAN_MAX_LEN + LOWPAN_LINK_MTU);
+ if (unpackHeaders(lowmsg, &u_info,
+ unpack_buf, LIB6LOWPAN_MAX_LEN) == NULL) {
+ ip_free(unpack_buf);
+ return msg;
+ }
+
+ ip = (struct ip6_hdr *)unpack_buf;
+
+
+ // first check if we forward or consume it
+ if (call IPRouting.isForMe(ip)) {
+ struct ip_metadata metadata;
+ dbg("IPDispatch", "is for me!\n");
+ // consume it:
+ // - get a buffer
+ // - if fragmented, wait for remaining fragments
+ // - if not, dispatch from here.
+
+ metadata.sender = call IEEE154Packet.source(msg);
+ metadata.lqi = call CC2420Packet.getLqi(msg);
+
+ ip->plen = htons(ntohs(ip->plen) - u_info.payload_offset);
+ switch (ip->nxt_hdr) {
+ case IANA_UDP:
+ ip->plen = htons(ntohs(ip->plen) + sizeof(struct udp_hdr));
+ }
+
+ if (!hasFrag1Header(lowmsg)) {
+ uint16_t amount_here = lowmsg->len - (u_info.payload_start - lowmsg->data);
+
+ // we can fill in the data and deliver the packet from here.
+ // this is the easy case...
+ // we malloc'ed a bit extra in this case so we don't have to
+ // copy the IP header; we can just add the payload after the unpacked
+ // buffers.
+ // if (rcv_buf == NULL) goto done;
+ ip_memcpy(u_info.header_end, u_info.payload_start, amount_here);
+ signal IP.recv[ip->nxt_hdr](ip, u_info.transport_ptr, &metadata);
+ } else {
+ // in this case, we need to set up a reconstruction
+ // structure so when the next packets come in, they can be
+ // filled in.
+ reconstruct_t *recon;
+ uint16_t tag, amount_here = lowmsg->len - (u_info.payload_start - lowmsg->data);
+ void *rcv_buf;
+
+ if (getFragDgramTag(lowmsg, &tag)) goto fail;
+
+ dbg("IPDispatch", "looking up frag tag: 0x%x\n", tag);
+ recon = get_reconstruct(lowmsg->src, tag);
+
+ // allocate a new struct for doing reassembly.
+ if (recon == NULL) {
+ goto fail;
+ }
+
+ // the total size of the IP packet
+ rcv_buf = ip_malloc(ntohs(ip->plen) + sizeof(struct ip6_hdr));
+
+ recon->metadata.sender = lowmsg->src;
+ recon->tag = tag;
+ recon->size = ntohs(ip->plen) + sizeof(struct ip6_hdr);
+ recon->buf = rcv_buf;
+ recon->transport_hdr = ((uint8_t *)rcv_buf) + (u_info.transport_ptr - unpack_buf);
+ recon->bytes_rcvd = u_info.payload_offset + amount_here + sizeof(struct ip6_hdr);
+ recon->timeout = T_ACTIVE;
+
+ if (rcv_buf == NULL) {
+ // if we didn't get a buffer better not memcopy anything
+ recon->timeout = T_FAILED1;
+ recon->size = 0;
+ goto fail;
+ }
+ if (amount_here > recon->size - sizeof(struct ip6_hdr)) {
+ call Leds.led1Toggle();
+ recon->timeout = T_FAILED1;
+ recon->size = 0;
+ ip_free(rcv_buf);
+ recon->buf = NULL;
+ goto fail;
+ }
+
+ ip_memcpy(rcv_buf, unpack_buf, u_info.payload_offset + sizeof(struct ip6_hdr));
+ ip_memcpy(rcv_buf + u_info.payload_offset + sizeof(struct ip6_hdr),
+ u_info.payload_start, amount_here);
+ ip_memcpy(&recon->metadata, &metadata, sizeof(struct ip_metadata));
+
+ goto done;
+ // that's it, we just filled in the first piece of the fragment
+ }
+ } else {
+ // otherwise set up forwarding information for the next
+ // fragments and enqueue this message_t on its merry way.
+ send_info_t *s_info;
+ send_entry_t *s_entry;
+ forward_entry_t *fwd;
+ message_t *msg_replacement;
+
+ *u_info.hlim = *u_info.hlim - 1;
+ if (*u_info.hlim == 0) {
+ uint16_t amount_here = lowmsg->len - (u_info.payload_start - lowmsg->data);
+ call ICMP.sendTimeExceeded(ip, &u_info, amount_here);
+ // by bailing here and not setting up an entry in the
+ // forwarding cache, following fragments will be dropped like
+ // they should be. we don't strictly follow the RFC that says
+ // we should return at least 64 bytes of payload.
+ ip_free(unpack_buf);
+ return msg;
+ }
+ s_info = getSendInfo();
+ s_entry = call SendEntryPool.get();
+ msg_replacement = call FragPool.get();
+ if (s_info == NULL || s_entry == NULL || msg_replacement == NULL) {
+ if (s_info != NULL)
+ SENDINFO_DECR(s_info);
+ if (s_entry != NULL)
+ call SendEntryPool.put(s_entry);
+ if (msg_replacement != NULL)
+ call FragPool.put(msg_replacement);
+ goto fail;
+ }
+
+ if (ip->nxt_hdr == NXTHDR_SOURCE) {
+ // this updates the source route in the message_t, if it
+ // exists...
+ updateSourceRoute(call IEEE154Packet.source(msg),
+ u_info.sh);
+ }
+
+ if (call IPRouting.getNextHop(ip, u_info.sh, lowmsg->src, &s_info->policy) != SUCCESS)
+ goto fwd_fail;
+
+ dbg("IPDispatch", "next hop is: 0x%x\n", s_info->policy.dest);
+
+ if (hasFrag1Header(lowmsg)) {
+ fwd = table_search(&forward_cache, forward_unused);
+ if (fwd == NULL) {
+ goto fwd_fail;
+ }
+
+ fwd->timeout = T_ACTIVE;
+ fwd->l2_src = call IEEE154Packet.source(msg);
+ getFragDgramTag(lowmsg, &fwd->old_tag);
+ fwd->new_tag = ++lib6lowpan_frag_tag;
+ // forward table gets a reference
+ SENDINFO_INCR(s_info);
+ fwd->s_info = s_info;
+ setFragDgramTag(lowmsg, lib6lowpan_frag_tag);
+ }
+
+ // give a reference to the send_entry
+ SENDINFO_INCR(s_info);
+ s_entry->msg = msg;
+ s_entry->info = s_info;
+
+ if (call SendQueue.enqueue(s_entry) != SUCCESS)
+ stats.encfail++;
+ post sendTask();
+
+ // s_info leaves lexical scope;
+ SENDINFO_DECR(s_info);
+ ip_free(unpack_buf);
+ return msg_replacement;
+
+ fwd_fail:
+ call FragPool.put(msg_replacement);
+ call SendInfoPool.put(s_info);
+ call SendEntryPool.put(s_entry);
+ }
+
+
+
+ fail:
+ done:
+ ip_free(unpack_buf);
+ return msg;
+ }
+
+ event message_t *IEEE154Receive.receive(message_t *msg, void *msg_payload, uint8_t len) {
+ packed_lowmsg_t lowmsg;
+ CHECK_NODE_ID msg;
+
+ // set up the ip message structaddFragment
+ lowmsg.data = msg_payload;
+ lowmsg.len = len;
+ lowmsg.src = call IEEE154Packet.source(msg);
+ lowmsg.dst = call IEEE154Packet.destination(msg);
+
+ stats.rx_total++;
+
+ call IPRouting.reportReception(call IEEE154Packet.source(msg),
+ call CC2420Packet.getLqi(msg));
+
+ lowmsg.headers = getHeaderBitmap(&lowmsg);
+ if (lowmsg.headers == LOWPAN_NALP_PATTERN) {
+ goto fail;
+ }
+
+ // consume it
+ if (!hasFragNHeader(&(lowmsg))) {
+ // in this case, we need to unpack the addressing information
+ // and either dispatch the packet locally or forward it.
+ msg = handle1stFrag(msg, &lowmsg);
+ goto done;
+ } else {
+ // otherwise, it's a fragN packet, and we just need to copy it
+ // into a buffer or forward it.
+ forward_entry_t *fwd;
+ reconstruct_t *recon;
+ uint8_t offset_cmpr;
+ uint16_t offset, amount_here, tag;
+ uint8_t *payload;
+
+ if (getFragDgramTag(&lowmsg, &tag)) goto fail;
+ if (getFragDgramOffset(&lowmsg, &offset_cmpr)) goto fail;
+
+ forward_lookup_tag = tag;
+ forward_lookup_src = call IEEE154Packet.source(msg);
+
+ fwd = table_search(&forward_cache, forward_lookup);
+ payload = getLowpanPayload(&lowmsg);
+
+ recon = get_reconstruct(lowmsg.src, tag);
+ if (recon != NULL && recon->timeout > T_UNUSED && recon->buf != NULL) {
+ // for packets we are reconstructing.
+
+ offset = (offset_cmpr * 8);
+ amount_here = lowmsg.len - (payload - lowmsg.data);
+
+ if (offset + amount_here > recon->size) goto fail;
+ ip_memcpy(recon->buf + offset, payload, amount_here);
+
+ recon->bytes_rcvd += amount_here;
+
+ if (recon->size == recon->bytes_rcvd) {
+ // signal and free the recon.
+ signalDone(recon);
+ }
+ } else if (fwd != NULL && fwd->timeout > T_UNUSED) {
+ // this only catches if we've forwarded all the past framents
+ // successfully.
+ message_t *replacement = call FragPool.get();
+ send_entry_t *s_entry = call SendEntryPool.get();
+ uint16_t lowpan_size;
+ uint8_t lowpan_offset;
+
+ if (replacement == NULL || s_entry == NULL) {
+ // we have to drop the rest of the framents if we don't have
+ // a buffer...
+ if (replacement != NULL)
+ call FragPool.put(replacement);
+ if (s_entry != NULL)
+ call SendEntryPool.put(s_entry);
+
+ stats.fw_drop++;
+ fwd->timeout = T_FAILED1;
+ goto fail;
+ }
+ // keep a reference for ourself, and pass it off to the
+ // send_entry_t
+ SENDINFO_INCR(fwd->s_info);
+
+ getFragDgramOffset(&lowmsg, &lowpan_offset);
+ getFragDgramSize(&lowmsg, &lowpan_size);
+ if ((lowpan_offset * 8) + (lowmsg.len - (payload - lowmsg.data)) == lowpan_size) {
+ // this is the last fragment. since delivery is in-order,
+ // we want to free up that forwarding table entry.
+ // take back the reference the table had.
+ SENDINFO_DECR(fwd->s_info);
+ fwd->timeout = T_UNUSED;
+ }
+
+ setFragDgramTag(&lowmsg, fwd->new_tag);
+
+ s_entry->msg = msg;
+ s_entry->info = fwd->s_info;
+
+ dbg("IPDispatch", "forwarding: dest: 0x%x\n",
+ fwd->s_info->policy.dest[s_entry->info->policy.current]);
+
+ if (call SendQueue.enqueue(s_entry) != SUCCESS) {
+ stats.encfail++;
+ dbg("Drops", "drops: receive enqueue failed\n");
+ }
+ post sendTask();
+ return replacement;
+
+ } else goto fail;
+ goto done;
+ }
+
+ fail:
+ dbg("Drops", "drops: receive()\n");;
+ stats.rx_drop++;
+ done:
+ return msg;
+ }
+
+
+ /*
+ * Send-side functionality
+ */
+
+ task void sendTask() {
+ send_entry_t *s_entry;
+ if (radioBusy || state != S_RUNNING) return;
+ if (call SendQueue.empty()) return;
+ // this does not dequeue
+ s_entry = call SendQueue.head();
+
+
+ call IEEE154Packet.setDestination(s_entry->msg,
+ s_entry->info->policy.dest[s_entry->info->policy.current]);
+ call PacketLink.setRetries(s_entry->msg, s_entry->info->policy.retries);
+ call PacketLink.setRetryDelay(s_entry->msg, s_entry->info->policy.delay);
+#ifdef LPL_SLEEP_INTERVAL
+ call LowPowerListening.setRxSleepInterval(s_entry->msg, LPL_SLEEP_INTERVAL);
+#endif
+
+ dbg("IPDispatch", "sendTask dest: 0x%x len: 0x%x \n", call IEEE154Packet.destination(s_entry->msg),
+ call Packet.payloadLength(s_entry->msg));
+
+ if (s_entry->info->failed) {
+ dbg("Drops", "drops: sendTask: dropping failed fragment\n");
+ goto fail;
+ }
+
+ if ((call IEEE154Send.send(call IEEE154Packet.destination(s_entry->msg),
+ s_entry->msg,
+ call Packet.payloadLength(s_entry->msg))) != SUCCESS) {
+ dbg("Drops", "drops: sendTask: send failed\n");
+ goto fail;
+ }
+ radioBusy = TRUE;
+ if (call SendQueue.empty()) return;
+ // this does not dequeue
+ s_entry = call SendQueue.head();
+
+ return;
+ fail:
+ post sendTask();
+ stats.tx_drop++;
+
+ // deallocate the memory associated with this request.
+ // other fragments associated with this packet will get dropped.
+ s_entry->info->failed = TRUE;
+ SENDINFO_DECR(s_entry->info);
+ call FragPool.put(s_entry->msg);
+ call SendEntryPool.put(s_entry);
+ call SendQueue.dequeue();
+ }
+
+
+ /*
+ * this interface is only for grownups; it is also only called for
+ * local sends.
+ *
+ * it will pack the message into the fragment pool and enqueue
+ * those fragments for sending
+ *
+ * it will set
+ * - payload length
+ * - version, traffic class and flow label
+ *
+ * the source and destination IP addresses must be set by higher
+ * layers.
+ */
+ command error_t IP.send[uint8_t prot](struct split_ip_msg *msg) {
+ uint16_t payload_length;
+
+ if (state != S_RUNNING) {
+ return EOFF;
+ }
+
+ if (msg->hdr.hlim != 0xff)
+ msg->hdr.hlim = call IPRouting.getHopLimit();
+
+ msg->hdr.nxt_hdr = prot;
+ ip_memclr(msg->hdr.vlfc, 4);
+ msg->hdr.vlfc[0] = IPV6_VERSION << 4;
+
+ call IPRouting.insertRoutingHeaders(msg);
+
+ payload_length = msg->data_len;
+
+ {
+ struct generic_header *cur = msg->headers;
+ while (cur != NULL) {
+ payload_length += cur->len;
+ cur = cur->next;
+ }
+ }
+
+ msg->hdr.plen = htons(payload_length);
+
+ // okay, so we ought to have a fully setup chain of headers here,
+ // so we ought to be able to compress everything into fragments.
+ //
+
+ {
+ send_info_t *s_info;
+ send_entry_t *s_entry;
+ uint8_t frag_len = 1;
+ message_t *outgoing;
+ fragment_t progress;
+ struct source_header *sh;
+ progress.offset = 0;
+
+ s_info = getSendInfo();
+ if (s_info == NULL) return ERETRY;
+
+ // fill in destination information on outgoing fragments.
+ sh = (msg->headers != NULL) ? (struct source_header *)msg->headers->hdr.ext : NULL;
+ if (call IPRouting.getNextHop(&msg->hdr, sh, 0x0,
+ &s_info->policy) != SUCCESS) {
+ dbg("Drops", "drops: IP send: getNextHop failed\n");
+ goto done;
+ }
+
+#ifdef DBG_TRACK_FLOWS
+ dbg_flowid++;
+#endif
+
+ //goto done;
+ while (frag_len > 0) {
+ s_entry = call SendEntryPool.get();
+ outgoing = call FragPool.get();
+
+ if (s_entry == NULL || outgoing == NULL) {
+ if (s_entry != NULL)
+ call SendEntryPool.put(s_entry);
+ if (outgoing != NULL)
+ call FragPool.put(outgoing);
+ // this will cause any fragments we have already enqueued to
+ // be dropped by the send task.
+ s_info->failed = TRUE;
+ dbg("Drops", "drops: IP send: no fragments\n");
+ goto done;
+ }
+
+#ifdef DBG_TRACK_FLOWS
+ (call getFlowID(outgoing))->src = TOS_NODE_ID;
+ (call getFlowID(outgoing))->dst = ((uint16_t )msg->hdr.dst_addr[14]) << 8 |
+ (uint16_t)msg->hdr.dst_addr[15];
+ (call getFlowID(outgoing))->id = dbg_flowid;
+ (call getFlowID(outgoing))->seq = 0;
+ (call getFlowID(outgoing))->nxt_hdr = prot;
+#endif
+
+ frag_len = getNextFrag(msg, &progress,
+ call Packet.getPayload(outgoing, call Packet.maxPayloadLength()),
+ call Packet.maxPayloadLength());
+ if (frag_len == 0) {
+ call FragPool.put(outgoing);
+ call SendEntryPool.put(s_entry);
+ goto done;
+ }
+ call Packet.setPayloadLength(outgoing, frag_len);
+
+ s_entry->msg = outgoing;
+ s_entry->info = s_info;
+
+ if (call SendQueue.enqueue(s_entry) != SUCCESS) {
+ stats.encfail++;
+ dbg("Drops", "drops: IP send: enqueue failed\n");
+ goto done;
+ }
+
+ SENDINFO_INCR(s_info);
+ printfUART("enqueue len 0x%x dest: 0x%x retries: 0x%x delay: 0x%x\n",frag_len,
+ s_info->policy.dest, s_info->policy.retries, s_info->policy.delay);
+ }
+ done:
+ SENDINFO_DECR(s_info);
+ post sendTask();
+ return SUCCESS;
+
+ }
+ }
+
+ event void IEEE154Send.sendDone(message_t *msg, error_t error) {
+ send_entry_t *s_entry = call SendQueue.head();
+ CHECK_NODE_ID;
+
+ radioBusy = FALSE;
+
+ if (state == S_STOPPING) {
+ call RadioControl.stop();
+ state = S_STOPPED;
+ goto fail;
+ }
+
+
+ if (!call PacketLink.wasDelivered(msg)) {
+
+ // if we haven't sent out any fragments yet, we can try rerouting
+ if (s_entry->info->frags_sent == 0) {
+ // SDH : TODO : if sending a fragment fails, abandon the rest of
+ // the fragments
+ s_entry->info->policy.current++;
+ if (s_entry->info->policy.current < s_entry->info->policy.nchoices) {
+ // this is the retry case; we don't need to change anything.
+ post sendTask();
+ return;
+ }
+ // no more next hops to try, so free the buffers and move on
+ }
+ // a fragment failed, and it wasn't the first. we drop all
+ // remaining fragments.
+ goto fail;
+ } else {
+ // the fragment was successfully sent.
+ s_entry->info->frags_sent++;
+ goto done;
+ }
+ goto done;
+
+ fail:
+ s_entry->info->failed = TRUE;
+ if (s_entry->info->policy.dest[0] != 0xffff)
+ dbg("Drops", "drops: sendDone: frag was not delivered\n");
+
+ done:
+ s_entry->info->policy.actRetries = call PacketLink.getRetries(msg);
+ call IPRouting.reportTransmission(&s_entry->info->policy);
+ // kill off any pending fragments
+ SENDINFO_DECR(s_entry->info);
+ call FragPool.put(s_entry->msg);
+ call SendEntryPool.put(s_entry);
+ call SendQueue.dequeue();
+
+ post sendTask();
+ }
+
+
+
+ event void ICMP.solicitationDone() {
+
+ }
+
+ /*
+ * Statistics interface
+ */
+ command void Statistics.get(ip_statistics_t *statistics) {
+ stats.fragpool = call FragPool.size();
+ stats.sendinfo = call SendInfoPool.size();
+ stats.sendentry= call SendEntryPool.size();
+ stats.sndqueue = call SendQueue.size();
+ stats.heapfree = ip_malloc_freespace();
+ ip_memcpy(statistics, &stats, sizeof(ip_statistics_t));
+ }
+
+ command void Statistics.clear() {
+ ip_memclr((uint8_t *)&stats, sizeof(ip_statistics_t));
+ }
+
+ default event void IP.recv[uint8_t nxt_hdr](struct ip6_hdr *iph,
+ void *payload,
+ struct ip_metadata *meta) {
+ }
+}
--- /dev/null
+/*
+ * "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 "IPDispatch.h"
+#include "PrintfUART.h"
+
+module IPRoutingP {
+ provides interface IPRouting;
+ provides interface Statistics<route_statistics_t>;
+ uses interface ICMP;
+ uses interface Boot;
+ uses interface IPAddress;
+ uses interface Random;
+
+ uses interface Timer<TMilli> as SortTimer;
+
+ uses interface IP as TGenSend;
+ uses interface Timer<TMilli> as TrafficGenTimer;
+
+ uses interface Leds;
+
+} implementation {
+
+ enum {
+ SHORT_EPOCH = 0,
+ LONG_EPOCH = 1,
+ };
+
+ //uint16_t current_epoch;
+ //route_statistics_t stats;
+ uint16_t last_qual;
+ uint8_t last_hops;
+
+ uint8_t num_low_neigh;
+
+ bool soliciting;
+
+ // pointer into the neighbor table of the current entry that is our
+ // first choice.
+ struct neigh_entry *default_route;
+ uint16_t default_route_failures;
+
+ uint32_t traffic_interval;
+ bool traffic_sent;
+
+ struct neigh_entry neigh_table[N_NEIGH];
+
+ void printTable();
+ error_t freeFullPath(struct flow_path* path);
+ void updateFlowCounts(struct flow_entry *target);
+ void updateRankings();
+ void swapNodes(struct neigh_entry *highNode, struct neigh_entry *lowNode);
+ uint8_t checkThresh(uint32_t firstVal, uint32_t secondVal, uint16_t thresh);
+ void evictNeighbor(struct neigh_entry *neigh);
+ uint16_t getMetric(struct neigh_entry *neigh);
+
+ uint16_t adjustLQI(uint8_t val) {
+ uint16_t result = (80 - (val - 50));
+ result = (((result * result) >> 3) * result) >> 3; // result = (result ^ 3) / 64
+ dbg("Lqi", "adjustLqi in: 0x%x out: 0x%x\n", val, result);
+ return result;
+ }
+
+ void clearStats(struct neigh_entry *r) {
+ int j;
+ for (j = 0; j < N_EPOCHS; j++) {
+ r->stats[j].total = 0;
+ r->stats[j].success = 0;
+ r->stats[j].receptions = 0;
+ }
+ }
+
+ void clearEpoch(uint8_t target_epoch) {
+ int i;
+ for (i = 0; i < N_NEIGH; i++) {
+ neigh_table[i].stats[target_epoch].total = 0;
+ neigh_table[i].stats[target_epoch].success = 0;
+ neigh_table[i].stats[target_epoch].receptions = 0;
+ }
+ }
+
+ cmpr_ip6_addr_t shortenAddr(ip6_addr_t addr) {
+ cmpr_ip6_addr_t shortAddr;
+ ip_memcpy(&shortAddr, &addr[14],2);
+ return shortAddr;
+ }
+
+ void restartTrafficGen() {
+ traffic_interval = TGEN_BASE_TIME;
+ // jitter the period by 10% to prevent synchronization
+ traffic_interval += (call Random.rand16()) % (TGEN_BASE_TIME);
+ if (call TrafficGenTimer.isRunning())
+ call TrafficGenTimer.stop();
+
+ call TrafficGenTimer.startOneShot(traffic_interval);
+ }
+
+ event void TrafficGenTimer.fired() {
+ struct split_ip_msg *msg;
+ if (traffic_sent) goto done;
+ msg = (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg));
+ if (msg == NULL) goto done;
+
+ ip_memclr((uint8_t *)&msg->hdr, sizeof(struct ip6_hdr));
+ inet_pton6("ff05::1", &msg->hdr.ip6_dst);
+ call IPAddress.getIPAddr(&msg->hdr.ip6_src);
+ msg->data = NULL;
+ msg->data_len = 0;
+ msg->headers = NULL;
+
+ dbg("IPRouting", "Sending generated message\n");
+ call TGenSend.send(msg);
+ ip_free(msg);
+ done:
+ // restart timer
+ dbg("IPRouting", "Done checking for tgen\n");
+ traffic_sent = FALSE;
+ traffic_interval *= 2;
+ if (traffic_interval > TGEN_MAX_INTERVAL)
+ traffic_interval = TGEN_MAX_INTERVAL;
+ call TrafficGenTimer.startOneShot(traffic_interval);
+ }
+
+ event void TGenSend.recv(struct ip6_hdr *iph,
+ void *payload,
+ struct ip_metadata *meta) {
+
+ }
+
+ event void Boot.booted() {
+ int i;
+
+ for (i = 0; i < N_NEIGH; i++) {
+ neigh_table[i].flags = 0;
+ clearStats(&neigh_table[i]);
+ }
+
+ // current_epoch = 0;
+ soliciting = FALSE;
+ //reRouting = FALSE;
+ default_route_failures = 0;
+ default_route = &neigh_table[0];
+ // boot with this true so the router will invalidate any state
+ // associated from us when it gets the first packet.
+ last_qual = 0xffff;
+ last_hops = 0xff;
+ num_low_neigh = 0;
+ call Statistics.clear();
+ call SortTimer.startPeriodic(1024L * 60);
+
+ traffic_sent = FALSE;
+ restartTrafficGen();
+ }
+
+ command bool IPRouting.isForMe(struct ip6_hdr *hdr) {
+ // the destination prefix is either link-local or global, or
+ // multicast (we accept all multicast packets), and the suffix is
+ // me.
+ struct in6_addr *my_address = call IPAddress.getPublicAddr();
+ return (((cmpPfx(my_address->s6_addr, hdr->ip6_dst.s6_addr) ||
+ cmpPfx(linklocal_prefix, hdr->ip6_dst.s6_addr))
+ && cmpPfx(&my_address->s6_addr[8], &hdr->ip6_dst.s6_addr[8]))
+ || cmpPfx(multicast_prefix, hdr->ip6_dst.s6_addr));
+ }
+
+
+ struct neigh_entry *getNeighEntry(cmpr_ip6_addr_t a) {
+ int i;
+ for (i = 0; i < N_NEIGH; i++) {
+ if (neigh_table[i].neighbor == a)
+ return &(neigh_table[i]);
+ }
+ return NULL;
+ }
+
+
+ uint16_t getConfidence(struct neigh_entry *neigh) {
+ //uint8_t i;
+ uint16_t conf = 0;
+ if (neigh != NULL && IS_NEIGH_VALID(neigh)) {
+ //for (i = 0; i < N_EPOCHS_COUNTED; i++) {
+ //conf += neigh->stats[(current_epoch + N_EPOCHS - i) % N_EPOCHS].total;
+ //}
+ conf = neigh->stats[LONG_EPOCH].total;
+ }
+ return conf;
+ }
+
+ uint16_t getReceptions(struct neigh_entry *neigh) {
+ //uint8_t i;
+ uint16_t receptions = 0;
+ if ((neigh != NULL) && (IS_NEIGH_VALID(neigh))) {
+ //for (i = 0; i < N_EPOCHS_COUNTED; i++) {
+ //receptions += neigh->stats[(current_epoch + N_EPOCHS - i) % N_EPOCHS].receptions;
+ //}
+ receptions += neigh->stats[receptions].receptions;
+ }
+ return receptions;
+ }
+
+ uint16_t getSuccess(struct neigh_entry *neigh) {
+ //uint8_t i;
+ uint16_t succ = 0;
+ if ((neigh != NULL) && (IS_NEIGH_VALID(neigh))) {
+ //for (i = 0; i < N_EPOCHS_COUNTED; i++) {
+ //succ += neigh->stats[(current_epoch + N_EPOCHS - i) % N_EPOCHS].success;
+ //}
+ succ += neigh->stats[LONG_EPOCH].success;
+ }
+ return succ;
+ }
+
+ uint16_t getLinkCost(struct neigh_entry *neigh) {
+ uint16_t conf, succ;
+ conf = getConfidence(neigh);
+ succ = getSuccess(neigh);
+ // we can return a real confidence if we have enough data
+ if (succ == 0 || conf == 0) return 0xff;
+ return ((conf * 10) / succ);
+ }
+
+
+ void printTable() {
+#ifdef PRINTFUART_ENABLED
+ uint8_t i;
+#ifdef CENTRALIZED_ROUTING
+ uint8_t j, k;
+#endif
+ dbg("Table", "----------------------------------------___\n");
+ dbg("Table", "ind\tvalid\tmature\tneigh\thops\tconf\trecep\tcost\tetx\tlqi\tmetric\n");
+ for (i = 0; i < N_NEIGH; i++) {
+ if (&neigh_table[i] == default_route)
+ dbg("Table", "-- default --\n");
+ dbg("Table", "0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\n", i,
+ (neigh_table[i].flags & T_VALID_MASK), (IS_MATURE(&(neigh_table[i]))),
+ neigh_table[i].neighbor, neigh_table[i].hops, getConfidence(&(neigh_table[i])),
+ getReceptions(&(neigh_table[i])), neigh_table[i].costEstimate,
+ getLinkCost(&(neigh_table[i])), neigh_table[i].linkEstimate,
+ getMetric(&(neigh_table[i])));
+ }
+ dbg("Table", "----------------------------------------\n");
+#endif
+ }
+
+ uint16_t getMetric(struct neigh_entry *r) {
+ return (((r == NULL) || (!(IS_NEIGH_VALID(r)))) ?
+ 0xffff : (r->costEstimate + getLinkCost(r)));
+ }
+
+ // Selects a potential neighbor that is not the current default route
+ void chooseNewRandomDefault(bool force) {
+ uint8_t i;
+ uint8_t numNeigh = 0;
+ uint8_t chosenNeigh;
+
+ dbg("IPRouting", "Looking for a new default route\n");
+
+ for (i = 1; i < N_NEIGH; i++) {
+ if (!(IS_NEIGH_VALID(&(neigh_table[i])))) break;
+ if (&neigh_table[i] == default_route) continue;
+ if (neigh_table[i].hops < neigh_table[0].hops)
+ numNeigh++;
+ }
+
+ // There exist other neighbors with respectable hop counts
+ if (numNeigh) {
+ chosenNeigh = (call Random.rand16()) % numNeigh;
+ for (i = 1; i < N_NEIGH; i++) {
+ if (&neigh_table[i] == default_route) continue;
+ if (neigh_table[i].hops < neigh_table[0].hops) {
+ if (chosenNeigh) {
+ chosenNeigh--;
+ } else {
+ default_route = &neigh_table[i];
+ default_route_failures = 0;
+ return;
+ }
+ }
+ }
+ }
+
+ if (!force) goto done;
+
+ numNeigh = 0;
+ for (i = 1; i < N_NEIGH; i++) {
+ if (!(IS_NEIGH_VALID(&(neigh_table[i])))) break;
+ if (&neigh_table[i] == default_route) continue;
+ if (neigh_table[i].costEstimate < neigh_table[0].costEstimate)
+ numNeigh++;
+ }
+
+ if (numNeigh) {
+ chosenNeigh = (call Random.rand16()) % numNeigh;
+ for (i = 1; i < N_NEIGH; i++) {
+ if (&neigh_table[i] == default_route) continue;
+ //if (neigh_table[i].costEstimate < getMetric(&(neigh_table[0]))) {
+ if (neigh_table[i].costEstimate < neigh_table[0].costEstimate) {
+ if (chosenNeigh) {
+ chosenNeigh--;
+ } else {
+ default_route = &neigh_table[i];
+ default_route_failures = 0;
+ return;
+ }
+ }
+ }
+ }
+ done:
+ dbg("IPRouting", "No random route found\n");
+ default_route = &neigh_table[0];
+ default_route_failures = 0;
+ }
+ /*
+ * return: a send policy for a given attempt, including destination and one-hop neighbor.
+ * if no default route is available, returns FAIL unless the
+ * packet is destined to a link-local address, or a
+ * all-node/all-routers local multicast group.
+ *
+ */
+ command error_t IPRouting.getNextHop(struct ip6_hdr *hdr,
+ struct source_header *sh,
+ hw_addr_t prev_hop,
+ send_policy_t *ret) {
+
+ int i;
+ prev_hop = 0;
+ ret->retries = 10;
+ ret->delay = 30;
+ ret->current = 0;
+ ret->nchoices = 0;
+
+
+ // we only use the address in the source header if the record option is not used
+ // otherwise, we use normal routing.
+ if (hdr->nxt_hdr == NXTHDR_SOURCE &&
+ (sh->dispatch & IP_EXT_SOURCE_RECORD_MASK) != IP_EXT_SOURCE_RECORD &&
+ (sh->dispatch & IP_EXT_SOURCE_INVAL) != IP_EXT_SOURCE_INVAL) {
+ // if it's source routed, grab the next address out of the header.
+
+ // if (sh->current == sh->nentries) return FAIL;
+
+ ret->dest[0] = ntohs(sh->hops[sh->current]);
+ ret->nchoices = 1;
+
+ dbg("IPRouting", "source dispatch: 0x%x, next hop: 0x%x, current: 0x%x\n",
+ sh->dispatch, ntohs(sh->hops[sh->current]), sh->current);
+
+ } else if (hdr->ip6_dst.s6_addr16[0] == htons(0xff02)) {
+ //hdr->dst_addr[0] == 0xff && (hdr->dst_addr[1] & 0xf) == 0x2) {
+ // if it's multicast, for now, we send it to the local broadcast
+ ret->dest[0] = 0xffff;
+ ret->nchoices = 1;
+ ret->retries = 0;
+ ret->delay = 0;
+ return SUCCESS;
+ } else if (cmpPfx(hdr->ip6_dst.s6_addr, linklocal_prefix)) {
+ ret->dest[0] = ntohs(hdr->ip6_dst.s6_addr16[7]); // (hdr->dst_addr[14] << 8) | hdr->dst_addr[15];
+ ret->nchoices = 1;
+ return SUCCESS; // Currently only want one choice for broadcast
+ }
+ // if (getNeighEntry(ntohs(shortenAddr(hdr->dst_addr))) != NULL) {
+ // dbg("IPRouting", "Directly adding next hop of dest: 0x%x\n", ntohs(shortenAddr(hdr->dst_addr)));
+ // ret->dest[ret->nchoices++] = ntohs(shortenAddr(hdr->dst_addr));
+ // }
+
+
+ //dbg("IPRouting", "flags: 0x%x neigh: 0x%x\n", r->flags, r->neighbor);
+ if (IS_NEIGH_VALID(default_route) && prev_hop != default_route->neighbor) {
+ ret->dest[ret->nchoices++] = default_route->neighbor;
+ } else {
+ dbg("IPRouting", "Invalid default route... quitting\n");
+ return FAIL;
+ }
+ i = 0;
+ while (ret->nchoices < N_PARENT_CHOICES && i < N_NEIGH) {
+ if (IS_NEIGH_VALID(&neigh_table[i]) &&
+ &neigh_table[i] != default_route &&
+ neigh_table[i].neighbor != prev_hop) {
+ ret->dest[ret->nchoices++] = neigh_table[i].neighbor;
+ }
+ i++;
+ }
+
+ if (ret->nchoices == 0)
+ return FAIL;
+
+ dbg("IPRouting", "getNextHop: nchoices: 0x%x\n", ret->nchoices);
+
+ return SUCCESS;
+ }
+
+ command uint8_t IPRouting.getHopLimit() {
+ // advertise our best path to the root
+ if (IS_NEIGH_VALID(&(neigh_table[0])))// && IS_MATURE(&neigh_table[0]))
+ return neigh_table[0].hops + 1;
+ else return 0xf0;
+ }
+
+ command uint16_t IPRouting.getQuality() {
+ if (IS_NEIGH_VALID(&(neigh_table[0])))
+ return getMetric(&(neigh_table[0]));
+ else return 0xffff;
+ }
+
+
+ /*
+ * An advertisement was received from a neighboring node
+ *
+ * Processing steps:
+ * 1) First must check to see if the neighbor already exists in the table
+ * a) If so, we are just updating its information
+ * 2) If not in table, check to make sure that the lqi passes the low-filter bar.
+ * a) If not, return
+ * 3) If there is an empty space
+ * a) Insert it in the open space
+ * b) (Do we then want to move it up to where it belongs based on total path cost?)
+ * 4) If there is no open space
+ * a) If the last entry doesn't meet the confidence threshold (CONF_EVICT_THRESHOLD), do nothing
+ * b) Otherwise, replace last entry if:
+ * i) Advertised Path Cost difference is greater than PATH_COST_DIFF_THRESH
+ * ii) Advertised Path Cost difference is within PATH_COST_DIFF_THRESH,
+ * and Link estimate is lower by at least LQI_DIFF_THRESH
+ * 5) Make sure to update the receptions statistic
+ */
+ command void IPRouting.reportAdvertisement(hw_addr_t neigh, uint8_t hops,
+ uint8_t lqi, uint16_t cost) {
+ //int i, place = N_NEIGH;
+ //bool mustInsert = FALSE, exists = FALSE;
+ //uint8_t maxCost = 0;
+ //bool recount = FALSE;
+ struct neigh_entry *neigh_slot = NULL;
+ dbg("IPRouting", "report adv: 0x%x 0x%x 0x%x 0x%x\n", neigh, hops, lqi, cost);
+ dbg("IPRouting", "my Cost: 0x%x, num_low_neigh: 0x%x, N_LOW_NEIGH: 0x%x\n",
+ getMetric(&(neigh_table[0])), num_low_neigh, N_LOW_NEIGH);
+
+ // If neighbor does not exist in table
+ if ((neigh_slot = getNeighEntry(neigh)) == NULL) {
+ dbg("IPRouting", "Advertisement from new neighbor 0x%x!\n", neigh);
+ if (adjustLQI(lqi) > LQI_ADMIT_THRESH || cost == 0xffff) {
+ dbg("IPRouting", "Poor Link. Rejecting\n");
+ return;
+ }
+ // free spots in the table.
+ if(!(IS_NEIGH_VALID(&(neigh_table[N_NEIGH - 1])))) {
+
+ dbg("IPRouting", "Neighbor being inserted in empty slot: 0x%x\n", N_NEIGH - 1);
+ for (neigh_slot = &(neigh_table[N_NEIGH - 1]);
+ neigh_slot > &(neigh_table[0]); neigh_slot--) {
+ // we might go ahead of other neighbors if we haven't heard
+ // from them either and our cost is better.
+ if (IS_NEIGH_VALID(neigh_slot - 1) &&
+ getConfidence(neigh_slot - 1) == 0 &&
+ (((struct neigh_entry *)(neigh_slot - 1))->costEstimate > cost)) {
+ swapNodes((neigh_slot - 1), neigh_slot);
+ } else if (IS_NEIGH_VALID(neigh_slot - 1)) {
+ // if we didn't catch on the first check and the next
+ // highest guy in the table is valid, we'll just go at the
+ // end. If this never catches, the loop will terminate
+ // with neigh_slot == &neigh_table[0].
+ break;
+ }
+ }
+ ip_memclr((void *)neigh_slot, sizeof(struct neigh_entry));
+ } else {
+ // evict the bottom guy?
+ dbg("IPRouting", "No empty slots...looking to replace bottom entry\n");
+ //if (getConfidence(&(neigh_table[N_NEIGH - 1])) >= CONF_EVICT_THRESHOLD) {
+ if (IS_MATURE(&(neigh_table[N_NEIGH - 1])) ||
+ hops <= neigh_table[N_NEIGH - 1].hops) {
+ dbg("IPRouting", "Bottom entry evictable\n");
+ // we're a lot better,
+ if ((checkThresh(neigh_table[N_NEIGH - 1].costEstimate, cost,
+ PATH_COST_DIFF_THRESH) == BELOW_THRESH) ||
+ // or we're about equal and the link estimate is better
+ ((checkThresh(neigh_table[N_NEIGH - 1].costEstimate, cost,
+ PATH_COST_DIFF_THRESH) == WITHIN_THRESH) &&
+ (checkThresh(neigh_table[N_NEIGH - 1].linkEstimate, adjustLQI(lqi),
+ LQI_DIFF_THRESH) == BELOW_THRESH))) {
+ dbg("Evictions", "evict: bottom entry\n");
+
+ // use evict to correctly handle the case when we evict
+ // the default route.
+ evictNeighbor(&neigh_table[N_NEIGH - 1]);
+ neigh_slot = &(neigh_table[N_NEIGH - 1]);
+ }
+ }
+ }
+ } else {
+ if (cost == 0xffff) {
+ dbg("Evictions", "evict with cost 0xffff\n");
+ evictNeighbor(neigh_slot);
+ return;
+ }
+ // Do this to prevent double counting because of reportReception
+ neigh_slot->stats[SHORT_EPOCH].receptions--;
+ }
+
+ if (neigh_slot != NULL) {
+ SET_NEIGH_VALID(neigh_slot);
+ neigh_slot->neighbor = neigh;
+ neigh_slot->hops = hops;
+ neigh_slot->costEstimate = cost;
+ neigh_slot->linkEstimate = adjustLQI(lqi);
+ neigh_slot->stats[SHORT_EPOCH].receptions++;
+ dbg("IPRouting", "currentEpoch: 0x%x, Receptions in epoch: 0x%x, Total Receptions: 0x%x\n",
+ SHORT_EPOCH, neigh_slot->stats[SHORT_EPOCH].receptions, getReceptions(neigh_slot));
+ }
+ printTable();
+ }
+
+ /*
+ * Reports packet reception
+ *
+ * Updates the link estimate, as well as the number of receptions
+ */
+ command void IPRouting.reportReception(hw_addr_t neigh, uint8_t lqi) {
+ struct neigh_entry *e = getNeighEntry(neigh);
+ dbg("IPRouting", "Packet received from 0x%x lqi: %u\n", neigh, lqi);
+ //if (e == NULL) e = addNeighEntry(neigh);
+ if (e != NULL) {
+ e->linkEstimate = adjustLQI(lqi);
+ // e->stats[current_epoch].receptions++;
+ //if (e == &(neigh_table[0]))
+ //resetNeighLow();
+ //else if (getMetric(e) < getMetric(&(neigh_table[0]))) {
+ //sortFlowTable();
+ //resetNeighLow();
+ //}
+ }
+ }
+
+ // Updates success (and failure) statistics
+ // Also needs to reroute if the number of failures hits the threshold
+ command void IPRouting.reportTransmission(send_policy_t *policy) {
+ int i;
+ struct neigh_entry *e = NULL;
+
+ // If not a broadcast address:
+ // 1. If none of the provided addresses worked, then we should send out a solicitation
+ // 2. All the failed nodes should have their totals increased by the max number of retries
+ // 3. The successful node should update both its total and success by one
+ // 4. If the successful node meets one of the following two conditions, it should be moved up one spot:
+ // a) It has a lower path cost and higher confidence than the above entry
+ // b) It has a similar path cost and confidence above a threshold (CONF_PROM_THRESHOLD)
+ // 5. If we have had too many consecutive losses (MAX_CONSEC_FAILURES) toggle ReRouting
+ if (policy->dest[0] != HW_BROADCAST_ADDR) {
+ // stats.messages++;
+ dbg("IPRouting", "reportTransmission: current: 0x%x, nchoices: 0x%x, retries: 0x%x\n",
+ policy->current, policy->nchoices, policy->actRetries);
+
+ // update the failed neighbor statistics
+ for (i = 0; i < policy->current; i++) {
+ e = getNeighEntry(policy->dest[i]);
+ if (e != NULL) {
+ // SDH : presumably retries == actRetries
+ e->stats[SHORT_EPOCH].total += policy->retries;
+
+ if (e == default_route) {
+ default_route_failures++;
+ }
+
+ dbg("IPRouting", "reportTransmissions: 0x%x failed\n", e->neighbor);
+
+ // stats.transmissions += policy->retries;
+ }
+ }
+
+ if (default_route_failures > MAX_CONSEC_FAILURES) {
+ dbg("IPRouting", "Too many consecutive failures!\n");
+ chooseNewRandomDefault(TRUE);
+ }
+
+ // if we succeeded sending the packet, increment the success on that one.
+ e = getNeighEntry(policy->dest[policy->current]);
+ if ((policy->current < policy->nchoices) && e != NULL) {
+ e->stats[SHORT_EPOCH].success += 1;
+ e->stats[SHORT_EPOCH].total += policy->actRetries;
+
+ dbg("IPRouting", "Success: 0x%x, Total: 0x%x, ETX: 0x%x (addr 0x%x)\n",
+ getSuccess(e), getConfidence(e), getLinkCost(e), e->neighbor);
+ dbg("IPRouting", "Actual attempts was 0x%x\n", policy->actRetries);
+
+ if (e == default_route)
+ default_route_failures++;
+
+
+ if ((e != &(neigh_table[0])) &&
+ // we have higher confidence and lower cost
+ (((getConfidence(e) > CONF_PROM_THRESHOLD) && // getConfidence(e - 1)) &&
+ (checkThresh(getMetric(e), getMetric(e-1), PATH_COST_DIFF_THRESH) == BELOW_THRESH)) ||
+ // we have similar cost and sufficient confidenceIP
+ ((checkThresh(getMetric(e), getMetric(e-1), PATH_COST_DIFF_THRESH) == WITHIN_THRESH) &&
+ (getConfidence(e) > CONF_PROM_THRESHOLD)))) {
+
+ dbg("IPRouting", "Promoting node 0x%x over node 0x%x\n", e->neighbor, (e-1)->neighbor);
+ swapNodes((e - 1), e);
+ }
+
+ // stats.successes += 1;
+ // stats.transmissions += policy->actRetries;
+ } else {
+ dbg("IPRouting", "FAILURE!!!!!\n");
+ }
+ }
+ }
+
+ /*
+ * @returns TRUE if the routing engine has established a default route.
+ */
+ command bool IPRouting.hasRoute() {
+ return (IS_NEIGH_VALID(&(neigh_table[0])));
+ }
+
+ void insertSourceHeader(struct split_ip_msg *msg, struct flow_entry *entry) {
+ // these actually need to be static
+ static uint8_t source_buf[sizeof(struct source_header) + MAX_PATH_LENGTH * sizeof(uint16_t)];
+ static struct generic_header g_sh;
+ struct source_header *sh = (struct source_header *)source_buf;
+ uint8_t i;
+
+ sh->len = sizeof(struct source_header) + entry->entries[0].pathE->path_len * sizeof(uint16_t);
+ sh->current = 0;
+ sh->dispatch = IP_EXT_SOURCE_DISPATCH;
+ sh->nxt_hdr = msg->hdr.nxt_hdr;
+ msg->hdr.nxt_hdr = NXTHDR_SOURCE;
+ g_sh.hdr.ext = (struct ip6_ext *)sh;
+ g_sh.len = sh->len;
+ g_sh.next = msg->headers;
+ msg->headers = &g_sh;
+
+ dbg("Install", "Inserted source header with length 0x%x and next hop: 0x%x and dispatch 0x%x\n",
+ entry->entries[0].pathE->path_len, entry->entries[0].pathE->path[0], sh->dispatch);
+
+ for (i = 0; i < entry->entries[0].pathE->path_len; i++) {
+ sh->hops[i] = ntohs(entry->entries[0].pathE->path[i]);
+ }
+ }
+
+ uint8_t convertTo8(uint16_t target) {
+ if (target > 0xFF)
+ return 0xFF;
+ return target;
+ }
+
+#ifdef DBG_TRACK_FLOWS
+ command void IPRouting.clearFlows() {
+ int i, j;
+ for (i = 0; i < N_FLOW_ENT; i++) {
+ SET_INVALID_SLOT((&(flow_table[i])));
+ flow_table[i].count = N_FLOW_ENT;
+ for (j = 0; j < N_FLOW_CHOICES; j++) {
+ SET_INVALID_ENTRY(flow_table[i].entries[j]);
+ }
+ }
+
+ for (i = 0; i < N_FULL_PATH_ENTRIES; i++) {
+ full_path_entries[i].path_len = 0;
+ }
+ }
+#endif
+
+ /*
+ * Inserts all necessary routing headers for the packet
+ *
+ * If packet is going to the root, inserts a topology information
+ * collection header
+ *
+ * AT: Should move source-routing header insertion to another function
+ * to avoid unnecessary allocation of buffer space
+ */
+ command void IPRouting.insertRoutingHeaders(struct split_ip_msg *msg) {
+ // these actually need to be static
+ static uint8_t sh_buf[sizeof(struct topology_header) +
+ (sizeof(struct topology_entry) * N_NEIGH)];
+ static struct generic_header record_route;
+ struct topology_header *th = (struct topology_header *)sh_buf;
+ int i, j = 0;
+
+ // AT: We theoretically only want to attach this topology header if we're
+ // sending this message to a controller. Isn't it easier to just check
+ // to see if the dest address matches that of the sink?
+ // SDH: how do you know what the address of the sink is?
+ if (msg->hdr.nxt_hdr == IANA_UDP || msg->hdr.nxt_hdr == NXTHDR_UNKNOWN) {
+ traffic_sent = TRUE;
+
+ th->len = sizeof(struct topology_header);
+ // only add topology information directly behind actual payload
+ // headers.
+ // SDH : TODO : check that this will not fragment the packet...
+ // AT: Why do we care about the number of hops? Debugging purposes?
+ th->nxt_hdr = msg->hdr.nxt_hdr;
+
+ // For all these 16-bit values, we're only using 8 bit values
+ for (i = 0; i < N_NEIGH; i++) {
+ if (IS_NEIGH_VALID(&neigh_table[i]) && j < 4 &&
+ (IS_MATURE(&neigh_table[i]) || default_route == &neigh_table[i])) {
+ th->topo[j].etx = convertTo8(getLinkCost(&neigh_table[i]));
+ th->topo[j].conf = convertTo8(getConfidence(&neigh_table[i]));
+ th->topo[j].hwaddr = htons(neigh_table[i].neighbor);
+ j++;
+ th->len += sizeof(struct topology_entry);
+ dbg("Lqi", "link est: 0x%x hops: 0x%x\n",
+ neigh_table[i].linkEstimate, neigh_table[i].hops);
+ }
+ }
+
+ record_route.hdr.ext = (struct ip6_ext *)th;
+ record_route.len = th->len;
+ record_route.next = msg->headers;
+ if (j > 0) {
+ msg->hdr.nxt_hdr = NXTHDR_TOPO;
+ msg->headers = &record_route;
+ }
+ }
+
+ }
+
+ /*
+ * Sort timer will no longer be used only for sorting, but rather to expire an epoch and
+ * change entry statistics
+ */
+ event void SortTimer.fired() {
+ dbg("IPRouting", "Epoch ended!\n");
+ printTable();
+
+ if (!call IPRouting.hasRoute() && !soliciting) {
+ call ICMP.sendSolicitations();
+ soliciting = TRUE;
+ }
+
+ if (checkThresh(call IPRouting.getQuality(), last_qual, 5) != WITHIN_THRESH ||
+ last_hops != call IPRouting.getHopLimit()) {
+ call ICMP.sendAdvertisements();
+ last_qual = call IPRouting.getQuality();
+ last_hops = call IPRouting.getHopLimit();
+ }
+
+ updateRankings();
+
+ if (call Random.rand16() % 32 < 8) {
+ dbg("IPRouting", "Attemting exploration\n");
+ chooseNewRandomDefault(FALSE);
+ } else {
+ // default_route = &neigh_table[0];
+ default_route_failures = 0;
+ }
+ }
+
+
+ /*
+ * This is called when the ICMP engine finishes sending out router solicitations.
+ *
+ * We will keep sending solicitations so long as we have not
+ * established a default route.
+ *
+ */
+ event void ICMP.solicitationDone() {
+ //int i;
+
+ dbg("IPRouting", "done soliciting\n");
+
+ soliciting = FALSE;
+
+ if (!call IPRouting.hasRoute()) {
+ call ICMP.sendSolicitations();
+ soliciting = TRUE;
+ }
+ }
+
+ command void Statistics.get(route_statistics_t *statistics) {
+ //struct neigh_entry *p = getNeighEntry((getFlowEntry_Header(NULL))->entries[0].nextHop);
+ // struct neigh_entry *p = &(neigh_table[0]);
+ // stats.hop_limit = call IPRouting.getHopLimit();
+// if (p != NULL) {
+// ip_memcpy(&stats.parent, p, sizeof(struct neigh_entry));
+ // stats.parentmetric = getMetric(p);
+// }
+ statistics->hop_limit = call IPRouting.getHopLimit();
+ statistics->parent = (uint16_t) default_route->neighbor;
+ statistics->parent_metric = call IPRouting.getQuality();
+ statistics->parent_etx = getMetric(default_route);
+ }
+
+ command void Statistics.clear() {
+ // ip_memclr((uint8_t *)&stats, sizeof(route_statistics_t));
+ }
+
+ void evictNeighbor(struct neigh_entry *neigh) {
+ struct neigh_entry *iterator;
+ bool reset_default = FALSE;
+
+ dbg("IPRouting", "Evicting neighbor 0x%x\n", neigh->neighbor);
+ dbg("Evictions", "evict: 0x%x\n", neigh->neighbor);
+
+ SET_NEIGH_INVALID(neigh);
+
+ if (neigh == default_route) {
+ reset_default = TRUE;
+ }
+
+ ip_memclr((uint8_t *)(neigh), sizeof(struct neigh_entry));
+ for (iterator = neigh; iterator < &(neigh_table[N_NEIGH - 1]); iterator++) {
+ if (!IS_NEIGH_VALID(iterator + 1)) break;
+ swapNodes(iterator, iterator + 1);
+ }
+
+ if (reset_default) {
+ // send new topology updates quickly to let an edge router know
+ // that something happened.
+ restartTrafficGen();
+ default_route = &neigh_table[0];
+ default_route_failures = 0;
+ }
+
+ printTable();
+ }
+
+ // Typically called after an epoch change
+ void updateRankings() {
+ uint8_t i;
+ bool evicted = FALSE;
+
+ for (i = 0; i < N_NEIGH; i++) {
+ UNSET_EVICT(neigh_table[i]);
+ if (!IS_NEIGH_VALID(&neigh_table[i])) continue;
+ neigh_table[i].stats[LONG_EPOCH].total += neigh_table[i].stats[SHORT_EPOCH].total;
+ neigh_table[i].stats[LONG_EPOCH].receptions += neigh_table[i].stats[SHORT_EPOCH].receptions;
+ neigh_table[i].stats[LONG_EPOCH].success += neigh_table[i].stats[SHORT_EPOCH].success;
+
+ if (neigh_table[i].stats[LONG_EPOCH].total & (0xf000)) {
+ // if we're this big, the etx computation might overflow.
+ // Make it smaller by dividing top and bottom by 2.
+ neigh_table[i].stats[LONG_EPOCH].total >>= 1;
+ neigh_table[i].stats[LONG_EPOCH].success >>= 1;
+ }
+
+ if (neigh_table[i].stats[LONG_EPOCH].total > CONF_EVICT_THRESHOLD)
+ SET_MATURE(&neigh_table[i]);
+
+ if (IS_MATURE(&(neigh_table[i]))) {
+ uint16_t cost;
+ // if we didn't try the link, don't evict it
+ if (neigh_table[i].stats[SHORT_EPOCH].total == 0) goto done_iter;
+ if (neigh_table[i].stats[SHORT_EPOCH].success == 0) {
+ cost = 0xff;
+ } else {
+ cost = (10 * neigh_table[i].stats[SHORT_EPOCH].total) /
+ neigh_table[i].stats[SHORT_EPOCH].success;
+ }
+ if (cost > LINK_EVICT_THRESH) {
+ dbg("Evictions", "cost: 0x%x, slot %i\n", cost, i);
+ SET_EVICT(neigh_table[i]);
+ }
+ }
+ done_iter:
+ neigh_table[i].stats[SHORT_EPOCH].total = 0;
+ neigh_table[i].stats[SHORT_EPOCH].receptions = 0;
+ neigh_table[i].stats[SHORT_EPOCH].success = 0;
+ }
+ for (i = 0; i < N_NEIGH; i++) {
+ if (IS_NEIGH_VALID(&neigh_table[i]) &&
+ SHOULD_EVICT(neigh_table[i])) {
+#if 0
+ // SDH : because of the overflow bug, this was never being
+ // triggered. I'm not sure it's actually a good idea because
+ // it seems to increase path lengths for heavily used routes.
+ // Let's disable it for now.
+ dbg("Evictions", "performing evict: %i\n", i);
+ evictNeighbor(&neigh_table[i]);
+ i --;
+#endif
+ evicted = TRUE;
+ }
+ }
+ if (evicted)
+ call ICMP.sendSolicitations();
+ }
+
+ void swapNodes(struct neigh_entry *highNode, struct neigh_entry *lowNode) {
+ struct neigh_entry tempNode;
+ if (highNode == NULL || lowNode == NULL) return;
+ ip_memcpy(&tempNode, highNode, sizeof(struct neigh_entry));
+ ip_memcpy(highNode, lowNode, sizeof(struct neigh_entry));
+ ip_memcpy(lowNode, &tempNode, sizeof(struct neigh_entry));
+
+ if (highNode == default_route) default_route = lowNode;
+ else if (lowNode == default_route) default_route = highNode;
+ }
+
+ uint8_t checkThresh(uint32_t firstVal, uint32_t secondVal, uint16_t thresh) {
+ if (((firstVal > secondVal) && ((firstVal - secondVal) <= thresh)) ||
+ ((secondVal >= firstVal) && (secondVal - firstVal) <= thresh)) return WITHIN_THRESH;
+ if (((firstVal > secondVal) && ((firstVal - secondVal) > thresh))) return ABOVE_THRESH;
+ return BELOW_THRESH;
+ }
+}
--- /dev/null
+/*
+ * "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) 2005
+ * The President and Fellows of Harvard College.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY 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.
+ */
+
+/*
+ * Writes printf like output to the UART.
+ * This works only on the AVR and MSP430 Microcontrollers!
+ * <p>
+ * Note: For AVR we explicitly place the print statements in ROM; for
+ * MSP430 this is done by default! For AVR, if we don't place it
+ * explicitely in ROM, the statements will go in RAM, which will
+ * quickly cause a descent size program to run out of RAM. By default
+ * it doesn't disable the interupts; disabling the interupts when
+ * writing to the UART, slows down/makes the mote quite unresponsive,
+ * and can lead to problems! If you wish to disable all printfs to
+ * the UART, then comment the flag: <code>PRINTFUART_ENABLED</code>.
+
+ * <p> <pre>
+ * How to use:
+ * // (0) In your Makefile, define PRINTFUART_ENABLED
+ * CFLAGS += -DPRINTFUART_ENABLED
+ * // (1) Call printfUART_init() from your initialization function
+ * // to initialize the UART
+ * printfUART_init();
+ * // (2) Set your UART client to the correct baud rate. Look at
+ * // the comments in printfUART_init(), to figure out what
+ * // baud to use for your particular mote
+ *
+ * // (3) Send printf statements like this:
+ * printfUART("Hello World, we are in year= %u\n", 2004);
+ * printfUART("Printing uint32_t variable, value= %lu\n", 4294967295);
+ *
+ * Examples and caveats:
+ * // (1) - Must use curly braces in single section statements.
+ * (Look in the app.c to see why -- hint: it's a macro)
+ * if (x < 3)
+ * {printfUART("The value of x is %i\n", x);}
+ * // (2) - Otherwise it more or less works like regular printf
+ * printfUART("\nThe value of x=%u, and y=%u\n", x, y);
+ * </pre>
+ * <pre>URL: http://www.eecs.harvard.edu/~konrad/projects/motetrack</pre>
+ * @author Konrad Lorincz
+ * @version 2.0, January 5, 2005
+ */
+#ifndef PRINTFUART_H
+#define PRINTFUART_H
+#include <stdarg.h>
+#include <stdio.h>
+
+// -------------------------------------------------------------------
+#ifdef PRINTFUART_ENABLED
+ #define DEBUGBUF_SIZE 256
+ char debugbuf[DEBUGBUF_SIZE];
+ char debugbufROMtoRAM[DEBUGBUF_SIZE];
+
+ #if defined(PLATFORM_MICAZ) || defined(PLATFORM_MICA2) || defined(PLATFORM_MICA2DOT)
+ #define printfUART(__format...) { \
+ static const char strROM[] PROGMEM = __format; \
+ strcpy_P((char*) &debugbufROMtoRAM, (PGM_P) &strROM); \
+ sprintf(debugbuf, debugbufROMtoRAM); \
+ writedebug(); \
+ }
+ #else // assume MSP430 architecture (e.g. TelosA, TelosB, etc.)
+ #define printfUART(__format...) { \
+ sprintf(debugbuf, __format); \
+ writedebug(); \
+ }
+ #endif
+#else
+ #define printfUART(X, args...) dbg("printf", X, ## args)
+// #define printfUART(__format...) {}
+ void printfUART_init() {}
+#endif
+
+#define NOprintfUART(__format...)
+
+
+// -------------------------------------------------------------------
+#ifdef PRINTFUART_ENABLED
+
+/**
+ * Initialize the UART port. Call this from your startup routine.
+ */
+#define printfUART_init() {atomic printfUART_init_private();}
+void printfUART_init_private()
+{
+ #if defined(PLATFORM_MICAZ) || defined(PLATFORM_MICA2)
+ // 56K baud
+ outp(0,UBRR0H);
+ outp(15, UBRR0L); //set baud rate
+ outp((1<<U2X),UCSR0A); // Set UART double speed
+ outp(((1 << UCSZ1) | (1 << UCSZ0)) , UCSR0C); // Set frame format: 8 data-bits, 1 stop-bit
+ inp(UDR0);
+ outp((1 << TXEN) ,UCSR0B); // Enable uart reciever and transmitter
+
+ #else
+ #if defined(PLATFORM_MICA2DOT)
+ // 19.2K baud
+ outp(0,UBRR0H); // Set baudrate to 19.2 KBps
+ outp(12, UBRR0L);
+ outp(0,UCSR0A); // Disable U2X and MPCM
+ outp(((1 << UCSZ1) | (1 << UCSZ0)) , UCSR0C);
+ inp(UDR0);
+ outp((1 << TXEN) ,UCSR0B);
+
+ #else
+ #if defined(PLATFORM_IMOTE2)
+ //async command result_t UART.init() {
+
+ /***
+ need to configure the ST UART pins for the correct functionality
+
+ GPIO<46> = STDRXD = ALT2(in)
+ GPIO<47> = STDTXD = ALT1(out)
+ *********/
+ //atomic{
+
+ //configure the GPIO Alt functions and directions
+ _GPIO_setaltfn(46,2); // STD_RXD
+ _GPIO_setaltfn(47,1); // STD_TXD
+
+ _GPDR(46) &= ~_GPIO_bit(46); // input
+ _GPDR(47) |= _GPIO_bit(47); // output
+
+ STLCR |=LCR_DLAB; //turn on DLAB so we can change the divisor
+ STDLL = 8; //configure to 115200;
+ STDLH = 0;
+ STLCR &= ~(LCR_DLAB); //turn off DLAB
+
+ STLCR |= 0x3; //configure to 8 bits
+
+ STMCR &= ~MCR_LOOP;
+ STMCR |= MCR_OUT2;
+ STIER |= IER_RAVIE;
+ STIER |= IER_TIE;
+ STIER |= IER_UUE; //enable the UART
+
+ //STMCR |= MCR_AFE; //Auto flow control enabled;
+ //STMCR |= MCR_RTS;
+
+ STFCR |= FCR_TRFIFOE; //enable the fifos
+
+// call Interrupt.allocate();
+// call Interrupt.enable();
+ //configure all the interrupt stuff
+ //make sure that the interrupt causes an IRQ not an FIQ
+ // __REG(0x40D00008) &= ~(1<<21);
+ //configure the priority as IPR1
+ //__REG(0x40D00020) = (1<<31 | 21);
+ //unmask the interrupt
+ //__REG(0x40D00004) |= (1<<21);
+
+ CKEN |= CKEN5_STUART; //enable the UART's clk
+
+
+ #else // assume TelosA, TelosB, etc.
+ // Variabel baud
+ // To change the baud rate, see /tos/platform/msp430/msp430baudrates.h
+ uint8_t source = SSEL_SMCLK;
+ uint16_t baudrate = 0x0012; // UBR_SMCLK_57600=0x0012
+ uint8_t mctl = 0x84; // UMCTL_SMCLK_57600=0x84
+ //uint16_t baudrate = 0x0009; // UBR_SMCLK_115200=0x0009
+ //uint8_t mctl = 0x10; // UMCTL_SMCLK_115200=0x10
+
+
+ uint16_t l_br = 0;
+ uint8_t l_mctl = 0;
+ uint8_t l_ssel = 0;
+
+ TOSH_SEL_UTXD1_MODFUNC();
+ TOSH_SEL_URXD1_MODFUNC();
+
+
+ UCTL1 = SWRST;
+ UCTL1 |= CHAR; // 8-bit char, UART-mode
+
+ U1RCTL &= ~URXEIE; // even erroneous characters trigger interrupts
+
+ UCTL1 = SWRST;
+ UCTL1 |= CHAR; // 8-bit char, UART-mode
+
+ if (l_ssel & 0x80) {
+ U1TCTL &= ~(SSEL_0 | SSEL_1 | SSEL_2 | SSEL_3);
+ U1TCTL |= (l_ssel & 0x7F);
+ }
+ else {
+ U1TCTL &= ~(SSEL_0 | SSEL_1 | SSEL_2 | SSEL_3);
+ U1TCTL |= SSEL_ACLK; // use ACLK, assuming 32khz
+ }
+
+ if ((l_mctl != 0) || (l_br != 0)) {
+ U1BR0 = l_br & 0x0FF;
+ U1BR1 = (l_br >> 8) & 0x0FF;
+ U1MCTL = l_mctl;
+ }
+ else {
+ U1BR0 = 0x03; // 9600 baud
+ U1BR1 = 0x00;
+ U1MCTL = 0x4A;
+ }
+
+ ME2 &= ~USPIE1; // USART1 SPI module disable
+ ME2 |= (UTXE1 | URXE1); // USART1 UART module enable
+
+ U1CTL &= ~SWRST;
+
+ IFG2 &= ~(UTXIFG1 | URXIFG1);
+ IE2 &= ~(UTXIE1 | URXIE1); // interrupt disabled
+
+
+
+ //async command void USARTControl.setClockSource(uint8_t source) {
+ // atomic {
+ l_ssel = source | 0x80;
+ U1TCTL &= ~(SSEL_0 | SSEL_1 | SSEL_2 | SSEL_3);
+ U1TCTL |= (l_ssel & 0x7F);
+ // }
+ //}
+ //async command void USARTControl.setClockRate(uint16_t baudrate, uint8_t mctl) {
+ //atomic {
+ l_br = baudrate;
+ l_mctl = mctl;
+ U1BR0 = baudrate & 0x0FF;
+ U1BR1 = (baudrate >> 8) & 0x0FF;
+ U1MCTL = mctl;
+ //}
+ //}
+
+ //async command result_t USARTControl.enableRxIntr(){
+ //atomic {
+ IFG2 &= ~URXIFG1;
+ IE2 |= URXIE1;
+ //}
+ //return SUCCESS;
+ //}
+
+ //async command result_t USARTControl.enableTxIntr(){
+ //atomic {
+ IFG2 &= ~UTXIFG1;
+ IE2 |= UTXIE1;
+ //}
+ //return SUCCESS;
+ //}
+
+ #endif
+ #endif
+ #endif
+}
+
+#if defined(PLATFORM_MICAZ) || defined(PLATFORM_MICA2) || defined(PLATFORM_MICA2DOT)
+#else
+#if defined(PLATFORM_IMOTE2)
+#else // assume AVR architecture (e.g. TelosA, TelosB)
+ bool isTxIntrPending()
+ {
+ if (U1TCTL & TXEPT) {
+ return TRUE;
+ }
+ return FALSE;
+ }
+#endif
+#endif
+
+/**
+ * Outputs a char to the UART.
+ */
+void UARTPutChar(char c)
+{
+ if (c == '\n')
+ UARTPutChar('\r');
+
+
+ #if defined(PLATFORM_MICAZ) || defined(PLATFORM_MICA2) || defined(PLATFORM_MICA2DOT)
+ loop_until_bit_is_set(UCSR0A, UDRE);
+ outb(UDR0,c);
+
+ #else
+ #if defined(PLATFORM_IMOTE2)
+ STTHR = c;
+
+ #else // assume AVR architecture (e.g. TelosA, TelosB)
+ U1TXBUF = c;
+ while( !isTxIntrPending() )
+ continue;
+ #endif
+ #endif
+}
+
+/**
+ * Outputs the entire debugbuf to the UART, or until it encounters '\0'.
+ */
+void writedebug()
+{
+ uint16_t i = 0;
+
+ while (debugbuf[i] != '\0' && i < DEBUGBUF_SIZE)
+ UARTPutChar(debugbuf[i++]);
+}
+
+#endif // PRINTFUART_ENABLED
+// -------------------------------------------------------------------
+
+#if 0
+// --------------------------------------------------------------
+#define assertUART(x) if (!(x)) { __assertUART(__FILE__, __LINE__); }
+void __assertUART(const char* file, int line)
+{
+ printfUART("ASSERT FAILED: file= %s, lineNbr= %i\n", file, line);
+ // for some reason, CLR means on
+ TOSH_MAKE_RED_LED_OUTPUT();
+ TOSH_MAKE_YELLOW_LED_OUTPUT();
+ TOSH_MAKE_GREEN_LED_OUTPUT();
+ TOSH_CLR_RED_LED_PIN();
+ TOSH_CLR_YELLOW_LED_PIN();
+ TOSH_CLR_GREEN_LED_PIN();
+ exit(1);
+}
+// --------------------------------------------------------------
+#endif
+
+#endif // PRINTFUART_H
+
--- /dev/null
+
+configuration TcpC {
+ provides interface Tcp[uint8_t client];
+} implementation {
+
+ components MainC, IPDispatchC, TcpP, IPAddressC;
+ components new TimerMilliC();
+
+ Tcp = TcpP;
+
+ MainC -> TcpP.Init;
+ TcpP.Boot -> MainC;
+ TcpP.IP -> IPDispatchC.IP[IANA_TCP];
+
+ TcpP.Timer -> TimerMilliC;
+ TcpP.IPAddress -> IPAddressC;
+}
--- /dev/null
+
+#include <table.h>
+#include <ip.h>
+
+module TcpP {
+ provides interface Tcp[uint8_t client];
+ provides interface Init;
+ uses {
+ interface Boot;
+
+ interface IP;
+ interface Timer<TMilli>;
+ interface IPAddress;
+ }
+} implementation {
+
+ enum {
+ N_CLIENTS = uniqueCount("TCP_CLIENT"),
+ };
+
+#include <tcplib.h>
+ struct tcplib_sock socks[N_CLIENTS];
+
+ int find_client(struct tcplib_sock *conn) {
+ int i;
+ for (i = 0; i < N_CLIENTS; i++)
+ if (&socks[i] == conn) break;
+
+ return i;
+ }
+
+ void conn_d(struct tcplib_sock *sock, int error) {
+ int cid = find_client(sock);
+ if (cid < N_CLIENTS)
+ signal Tcp.connectDone[cid](error == 0);
+ }
+
+ void rx(struct tcplib_sock *sock, void *data, int len) {
+ int cid = find_client(sock);
+ if (cid < N_CLIENTS)
+ signal Tcp.recv[cid](data, len);
+ }
+
+ void cl(struct tcplib_sock *sock) {
+ tcplib_close(sock);
+ }
+
+ void cd(struct tcplib_sock *sock) {
+ int cid = find_client(sock);
+ tcplib_init_sock(sock);
+ if (cid < N_CLIENTS)
+ signal Tcp.closed[cid](0);
+ }
+
+ void init_ops(struct tcplib_sock *sock) {
+ sock->ops.connect_done = conn_d;
+ sock->ops.recvfrom = rx;
+ sock->ops.closed = cl;
+ sock->ops.close_done = cd;
+ }
+
+
+
+ void setSrcAddr(struct split_ip_msg *msg) {
+ if (msg->hdr.ip6_dst.s6_addr16[0] == htons(0xff02) ||
+ msg->hdr.ip6_dst.s6_addr16[0] == htons(0xfe80)) {
+// (msg->hdr.dst_addr[0] == 0xff && (msg->hdr.dst_addr[1] & 0xf) == 0x2) ||
+// (msg->hdr.dst_addr[0] == 0xfe && msg->hdr.dst_addr[2] == 0x80)) {
+ call IPAddress.getLLAddr(&msg->hdr.ip6_src);
+ } else {
+ call IPAddress.getIPAddr(&msg->hdr.ip6_src);
+ }
+ }
+
+ struct tcplib_sock socks[uniqueCount("TCP_CLIENT")];
+
+ struct tcplib_sock *tcplib_accept(struct tcplib_sock *conn,
+ struct sockaddr_in6 *from) {
+ void *rx_buf = NULL, *tx_buf = NULL;
+ int rx_buf_len, tx_buf_len;
+ int cid = find_client(conn);
+
+ printfUART("tcplib_accept: cid: %i\n", cid);
+
+ if (cid == N_CLIENTS) return NULL;
+ if (signal Tcp.accept[cid](from, &rx_buf, &rx_buf_len,
+ &tx_buf, &tx_buf_len)) {
+ if (rx_buf == NULL || tx_buf == NULL) return NULL;
+ conn->rx_buf = rx_buf;
+ conn->rx_buf_len = rx_buf_len;
+ conn->tx_buf = tx_buf;
+ conn->tx_buf_len = tx_buf_len;
+ init_ops(conn);
+ return conn;
+ }
+ return NULL;
+ }
+
+ void tcplib_send_out(struct split_ip_msg *msg, struct tcp_hdr *tcph) {
+ printfUART("tcp output\n");
+ setSrcAddr(msg);
+ tcph->chksum = htons(msg_cksum(msg, IANA_TCP));
+ call IP.send(msg);
+ }
+
+#include "circ.c"
+#include "tcplib.c"
+
+ command error_t Init.init() {
+ int i;
+ for (i = 0; i < uniqueCount("TCP_CLIENT"); i++) {
+ tcplib_init_sock(&socks[i]);
+ }
+ return SUCCESS;
+ }
+
+ event void Boot.booted() {
+ call Timer.startPeriodic(512);
+ }
+
+ event void Timer.fired() {
+ tcplib_timer_process();
+ }
+
+ event void IP.recv(struct ip6_hdr *iph,
+ void *payload,
+ struct ip_metadata *meta) {
+
+ printfUART("tcp packet received\n");
+ tcplib_process(iph, payload);
+ }
+
+
+ command error_t Tcp.bind[uint8_t client](uint16_t port) {
+ struct sockaddr_in6 addr;
+ ip_memclr(addr.sin6_addr.s6_addr, 16);
+ addr.sin6_port = htons(port);
+ tcplib_bind(&socks[client], &addr);
+ return SUCCESS;
+ }
+
+ command error_t Tcp.connect[uint8_t client](struct sockaddr_in6 *dest,
+ void *rx_buf, int rx_buf_len,
+ void *tx_buf, int tx_buf_len) {
+ socks[client].rx_buf;
+ socks[client].rx_buf_len = rx_buf_len;
+ socks[client].tx_buf = tx_buf;
+ socks[client].tx_buf_len = tx_buf_len;
+ tcplib_connect(&socks[client], dest);
+ }
+
+ command error_t Tcp.send[uint8_t client](void *payload, uint16_t len) {
+ tcplib_send(&socks[client], payload, len);
+ return SUCCESS;
+ }
+
+ command error_t Tcp.close[uint8_t client]() {
+ if (!tcplib_close(&socks[client]))
+ return SUCCESS;
+ return FAIL;
+ }
+
+ default event bool Tcp.accept[uint8_t cid](struct sockaddr_in6 *from,
+ void **rx_buf, int *rx_buf_len,
+ void **tx_buf, int *tx_buf_len) {
+ return FALSE;
+ }
+
+ default event void Tcp.connectDone[uint8_t cid](error_t e) {}
+ default event void Tcp.recv[uint8_t cid](void *payload, uint16_t len) { }
+ default event void Tcp.closed[uint8_t cid](error_t e) { }
+
+
+
+
+
+}
--- /dev/null
+
+
+generic configuration TcpSocketC() {
+ provides interface Tcp;
+} implementation {
+
+ components TcpC;
+
+ Tcp = TcpC.Tcp[unique("TCP_CLIENT")];
+
+}
--- /dev/null
+
+configuration UdpC {
+ provides interface UDP[uint8_t clnt];
+} implementation {
+
+ components MainC, IPDispatchC, UdpP, IPAddressC;
+ UDP = UdpP;
+
+ MainC -> UdpP.Init;
+ UdpP.IP -> IPDispatchC.IP[IANA_UDP];
+ UdpP.IPAddress -> IPAddressC;
+}
--- /dev/null
+
+#include <ip_malloc.h>
+#include <in_cksum.h>
+
+module UdpP {
+ provides interface UDP[uint8_t clnt];
+ provides interface Init;
+ uses interface IP;
+ uses interface IPAddress;
+} implementation {
+
+ enum {
+ N_CLIENTS = uniqueCount("UDP_CLIENT"),
+ };
+
+ uint16_t local_ports[N_CLIENTS];
+
+ enum {
+ LOCAL_PORT_START = 51024U,
+ LOCAL_PORT_STOP = 54999U,
+ };
+ uint16_t last_localport = LOCAL_PORT_START;
+
+ uint16_t alloc_lport(uint8_t clnt) {
+ int i, done = 0;
+ uint16_t compare = htons(last_localport);
+ last_localport = (last_localport < LOCAL_PORT_START) ? last_localport + 1 : LOCAL_PORT_START;
+ while (!done) {
+ done = 1;
+ for (i = 0; i < N_CLIENTS; i++) {
+ if (local_ports[i] == compare) {
+ last_localport = (last_localport < LOCAL_PORT_START) ? last_localport + 1 : LOCAL_PORT_START;
+ compare = htons(last_localport);
+ done = 0;
+ break;
+ }
+ }
+ }
+ return last_localport;
+ }
+
+ command error_t Init.init() {
+ ip_memclr((uint8_t *)local_ports, sizeof(uint16_t) * N_CLIENTS);
+ return SUCCESS;
+ }
+
+ void setSrcAddr(struct split_ip_msg *msg) {
+ if (msg->hdr.ip6_dst.s6_addr16[7] == htons(0xff02) ||
+ msg->hdr.ip6_dst.s6_addr16[7] == htons(0xfe80)) {
+ call IPAddress.getLLAddr(&msg->hdr.ip6_src);
+ } else {
+ call IPAddress.getIPAddr(&msg->hdr.ip6_src);
+ }
+ }
+
+
+ command error_t UDP.bind[uint8_t clnt](uint16_t port) {
+ int i;
+ port = htons(port);
+ for (i = 0; i < N_CLIENTS; i++)
+ if (i != clnt && local_ports[i] == port)
+ return FAIL;
+ local_ports[clnt] = port;
+ return SUCCESS;
+ }
+
+
+ event void IP.recv(struct ip6_hdr *iph,
+ void *payload,
+ struct ip_metadata *meta) {
+ int i;
+ struct sockaddr_in6 addr;
+ struct udp_hdr *udph = (struct udp_hdr *)payload;
+
+ dbg("UDP", "UDP - IP.recv: len: %i srcport: %i dstport: %i\n",
+ ntohs(iph->plen), ntohs(udph->srcport), ntohs(udph->dstport));
+
+ for (i = 0; i < N_CLIENTS; i++)
+ if (local_ports[i] == udph->dstport)
+ break;
+
+ if (i == N_CLIENTS) {
+ // TODO : send ICMP port closed message here.
+ return;
+ }
+ ip_memcpy(&addr.sin6_addr, &iph->ip6_src, 16);
+ addr.sin6_port = udph->srcport;
+
+ signal UDP.recvfrom[i](&addr, (void *)(udph + 1), ntohs(iph->plen) - sizeof(struct udp_hdr), meta);
+ }
+
+ /*
+ * Injection point of IP datagrams. This is only called for packets
+ * being sent from this mote; packets which are being forwarded
+ * never lave the stack and so never use this entry point.
+ *
+ * @msg an IP datagram with header fields (except for length)
+ * @plen the length of the data payload added after the headers.
+ */
+ command error_t UDP.sendto[uint8_t clnt](struct sockaddr_in6 *dest, void *payload,
+ uint16_t len) {
+ struct split_ip_msg *msg;
+ struct udp_hdr *udp;
+ struct generic_header *g_udp;
+ error_t rc;
+
+ // todo check + alloc local port
+
+ msg = (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg) +
+ sizeof(struct udp_hdr) +
+ sizeof(struct generic_header));
+
+ if (msg == NULL) {
+ dbg("Drops", "drops: UDP send: malloc failure\n");
+ return ERETRY;
+ }
+ udp = (struct udp_hdr *)(msg + 1);
+ g_udp = (struct generic_header *)(udp + 1);
+
+ // fill in all the packet fields
+ ip_memclr((uint8_t *)&msg->hdr, sizeof(struct ip6_hdr));
+ ip_memclr((uint8_t *)udp, sizeof(struct udp_hdr));
+
+ setSrcAddr(msg);
+ memcpy(&msg->hdr.ip6_dst, dest->sin6_addr.s6_addr, 16);
+
+ if (local_ports[clnt] == 0 && alloc_lport(clnt) == 0) return FAIL;
+ udp->srcport = local_ports[clnt];
+ udp->dstport = dest->sin6_port;
+ udp->len = htons(len + sizeof(struct udp_hdr));
+ udp->chksum = 0;
+
+ // set up the pointers
+ g_udp->len = sizeof(struct udp_hdr);
+ g_udp->hdr.udp = udp;
+ g_udp->next = NULL;
+ msg->headers = g_udp;
+ msg->data_len = len;
+ msg->data = payload;
+
+ udp->chksum = htons(msg_cksum(msg, IANA_UDP));
+
+ rc = call IP.send(msg);
+
+ ip_free(msg);
+ return rc;
+
+ }
+
+ default event void UDP.recvfrom[uint8_t clnt](struct sockaddr_in6 *from, void *payload,
+ uint16_t len, struct ip_metadata *meta) {
+
+ }
+}
--- /dev/null
+
+generic configuration UdpSocketC() {
+ provides interface UDP;
+} implementation {
+
+ components UdpC;
+
+ UDP = UdpC.UDP[unique("UDP_CLIENT")];
+}
--- /dev/null
+/*
+ * "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."
+ *
+ */
+
+interface ICMP {
+
+ command uint16_t cksum(struct split_ip_msg *msg, uint8_t nxt_hdr);
+
+ // called to start sending router solicitations
+ command void sendSolicitations();
+
+ // called when we are done sending router solicitations
+ event void solicitationDone();
+
+ command void sendAdvertisements();
+
+ command void sendTimeExceeded(struct ip6_hdr *hdr, unpack_info_t *u_info, uint16_t amount_here);
+
+}
--- /dev/null
+
+#include <ICMP.h>
+
+interface ICMPPing {
+
+ command error_t ping(struct in6_addr *target, uint16_t period, uint16_t n);
+
+ event void pingReply(struct in6_addr *source, struct icmp_stats *stats);
+
+ event void pingDone(uint16_t ping_rcv, uint16_t ping_n);
+
+}
--- /dev/null
+
+interface IP {
+
+ /*
+ * sends the message with the headers and payload given. Things
+ * which we know how to compress should be part of the data passed
+ * in as headers; things which we cannot compress must be passed as
+ * payload.
+
+ * the interface is this way so that the stack may insert extra
+ * (routing, snooping) headers between the two sections.
+ * once the call returns, the stack has no claim on the buffer
+ * pointed to
+ */
+ command error_t send(struct split_ip_msg *msg);
+
+ /*
+ * indicate that the stack has finished writing data into the
+ * receive buffer.
+ */
+ event void recv(struct ip6_hdr *iph, void *payload, struct ip_metadata *meta);
+
+}
--- /dev/null
+/*
+ * "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 <6lowpan.h>
+
+interface IPAddress {
+ command hw_addr_t getShortAddr();
+ command void setShortAddr(hw_addr_t newaddr);
+
+ command struct in6_addr *getPublicAddr();
+ command void getLLAddr(struct in6_addr *addr);
+ command void getIPAddr(struct in6_addr *addr);
+
+ command void setPrefix(uint8_t *prefix);
+
+ command bool haveAddress();
+}
--- /dev/null
+/*
+ * "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."
+ *
+ */
+
+/*
+ * This interface presents the interface to the IP routing engine.
+ * Related interfaces are the forwarding engine, which implements
+ * the routing decision whare are communicated by this interface,
+ * and the ICMP interface, which deals with sending and receiving
+ * ICMP traffic.
+ *
+ */
+
+#include "IPDispatch.h"
+
+interface IPRouting {
+ /*
+ * returns weather or not the node should consume a packet addressed
+ * to a given address. Interprets link-local and global addresses,
+ * and manages multicast group membership.
+ */
+ command bool isForMe(struct ip6_hdr *a);
+
+ /*
+ * returns a policy for sending this message to someone else.
+ * the send policy includes the layer 2 address, number of retransmissions,
+ * and spacing between them.
+ *
+ */
+ command error_t getNextHop(struct ip6_hdr *hdr,
+ struct source_header *sh,
+ hw_addr_t prev_hop,
+ send_policy_t *ret);
+
+
+ /*
+ * returns the currently configured default IP hop limit.
+ *
+ */
+ command uint8_t getHopLimit();
+
+ command uint16_t getQuality();
+
+ /*
+ *
+ *
+ */
+ command void reportAdvertisement(hw_addr_t neigh, uint8_t hops,
+ uint8_t lqi, uint16_t cost);
+
+ /*
+ * informs the router of a reception from a neighbor, along with the
+ * the rssi of the received packet.
+ *
+ */
+ command void reportReception(hw_addr_t neigh, uint8_t lqi);
+
+ /*
+ * the result of sending to a neighbor.
+ */
+ command void reportTransmission(send_policy_t *send);
+
+ /*
+ * @returns TRUE if the routing engine has established a default route.
+ */
+ command bool hasRoute();
+
+ command void insertRoutingHeaders(struct split_ip_msg *msg);
+
+#ifdef CENTRALIZED_ROUTING
+ command error_t installFlowEntry(struct rinstall_header* rih, bool isMine);
+
+ command void clearFlows();
+#endif
+
+}
--- /dev/null
+/*
+ * "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."
+ *
+ */
+
+
+interface Statistics <stat_str> {
+
+ /*
+ * Fills the given structure with the requested statistics.
+ */
+ command void get(stat_str *stats);
+
+ /*
+ * Reset whatever statistics are being collected.
+ */
+ command void clear();
+
+}
--- /dev/null
+
+
+interface Tcp {
+
+ /*
+ * Bind the socket to a local address
+ */
+ command error_t bind(uint16_t port);
+
+ /*
+ * Accept an incomming connection.
+ */
+ event bool accept(struct sockaddr_in6 *from,
+ void **rx_buf, int *rx_buf_len,
+ void **tx_buf, int *tx_buf_len);
+
+ /*
+ * Split-phase connect: connect to a remote endpoint.
+ *
+ * The socket should not be used until connectDone is signaled.
+ */
+ command error_t connect(struct sockaddr_in6 *dest,
+ void *rx_buf, int rx_buf_len,
+ void *tx_buf, int tx_buf_len);
+ event void connectDone(error_t e);
+
+ /*
+ * Send and receive data on a socket. The socket must be CONNECTed
+ * for these to succeed.
+ */
+ command error_t send(void *payload, uint16_t len);
+
+ event void recv(void *payload, uint16_t len);
+
+ /*
+ * terminate a connection.
+ */
+ command error_t close();
+
+ /*
+ * notify the app that the socket connection has been closed or
+ * reset by the other end, or else a timeout has occured and the
+ * local side has given up.
+ */
+ event void closed(error_t e);
+}
--- /dev/null
+
+interface UDP {
+ /*
+ * bind a local address. to cut down memory requirements and handle the
+ * common case well, you can only bind a port; all local interfaces are
+ * implicitly bound. the port should be passed in host byte-order (is
+ * this confusing?
+ */
+
+ command error_t bind(uint16_t port);
+
+ /*
+ * send a payload to the socket address indicated
+ * once the call returns, the stack has no claim on the buffer pointed to
+ */
+ command error_t sendto(struct sockaddr_in6 *dest, void *payload,
+ uint16_t len);
+
+ /*
+ * indicate that the stack has finished writing data into the
+ * receive buffer. if error is not SUCCESS, the payload does not
+ * contain valid data and the src pointer should not be used.
+ */
+ event void recvfrom(struct sockaddr_in6 *src, void *payload,
+ uint16_t len, struct ip_metadata *meta);
+
+}
--- /dev/null
+
+interface BootImage {
+ command void reboot();
+ command error_t boot(uint8_t img_num);
+
+ // Added by Jaein Jeong
+ command error_t erase(uint8_t img_num);
+}
--- /dev/null
+/* Copyright (c) 2007 Johns Hopkins University.
+* 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 (updated) modification history and the author appear in
+* all copies of this source code.
+*
+* 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 HOLDERS OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+* OR PROFITS) 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.
+*/
+
+/**
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ */
+
+#ifndef __DELUGE_H__
+#define __DELUGE_H__
+
+typedef nx_struct DelugeIdent {
+ nx_uint32_t uidhash; // unique id of the image
+ nx_uint32_t size; // size of the whole image (ident + CRCs + binary)
+ nx_uint8_t numPgs; // number of pages of complete image
+ nx_uint8_t reserved;
+ nx_uint16_t crc; // crc over the above 4 fields
+ nx_uint8_t appname[16];
+ nx_uint8_t username[16];
+ nx_uint8_t hostname[16];
+ nx_uint8_t platform[16];
+ nx_uint32_t timestamp;
+ nx_uint32_t userhash;
+} DelugeIdent;
+
+typedef nx_struct DelugePatchCmd {
+ nx_uint16_t linenum; // sequence number of patches, starting from 0
+ nx_uint8_t cmd; // patch cmd: 16 for upload, 17 for copy
+ nx_uint16_t dst_offset;
+ nx_uint16_t data_length; // byte length of the data
+ nx_uint16_t src_offset;
+ nx_uint8_t reserved[7];
+ nx_uint8_t data[0]; // data for the upload command
+} DelugePatchCmd;
+
+enum {
+ DELUGE_INVALID_UID = 0xffffffff,
+ DELUGE_NUM_VOLUMES = 4,
+ DELUGE_IDENT_SIZE = 128,
+ DELUGE_MAX_PAGES = 128,
+ DELUGE_CRC_SIZE = sizeof(uint16_t),
+ DELUGE_CRC_BLOCK_SIZE = DELUGE_MAX_PAGES * DELUGE_CRC_SIZE,
+ DELUGE_BYTES_PER_PAGE = 23 * 48,
+};
+
+enum {
+ MAX_PATCH_DATA_SIZE = 512,
+ PATCH_LINE_SIZE = 16,
+};
+
+#define UQ_DELUGE_METADATA "DelugeMetadata.client"
+#define UQ_DELUGE_VOLUME_MANAGER "DelugeVolumeManager.client"
+#define UQ_DELUGE_VERIFY "DelugeVerify.client"
+#define UQ_DELUGE_PATCH "DelugePatch.client"
+#define UQ_DELUGE_READ_IDENT "DelugeReadIdent.client"
+
+typedef struct BootArgs {
+ uint16_t address;
+ uint32_t imageAddr;
+ uint8_t gestureCount;
+ bool noReprogram;
+} BootArgs;
+
+enum {
+ NWPROG_CMD_ERASE = 1,
+ NWPROG_CMD_WRITE = 2,
+};
+
+enum{
+ PATCH_CMD_UPLOAD = 16,
+ PATCH_CMD_COPY = 17,
+};
+
+typedef nx_struct prog_req {
+ nx_uint8_t cmd;
+ nx_uint8_t imgno;
+ nx_uint16_t offset;
+ nx_uint8_t data[0];
+} prog_req_t;
+
+typedef nx_struct prog_reply {
+ nx_uint8_t error;
+ nx_struct prog_req req;
+} prog_reply_t;
+
+#endif
--- /dev/null
+/**
+ * An interface for obtaining the identification data of an
+ * image. The pointer returned by readDone will be destroyed by the
+ * next read.
+ *
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+interface DelugePatch
+{
+ command error_t decodePatch(uint8_t imgNumPatch, uint8_t imgNumSrc, uint8_t imgNumDst);
+ event void decodePatchDone(uint8_t imgNumPatch, uint8_t imgNumSrc, uint8_t imgNumDst, error_t error);
+}
--- /dev/null
+/* Copyright (c) 2007 Johns Hopkins University.
+* 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 (updated) modification history and the author appear in
+* all copies of this source code.
+*
+* 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 HOLDERS OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+* OR PROFITS) 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.
+*/
+
+/**
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+configuration DelugePatchC
+{
+ provides interface DelugePatch[uint8_t client];
+ uses event void storageReady();
+}
+
+implementation
+{
+ components MainC;
+ components DelugePatchP;
+
+ DelugePatch = DelugePatchP;
+ storageReady = DelugePatchP;
+
+ components new BlockReaderC(VOLUME_GOLDENIMAGE) as BlockReaderGoldenImage;
+ components new BlockReaderC(VOLUME_DELUGE1) as BlockReaderDeluge1;
+ components new BlockReaderC(VOLUME_DELUGE2) as BlockReaderDeluge2;
+ components new BlockReaderC(VOLUME_DELUGE3) as BlockReaderDeluge3;
+
+ DelugePatchP.BlockRead[VOLUME_GOLDENIMAGE] -> BlockReaderGoldenImage;
+ DelugePatchP.BlockRead[VOLUME_DELUGE1] -> BlockReaderDeluge1;
+ DelugePatchP.BlockRead[VOLUME_DELUGE2] -> BlockReaderDeluge2;
+ DelugePatchP.BlockRead[VOLUME_DELUGE3] -> BlockReaderDeluge3;
+
+ components new BlockWriterC(VOLUME_GOLDENIMAGE) as BlockWriterGoldenImage;
+ components new BlockWriterC(VOLUME_DELUGE1) as BlockWriterDeluge1;
+ components new BlockWriterC(VOLUME_DELUGE2) as BlockWriterDeluge2;
+ components new BlockWriterC(VOLUME_DELUGE3) as BlockWriterDeluge3;
+
+ DelugePatchP.BlockWrite[VOLUME_GOLDENIMAGE] -> BlockWriterGoldenImage;
+ DelugePatchP.BlockWrite[VOLUME_DELUGE1] -> BlockWriterDeluge1;
+ DelugePatchP.BlockWrite[VOLUME_DELUGE2] -> BlockWriterDeluge2;
+ DelugePatchP.BlockWrite[VOLUME_DELUGE3] -> BlockWriterDeluge3;
+}
--- /dev/null
+/* Copyright (c) 2007 Johns Hopkins University.
+* 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 (updated) modification history and the author appear in
+* all copies of this source code.
+*
+* 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 HOLDERS OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+* OR PROFITS) 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.
+*/
+
+/**
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+generic configuration DelugePatchClientC()
+{
+ provides interface DelugePatch;
+}
+
+implementation
+{
+ enum {
+ CLIENT_ID = unique(UQ_DELUGE_PATCH)
+ };
+
+ components DelugePatchC;
+ DelugePatch = DelugePatchC.DelugePatch[CLIENT_ID];
+}
--- /dev/null
+/* Copyright (c) 2007 Johns Hopkins University.
+* 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 (updated) modification history and the author appear in
+* all copies of this source code.
+*
+* 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 HOLDERS OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+* OR PROFITS) 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.
+*/
+
+/**
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+#include "imgNum2volumeId.h"
+
+module DelugePatchP
+{
+ provides interface DelugePatch[uint8_t client];
+ uses {
+ interface BlockRead[uint8_t volumeId];
+ interface BlockWrite[uint8_t volumeId];
+ interface StorageMap[uint8_t volumeId];
+ event void storageReady();
+ }
+}
+
+implementation
+{
+ enum {
+ S_READ_IDENT,
+ S_READY,
+ S_BUSY,
+ S_READ_PATCH_CMD,
+ S_READ_PATCH_DATA,
+ S_READ_PATCH_COPY,
+ S_WRITE_PATCH,
+ };
+
+ DelugeIdent ident;
+ DelugePatchCmd patch;
+
+ uint8_t patchData[MAX_PATCH_DATA_SIZE];
+
+ uint8_t state;
+ uint8_t currentClient;
+
+ uint16_t patchNumLinesRead;
+ uint16_t patchNumLines;
+
+ uint32_t patchByteAddr;
+ uint8_t patchVolume;
+ uint8_t patchImageIdx;
+ uint8_t patchPage;
+
+ uint32_t dstByteAddr;
+ uint8_t srcVolume;
+ uint8_t srcImageIdx;
+ uint8_t srcPage;
+
+ uint32_t dstByteAddr;
+ uint8_t dstVolume;
+ uint8_t dstImageIdx;
+ uint8_t dstPage;
+
+
+ void setStorageReady()
+ {
+ signal storageReady();
+ state = S_READY;
+ }
+
+ void notifySuccess()
+ {
+ signal DelugePatch.decodePatchDone[currentClient](
+ patchImageIdx, srcImageIdx, dstImageIdx, SUCCESS);
+ setStorageReady();
+ }
+
+ void notifyFailure(error_t error)
+ {
+ signal DelugePatch.decodePatchDone[currentClient](
+ patchImageIdx, srcImageIdx, dstImageIdx, error);
+ setStorageReady();
+ }
+
+ command error_t DelugePatch.decodePatch[uint8_t client](uint8_t imgNumPatch,
+ uint8_t imgNumSrc,
+ uint8_t imgNumDst)
+ {
+ patchImageIdx = imgNumPatch;
+ patchVolume = _imgNum2volumeId[patchImageIdx];
+ srcImageIdx = imgNumSrc;
+ srcVolume = _imgNum2volumeId[srcImageIdx];
+ dstImageIdx = imgNumDst;
+ dstVolume = _imgNum2volumeId[dstImageIdx];
+
+ // First, read the DelugeIdent section.
+ if (patchImageIdx < DELUGE_NUM_VOLUMES) {
+ state = S_READ_IDENT;
+ call BlockRead.read[patchVolume](0, &ident, sizeof(ident));
+ } else {
+ signal storageReady();
+ state = S_READY;
+ }
+
+ return SUCCESS;
+ }
+
+ event void BlockRead.readDone[uint8_t imgNum](
+ storage_addr_t addr, void* buf, storage_len_t len, error_t error)
+ {
+ switch (state) {
+ case S_BUSY:
+ notifyFailure(error);
+ break;
+ // Read the DelugeIdent structure into ident.
+ // If it is valid, ident.userhash contains
+ // number of patch command lines.
+ // Initialize patchByteAddr to the beginning of
+ // the patch commands.
+ case S_READ_IDENT:
+ if (error == SUCCESS) {
+ if (ident.uidhash != DELUGE_INVALID_UID) {
+ patchNumLines = ident.userhash;
+ state = S_READ_PATCH_CMD;
+ patchByteAddr = DELUGE_IDENT_SIZE + DELUGE_CRC_BLOCK_SIZE;
+ call BlockRead.read[patchVolume](patchByteAddr, &patch, sizeof(patch));
+ break;
+ }
+ }
+ notifyFailure(error);
+ break;
+ // Read a patch command.
+ // If successful, check it is UPLOAD or COPY.
+ // For an UPLOAD commandy
+ // increment the number of patch lines read,
+ // increase patchByteAddr by PATCH_LINE_SIZE,
+ // and read the patch data.
+ // For a COPY command,
+ // increment the number of patch lines read,
+ // increase patchByteAddr by PATCH_LINE_SIZE,
+ // and read data from the source volume.
+ case S_READ_PATCH_CMD:
+ if (error == SUCCESS) {
+ if (patch.cmd == PATCH_CMD_UPLOAD) {
+ patchNumLinesRead++;
+ patchByteAddr += PATCH_LINE_SIZE; // read the next line of patch
+ state = S_READ_PATCH_DATA;
+ call BlockRead.read[patchVolume](patchByteAddr, patchData, patch.data_length);
+ break;
+ }
+ else if (patch.cmd == PATCH_CMD_COPY) {
+ patchNumLinesRead++;
+ patchByteAddr += PATCH_LINE_SIZE; // read the next line of patch
+ state = S_READ_PATCH_COPY;
+ call BlockRead.read[srcVolume](patch.src_offset, patchData, patch.data_length);
+ break;
+ }
+ }
+ notifyFailure(error);
+ break;
+ // When the patch data of PATCH_UPLOAD is ready,
+ // increase patchByteAddr ceiling(len / PATCH_LINE_SIZE) * PATCH_LINE_SIZE,
+ // and write it into the destination volume.
+ case S_READ_PATCH_DATA:
+ if (error == SUCCESS) {
+ state = S_WRITE_PATCH;
+ patchByteAddr += ((len + PATCH_LINE_SIZE - 1) / PATCH_LINE_SIZE * PATCH_LINE_SIZE);
+ call BlockWrite.write[dstVolume](patch.dst_offset, buf, len);
+ break;
+ }
+ notifyFailure(error);
+ break;
+ // When the source data of PATCH_COPY is ready,
+ // write it into the destination volume.
+ case S_READ_PATCH_COPY:
+ if (error == SUCCESS) {
+ state = S_WRITE_PATCH;
+ call BlockWrite.write[dstVolume](patch.dst_offset, buf, len);
+ break;
+ }
+ notifyFailure(error);
+ break;
+ }
+ }
+
+ event void BlockWrite.writeDone[uint8_t imgNum](
+ storage_addr_t addr, void* buf, storage_len_t len, error_t error)
+ {
+ switch (state) {
+ case S_WRITE_PATCH:
+ if (error == SUCCESS) {
+ // When more patch commands remaining, read the next one.
+ if (patchNumLinesRead < patchNumLines) {
+ state = S_READ_PATCH_CMD;
+ call BlockRead.read[patchVolume](patchByteAddr, &patch, sizeof(patch));
+ }
+ else {
+ notifySuccess();
+ }
+ break;
+ }
+ notifyFailure(error);
+ break;
+ }
+ }
+
+ event void BlockWrite.eraseDone[uint8_t imgNum](error_t error)
+ {
+ switch (state) {
+ case S_READY:
+ signal BlockWrite.eraseDone[imgNum](error);
+ break;
+ }
+ }
+
+ default command error_t BlockWrite.write[uint8_t imgNum](
+ storage_addr_t addr, void* buf, storage_len_t len) { return FAIL; }
+ default command error_t BlockRead.read[uint8_t imgNum](
+ storage_addr_t addr, void* buf, storage_len_t len) { return FAIL; }
+ default command error_t BlockRead.computeCrc[uint8_t imgNum](
+ storage_addr_t addr, storage_len_t len, uint16_t crc) { return FAIL; }
+ event void BlockRead.computeCrcDone[uint8_t imgNum](
+ storage_addr_t addr, storage_len_t len, uint16_t crc, error_t error) {}
+ event void BlockWrite.syncDone[uint8_t imgNum](error_t error) {}
+ default command error_t BlockWrite.erase[uint8_t imgNum]() { return FAIL; }
+ default event void storageReady() {}
+ default event void DelugePatch.decodePatchDone[uint8_t client](
+ uint8_t imgNumPatch, uint8_t imgNumSrc, uint8_t imgNumDst, error_t error) {}
+
+}
--- /dev/null
+/**
+ * An interface for obtaining the identification data of an
+ * image. The pointer returned by readDone will be destroyed by the
+ * next read.
+ *
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+interface DelugeReadIdent
+{
+ command error_t readNumVolumes();
+ command error_t readVolume(uint8_t imgNum);
+
+ event void readNumVolumesDone(uint8_t validVolumes, uint8_t volumeFields, error_t error);
+ event void readVolumeDone(uint8_t imgNum, DelugeIdent* ident, error_t error);
+
+ //command error_t read(uint8_t imgNum);
+ //event void readDone(uint8_t imgNum, DelugeIdent* ident, error_t error);
+}
--- /dev/null
+/* Copyright (c) 2007 Johns Hopkins University.
+* 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 (updated) modification history and the author appear in
+* all copies of this source code.
+*
+* 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 HOLDERS OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+* OR PROFITS) 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.
+*/
+
+/**
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+configuration DelugeReadIdentC
+{
+ provides interface DelugeReadIdent[uint8_t client];
+ uses event void storageReady();
+}
+
+implementation
+{
+ components MainC;
+ components DelugeReadIdentP;
+
+ DelugeReadIdent = DelugeReadIdentP;
+ storageReady = DelugeReadIdentP;
+ DelugeReadIdentP.Boot -> MainC;
+
+ components new BlockReaderC(VOLUME_GOLDENIMAGE) as BlockReaderGoldenImage;
+ components new BlockReaderC(VOLUME_DELUGE1) as BlockReaderDeluge1;
+ components new BlockReaderC(VOLUME_DELUGE2) as BlockReaderDeluge2;
+ components new BlockReaderC(VOLUME_DELUGE3) as BlockReaderDeluge3;
+
+ DelugeReadIdentP.BlockRead[VOLUME_GOLDENIMAGE] -> BlockReaderGoldenImage;
+ DelugeReadIdentP.BlockRead[VOLUME_DELUGE1] -> BlockReaderDeluge1;
+ DelugeReadIdentP.BlockRead[VOLUME_DELUGE2] -> BlockReaderDeluge2;
+ DelugeReadIdentP.BlockRead[VOLUME_DELUGE3] -> BlockReaderDeluge3;
+}
--- /dev/null
+/* Copyright (c) 2007 Johns Hopkins University.
+* 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 (updated) modification history and the author appear in
+* all copies of this source code.
+*
+* 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 HOLDERS OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+* OR PROFITS) 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.
+*/
+
+/**
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+generic configuration DelugeReadIdentClientC()
+{
+ provides interface DelugeReadIdent;
+}
+
+implementation
+{
+ enum {
+ CLIENT_ID = unique(UQ_DELUGE_READ_IDENT)
+ };
+
+ components DelugeReadIdentC;
+ DelugeReadIdent = DelugeReadIdentC.DelugeReadIdent[CLIENT_ID];
+}
--- /dev/null
+/* Copyright (c) 2007 Johns Hopkins University.
+* 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 (updated) modification history and the author appear in
+* all copies of this source code.
+*
+* 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 HOLDERS OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+* OR PROFITS) 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.
+*/
+
+/**
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+#include "imgNum2volumeId.h"
+
+module DelugeReadIdentP
+{
+ provides interface DelugeReadIdent[uint8_t client];
+ uses {
+ interface Boot;
+ interface BlockRead[uint8_t volumeId];
+ interface StorageMap[uint8_t volumeId];
+ event void storageReady();
+ }
+}
+
+implementation
+{
+ enum {
+ S_READY,
+ S_READ_VOLUME,
+ S_READ_NUM_VOLUMES,
+ };
+
+ DelugeIdent ident;
+ uint8_t state;
+ uint8_t currentClient;
+ uint8_t currentIdx;
+ uint8_t currentVolume;
+ uint8_t fields;
+ uint8_t validVolumes;
+
+ event void Boot.booted() { }
+
+ command error_t DelugeReadIdent.readVolume[uint8_t client](uint8_t imgNum)
+ {
+ if (state != S_READY) {
+ return FAIL;
+ }
+ else {
+ currentClient = client;
+ currentIdx = imgNum;
+ currentVolume = _imgNum2volumeId[currentIdx];
+ if (imgNum < DELUGE_NUM_VOLUMES) {
+ state = S_READ_VOLUME;
+ return call BlockRead.read[currentVolume](0, &ident, sizeof(ident));
+ }
+ else {
+ return FAIL;
+ }
+ }
+ }
+
+ command error_t DelugeReadIdent.readNumVolumes[uint8_t client]()
+ {
+ if (state != S_READY) {
+ return FAIL;
+ }
+ else {
+ fields = 0;
+ validVolumes = 0;
+ currentClient = client;
+ currentIdx = 0;
+ currentVolume = _imgNum2volumeId[currentIdx];
+ state = S_READ_NUM_VOLUMES;
+ return call BlockRead.read[currentVolume](0, &ident, sizeof(ident));
+ }
+ }
+
+
+ event void BlockRead.readDone[uint8_t imgNum](
+ storage_addr_t addr, void* buf, storage_len_t len, error_t error)
+ {
+ switch (state) {
+ case S_READ_VOLUME:
+ if (error == SUCCESS && ident.uidhash != DELUGE_INVALID_UID) {
+ signal DelugeReadIdent.readVolumeDone[currentClient](currentIdx, buf, SUCCESS);
+ }
+ else {
+ signal DelugeReadIdent.readVolumeDone[currentClient](currentIdx, buf, FAIL);
+ }
+ state = S_READY;
+ signal storageReady();
+ break;
+ case S_READ_NUM_VOLUMES:
+ if (error == SUCCESS && ident.uidhash != DELUGE_INVALID_UID) {
+ // Increment valid volumes only when uidhash is valid.
+ fields |= (1 << currentIdx);
+ validVolumes++;
+ }
+
+ // Increment the number volumes read.
+ currentIdx++;
+ currentVolume = _imgNum2volumeId[currentIdx];
+
+ // Read the next volume when it didn't reach the end.
+ if (currentIdx < DELUGE_NUM_VOLUMES) {
+ call BlockRead.read[currentVolume](0, &ident, sizeof(ident));
+ }
+ // Otherwise, notify the success.
+ else {
+ state = S_READY;
+ signal storageReady();
+ signal DelugeReadIdent.readNumVolumesDone[currentClient](
+ validVolumes, fields, SUCCESS);
+ }
+ break;
+ }
+ }
+
+ event void BlockRead.computeCrcDone[uint8_t imgNum](
+ storage_addr_t addr, storage_len_t len, uint16_t crc, error_t error) {}
+ default command error_t BlockRead.read[uint8_t imgNum](
+ storage_addr_t addr, void* buf, storage_len_t len) { return FAIL; }
+ default command error_t BlockRead.computeCrc[uint8_t imgNum](
+ storage_addr_t addr, storage_len_t len, uint16_t crc) { return FAIL; }
+ default event void storageReady() {}
+ default event void DelugeReadIdent.readNumVolumesDone[uint8_t client](
+ uint8_t validVols, uint8_t volumeFields, error_t error) {}
+ default event void DelugeReadIdent.readVolumeDone[uint8_t client](
+ uint8_t imgNum, DelugeIdent* id, error_t error) {}
+
+}
+
--- /dev/null
+/**
+ * An interface for obtaining the identification data of an
+ * image. The pointer returned by readDone will be destroyed by the
+ * next read.
+ *
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+interface DelugeVerify
+{
+ command error_t verifyImg(uint8_t imgNum);
+ event void verifyImgDone(uint8_t imgNum, error_t error);
+}
--- /dev/null
+/* Copyright (c) 2007 Johns Hopkins University.
+* 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 (updated) modification history and the author appear in
+* all copies of this source code.
+*
+* 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 HOLDERS OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+* OR PROFITS) 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.
+*/
+
+/**
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+configuration DelugeVerifyC
+{
+ provides interface DelugeVerify[uint8_t client];
+ uses event void storageReady();
+}
+
+implementation
+{
+ components MainC;
+ components DelugeVerifyP;
+
+ DelugeVerify = DelugeVerifyP;
+ storageReady = DelugeVerifyP;
+
+ components new BlockReaderC(VOLUME_GOLDENIMAGE) as BlockReaderGoldenImage;
+ components new BlockReaderC(VOLUME_DELUGE1) as BlockReaderDeluge1;
+ components new BlockReaderC(VOLUME_DELUGE2) as BlockReaderDeluge2;
+ components new BlockReaderC(VOLUME_DELUGE3) as BlockReaderDeluge3;
+
+ DelugeVerifyP.BlockRead[VOLUME_GOLDENIMAGE] -> BlockReaderGoldenImage;
+ DelugeVerifyP.BlockRead[VOLUME_DELUGE1] -> BlockReaderDeluge1;
+ DelugeVerifyP.BlockRead[VOLUME_DELUGE2] -> BlockReaderDeluge2;
+ DelugeVerifyP.BlockRead[VOLUME_DELUGE3] -> BlockReaderDeluge3;
+
+ components new BlockWriterC(VOLUME_GOLDENIMAGE) as BlockWriterGoldenImage;
+ components new BlockWriterC(VOLUME_DELUGE1) as BlockWriterDeluge1;
+ components new BlockWriterC(VOLUME_DELUGE2) as BlockWriterDeluge2;
+ components new BlockWriterC(VOLUME_DELUGE3) as BlockWriterDeluge3;
+
+ DelugeVerifyP.BlockWrite[VOLUME_GOLDENIMAGE] -> BlockWriterGoldenImage;
+ DelugeVerifyP.BlockWrite[VOLUME_DELUGE1] -> BlockWriterDeluge1;
+ DelugeVerifyP.BlockWrite[VOLUME_DELUGE2] -> BlockWriterDeluge2;
+ DelugeVerifyP.BlockWrite[VOLUME_DELUGE3] -> BlockWriterDeluge3;
+}
--- /dev/null
+/* Copyright (c) 2007 Johns Hopkins University.
+* 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 (updated) modification history and the author appear in
+* all copies of this source code.
+*
+* 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 HOLDERS OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+* OR PROFITS) 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.
+*/
+
+/**
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+generic configuration DelugeVerifyClientC()
+{
+ provides interface DelugeVerify;
+}
+
+implementation
+{
+ enum {
+ CLIENT_ID = unique(UQ_DELUGE_VERIFY)
+ };
+
+ components DelugeVerifyC;
+ DelugeVerify = DelugeVerifyC.DelugeVerify[CLIENT_ID];
+}
--- /dev/null
+/* Copyright (c) 2007 Johns Hopkins University.
+* 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 (updated) modification history and the author appear in
+* all copies of this source code.
+*
+* 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 HOLDERS OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+* OR PROFITS) 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.
+*/
+
+/**
+ * @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+#include "imgNum2volumeId.h"
+
+module DelugeVerifyP
+{
+ provides interface DelugeVerify[uint8_t client];
+ uses {
+ interface BlockRead[uint8_t volumeId];
+ interface BlockWrite[uint8_t volumeId];
+ interface StorageMap[uint8_t volumeId];
+ event void storageReady();
+ }
+}
+
+implementation
+{
+ enum {
+ S_READ_IDENT,
+ S_READ_CRC,
+ S_CRC,
+ S_READY,
+ S_BUSY,
+ };
+
+ DelugeIdent ident;
+ uint8_t state;
+ uint8_t currentVolume;
+ uint8_t currentImageIdx;
+ uint8_t currentPage;
+ nx_uint16_t currentCrc;
+ uint8_t currentClient;
+
+ void setStorageReady()
+ {
+ signal storageReady();
+ state = S_READY;
+ }
+
+ uint32_t calcCrcAddr()
+ {
+ return DELUGE_IDENT_SIZE + currentPage * sizeof(uint16_t);
+ }
+
+ uint32_t calcPageAddr()
+ {
+ return DELUGE_IDENT_SIZE + DELUGE_CRC_BLOCK_SIZE + currentPage * DELUGE_BYTES_PER_PAGE;
+ }
+
+ command error_t DelugeVerify.verifyImg[uint8_t client](uint8_t imgNum)
+ {
+ // We are going to verify the integrity of the specified image.
+ // We first read the ident to find the number of pages and
+ // then iterate over all of them, compute the CRC and
+ // check it against the corresponding value from the CRCs block.
+ state = S_READ_IDENT;
+ currentImageIdx = imgNum;
+ currentVolume = _imgNum2volumeId[currentImageIdx];
+
+ if (currentImageIdx < DELUGE_NUM_VOLUMES) {
+ state = S_READ_IDENT;
+ call BlockRead.read[currentVolume](0, &ident, sizeof(ident));
+ } else {
+ signal storageReady();
+ state = S_READY;
+ }
+
+ return SUCCESS;
+ }
+
+ event void BlockRead.readDone[uint8_t imgNum](storage_addr_t addr, void* buf, storage_len_t len, error_t error)
+ {
+ switch (state) {
+ case S_BUSY:
+ setStorageReady();
+ signal DelugeVerify.verifyImgDone[currentClient](imgNum, error);
+ break;
+ case S_READ_IDENT:
+ if (error == SUCCESS) {
+ if (ident.uidhash != DELUGE_INVALID_UID) {
+ currentPage = 0;
+ state = S_READ_CRC;
+ call BlockRead.read[currentVolume](calcCrcAddr(), ¤tCrc, sizeof(currentCrc));
+ break;
+ }
+ }
+ setStorageReady();
+ signal DelugeVerify.verifyImgDone[currentClient](imgNum, FAIL);
+ break;
+ case S_READ_CRC:
+ state = S_CRC;
+ call BlockRead.computeCrc[currentVolume](calcPageAddr(), DELUGE_BYTES_PER_PAGE, 0);
+ break;
+ }
+ }
+
+ event void BlockRead.computeCrcDone[uint8_t imgNum](storage_addr_t addr, storage_len_t len, uint16_t crc, error_t error)
+ {
+ switch (state) {
+ case S_CRC:
+ if (crc != currentCrc) {
+ setStorageReady();
+ signal DelugeVerify.verifyImgDone[currentClient](imgNum, FAIL);
+ } else {
+ currentPage++;
+ if (currentPage < ident.numPgs) {
+ state = S_READ_CRC;
+ call BlockRead.read[currentVolume](calcCrcAddr(), ¤tCrc, sizeof(currentCrc));
+ }
+ else {
+ setStorageReady();
+ signal DelugeVerify.verifyImgDone[currentClient](imgNum, error);
+ }
+ }
+ break;
+ }
+ }
+
+ default command error_t BlockRead.read[uint8_t imgNum](storage_addr_t addr, void* buf, storage_len_t len) { return FAIL; }
+ default command error_t BlockRead.computeCrc[uint8_t imgNum](storage_addr_t addr, storage_len_t len, uint16_t crc) { return FAIL; }
+
+ event void BlockWrite.writeDone[uint8_t imgNum](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {}
+ event void BlockWrite.eraseDone[uint8_t imgNum](error_t error)
+ {
+ switch (state) {
+ case S_READY:
+ signal BlockWrite.eraseDone[imgNum](error);
+ break;
+ }
+ }
+
+ event void BlockWrite.syncDone[uint8_t imgNum](error_t error) {}
+ default command error_t BlockWrite.erase[uint8_t imgNum]() { return FAIL; }
+ default event void storageReady() {}
+ default event void DelugeVerify.verifyImgDone[uint8_t client](uint8_t imgNum, error_t error) {}
+
+}
--- /dev/null
+
+#include "StorageVolumes.h"
+#include "Deluge.h"
+
+configuration NWProgC {
+ provides interface BootImage;
+} implementation {
+
+ // send and receive pages
+ components MainC, IPDispatchC;
+ components NetProgC, NWProgP;
+
+ BootImage = NWProgP;
+
+ components BlockStorageManagerC;
+ components new BlockStorageLockClientC();
+ components new BlockWriterC(VOLUME_GOLDENIMAGE) as BlockWriterDeluge0;
+ components new BlockWriterC(VOLUME_DELUGE1) as BlockWriterDeluge1;
+ components new BlockWriterC(VOLUME_DELUGE2) as BlockWriterDeluge2;
+ components new BlockWriterC(VOLUME_DELUGE3) as BlockWriterDeluge3;
+
+ NWProgP.Boot -> MainC;
+ NWProgP.NetProg -> NetProgC;
+ NWProgP.StorageMap -> BlockStorageManagerC;
+ NWProgP.Recv -> IPDispatchC.UDP[5213];
+ NWProgP.Resource -> BlockStorageLockClientC;
+
+ NWProgP.BlockWrite[VOLUME_GOLDENIMAGE] -> BlockWriterDeluge0;
+ NWProgP.BlockWrite[VOLUME_DELUGE1] -> BlockWriterDeluge1;
+ NWProgP.BlockWrite[VOLUME_DELUGE2] -> BlockWriterDeluge2;
+ NWProgP.BlockWrite[VOLUME_DELUGE3] -> BlockWriterDeluge3;
+
+ components new ShellCommandC("nwprog");
+ NWProgP.ShellCommand -> ShellCommandC;
+ components new TimerMilliC();
+ NWProgP.RebootTimer -> TimerMilliC;
+ components new DelugeMetadataClientC();
+ NWProgP.DelugeMetadata -> DelugeMetadataClientC;
+
+}
--- /dev/null
+
+#include <Storage.h>
+#include <Shell.h>
+#include "imgNum2volumeId.h"
+#include "Deluge.h"
+
+module NWProgP {
+ provides interface BootImage;
+ uses {
+ interface Boot;
+ interface UDP as Recv;
+ interface StorageMap[uint8_t imag_num];
+ interface NetProg;
+ interface BlockWrite[uint8_t img_num];
+ interface Resource;
+ interface ShellCommand;
+ interface DelugeMetadata;
+ interface Timer<TMilli> as RebootTimer;
+ event void storageReady();
+ }
+} implementation {
+
+ enum {
+ S_IDLE,
+ S_BUSY,
+ };
+ uint8_t state;
+ struct sockaddr_in6 endpoint;
+ prog_reply_t reply;
+
+ // Begin-added by Jaein Jeong
+ command error_t BootImage.erase(uint8_t img_num) {
+ error_t error = call BlockWrite.erase[img_num]();
+ return error;
+ }
+ // End-added
+
+ command void BootImage.reboot() {
+ call NetProg.reboot();
+ }
+
+ command error_t BootImage.boot(uint8_t img_num) {
+ return call NetProg.programImageAndReboot(call StorageMap.getPhysicalAddress[img_num](0));
+ }
+
+ event void Boot.booted() {
+ state = S_IDLE;
+ }
+
+ void sendDone(error_t error) {
+ reply.error = error;
+ call Recv.sendto(&endpoint, &reply, sizeof(prog_reply_t));
+ }
+
+ event void Recv.recvfrom(struct sockaddr_in6 *from,
+ void *payload, uint16_t len,
+ struct ip_metadata *meta) {
+ prog_req_t *req = (prog_req_t *)payload;
+ uint8_t imgNum = imgNum2volumeId(req->imgno);
+ error_t error = FAIL;
+ void *buffer;
+ // just copy the payload out and write it into flash
+ // we'll send the ack from the write done event.
+ if (state != S_IDLE) return;
+
+ memcpy(&endpoint, from, sizeof(struct sockaddr_in6));
+ memcpy(&reply.req, req, sizeof(prog_req_t));
+
+ if (!call Resource.isOwner()) {
+ error = call Resource.immediateRequest();
+ }
+ if (error == SUCCESS) {
+ switch (req->cmd) {
+ case NWPROG_CMD_ERASE:
+ error = call BlockWrite.erase[imgNum]();
+ break;
+ case NWPROG_CMD_WRITE:
+ len -= sizeof(prog_req_t);
+ buffer = ip_malloc(len);
+ if (buffer == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ memcpy(buffer, req->data, len);
+ error = call BlockWrite.write[imgNum](req->offset,
+ buffer,
+ len);
+ if (error != SUCCESS) ip_free(buffer);
+ break;
+ default:
+ error = FAIL;
+ }
+ }
+
+ if (error != SUCCESS) {
+ sendDone(error);
+ call Resource.release();
+ } else {
+ state = S_BUSY;
+ }
+ }
+
+ event void BlockWrite.writeDone[uint8_t img_num](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {
+ if (state != S_BUSY) return;
+ sendDone(error);
+ call Resource.release();
+ state = S_IDLE;
+ ip_free(buf);
+ }
+
+ event void BlockWrite.eraseDone[uint8_t img_num](error_t error) {
+ if (state != S_BUSY) return;
+ if (error == SUCCESS)
+ call BlockWrite.sync[img_num]();
+ else {
+ sendDone(error);
+ state = S_IDLE;
+ call Resource.release();
+ }
+ }
+
+ event void BlockWrite.syncDone[uint8_t img_num](error_t error) {
+ if (state != S_BUSY) return;
+ sendDone(error);
+ state = S_IDLE;
+ call Resource.release();
+ }
+
+ event void Resource.granted() {
+
+ }
+
+
+ /*
+ * Shell command implementation
+ */
+ char *nwprog_help_str = "nwprog [list | boot <imgno> [when] | reboot]\n";
+ uint8_t nwprog_currentvol, nwprog_validvols;
+ uint8_t boot_image;
+
+ uint8_t volumeID2imgNum(uint8_t volumeID) {
+ switch(volumeID) {
+ case VOLUME_GOLDENIMAGE: return 0;
+ case VOLUME_DELUGE1: return 1;
+ case VOLUME_DELUGE2: return 2;
+ case VOLUME_DELUGE3: return 3;
+ }
+ }
+ event void DelugeMetadata.readDone(uint8_t imgNum, DelugeIdent* ident, error_t error) {
+ int len;
+ char *reply_buf = call ShellCommand.getBuffer(MAX_REPLY_LEN);
+ if (error == SUCCESS) {
+ if (ident->uidhash != DELUGE_INVALID_UID) {
+ len = snprintf(reply_buf, MAX_REPLY_LEN,
+ "image: %i\n\t[size: %li]\n\t[app: %s]\n\t[user: %s]\n\t[host: %s]\n\t[arch: %s]\n\t[time: 0x%lx]\n",
+ volumeID2imgNum(imgNum), ident->size, (char *)ident->appname, (char *) ident->username,
+ (char *)ident->hostname, (char *)ident->platform, (uint32_t)ident->timestamp);
+ nwprog_validvols++;
+ call ShellCommand.write(reply_buf, len);
+ }
+
+ }
+ if (++nwprog_currentvol < DELUGE_NUM_VOLUMES) {
+ call DelugeMetadata.read(imgNum2volumeId(nwprog_currentvol));
+ } else {
+ len = snprintf(reply_buf, MAX_REPLY_LEN,
+ "%i valid image(s)\n", nwprog_validvols);
+ call ShellCommand.write(reply_buf, len);
+ }
+ }
+
+ event void RebootTimer.fired() {
+ call BootImage.boot(boot_image);
+ }
+
+
+ event char *ShellCommand.eval(int argc, char **argv) {
+ if (argc >= 2) {
+ if (memcmp(argv[1], "list", 4) == 0) {
+ nwprog_currentvol = 0;
+ nwprog_validvols = 0;
+ call DelugeMetadata.read(imgNum2volumeId(nwprog_currentvol));
+ return NULL;
+ } else if (memcmp(argv[1], "boot", 4) == 0 && (argc == 3 || argc == 4)) {
+ uint32_t when = 15;
+ boot_image = atoi(argv[2]),
+ boot_image = imgNum2volumeId(boot_image);
+ if (argc == 4)
+ when = atoi(argv[3]);
+ if (when == 0)
+ call RebootTimer.stop();
+ else {
+ char *ack = call ShellCommand.getBuffer(15);
+ snprintf(ack, 15, "REBOOT %li\n", when);
+ call RebootTimer.startOneShot(when);
+ return ack;
+ }
+ return NULL;
+ } else if (memcmp(argv[1], "reboot", 6) == 0) {
+ call BootImage.reboot();
+ } else if (memcmp(argv[1], "erase", 5) == 0 && argc == 3) {
+ uint8_t img = atoi(argv[2]);
+ img = imgNum2volumeId(img);
+
+ return NULL;
+ }
+ }
+ return nwprog_help_str;
+ }
+
+ default command error_t BlockWrite.write[uint8_t imgNum](storage_addr_t addr, void* buf, storage_len_t len) { return FAIL; }
+ default command error_t BlockWrite.erase[uint8_t imgNum]() { return FAIL; }
+ default command error_t BlockWrite.sync[uint8_t imgNum]() { return FAIL; }
+
+}
--- /dev/null
+/*
+ * "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 _SERIALDEVCONF_H_
+#define _SERIALDEVCONF_H_
+
+enum {
+ TOS_SERIAL_DEVCONF = 3,
+};
+
+#endif
--- /dev/null
+/*
+ * "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."
+ *
+ */
+//$Id$
+
+/* "Copyright (c) 2000-2005 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 communication 802.15.4 message_t packets over the
+ * serial port.
+ *
+ * @author Philip Levis
+ * @author Ben Greenstein
+ * @date August 7 2005
+ *
+ */
+
+#include "SerialDevConf.h"
+configuration SerialDevConfC {
+ provides {
+ interface Send;
+ interface Receive;
+ }
+ uses interface Leds;
+}
+implementation {
+ components SerialPacketInfoDevConfP as Info, SerialDispatcherC;
+
+ Leds = SerialDispatcherC;
+ Send = SerialDispatcherC.Send[TOS_SERIAL_DEVCONF];
+ Receive = SerialDispatcherC.Receive[TOS_SERIAL_DEVCONF];
+ SerialDispatcherC.SerialPacketInfo[TOS_SERIAL_DEVCONF] -> Info;
+}
--- /dev/null
+/*
+ * "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) 2000-2005 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."
+ */
+
+module SerialPacketInfoDevConfP {
+ provides interface SerialPacketInfo as Info;
+}
+implementation {
+ async command uint8_t Info.offset() {
+ // no header
+ return sizeof(message_header_t);
+ }
+ async command uint8_t Info.dataLinkLength(message_t* msg, uint8_t upperLen) {
+ // no header or footer
+ return upperLen;
+ }
+ async command uint8_t Info.upperLength(message_t* msg, uint8_t dataLinkLen) {
+ return dataLinkLen;
+ }
+}
--- /dev/null
+
+#include "StorageVolumes.h"
+
+configuration FlashShellC {
+
+} implementation {
+ components new ShellCommandC("flash");
+ FlashShellP.ShellCommand -> ShellCommandC;
+
+ components new BlockStorageC(VOLUME_DELUGE1);
+ FlashShellP.BlockRead -> BlockStorageC;
+ FlashShellP.BlockWrite -> BlockStorageC;
+
+}
--- /dev/null
+module FlashShellP {
+ uses {
+ interface Boot;
+ interface Leds;
+ interface ShellCommand;
+ interface BlockRead;
+ interface BlockWrite;
+ }
+} implementation {
+
+ event void Boot.booted() {
+ if (call BlockWrite.erase() != SUCCESS)
+ call Leds.led1Toggle();
+ }
+
+ event void BlockRead.readDone(storage_addr_t addr, void* buf, storage_len_t len,
+ error_t error) {
+ uint16_t r_len = snprintf(reply_buf, MAX_REPLY_LEN,"read done addr: 0x%x len: %i error: %i data: ",
+ addr, len, error);
+ if (len < MAX_REPLY_LEN - r_len - 1)
+ memcpy(reply_buf + r_len, buf, len);
+ reply_buf[r_len + len + 1] = '\n';
+ call UDP.sendto(&session_endpoint, reply_buf, r_len + len + 1);
+
+ }
+
+ event void BlockRead.computeCrcDone(storage_addr_t addr, storage_len_t len,
+ uint16_t crc, error_t error) {
+
+ }
+
+ event void BlockWrite.writeDone(storage_addr_t addr, void* buf, storage_len_t len,
+ error_t error) {
+ uint16_t r_len = snprintf(reply_buf, MAX_REPLY_LEN,"write done addr: 0x%x len: %i error: %i\n",
+ addr, len, error);
+ call UDP.sendto(&session_endpoint, reply_buf, r_len);
+ }
+
+ event void BlockWrite.eraseDone(error_t error) {
+ call Leds.led0Toggle();
+ }
+
+ event void BlockWrite.syncDone(error_t error) {
+
+ }
+}
--- /dev/null
+
+interface RegisterShellCommand {
+ event char *getCommandName();
+}
--- /dev/null
+#ifndef _SHELL_H
+#define _SHELL_H
+
+enum {
+ MAX_REPLY_LEN = 128,
+};
+
+#endif
--- /dev/null
+
+interface ShellCommand {
+
+ /*
+ * evaluate the command that this command provides
+ * @argc the number of arguments
+ * @argv the arguments
+ * @return a string to send back as the reply to the shell client.
+ * if NULL, nothing is sent.
+ */
+ event char *eval(int argc, char **argv);
+
+ /*
+ * request a buffer. The result of this command may be returned
+ * from 'eval', but otherwise the buffer may not be used outside of
+ * the context it is called from.
+ */
+ command char *getBuffer(uint16_t len);
+
+ /*
+ * write a string to the shell buffer; if no client is connected it
+ * will fail silently
+ */
+ command void write(char *str, int len);
+}
--- /dev/null
+
+generic configuration ShellCommandC(char cmd_name[]) {
+ provides interface ShellCommand;
+} implementation {
+
+ enum {
+ CMD_ID = unique("UDPSHELL_CLIENTCOUNT"),
+ };
+
+ components new ShellCommandP(cmd_name), UDPShellP;
+
+ ShellCommandP.RegisterShellCommand -> UDPShellP.RegisterShellCommand[CMD_ID];
+ ShellCommand = UDPShellP.ShellCommand[CMD_ID];
+}
--- /dev/null
+
+generic module ShellCommandP(char cmd_name[]) {
+ uses interface RegisterShellCommand;
+} implementation {
+ event char *RegisterShellCommand.getCommandName() {
+ return cmd_name;
+ }
+}
--- /dev/null
+/*
+ * "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 <6lowpan.h>
+
+configuration UDPShellC {
+
+
+} implementation {
+
+ components new UdpSocketC();
+ components UDPShellP, LedsC;
+
+ UDPShellP.UDP -> UdpSocketC;
+
+ UDPShellP.Leds -> LedsC;
+ components ICMPResponderC;
+ UDPShellP.ICMPPing -> ICMPResponderC.ICMPPing[unique("PING")];
+
+#if defined(PLATFORM_TELOSB) || defined(PLATFORM_EPIC)
+ components CounterMilli32C;
+ UDPShellP.Uptime -> CounterMilli32C;
+#endif
+
+ components MainC;
+ UDPShellP.Boot -> MainC;
+
+}
--- /dev/null
+/*
+ * "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 <ip.h>
+#include <IPDispatch.h>
+#include <ICMP.h>
+#include "Shell.h"
+
+module UDPShellP {
+ provides {
+ interface ShellCommand[uint8_t cmd_id];
+ interface RegisterShellCommand[uint8_t cmd_id];
+ }
+ uses {
+ interface Boot;
+ interface UDP;
+ interface Leds;
+
+ interface ICMPPing;
+#if defined(PLATFORM_TELOSB) || defined(PLATFORM_EPIC)
+ interface Counter<TMilli, uint32_t> as Uptime;
+#endif
+
+ }
+
+} implementation {
+
+ bool session_active;
+ struct sockaddr_in6 session_endpoint;
+ uint32_t boot_time;
+ uint64_t uptime;
+
+ enum {
+ N_EXTERNAL = uniqueCount("UDPSHELL_CLIENTCOUNT"),
+ };
+
+ // and corresponding indeces
+ enum {
+ N_BUILTINS = 5,
+ // the maximum number of arguments a command can take
+ N_ARGS = 10,
+ CMD_HELP = 0,
+ CMD_ECHO = 1,
+ CMD_PING6 = 2,
+ CMD_TRACERT6 = 3,
+
+ CMD_NO_CMD = 0xfe,
+ CMDNAMSIZ = 10,
+ };
+
+ struct cmd_name {
+ uint8_t c_len;
+ char c_name[CMDNAMSIZ];
+ };
+ struct cmd_builtin {
+ void (*action)(int, char **);
+ };
+
+ struct cmd_name externals[N_EXTERNAL];
+
+
+ event void Boot.booted() {
+ int i;
+ atomic {
+ uptime = 0;
+#if defined(PLATFORM_TELOSB) || defined(PLATFORM_EPIC)
+ boot_time = call Uptime.get();
+#endif
+ }
+ for (i = 0; i < N_EXTERNAL; i++) {
+ externals[i].c_name[CMDNAMSIZ-1] = '\0';
+ strncpy(externals[i].c_name, signal RegisterShellCommand.getCommandName[i](), CMDNAMSIZ);
+ externals[i].c_len = strlen(externals[i].c_name);
+ }
+ call UDP.bind(2000);
+ }
+
+ char reply_buf[MAX_REPLY_LEN];
+ char *help_str = "sdsh-0.9\tbuiltins: [help, echo, ping6, uptime, ident]\n";
+ const char *ping_fmt = "%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x: icmp_seq=%i ttl=%i time=%i ms\n";
+ const char *ping_summary = "%i packets transmitted, %i received\n";
+
+ void action_help(int argc, char **argv) {
+ int i = 0;
+ char *pos = reply_buf;
+ call UDP.sendto(&session_endpoint, help_str, strlen(help_str));
+ if (N_EXTERNAL > 0) {
+ strcpy(pos, "\t\t[");
+ pos += 3;
+ for (i = 0; i < N_EXTERNAL; i++) {
+ if (externals[i].c_len + 4 < MAX_REPLY_LEN - (pos - reply_buf)) {
+ memcpy(pos, externals[i].c_name, externals[i].c_len);
+ pos += externals[i].c_len;
+ if (i < N_EXTERNAL-1) {
+ pos[0] = ',';
+ pos[1] = ' ';
+ pos += 2;
+ }
+ } else {
+ pos[0] = '.';
+ pos[1] = '.';
+ pos[2] = '.';
+ pos += 3;
+ break;
+ }
+ }
+ *pos++ = ']';
+ *pos++ = '\n';
+ call UDP.sendto(&session_endpoint, reply_buf, pos - reply_buf);
+ }
+ }
+
+ command char *ShellCommand.getBuffer[uint8_t cmd_id](uint16_t len) {
+ reply_buf[0] = '\0';
+ if (len <= MAX_REPLY_LEN) return reply_buf;
+ return NULL;
+ }
+
+ command void ShellCommand.write[uint8_t cmd_id](char *str, int len) {
+ call UDP.sendto(&session_endpoint, str, len);
+ }
+
+ void action_echo(int argc, char **argv) {
+ int i, arg_len;
+ char *payload = reply_buf;
+
+ if (argc < 2) return;
+ for (i = 1; i < argc; i++) {
+ arg_len = strlen(argv[i]);
+ if ((payload - reply_buf) + arg_len + 1 > MAX_REPLY_LEN) break;
+ memcpy(payload, argv[i], arg_len);
+ payload += arg_len;
+ *payload = ' ';
+ payload++;
+ }
+ *(payload - 1) = '\n';
+
+ call UDP.sendto(&session_endpoint, reply_buf, payload - reply_buf);
+ }
+
+ void action_ping6(int argc, char **argv) {
+ struct in6_addr dest;
+
+ if (argc < 2) return;
+ inet_pton6(argv[1], &dest);
+ call ICMPPing.ping(&dest, 1024, 10);
+ }
+
+
+ void action_uptime(int argc, char **argv) {
+#if defined(PLATFORM_TELOSB) || defined(PLATFORM_EPIC)
+ int len;
+ uint64_t tval = call Uptime.get();
+ atomic
+ tval = (uptime + tval - boot_time) / 1024;
+ len = snprintf(reply_buf, MAX_REPLY_LEN, "up %li seconds\n",
+ (uint32_t)tval);
+ call UDP.sendto(&session_endpoint, reply_buf, len);
+#endif
+ }
+
+ void action_ident(int argc, char **argv) {
+ int len;
+ len = snprintf(reply_buf, MAX_REPLY_LEN,
+ "\t[app: %s]\n\t[user: %s]\n\t[host: %s]\n\t[time: 0x%lx]\n",
+ IDENT_APPNAME, IDENT_USERNAME, IDENT_HOSTNAME, IDENT_TIMESTAMP);
+ call UDP.sendto(&session_endpoint, reply_buf, len);
+ }
+
+ // commands
+ struct cmd_name builtins[N_BUILTINS] = {{4, "help"},
+ {4, "echo"},
+ {5, "ping6"},
+ {6, "uptime"},
+ {5, "ident"}};
+ struct cmd_builtin builtin_actions[N_BUILTINS] = {{action_help},
+ {action_echo},
+ {action_ping6},
+ {action_uptime},
+ {action_ident}};
+
+
+ // break up a command given as a string into a sequence of null terminated
+ // strings, and initialize the argv array to point into it.
+ void init_argv(char *cmd, uint16_t len, char **argv, int *argc) {
+ int inArg = 0;
+ *argc = 0;
+ while (len > 0 && *argc < N_ARGS) {
+ if (*cmd == ' ' || *cmd == '\n' || *cmd == '\t' || *cmd == '\0' || len == 1){
+ if (inArg) {
+ *argc = *argc + 1;
+ inArg = 0;
+ *cmd = '\0';
+ }
+ } else if (!inArg) {
+ argv[*argc] = cmd;
+ inArg = 1;
+ }
+ cmd ++;
+ len --;
+ }
+ }
+
+ int lookup_cmd(char *cmd, int dbsize, struct cmd_name *db) {
+ int i;
+ for (i = 0; i < dbsize; i++) {
+ if (memcmp(cmd, db[i].c_name, db[i].c_len) == 0
+ && cmd[db[i].c_len] == '\0')
+ return i;
+ }
+ return CMD_NO_CMD;
+ }
+
+ event void UDP.recvfrom(struct sockaddr_in6 *from, void *data,
+ uint16_t len, struct ip_metadata *meta) {
+ char *argv[N_ARGS];
+ int argc, cmd;
+
+ memcpy(&session_endpoint, from, sizeof(struct sockaddr_in6));
+ init_argv((char *)data, len, argv, &argc);
+
+ if (argc > 0) {
+ cmd = lookup_cmd(argv[0], N_BUILTINS, builtins);
+ if (cmd != CMD_NO_CMD) {
+ builtin_actions[cmd].action(argc, argv);
+ return;
+ }
+ cmd = lookup_cmd(argv[0], N_EXTERNAL, externals);
+ if (cmd != CMD_NO_CMD) {
+ char *reply = signal ShellCommand.eval[cmd](argc, argv);
+ if (reply != NULL)
+ call UDP.sendto(&session_endpoint, reply, strlen(reply));
+ return;
+ }
+ cmd = snprintf(reply_buf, MAX_REPLY_LEN, "sdsh: %s: command not found\n", argv[0]);
+ call UDP.sendto(&session_endpoint, reply_buf, cmd);
+ }
+ }
+
+ event void ICMPPing.pingReply(struct in6_addr *source, struct icmp_stats *stats) {
+ int len;
+ len = snprintf(reply_buf, MAX_REPLY_LEN, ping_fmt,
+ source->s6_addr[0],source->s6_addr[1],source->s6_addr[2],source->s6_addr[3],
+ source->s6_addr[4],source->s6_addr[5],source->s6_addr[6],source->s6_addr[7],
+ source->s6_addr[8],source->s6_addr[9],source->s6_addr[10],source->s6_addr[11],
+ source->s6_addr[12],source->s6_addr[13],source->s6_addr[14],source->s6_addr[15],
+ stats->seq, stats->ttl, stats->rtt);
+ call UDP.sendto(&session_endpoint, reply_buf, len);
+ }
+
+ event void ICMPPing.pingDone(uint16_t ping_rcv, uint16_t ping_n) {
+ int len;
+ len = snprintf(reply_buf, MAX_REPLY_LEN, ping_summary, ping_n, ping_rcv);
+ call UDP.sendto(&session_endpoint, reply_buf, len);
+ }
+
+#if defined(PLATFORM_TELOSB) || defined(PLATFORM_EPIC)
+ async event void Uptime.overflow() {
+ atomic
+ uptime += 0xffffffff;
+ }
+#endif
+
+ default event char *ShellCommand.eval[uint8_t cmd_id](int argc, char **argv) {
+ return NULL;
+ }
+ default event char *RegisterShellCommand.getCommandName[uint8_t cmd_id]() {
+ return NULL;
+ }
+}
--- /dev/null
+
+#include <stdlib.h>
+#include "table.h"
+
+void table_init(table_t *table, void *data,
+ uint16_t elt_len, uint16_t n_elts) {
+ table->data = data;
+ table->elt_len = elt_len;
+ table->n_elts = n_elts;
+}
+
+void *table_search(table_t *table, int (*pred)(void *)) {
+ int i;
+ void *cur;
+ for (i = 0; i < table->n_elts; i++) {
+ cur = table->data + (i * table->elt_len);
+ switch (pred(cur)) {
+ case 1: return cur;
+ case -1: return NULL;
+ default: continue;
+ }
+ }
+ return NULL;
+}
+
+void table_map(table_t *table, void(*fn)(void *)) {
+ int i;
+ for (i = 0; i < table->n_elts; i++)
+ fn(table->data + (i * table->elt_len));
+}
+
--- /dev/null
+#ifndef TABLE_H_
+#define TABLE_H_
+
+#include <stdint.h>
+
+typedef struct {
+ void *data;
+ uint16_t elt_len;
+ uint16_t n_elts;
+} table_t;
+
+void table_init(table_t *table, void *data,uint16_t elt_len, uint16_t n_elts);
+void *table_search(table_t *table, int (*pred)(void *));
+void table_map(table_t *table, void (*fn)(void *));
+
+#endif