Пример #1
0
/*---------------------------------------------------------------------------*/
void
rpl_purge_routes(void)
{
  uip_ds6_route_t *r;
  uip_ipaddr_t prefix;
  rpl_dag_t *dag;
  rpl_instance_t *instance; //changed

  /* First pass, decrement lifetime */
  r = uip_ds6_route_head();

  while(r != NULL) {
    if(r->state.lifetime >= 1) {
      /*
       * If a route is at lifetime == 1, set it to 0, scheduling it for
       * immediate removal below. This achieves the same as the original code,
       * which would delete lifetime <= 1
       */
      r->state.lifetime--;
    }
    r = uip_ds6_route_next(r);
  }

  /* Second pass, remove dead routes */
  r = uip_ds6_route_head();

  while(r != NULL) {
    /*Pre-change handle second_instance*/
    if(r->state.lifetime < 1) {
      /* Routes with lifetime == 1 have only just been decremented from 2 to 1,
       * thus we want to keep them. Hence < and not <= */
      uip_ipaddr_copy(&prefix, &r->ipaddr);
      uip_ds6_route_rm(r);
      r = uip_ds6_route_head();
      PRINTF("No more routes to ");
      PRINT6ADDR(&prefix);
      /*Changed*/
      instance = rpl_get_instance(r->state.instance_id);
      dag = instance->current_dag;
      //dag1 = second_instance->current_dag;
      /* Propagate this information with a No-Path DAO to preferred parent if we are not a RPL Root */
      if(dag->rank != ROOT_RANK(instance)) {
        PRINTF(" -> generate No-Path DAO\n");
        dao_output_target(dag->preferred_parent, &prefix, RPL_ZERO_LIFETIME);
        /* Don't schedule more than 1 No-Path DAO, let next iteration handle that */
        return;
      }
      PRINTF("\n");
    } else {
      r = uip_ds6_route_next(r);
    }
  }
}
Пример #2
0
static void
assert_nbr_routes_list_sane(void)
{
  uip_ds6_route_t *r;
  int count;

  /* Check if the route list has an infinite loop. */
  for(r = uip_ds6_route_head(),
        count = 0;
      r != NULL &&
        count < UIP_DS6_ROUTE_NB * 2;
      r = uip_ds6_route_next(r),
        count++);

  if(count > UIP_DS6_ROUTE_NB) {
    printf("uip-ds6-route.c: assert_nbr_routes_list_sane route list is in infinite loop\n");
  }

  /* Make sure that the route list has as many entries as the
     num_routes vairable. */
  if(count < num_routes) {
    printf("uip-ds6-route.c: assert_nbr_routes_list_sane too few entries on route list: should be %d, is %d, max %d\n",
           num_routes, count, UIP_CONF_MAX_ROUTES);
  }
}
Пример #3
0
/*---------------------------------------------------------------------------*/			
static unsigned short
make_routes(void *p)
{
  static const char httpd_cgi_rtes1[] HTTPD_STRING_ATTR = "(%u (via ";
  static const char httpd_cgi_rtes2[] HTTPD_STRING_ATTR = ") %lus<br>";
  static const char httpd_cgi_rtes3[] HTTPD_STRING_ATTR = ")<br>";
  uint8_t i,j=0;
  uint16_t numprinted;
  uip_ds6_route_t *r;

  numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh);
  for(r = uip_ds6_route_head();
      r != NULL;
      r = uip_ds6_route_next(r)) {
    j++;
    numprinted += httpd_cgi_sprint_ip6(r->ipaddr, uip_appdata + numprinted);
    numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes1, r->length);
    numprinted += httpd_cgi_sprint_ip6(uip_ds6_route_nexthop(r), uip_appdata + numprinted);
    if(r->state.lifetime < 3600) {
      numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes2, r->state.lifetime);
    } else {
      numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes3);
    }
  }
  if (j==0) numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrn);
  numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf,UIP_DS6_ROUTE_NB-j);
  return numprinted;
}
Пример #4
0
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_lookup(uip_ipaddr_t *addr)
{
  uip_ds6_route_t *r;
  uip_ds6_route_t *found_route;
  uint8_t longestmatch;

//ADILA EDIT 10/11/14
//uint8_t found_route_ch;
//-------------------

  PRINTF("uip-ds6-route: Looking up route for ");
  PRINT6ADDR(addr);
  PRINTF("\n");


  found_route = NULL;
  longestmatch = 0;
  for(r = uip_ds6_route_head();
      r != NULL;
      r = uip_ds6_route_next(r)) {
    if(r->length >= longestmatch &&
       uip_ipaddr_prefixcmp(addr, &r->ipaddr, r->length)) {
      longestmatch = r->length;
      found_route = r;

//ADILA EDIT 10/11/14
//found_route_ch = r->nbrCh;
//-------------------
    }
  }

  if(found_route != NULL) {
    PRINTF("uip-ds6-route: Found route: ");
    PRINT6ADDR(addr);
    PRINTF(" via ");
    PRINT6ADDR(uip_ds6_route_nexthop(found_route));
    PRINTF("\n");

//ADILA EDIT 10/11/14
/*    printf("uip-ds6-route: Found route: ");
    uip_debug_ipaddr_print(addr);
    printf(" via ");
    uip_debug_ipaddr_print(uip_ds6_route_nexthop(found_route));
    printf("\n");
*/
//printf("FOUND ROUTE CHANGE TO NEXTHOP CHANNEL %d\n\n", found_route_ch);
/*printf("Found route change to nexthop channel %d ", found_route_ch);
uip_debug_ipaddr_print(uip_ds6_route_nexthop(found_route));
printf("\n");*/
//PRINTF("FOUND ROUTE CHANGE TO NEXTHOP CHANNEL %d\n\n", found_route_ch);
//@
//cc2420_set_channel(found_route_ch);
//-------------------
  } else {
    PRINTF("uip-ds6-route: No route found\n");
  }

  return found_route;
}
Пример #5
0
/*---------------------------------------------------------------------------*/
void
rpl_remove_routes(rpl_dag_t *dag)
{
  uip_ds6_route_t *r;
#if RPL_CONF_MULTICAST
  uip_mcast6_route_t *mcast_route;
#endif

  r = uip_ds6_route_head();

  while(r != NULL) {
    if(r->state.dag == dag) {
      uip_ds6_route_rm(r);
      r = uip_ds6_route_head();
    } else {
      r = uip_ds6_route_next(r);
    }
  }

#if RPL_CONF_MULTICAST
  mcast_route = uip_mcast6_route_list_head();

  while(mcast_route != NULL) {
    if(mcast_route->dag == dag) {
      uip_mcast6_route_rm(mcast_route);
      mcast_route = uip_mcast6_route_list_head();
    } else {
      mcast_route = list_item_next(mcast_route);
    }
  }
#endif
}
Пример #6
0
/*---------------------------------------------------------------------------*/
void
uip_ds6_route_rm(uip_ds6_route_t *route)
{
#if DEBUG != DEBUG_NONE
  assert_nbr_routes_list_sane();
#endif /* DEBUG != DEBUG_NONE */
  if(route != NULL && route->routes != NULL) {

    PRINTF("uip_ds6_route_rm: removing route: ");
    PRINT6ADDR(&route->ipaddr);
    PRINTF("\n");

    list_remove(route->routes->route_list, route);
    if(list_head(route->routes->route_list) == NULL) {
      /* If this was the only route using this neighbor, remove the
         neibhor from the table */
      PRINTF("uip_ds6_route_rm: removing neighbor too\n");
      nbr_table_remove(nbr_routes, route->routes->route_list);
    }
    memb_free(&routememb, route);

    num_routes--;

    PRINTF("uip_ds6_route_rm num %d\n", num_routes);

#if UIP_DS6_NOTIFICATIONS
    call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_RM,
        &route->ipaddr, uip_ds6_route_nexthop(route));
#endif
#if 0 //(DEBUG & DEBUG_ANNOTATE) == DEBUG_ANNOTATE
    /* we need to check if this was the last route towards "nexthop" */
    /* if so - remove that link (annotation) */
    uip_ds6_route_t *r;
    for(r = uip_ds6_route_head();
        r != NULL;
        r = uip_ds6_route_next(r)) {
      uip_ipaddr_t *nextr, *nextroute;
      nextr = uip_ds6_route_nexthop(r);
      nextroute = uip_ds6_route_nexthop(route);
      if(nextr != NULL &&
         nextroute != NULL &&
         uip_ipaddr_cmp(nextr, nextroute)) {
        /* we found another link using the specific nexthop, so keep the #L */
        return;
      }
    }
    ANNOTATE("#L %u 0\n", uip_ds6_route_nexthop(route)->u8[sizeof(uip_ipaddr_t) - 1]);
#endif
  }

#if DEBUG != DEBUG_NONE
  assert_nbr_routes_list_sane();
#endif /* DEBUG != DEBUG_NONE */
  return;
}
Пример #7
0
uip_ds6_route_t *
uip_ds6_route_lookup_by_nexthop(uip_ipaddr_t *ipaddr)
{
  uip_ds6_route_t *r;
  for(r = uip_ds6_route_head();
      r != NULL;
      r = uip_ds6_route_next(r)) {
    if(uip_ipaddr_cmp(uip_ds6_route_nexthop(r), ipaddr)) {
      return r;
    }
  }
  return NULL;
}
Пример #8
0
/*develop the handler*/
void
routes_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
	int32_t strpos = 0;
	uip_ds6_route_t *r;
	volatile uint8_t i;

	size_t len = 0;
	uint8_t index;   //>>>>>>>>>>>>>>>>>>index used while experimenting eg. : GET rplinfo/routes?index=1
	const char *pstr;
	uint8_t count;

	/*Count the number of the routes and return them*/
	count=uip_ds6_route_num_routes();

	if((len = REST.get_query_variable(request, "index", &pstr))) // Parse for the index variable and compare value
	{
		index=(uint8_t)atoi(pstr);

		if(index >= count)
		{
			strpos = snprintf((char *)buffer,preferred_size, "{}"); 
			/*
			 if index is greater or same as count value return empty brackets
			 */
		}else
		{
			/*seek route entry and return it*/
			i = 0;
			for(r = uip_ds6_route_head(); r != NULL; r = uip_ds6_route_next(r), i++)
			{
				if (i == index)
				{
					break;
				}
			}
			strpos = create_route_msg((char *)buffer, r);
		}

		REST.set_header_content_type(response, REST.type.APPLICATION_JSON); // Header will be in JSON format...
	}else
	{
		// index not provided
		strpos += snprintf((char *)buffer, preferred_size, "%d", count);
	}

	//*offset = -1;
	REST.set_response_payload(response, (char *)buffer, strpos); // Setting the payload of response.

}
Пример #9
0
/*---------------------------------------------------------------------------*/
static
PT_THREAD(routes(struct httpd_state *s, char *ptr))
{
  PSOCK_BEGIN(&s->sout);

  for(s->u.ptr = uip_ds6_route_head();
      s->u.ptr != NULL;
      s->u.ptr = uip_ds6_route_next(s->u.ptr)) {
    PSOCK_GENERATOR_SEND(&s->sout, make_route, s);
  }
  PSOCK_GENERATOR_SEND(&s->sout, make_routes_roomfor, s);

  PSOCK_END(&s->sout);
}
Пример #10
0
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_lookup(uip_ipaddr_t *addr)
{
  uip_ds6_route_t *r;
  uip_ds6_route_t *found_route;
  uint8_t longestmatch;

  PRINTF("uip-ds6-route: Looking up route for ");
  PRINT6ADDR(addr);
  PRINTF("\n");


  found_route = NULL;
  longestmatch = 0;
  for(r = uip_ds6_route_head();
      r != NULL;
      r = uip_ds6_route_next(r)) {
    if(r->length >= longestmatch &&
       uip_ipaddr_prefixcmp(addr, &r->ipaddr, r->length)) {
      longestmatch = r->length;
      found_route = r;
      /* check if total match - e.g. all 128 bits do match */
      if(longestmatch == 128) {
	break;
      }
    }
  }

  if(found_route != NULL) {
    PRINTF("uip-ds6-route: Found route: ");
    PRINT6ADDR(addr);
    PRINTF(" via ");
    PRINT6ADDR(uip_ds6_route_nexthop(found_route));
    PRINTF("\n");
  } else {
    PRINTF("uip-ds6-route: No route found\n");
  }

  if(found_route != NULL && found_route != list_head(routelist)) {
    /* If we found a route, we put it at the start of the routeslist
       list. The list is ordered by how recently we looked them up:
       the least recently used route will be at the end of the
       list - for fast lookups (assuming multiple packets to the same node). */

    list_remove(routelist, found_route);
    list_push(routelist, found_route);
  }

  return found_route;
}
Пример #11
0
static uip_ds6_route_t *
find_route_entry_by_dao_ack(uint8_t seq)
{
  uip_ds6_route_t *re;
  re = uip_ds6_route_head();
  while(re != NULL) {
    if(re->state.dao_seqno_out == seq && RPL_ROUTE_IS_DAO_PENDING(re)) {
      /* found it! */
      return re;
    }
    re = uip_ds6_route_next(re);
  }
  return NULL;
}
Пример #12
0
/*---------------------------------------------------------------------------*/
static uint16_t
print_routes(char *msg, int size)
{
  uip_ds6_route_t *r = uip_ds6_route_head();
  int len = strlen(msg);
  while(r != NULL && len < size + 30) {
    /* output a route entry */
    len += sprint_addr6(&msg[len], &r->ipaddr);
    len += snprintf(&msg[len], size, "->");
    len += sprint_addr6(&msg[len], uip_ds6_route_nexthop(r));
    len += snprintf(&msg[len], size, "\n");
    r = uip_ds6_route_next(r);
  }
  return len;
}
Пример #13
0
/*---------------------------------------------------------------------------*/
void
rpl_remove_routes(rpl_dag_t *dag)
{
  uip_ds6_route_t *r;

  r = uip_ds6_route_head();

  while(r != NULL) {
    if(r->state.dag == dag) {
      uip_ds6_route_rm(r);
      r = uip_ds6_route_head();
    } else {
      r = uip_ds6_route_next(r);
    }
  }
}
Пример #14
0
/*---------------------------------------------------------------------------*/
static
PT_THREAD(routesping(struct httpd_state *s, char *ptr))
{
  PSOCK_BEGIN(&s->sout);

  for(s->u.ptr = uip_ds6_route_head();
      s->u.ptr != NULL;
      s->u.ptr = uip_ds6_route_next(s->u.ptr)) {
    uip_ds6_route_t *r = (uip_ds6_route_t*) s->u.ptr;
    simple_udp_ping_send_ping(&r->ipaddr);
    PSOCK_GENERATOR_SEND(&s->sout, make_route, s);
  }
  PSOCK_GENERATOR_SEND(&s->sout, make_routes_roomfor, s);

  PSOCK_END(&s->sout);
}
Пример #15
0
/*---------------------------------------------------------------------------*/
void
rpl_remove_routes_by_nexthop(uip_ipaddr_t *nexthop, rpl_dag_t *dag)
{
  uip_ds6_route_t *r;

  r = uip_ds6_route_head();

  while(r != NULL) {
    if(uip_ipaddr_cmp(uip_ds6_route_nexthop(r), nexthop) &&
        r->state.dag == dag) {
      r->state.lifetime = 0;
    }
    r = uip_ds6_route_next(r);
  }
  ANNOTATE("#L %u 0\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
}
/*---------------------------------------------------------------------------*/
static void
print_network_status(void)
{
  int i;
  uint8_t state;
  uip_ds6_defrt_t *default_route;
  uip_ds6_route_t *route;

  PRINTA("--- Network status ---\n");
  
  /* Our IPv6 addresses */
  PRINTA("- Server IPv6 addresses:\n");
  for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
    state = uip_ds6_if.addr_list[i].state;
    if(uip_ds6_if.addr_list[i].isused &&
       (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
      PRINTA("-%d- ",i);
      uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr);
      PRINTA("\n");
    }
  }
  
  /* Our default route */
  PRINTA("- Default route:\n");
  default_route = uip_ds6_defrt_lookup(uip_ds6_defrt_choose());
  if(default_route != NULL) {
    PRINTA("-- ");
    uip_debug_ipaddr_print(&default_route->ipaddr);;
    PRINTA(" (lifetime: %lu seconds)\n", (unsigned long)default_route->lifetime.interval);
  } else {
    PRINTA("-- None\n");
  }

  /* Our routing entries */
  PRINTA("- Routing entries (%u in total):\n", uip_ds6_route_num_routes());
  route = uip_ds6_route_head();
  while(route != NULL) {
    PRINTA("-- ");
    uip_debug_ipaddr_print(&route->ipaddr);
    PRINTA(" via ");
    uip_debug_ipaddr_print(uip_ds6_route_nexthop(route));
    PRINTA(" (lifetime: %lu seconds)\n", (unsigned long)route->state.lifetime);
    route = uip_ds6_route_next(route); 
  }
  
  PRINTA("----------------------\n");
}
Пример #17
0
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_lookup(uip_ipaddr_t *addr)
{
    uip_ds6_route_t *r;
    uip_ds6_route_t *found_route;
    uint8_t longestmatch;

    PRINTF("uip-ds6-route: Looking up route for ");
    PRINT6ADDR(addr);
    PRINTF("\n");


    found_route = NULL;
    longestmatch = 0;
    for(r = uip_ds6_route_head();
            r != NULL;
            r = uip_ds6_route_next(r)) {
        if(r->length >= longestmatch &&
                uip_ipaddr_prefixcmp(addr, &r->ipaddr, r->length)) {
            longestmatch = r->length;
            found_route = r;
        }
    }

    if(found_route != NULL) {
        PRINTF("uip-ds6-route: Found route: ");
        PRINT6ADDR(addr);
        PRINTF(" via ");
        PRINT6ADDR(uip_ds6_route_nexthop(found_route));
        PRINTF("\n");
    } else {
        PRINTF("uip-ds6-route: No route found\n");
    }

    if(found_route != NULL) {
        /* If we found a route, we put it at the end of the routeslist
           list. The list is ordered by how recently we looked them up:
           the least recently used route will be at the start of the
           list. */
        list_remove(routelist, found_route);
        list_add(routelist, found_route);
    }

    return found_route;
}
Пример #18
0
void
routes_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
  int32_t strpos = 0;
  uip_ds6_route_t *r;
  volatile uint8_t i;

  size_t len = 0;
  uint8_t index;
  const char *pstr;
  uint8_t count;

  /* count the number of routes and return the total */
  count = uip_ds6_route_num_routes();

  if ((len = REST.get_query_variable(request, "index", &pstr))) {

    index = (uint8_t)atoi(pstr);

    if (index >= count ) {
      strpos = snprintf((char *)buffer, preferred_size, "{}");
    } else {
      /* seek to the route entry and return it */
      i = 0;
      for(r = uip_ds6_route_head(); r != NULL; r = uip_ds6_route_next(r), i++) {
	if (i == index) {
	  break;
	}
      }
      strpos = create_route_msg((char *)buffer, r);
    }

    REST.set_header_content_type(response, APPLICATION_JSON);

  } else { /* index not provided */
    strpos += snprintf((char *)buffer, preferred_size, "%d", count);
  }

  *offset = -1;

  REST.set_response_payload(response, (char *)buffer, strpos);

}
void
collect_common_net_print(void)
{
  rpl_dag_t *dag;
  uip_ds6_route_t *r;

  /* Let's suppose we have only one instance */
  dag = rpl_get_any_dag();
  if(dag->preferred_parent != NULL) {
    PRINTF("Preferred parent: ");
    PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
    PRINTF("\n");
  }
  for(r = uip_ds6_route_head();
      r != NULL;
      r = uip_ds6_route_next(r)) {
    PRINT6ADDR(&r->ipaddr);
  }
  PRINTF("---\n");
}
Пример #20
0
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_lookup(uip_ipaddr_t *addr)
{
  uip_ds6_route_t *r;
  uip_ds6_route_t *found_route;
  uint8_t longestmatch;

  PRINTF("uip-ds6-route: Looking up route for ");
  PRINT6ADDR(addr);
  PRINTF("\n");


  found_route = NULL;
  longestmatch = 0;
  for(r = uip_ds6_route_head();
      r != NULL;
      r = uip_ds6_route_next(r)) {
    if(r->length >= longestmatch &&
       uip_ipaddr_prefixcmp(addr, &r->ipaddr, r->length)) {
      longestmatch = r->length;
      found_route = r;
    }
  }

  if(found_route != NULL) {
    PRINTF("uip-ds6-route: Found route: ");
    PRINT6ADDR(addr);
    PRINTF(" via ");
    PRINT6ADDR(uip_ds6_route_nexthop(found_route));
    PRINTF("\n");
  } else {
    PRINTF("uip-ds6-route: No route found\n");
  }

  return found_route;
}
Пример #21
0
static
PT_THREAD(generate_network(struct httpd_state *s))
{
  static int i;
  static uip_ds6_route_t *r;
  static uip_ds6_defrt_t *dr;
  static uip_ds6_nbr_t *nbr;
#if CETIC_6LBR_WITH_MULTICAST
  static uip_mcast6_route_t *mcast_route;
#endif
#if RPL_WITH_NON_STORING
  static rpl_ns_node_t *link;
#endif

  PSOCK_BEGIN(&s->sout);
  add("<br /><h2>Addresses</h2><pre>");
  SEND_STRING(&s->sout, buf);
  reset_buf();

  for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
    if(uip_ds6_if.addr_list[i].isused) {
      ipaddr_add(&uip_ds6_if.addr_list[i].ipaddr);
      add(" ");
      add_address_type(uip_ds6_if.addr_list[i].type);
      add(" ");
      add_address_state(uip_ds6_if.addr_list[i].state);
      if(!uip_ds6_if.addr_list[i].isinfinite) {
        add(" %u s", stimer_remaining(&uip_ds6_if.addr_list[i].vlifetime));
      }
      add("\n");
      SEND_STRING(&s->sout, buf);
      reset_buf();
    }
  }

  add("</pre><h2>Multicast groups</h2><pre>");
  for(i = 0; i < UIP_DS6_MADDR_NB; i++) {
    if(uip_ds6_if.maddr_list[i].isused) {
      ipaddr_add(&uip_ds6_if.maddr_list[i].ipaddr);
      add("\n");
      SEND_STRING(&s->sout, buf);
      reset_buf();
    }
  }

  add("</pre><h2>Prefixes</h2><pre>");
  for(i = 0; i < UIP_DS6_PREFIX_NB; i++) {
    if(uip_ds6_prefix_list[i].isused) {
      ipaddr_add(&uip_ds6_prefix_list[i].ipaddr);
#if UIP_CONF_ROUTER
      if(uip_ds6_prefix_list[i].advertise) {
        add(" Adv");
      }
#else
      if(uip_ds6_prefix_list[i].isinfinite) {
        add(" Inf");
      }
#endif
      add("\n");
    }
  }
  SEND_STRING(&s->sout, buf);
  reset_buf();

#if CETIC_6LBR_WITH_IP64
  if((nvm_data.global_flags & CETIC_GLOBAL_IP64) != 0) {
    add("</pre><h2>IP64</h2><pre>");
    if((nvm_data.eth_ip64_flags & CETIC_6LBR_IP64_DHCP) == 0 || ip64_hostaddr_is_configured()) {
      add("Address : ");
      ip4addr_add(ip64_get_hostaddr());
      add("<br />");
      add("Netmask : ");
      ip4addr_add(ip64_get_netmask());
      add("<br />");
      add("Gateway : ");
      ip4addr_add(ip64_get_draddr());
      add("<br />");
      if((nvm_data.eth_ip64_flags & CETIC_6LBR_IP64_DHCP) != 0) {
        add("DHCP Server : ");
        ip4addr_add_u8(cetic_6lbr_ip64_dhcp_state->serverid);
        add("<br />");
        add("DHCP lease time : %d s<br />",
            uip_ntohs(cetic_6lbr_ip64_dhcp_state->lease_time[0])*65536ul + uip_ntohs(cetic_6lbr_ip64_dhcp_state->lease_time[1]));
      }
    } else {
      add("Waiting configuration<br />");
    }
    SEND_STRING(&s->sout, buf);
    reset_buf();
  }
#endif

  add("</pre><h2>Neighbors</h2><pre>");

  for(nbr = nbr_table_head(ds6_neighbors);
      nbr != NULL;
      nbr = nbr_table_next(ds6_neighbors, nbr)) {

    if ((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_CONFIG) == 0) {
      add("[<a href=\"nbr-rm?");
      ipaddr_add(&nbr->ipaddr);
      add("\">del</a>] ");
    }
#if CETIC_6LBR_NODE_CONFIG_HAS_NAME
    if ( node_config_loaded ) {
      add("%s : ", node_config_get_name(node_config_find_by_lladdr(uip_ds6_nbr_get_ll(nbr))));
    }
#endif
    ipaddr_add(&nbr->ipaddr);
    add(" ");
    lladdr_add(uip_ds6_nbr_get_ll(nbr));
    add(" ");
    add_network_cases(nbr->state);
#if UIP_SWITCH_LOOKUP
    if(nbr->ifindex != NETWORK_ITF_UNKNOWN) {
      add(" if:%u", nbr->ifindex);
    }
#endif
    add("\n");
    SEND_STRING(&s->sout, buf);
    reset_buf();
  }

  add("</pre><h2>Routes</h2><pre>");
  SEND_STRING(&s->sout, buf);
  reset_buf();
  for(r = uip_ds6_route_head(), i = 0; r != NULL;
      r = uip_ds6_route_next(r), ++i) {
    if ((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_CONFIG) == 0) {
      add("[<a href=\"route-rm?");
      ipaddr_add(&r->ipaddr);
      add("\">del</a>] ");
    }
#if CETIC_6LBR_NODE_CONFIG_HAS_NAME
    if ( node_config_loaded ) {
      add("%s (", node_config_get_name(node_config_find_by_ip(&r->ipaddr)));
      ipaddr_add(&r->ipaddr);
      add("/%u) via ", r->length);
    } else {
      ipaddr_add(&r->ipaddr);
      add("/%u via ", r->length);
    }
    if ( node_config_loaded ) {
      add("%s (", node_config_get_name(node_config_find_by_ip(uip_ds6_route_nexthop(r))));
      ipaddr_add(uip_ds6_route_nexthop(r));
      add(")");
    } else {
      ipaddr_add(uip_ds6_route_nexthop(r));
    }
#else
    ipaddr_add(&r->ipaddr);
    add("/%u via ", r->length);
    ipaddr_add(uip_ds6_route_nexthop(r));
#endif
#if CETIC_6LBR_WITH_RPL
    if(r->state.lifetime != RPL_ROUTE_INFINITE_LIFETIME) {
#else
    if(r->neighbor_routes != NULL) {
#endif
      add(" %lu s\n", r->state.lifetime);
    } else {
      add("Inf\n");
    }
    SEND_STRING(&s->sout, buf);
    reset_buf();
  }
#if RPL_WITH_NON_STORING
  add("</pre><h2>Links</h2><pre>");
  for(link = rpl_ns_node_head(); link != NULL; link = rpl_ns_node_next(link)) {
    if(link->parent != NULL) {
      uip_ipaddr_t child_ipaddr;
      uip_ipaddr_t parent_ipaddr;

      rpl_ns_get_node_global_addr(&child_ipaddr, link);
      rpl_ns_get_node_global_addr(&parent_ipaddr, link->parent);
#if CETIC_6LBR_NODE_CONFIG_HAS_NAME
      if ( node_config_loaded ) {
        add("%s (", node_config_get_name(node_config_find_by_ip(&child_ipaddr)));
        ipaddr_add(&child_ipaddr);
        add(") via ");
      } else {
        ipaddr_add(&child_ipaddr);
        add(" via ");
      }
      if ( node_config_loaded ) {
        add("%s (", node_config_get_name(node_config_find_by_ip(&parent_ipaddr)));
        ipaddr_add(&parent_ipaddr);
        add(")");
      } else {
        ipaddr_add(&parent_ipaddr);
      }
#else
      ipaddr_add(&child_ipaddr);
      add(" via ");
      ipaddr_add(&parent_ipaddr);
#endif
      add(" %lu s\n", link->lifetime);
      SEND_STRING(&s->sout, buf);
      reset_buf();
    }
  }
#endif

#if CETIC_6LBR_WITH_MULTICAST
  add("</pre><h2>Routed multicast groups</h2><pre>");
  for(mcast_route = uip_mcast6_route_list_head(), i = 0; mcast_route != NULL;
      mcast_route = list_item_next(mcast_route), ++i) {
    if ((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_CONFIG) == 0) {
      add("[<a href=\"mcast-rm?");
      ipaddr_add(&mcast_route->group);
      add("\">del</a>] ");
    }
    ipaddr_add(&mcast_route->group);
    add(" %lu s\n", mcast_route->lifetime);
    SEND_STRING(&s->sout, buf);
    reset_buf();
  }
#endif

  add("</pre><h2>Default Routers</h2><pre>");

  for(dr = uip_ds6_defrt_head(); dr != NULL; dr = list_item_next(r)) {
    ipaddr_add(&dr->ipaddr);
    if(dr->isinfinite) {
      add(" Inf");
    } else {
      add(" %u s", stimer_remaining(&dr->lifetime));
    }
    add("\n");
    SEND_STRING(&s->sout, buf);
    reset_buf();
  }

#if UIP_CONF_DS6_ROUTE_INFORMATION
  add("</pre><h2>Route info</h2><pre>");
  for(i = 0; i < UIP_DS6_ROUTE_INFO_NB; i++) {
    if(uip_ds6_route_info_list[i].isused) {
      ipaddr_add(&uip_ds6_route_info_list[i].ipaddr);
      add("/%u (%x) %u s\n", uip_ds6_route_info_list[i].length,
          uip_ds6_route_info_list[i].flags,
          uip_ds6_route_info_list[i].lifetime);
    }
  }
  SEND_STRING(&s->sout, buf);
  reset_buf();
#endif

  add("</pre><h2>DNS server</h2><pre>");
  //Note: Currently we assume only one DNS server
  uip_ipaddr_t * dns = uip_nameserver_get(0);
  if(!uip_is_addr_unspecified(dns)) {
    ipaddr_add(dns);
    add(" %u s\n", uip_nameserver_next_expiration());
  }
  SEND_STRING(&s->sout, buf);
  reset_buf();

#if CETIC_6LBR_WITH_IP64
  if((nvm_data.global_flags & CETIC_GLOBAL_IP64) != 0) {
    add("</pre><h2>IP64 connections mapping</h2><pre>");
    static struct ip64_addrmap_entry *m;
    for(m = ip64_addrmap_list();
        m != NULL;
        m = list_item_next(m)) {
      if(timer_expired(&m->timer)) continue;
      ipaddr_add(&m->ip6addr);
      add("%%%d (%d)", m->ip6port, m->protocol);
      if(m->ip6to4 && m->ip4to6) {
        add(" <-> ");
      } else if(m->ip6to4) {
        add(" -> ");
      } else {
        add(" <- ");
      }
      ip4addr_add(&m->ip4addr);
      add("%%%d : %d (%x) %us\n", m->ip4port, m->mapped_port,
          m->flags, (m->timer.interval - (clock_time() - m->timer.start)) / CLOCK_SECOND);
      SEND_STRING(&s->sout, buf);
      reset_buf();
    }
  }
#endif

#if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0
  add("</pre><h2>6LoWPAN Prefix contexts</h2><pre>");
  for(i = 0; i < SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; i++) {
    if(addr_contexts[i].used == 1) {
      add("%d : ", addr_contexts[i].number);
      ipaddr_add_u8_len(addr_contexts[i].prefix, 8);
      add("\n");
    }
  }
  add("</pre><br />");
  SEND_STRING(&s->sout, buf);
  reset_buf();
#endif

#if CETIC_6LBR_TRANSPARENTBRIDGE
  add("<h2>HW Prefixes cache</h2><pre>");
  for(i = 0; i < prefixCounter; i++) {
    add("%02x:%02x:%02x\n", prefixBuffer[i][0], prefixBuffer[i][1],
        prefixBuffer[i][2]);
  }
  SEND_STRING(&s->sout, buf);
  add("</pre><br />");
  reset_buf();
#endif
  PSOCK_END(&s->sout);
}
static void
add_network_cases(const uint8_t state)
{
  switch (state) {
  case NBR_INCOMPLETE:
    add("Incomplete");
    break;
  case NBR_REACHABLE:
    add("Reachable");
    break;
  case NBR_STALE:
    add("Stale");
    break;
  case NBR_DELAY:
    add("Delay");
    break;
  case NBR_PROBE:
    add("Probe");
    break;
  }
}

static httpd_cgi_call_t *
webserver_network_route_add(struct httpd_state *s)
{
#if UIP_DS6_STATIC_ROUTES
  uip_ds6_route_t *route;
  uip_ipaddr_t ipaddr;
  uint8_t length;
  uip_ipaddr_t nexthop;
  char *p;
  char *sep;
  webserver_result_title = "Network";
  webserver_result_text = "Add route: Route not created";
  do {
    if(!s->query) break;
    p = s->query;
    sep = index(p, '=');
    if(sep == NULL) break;
    *sep = 0;
    if(strcmp(p, "target") != 0) break;
    p = sep + 1;
    sep = index(p, '&');
    if(sep == NULL) break;
    *sep = 0;
    if(uiplib_ipaddrconv(p, &ipaddr) == 0) break;
    p = sep + 1;
    sep = index(p, '=');
    if(sep == NULL) break;
    *sep = 0;
    if(strcmp(p, "length") != 0) break;
    p = sep + 1;
    sep = index(p, '&');
    if(sep == NULL) break;
    *sep = 0;
    length = atoi(p);
    p = sep + 1;
    sep = index(p, '=');
    if(sep == NULL) break;
    *sep = 0;
    if(strcmp(p, "nexthop") != 0) break;
    p = sep + 1;
    if(uiplib_ipaddrconv(p, &nexthop) == 0) break;
    route = uip_ds6_route_add_static(&ipaddr, length, &nexthop);
    if(route) {
      webserver_result_text = "Route created";
    }
  } while (0);
#else
  webserver_result_title = "Network";
  webserver_result_text = "Add route: not supported";
#endif
  return &webserver_result_page;
}
Пример #22
0
/*---------------------------------Main Routine----------------------------*/
int
main(void)
{
  /* GCC depends on register r1 set to 0 (?) */
  asm volatile ("clr r1");
  
  /* Initialize in a subroutine to maximize stack space */
  initialize();

#if DEBUG
{struct process *p;
 for(p = PROCESS_LIST();p != NULL; p = ((struct process *)p->next)) {
  PRINTA("Process=%p Thread=%p  Name=\"%s\" \n",p,p->thread,PROCESS_NAME_STRING(p));
 }
}
#endif

  while(1) {
    process_run();

    watchdog_periodic();

/* Print rssi of all received packets, useful for range testing */
#ifdef RF230_MIN_RX_POWER
    uint8_t lastprint;
    if (rf230_last_rssi != lastprint) {        //can be set in halbb.c interrupt routine
        PRINTA("%u ",rf230_last_rssi);
        lastprint=rf230_last_rssi;
    }
#endif

#if 0
/* Clock.c can trigger a periodic PLL calibration in the RF230BB driver.
 * This can show when that happens.
 */
    extern uint8_t rf230_calibrated;
    if (rf230_calibrated) {
      PRINTA("\nRF230 calibrated!\n");
      rf230_calibrated=0;
    }
#endif

#if TESTRTIMER
/* Timeout can be increased up to 8 seconds maximum.
 * A one second cycle is convenient for triggering the various debug printouts.
 * The triggers are staggered to avoid printing everything at once.
 * My Jackdaw is 4% slow.
 */
    if (rtimerflag) {
      rtimer_set(&rt, RTIMER_NOW()+ RTIMER_ARCH_SECOND*1UL, 1,(void *) rtimercycle, NULL);
      rtimerflag=0;

#if STAMPS
if ((rtime%STAMPS)==0) {
  PRINTA("%us ",rtime);
  if (rtime%STAMPS*10) PRINTA("\n");
}
#endif
      rtime+=1;

#if PINGS && UIP_CONF_IPV6_RPL
extern void raven_ping6(void);
if ((rtime%PINGS)==1) {
  PRINTA("**Ping\n");
  raven_ping6();
}
#endif

#if ROUTES && UIP_CONF_IPV6_RPL
if ((rtime%ROUTES)==2) {

extern uip_ds6_netif_t uip_ds6_if;

  uint8_t i,j;
  uip_ds6_nbr_t *nbr;

  PRINTA("\nAddresses [%u max]\n",UIP_DS6_ADDR_NB);
  for (i=0;i<UIP_DS6_ADDR_NB;i++) {
    if (uip_ds6_if.addr_list[i].isused) {
      uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr);
      PRINTA("\n");
    }
  }
  PRINTA("\nNeighbors [%u max]\n",NBR_TABLE_MAX_NEIGHBORS);

  for(nbr = nbr_table_head(ds6_neighbors);
      nbr != NULL;
      nbr = nbr_table_next(ds6_neighbors, nbr)) {
    uip_debug_ipaddr_print(&nbr->ipaddr);
    PRINTA("\n");
    j=0;
  }
  if (j) PRINTA("  <none>");
  PRINTA("\nRoutes [%u max]\n",UIP_DS6_ROUTE_NB);
  uip_ds6_route_t *r;
  for(r = uip_ds6_route_head();
      r != NULL;
      r = uip_ds6_route_next(r)) {
    if(r->isused) {
      uip_debug_ipaddr_print(&r->ipaddr);
      PRINTA("/%u (via ", r->length);
      uip_debug_ipaddr_print(uip_ds6_route_nexthop(r));
 //     if(r->state.lifetime < 600) {
        PRINTA(") %lus\n", r->state.lifetime);
 //     } else {
 //       PRINTA(")\n");
 //     }
      j=0;
    }
  }
  if (j) PRINTA("  <none>");
  PRINTA("\n---------\n");
}
#endif

#if STACKMONITOR && CONFIG_STACK_MONITOR
if ((rtime%STACKMONITOR)==3) {
  extern uint16_t __bss_end;
  uint16_t p=(uint16_t)&__bss_end;
  do {
    if (*(uint16_t *)p != 0x4242) {
      PRINTA("Never-used stack > %d bytes\n",p-(uint16_t)&__bss_end);
      break;
    }
    p+=100;
  } while (p<RAMEND-10);
}
#endif

    }
#endif /* TESTRTIMER */

//Use with RF230BB DEBUGFLOW to show path through driver
#if RF230BB&&0
extern uint8_t debugflowsize,debugflow[];  //in rf230bb.c
  if (debugflowsize) {
    debugflow[debugflowsize]=0;
    PRINTA("%s",debugflow);
    debugflowsize=0;
   }
#endif

  }
  return 0;
}
Пример #23
0
/*---------------------------------------------------------------------------*/
static
PT_THREAD(generate_routes(struct httpd_state *s))
{
  static uip_ds6_route_t *r;
  static uip_ds6_nbr_t *nbr;
#if BUF_USES_STACK
  char buf[256];
#endif
#if WEBSERVER_CONF_LOADTIME
  static clock_time_t numticks;
  numticks = clock_time();
#endif

  PSOCK_BEGIN(&s->sout);

  SEND_STRING(&s->sout, TOP);
#if BUF_USES_STACK
  bufptr = buf;bufend=bufptr+sizeof(buf);
#else
  blen = 0;
#endif
  ADD("Neighbors<pre>");

  for(nbr = nbr_table_head(ds6_neighbors);
      nbr != NULL;
      nbr = nbr_table_next(ds6_neighbors, nbr)) {

#if WEBSERVER_CONF_NEIGHBOR_STATUS
#if BUF_USES_STACK
{char* j=bufptr+25;
      ipaddr_add(&nbr->ipaddr);
      while (bufptr < j) ADD(" ");
      switch (nbr->state) {
      case NBR_INCOMPLETE: ADD(" INCOMPLETE");break;
      case NBR_REACHABLE: ADD(" REACHABLE");break;
      case NBR_STALE: ADD(" STALE");break;
      case NBR_DELAY: ADD(" DELAY");break;
      case NBR_PROBE: ADD(" NBR_PROBE");break;
      }
}
#else
{uint8_t j=blen+25;
      ipaddr_add(&nbr->ipaddr);
      while (blen < j) ADD(" ");
      switch (nbr->state) {
      case NBR_INCOMPLETE: ADD(" INCOMPLETE");break;
      case NBR_REACHABLE: ADD(" REACHABLE");break;
      case NBR_STALE: ADD(" STALE");break;
      case NBR_DELAY: ADD(" DELAY");break;
      case NBR_PROBE: ADD(" NBR_PROBE");break;
      }
}
#endif
#else
      ipaddr_add(&nbr->ipaddr);
#endif

      ADD("\n");
#if BUF_USES_STACK
      if(bufptr > bufend - 45) {
        SEND_STRING(&s->sout, buf);
        bufptr = buf; bufend = bufptr + sizeof(buf);
      }
#else
      if(blen > sizeof(buf) - 45) {
        SEND_STRING(&s->sout, buf);
        blen = 0;
      }
#endif
  }
  ADD("</pre>Routes<pre>");
  SEND_STRING(&s->sout, buf);
#if BUF_USES_STACK
  bufptr = buf; bufend = bufptr + sizeof(buf);
#else
  blen = 0;
#endif

  for(r = uip_ds6_route_head(); r != NULL; r = uip_ds6_route_next(r)) {

#if BUF_USES_STACK
#if WEBSERVER_CONF_ROUTE_LINKS
    ADD("<a href=http://[");
    ipaddr_add(&r->ipaddr);
    ADD("]/status.shtml>");
    ipaddr_add(&r->ipaddr);
    ADD("</a>");
#else
    ipaddr_add(&r->ipaddr);
#endif
#else
#if WEBSERVER_CONF_ROUTE_LINKS
    ADD("<a href=http://[");
    ipaddr_add(&r->ipaddr);
    ADD("]/status.shtml>");
    SEND_STRING(&s->sout, buf); //TODO: why tunslip6 needs an output here, wpcapslip does not
    blen = 0;
    ipaddr_add(&r->ipaddr);
    ADD("</a>");
#else
    ipaddr_add(&r->ipaddr);
#endif
#endif
    ADD("/%u (via ", r->length);
    ipaddr_add(uip_ds6_route_nexthop(r));
    if(1 || (r->state.lifetime < 600)) {
      ADD(") %lus\n", (unsigned long)r->state.lifetime);
    } else {
      ADD(")\n");
    }
    SEND_STRING(&s->sout, buf);
#if BUF_USES_STACK
    bufptr = buf; bufend = bufptr + sizeof(buf);
#else
    blen = 0;
#endif
  }
  ADD("</pre>");

#if WEBSERVER_CONF_FILESTATS
  static uint16_t numtimes;
  ADD("<br><i>This page sent %u times</i>",++numtimes);
#endif

#if WEBSERVER_CONF_LOADTIME
  numticks = clock_time() - numticks + 1;
  ADD(" <i>(%u.%02u sec)</i>",numticks/CLOCK_SECOND,(100*(numticks%CLOCK_SECOND))/CLOCK_SECOND));
#endif

  SEND_STRING(&s->sout, buf);
  SEND_STRING(&s->sout, BOTTOM);

  PSOCK_END(&s->sout);
}
Пример #24
0
static void generate_routes()
{
	static uip_ds6_route_t *r;
	static uip_ds6_nbr_t *nbr;
#if BUF_USES_STACK
	char buf[256];
	bufptr = buf;bufend=bufptr+sizeof(buf);
#else
	blen = 0;
#endif
	ADD("Neighbors\n");

	for(nbr = nbr_table_head(ds6_neighbors);
			nbr != NULL;
			nbr = nbr_table_next(ds6_neighbors, nbr)) {

#if BUF_USES_STACK
		{char* j=bufptr+25;
		ipaddr_add(&nbr->ipaddr);
		while (bufptr < j) ADD(" ");
		switch (nbr->state) {
		case NBR_INCOMPLETE: ADD(" INCOMPLETE");break;
		case NBR_REACHABLE: ADD(" REACHABLE");break;
		case NBR_STALE: ADD(" STALE");break;
		case NBR_DELAY: ADD(" DELAY");break;
		case NBR_PROBE: ADD(" NBR_PROBE");break;
		}
		}
#else
		{uint8_t j=blen+25;
		ipaddr_add(&nbr->ipaddr);
		while (blen < j) ADD(" ");
		switch (nbr->state) {
		case NBR_INCOMPLETE: ADD(" INCOMPLETE");break;
		case NBR_REACHABLE: ADD(" REACHABLE");break;
		case NBR_STALE: ADD(" STALE");break;
		case NBR_DELAY: ADD(" DELAY");break;
		case NBR_PROBE: ADD(" NBR_PROBE");break;
		}
		}
#endif
		ADD("\n");
#if BUF_USES_STACK
		if(bufptr > bufend - 45) {
			PRINTF("%s", buf);
			bufptr = buf; bufend = bufptr + sizeof(buf);
		}
#else
		if(blen > sizeof(buf) - 45) {
			PRINTF("%s", buf);
			blen = 0;
		}
#endif
	}
	ADD("\nRoutes\n");
	PRINTF("%s", buf);
#if BUF_USES_STACK
	bufptr = buf; bufend = bufptr + sizeof(buf);
#else
	blen = 0;
#endif

	for(r = uip_ds6_route_head(); r != NULL; r = uip_ds6_route_next(r)) {
		ipaddr_add(&r->ipaddr);
		ADD("/%u (via ", r->length);
		ipaddr_add(uip_ds6_route_nexthop(r));
		if(1 || (r->state.lifetime < 600)) {
			ADD(") %us\n", (unsigned int)r->state.lifetime); // iotlab printf does not have %lu
		} else {
			ADD(")\n");
		}
		PRINTF("%s", buf);
#if BUF_USES_STACK
		bufptr = buf; bufend = bufptr + sizeof(buf);
#else
		blen = 0;
#endif
	}
}
Пример #25
0
/*---------------------------------------------------------------------------*/
static
PT_THREAD(generate_routes(struct httpd_state *s))
{
  static int i;
  static uip_ds6_route_t *r;
  static uip_ds6_nbr_t *nbr;

  PSOCK_BEGIN(&s->sout);

  SEND_STRING(&s->sout, TOP);

  blen = 0;
  ADD("Neighbors<pre>");
  for(nbr = nbr_table_head(ds6_neighbors);
      nbr != NULL;
      nbr = nbr_table_next(ds6_neighbors, nbr)) {
    ipaddr_add(&nbr->ipaddr);
    ADD("\n");
    if(blen > sizeof(buf) - 45) {
      SEND_STRING(&s->sout, buf);
      blen = 0;
    }
  }

  ADD("</pre>Routes<pre>");
  SEND_STRING(&s->sout, buf);
  blen = 0;
  for(r = uip_ds6_route_head();
      r != NULL;
      r = uip_ds6_route_next(r)) {
    ipaddr_add(&r->ipaddr);
    ADD("/%u (via ", r->length);
    ipaddr_add(uip_ds6_route_nexthop(r));
    if(r->state.lifetime < 600) {
      ADD(") %lus\n", (unsigned long)r->state.lifetime);
    } else {
      ADD(")\n");
    }
    SEND_STRING(&s->sout, buf);
    blen = 0;
  }
  ADD("</pre>");
//if(blen > 0) {
  SEND_STRING(&s->sout, buf);
// blen = 0;
//}

  if(sensor_count > 0) {
    ADD("</pre>Sensors<pre>");
    SEND_STRING(&s->sout, buf);
    blen = 0;
    for(i = 0; i < sensor_count; i++) {
      ADD("%s\n", sensors[i]);
      SEND_STRING(&s->sout, buf);
      blen = 0;
    }
    ADD("</pre>");
    SEND_STRING(&s->sout, buf);
  }


  SEND_STRING(&s->sout, BOTTOM);

  PSOCK_END(&s->sout);
}