From 726f927c40bbf28d93dd1d29fc08b60d53e7c266 Mon Sep 17 00:00:00 2001 From: doganyazar Date: Wed, 24 Nov 2010 10:16:45 +0000 Subject: [PATCH] Bug fix and updates --- apps/rest-common/rest-util.c | 71 +++++++-- apps/rest-common/rest-util.h | 6 + apps/rest-common/rest.c | 240 +++++++++++++++++++++++------- apps/rest-common/rest.h | 64 +++++--- apps/rest-common/static-routing.c | 27 ++-- apps/rest-common/static-routing.h | 14 +- 6 files changed, 311 insertions(+), 111 deletions(-) diff --git a/apps/rest-common/rest-util.c b/apps/rest-common/rest-util.c index 71e03d1ea..b7e7f118e 100644 --- a/apps/rest-common/rest-util.c +++ b/apps/rest-common/rest-util.c @@ -1,14 +1,9 @@ -/* - * rest-util.c - * - * Created on: Oct 26, 2010 - * Author: dogan - */ - #include /*for size_t*/ #include /*for isxdigit*/ #include +#include "contiki-net.h" + /*Copied from mangoose http server*/ size_t decode(const char *src, size_t srclen, char *dst, size_t dstlen, int is_form) @@ -50,18 +45,15 @@ get_variable(const char *name, const char *buffer, size_t buflen, char* output, var_len = strlen(name); end = buffer + buflen; - for (start = buffer; start + var_len < end; start++) - { + for (start = buffer; start + var_len < end; start++){ if ((start == buffer || start[-1] == '&') && start[var_len] == '=' && - ! strncmp(name, start, var_len)) - { + ! strncmp(name, start, var_len)) { /* Point p to variable value */ start += var_len + 1; /* Point s to the end of the value */ end_of_value = (const char *) memchr(start, '&', end - start); - if (end_of_value == NULL) - { + if (end_of_value == NULL) { end_of_value = end; } @@ -71,3 +63,56 @@ get_variable(const char *name, const char *buffer, size_t buflen, char* output, return 0; } + +uint32_t +read_int(uint8_t *buf, uint8_t size) +{ + uint32_t data = 0; + + if (size >= 1 && size <= 4) { + uint8_t *p = (uint8_t *)&data; + memcpy(p + 4 - size, buf, size); + } + + return uip_ntohl(data); +} + + +int +write_int(uint8_t *buf, uint32_t data, uint8_t size) +{ + int success = 0; + + if (size >= 1 && size <= 4) { + data = uip_htonl(data); + memcpy(buf, ((char*)(&data)) + 4 - size, size); + success = size; + } + + return success; +} + +int +write_variable_int(uint8_t *buf, uint32_t data) +{ + uint8_t size = 4; + if (data <= 0xFF) { + size = 1; + } else if (data <= 0xFFFF) { + size = 2; + } else if (data <= 0xFFFFFF) { + size = 3; + } + return write_int(buf, data, size); +} + +uint16_t log_2(uint16_t value) +{ + uint16_t result = 0; + do { + value = value >> 1; + result++; + } while (value); + + return result ? result - 1 : result; +} diff --git a/apps/rest-common/rest-util.h b/apps/rest-common/rest-util.h index 277468f98..421c8b3ea 100644 --- a/apps/rest-common/rest-util.h +++ b/apps/rest-common/rest-util.h @@ -11,4 +11,10 @@ size_t decode(const char *src, size_t srclen, char *dst, size_t dstlen, int is_form); int get_variable(const char *name, const char *buffer, size_t buflen, char* output, size_t output_len, int decode_type); +uint32_t read_int(uint8_t *buf, uint8_t size); +int write_int(uint8_t *buf, uint32_t data, uint8_t size); +int write_variable_int(uint8_t *buf, uint32_t data); + +uint16_t log_2(uint16_t value); + #endif /* RESTUTIL_H_ */ diff --git a/apps/rest-common/rest.c b/apps/rest-common/rest.c index dec10f8bd..4a86fb516 100755 --- a/apps/rest-common/rest.c +++ b/apps/rest-common/rest.c @@ -3,17 +3,24 @@ #include "rest.h" #include "buffer.h" -#define DEBUG 1 +#define DEBUG 0 #if DEBUG #include #define PRINTF(...) printf(__VA_ARGS__) +#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((u8_t *)addr)[0], ((u8_t *)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_t *)addr)[15]) +#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5]) #else #define PRINTF(...) +#define PRINT6ADDR(addr) +#define PRINTLLADDR(addr) #endif /*FIXME it is possible to define some of the rest functions as MACROs rather than functions full of ifdefs.*/ +PROCESS_NAME(rest_manager_process); + LIST(restful_services); +LIST(restful_periodic_services); void rest_init(void) @@ -26,84 +33,44 @@ rest_init(void) http_set_service_callback(rest_invoke_restful_service); #endif /*WITH_COAP*/ - //start the coap server - process_start(SERVER_PROCESS, NULL); + /*Start rest framework process*/ + process_start(&rest_manager_process, NULL); } void -rest_activate_resource(Resource_t* resource) +rest_activate_resource(resource_t* resource) { /*add it to the restful web service link list*/ list_add(restful_services, resource); } -int -rest_invoke_restful_service(REQUEST* request, RESPONSE* response) +void +rest_activate_periodic_resource(periodic_resource_t* periodic_resource) { - int found = 0; - const char* url = request->url; - uint16_t url_len = request->url_len; - - PRINTF("rest_invoke_restful_service url %s url_len %d -->\n", url, url_len); - - Resource_t* resource = NULL; - - for ( resource = (Resource_t*)list_head(restful_services); resource ; resource = resource->next ){ - /*if the web service handles that kind of requests and urls matches*/ - /*FIXME Need to make case insensitive?*/ - if (url && strlen(resource->url) == url_len && strncmp(resource->url, url, url_len) == 0){ - found = 1; - method_t method = rest_get_method_type(request); - - PRINTF("method %u, resource->methods_to_handle %u\n", (uint16_t)method, resource->methods_to_handle); - - //DY FIX_ME resources can only handle 1 method currently anyway, fix this - if ( resource->methods_to_handle & method ) { - - /*call pre handler if it exists*/ - if (!resource->pre_handler || resource->pre_handler(request, response)) { - /* call handler function*/ - resource->handler(request, response); - - /*call post handler if it exists*/ - if (resource->post_handler) { - resource->post_handler(request, response); - } - } - } else { - rest_set_response_status(response, METHOD_NOT_ALLOWED_405); - } - break; - } - } - - if (!found) { - rest_set_response_status(response, NOT_FOUND_404); - } - - return found; + list_add(restful_periodic_services, periodic_resource); + rest_activate_resource(periodic_resource->resource); } void -rest_set_user_data(Resource_t* resource, void* user_data) +rest_set_user_data(resource_t* resource, void* user_data) { resource->user_data = user_data; } void* -rest_get_user_data(Resource_t* resource) +rest_get_user_data(resource_t* resource) { return resource->user_data; } void -rest_set_pre_handler(Resource_t* resource, restful_pre_handler pre_handler) +rest_set_pre_handler(resource_t* resource, restful_pre_handler pre_handler) { resource->pre_handler = pre_handler; } void -rest_set_post_handler(Resource_t* resource, restful_post_handler post_handler) +rest_set_post_handler(resource_t* resource, restful_post_handler post_handler) { resource->post_handler = post_handler; } @@ -118,33 +85,79 @@ void rest_set_response_status(RESPONSE* response, status_code_t status) { #ifdef WITH_COAP - coap_set_code(response, (uint8_t)status); + coap_set_code(response, status); #else /*WITH_COAP*/ http_set_status(response, status); #endif /*WITH_COAP*/ } +#ifdef WITH_COAP +static method_t coap_to_rest_method(coap_method_t method) +{ + return (method_t)(1 << (method - 1)); +} + +static coap_method_t rest_to_coap_method(method_t method) +{ + coap_method_t coap_method = COAP_GET; + switch (method) { + case METHOD_GET: + coap_method = COAP_GET; + break; + case METHOD_POST: + coap_method = COAP_POST; + break; + case METHOD_PUT: + coap_method = COAP_PUT; + break; + case METHOD_DELETE: + coap_method = COAP_DELETE; + break; + default: + break; + } + return coap_method; +} +#endif /*WITH_COAP*/ method_t rest_get_method_type(REQUEST* request) { #ifdef WITH_COAP - return (method_t)((request->code) << (request->code - 1)); + return coap_to_rest_method(coap_get_method(request)); #else return (method_t)(request->request_type); #endif } +/*Only defined for COAP for now.*/ +#ifdef WITH_COAP void -rest_set_payload(RESPONSE* response, uint8_t* payload, uint16_t size) +rest_set_method_type(REQUEST* request, method_t method) +{ + coap_set_method(request, rest_to_coap_method(method)); +} +#endif /*WITH_COAP*/ + +void +rest_set_response_payload(RESPONSE* response, uint8_t* payload, uint16_t size) { #ifdef WITH_COAP coap_set_payload(response, payload, size); #else - http_set_payload(response, payload, size); + http_set_res_payload(response, payload, size); #endif /*WITH_COAP*/ } +/*Only defined for COAP for now.*/ +#ifdef WITH_COAP +void +rest_set_request_payload(REQUEST* request, uint8_t* payload, uint16_t size) +{ + coap_set_payload(request, payload, size); +} +#endif /*WITH_COAP*/ + int rest_get_query_variable(REQUEST* request, const char *name, char* output, uint16_t output_size) { @@ -199,3 +212,118 @@ rest_set_header_etag(RESPONSE* response, uint8_t* etag, uint8_t size) return http_set_res_header(response, HTTP_HEADER_NAME_ETAG, temp_etag, 1); #endif /*WITH_COAP*/ } + +int +rest_invoke_restful_service(REQUEST* request, RESPONSE* response) +{ + int found = 0; + const char* url = request->url; + uint16_t url_len = request->url_len; + + PRINTF("rest_invoke_restful_service url %s url_len %d -->\n", url, url_len); + + resource_t* resource = NULL; + + for (resource = (resource_t*)list_head(restful_services); resource; resource = resource->next) { + /*if the web service handles that kind of requests and urls matches*/ + if (url && strlen(resource->url) == url_len && strncmp(resource->url, url, url_len) == 0){ + found = 1; + method_t method = rest_get_method_type(request); + + PRINTF("method %u, resource->methods_to_handle %u\n", (uint16_t)method, resource->methods_to_handle); + + if (resource->methods_to_handle & method) { + + /*FIXME Move somewhere else*/ + #ifdef WITH_COAP + uint32_t lifetime = 0; + if (coap_get_header_subscription_lifetime(request, &lifetime)) { + PRINTF("Lifetime %lu\n", lifetime); + + periodic_resource_t* periodic_resource = NULL; + for (periodic_resource = (periodic_resource_t*)list_head(restful_periodic_services); + periodic_resource; + periodic_resource = periodic_resource->next) { + if (periodic_resource->resource == resource) { + PRINTF("Periodic Resource Found\n"); + PRINT6ADDR(&request->addr); + periodic_resource->lifetime = lifetime; + uip_ipaddr_copy(&periodic_resource->addr, &request->addr); + } + } + } + #endif /*WITH_COAP*/ + + /*call pre handler if it exists*/ + if (!resource->pre_handler || resource->pre_handler(request, response)) { + /* call handler function*/ + resource->handler(request, response); + + /*call post handler if it exists*/ + if (resource->post_handler) { + resource->post_handler(request, response); + } + } + } else { + rest_set_response_status(response, METHOD_NOT_ALLOWED_405); + } + break; + } + } + + if (!found) { + rest_set_response_status(response, NOT_FOUND_404); + } + + return found; +} + +PROCESS(rest_manager_process, "Rest Process"); + +PROCESS_THREAD(rest_manager_process, ev, data) +{ + PROCESS_BEGIN(); + + /*start the coap or http server*/ + process_start(SERVER_PROCESS, NULL); + + PROCESS_PAUSE(); + + /*Periodic resources are only available to COAP implementation*/ +#ifdef WITH_COAP + periodic_resource_t* periodic_resource = NULL; + for (periodic_resource = (periodic_resource_t*)list_head(restful_periodic_services); periodic_resource; periodic_resource = periodic_resource->next) { + if (periodic_resource->period) { + PRINTF("Set timer for Res: %s to %u\n", periodic_resource->resource->url, periodic_resource->period); + etimer_set(periodic_resource->timer, CLOCK_SECOND * periodic_resource->period); + } + } + + while(1) { + PROCESS_WAIT_EVENT(); + if (ev == PROCESS_EVENT_TIMER) { + for (periodic_resource=(periodic_resource_t*)list_head(restful_periodic_services);periodic_resource;periodic_resource = periodic_resource->next) { + if (periodic_resource->period && etimer_expired(periodic_resource->timer)) { + PRINTF("Etimer expired for %s (period:%u life:%lu)\n", periodic_resource->resource->url, periodic_resource->period, periodic_resource->lifetime); + /*call the periodic handler function if exists*/ + if (periodic_resource->periodic_handler) { + if ((periodic_resource->periodic_handler)(periodic_resource->resource) && periodic_resource->lifetime) { + resource_changed(periodic_resource); + } + /*Update lifetime*/ + if (periodic_resource->lifetime > periodic_resource->period) { + periodic_resource->lifetime -= periodic_resource->period; + } else { + periodic_resource->lifetime = 0; + } + PRINTF("%s life upd:%lu\n", periodic_resource->resource->url, periodic_resource->lifetime); + } + etimer_reset(periodic_resource->timer); + } + } + } + } +#endif /*WITH_COAP*/ + + PROCESS_END(); +} diff --git a/apps/rest-common/rest.h b/apps/rest-common/rest.h index f596383ef..88de7a157 100755 --- a/apps/rest-common/rest.h +++ b/apps/rest-common/rest.h @@ -20,15 +20,14 @@ #define SERVER_PROCESS (&http_server) #endif /*WITH_COAP*/ -struct Resource_t; +struct resource_t; /*REST method types*/ typedef enum { METHOD_GET = (1 << 0), - METHOD_HEAD = (1 << 1), - METHOD_POST = (1 << 2), - METHOD_PUT = (1 << 3), - METHOD_DELETE = (1 << 4) + METHOD_POST = (1 << 1), + METHOD_PUT = (1 << 2), + METHOD_DELETE = (1 << 3) } method_t; /*Signature of handler functions*/ @@ -36,13 +35,14 @@ typedef void (*restful_handler) (REQUEST* request, RESPONSE* response); typedef int (*restful_pre_handler) (REQUEST* request, RESPONSE* response); typedef void (*restful_post_handler) (REQUEST* request, RESPONSE* response); -typedef void (*restful_periodic_handler) (struct Resource_t* resource); +typedef int (*restful_periodic_handler) (struct resource_t* resource); +typedef void (*restful_periodic_request_generator) (REQUEST* request); /* * Data structure representing a resource in REST. */ -struct Resource_t { - struct Resource_t *next; /*points to next resource defined*/ +struct resource_t { + struct resource_t *next; /*points to next resource defined*/ method_t methods_to_handle; /*handled HTTP methods*/ const char* url; /*handled URL*/ restful_handler handler; /*handler function*/ @@ -50,17 +50,39 @@ struct Resource_t { restful_post_handler post_handler; /*to be called after handler, may perform finalizations (cleanup, etc)*/ void* user_data; /*pointer to user specific data*/ }; -typedef struct Resource_t Resource_t; +typedef struct resource_t resource_t; +struct periodic_resource_t { + struct periodic_resource_t *next; + resource_t *resource; + uint16_t period; + struct etimer* timer; + restful_periodic_handler periodic_handler; + restful_periodic_request_generator periodic_request_generator; + uint32_t lifetime; + uip_ipaddr_t addr; + struct uip_udp_conn *client_conn; +}; +typedef struct periodic_resource_t periodic_resource_t; /* * Macro to define a Resource * Resources are statically defined for the sake of efficiency and better memory management. */ -#define RESOURCE(name, methods_to_handle,url) \ -void name##_handler(REQUEST* request, RESPONSE* response); \ +#define RESOURCE(name, methods_to_handle, url) \ +void name##_handler(REQUEST*, RESPONSE*); \ +resource_t resource_##name = {NULL, methods_to_handle, url, name##_handler, NULL, NULL, NULL} + +/* + * Macro to define a Periodic Resource + */ +#define PERIODIC_RESOURCE(name, methods_to_handle, url, period) \ +RESOURCE(name, methods_to_handle, url); \ +int name##_periodic_handler(resource_t*); \ +void name##_periodic_request_generator(REQUEST*); \ struct etimer timer_##name; \ -Resource_t resource_##name = {NULL, methods_to_handle, url, name##_handler, NULL, NULL, NULL} +periodic_resource_t periodic_resource_##name = {NULL, &resource_##name, period, &timer_##name, name##_periodic_handler, name##_periodic_request_generator, 0} + /* * Initializes REST framework and starts HTTP or COAP process @@ -70,7 +92,9 @@ void rest_init(void); /* * Resources wanted to be accessible should be activated with the following code. */ -void rest_activate_resource(Resource_t* resource); +void rest_activate_resource(resource_t* resource); + +void rest_activate_periodic_resource(periodic_resource_t* periodic_resource); /* * To be called by HTTP/COAP server as a callback function when a new service request appears. @@ -98,6 +122,7 @@ int rest_get_query_variable(REQUEST* request, const char *name, char* output, ui int rest_get_post_variable(REQUEST* request, const char *name, char* output, uint16_t output_size); method_t rest_get_method_type(REQUEST* request); +void rest_set_method_type(REQUEST* request, method_t method); /* * Getter for the request content type @@ -120,32 +145,33 @@ int rest_set_header_etag(RESPONSE* response, uint8_t* etag, uint8_t size); void rest_set_response_status(RESPONSE* response, status_code_t status); /* - * Setter for the payload of the response + * Setter for the payload of the request and response */ -void rest_set_payload(RESPONSE* response, uint8_t* payload, uint16_t size); +void rest_set_request_payload(RESPONSE* response, uint8_t* payload, uint16_t size); +void rest_set_response_payload(RESPONSE* response, uint8_t* payload, uint16_t size); /* * Getter method for user specific data. */ -void* rest_get_user_data(Resource_t* resource); +void* rest_get_user_data(resource_t* resource); /* * Setter method for user specific data. */ -void rest_set_user_data(Resource_t* resource, void* user_data); +void rest_set_user_data(resource_t* resource, void* user_data); /* * Sets the pre handler function of the Resource. * If set, this function will be called just before the original handler function. * Can be used to setup work before resource handling. */ -void rest_set_pre_handler(Resource_t* resource, restful_pre_handler pre_handler); +void rest_set_pre_handler(resource_t* resource, restful_pre_handler pre_handler); /* * Sets the post handler function of the Resource. * If set, this function will be called just after the original handler function. * Can be used to do cleanup (deallocate memory, etc) after resource handling. */ -void rest_set_post_handler(Resource_t* resource, restful_post_handler post_handler); +void rest_set_post_handler(resource_t* resource, restful_post_handler post_handler); #endif /*REST_H_*/ diff --git a/apps/rest-common/static-routing.c b/apps/rest-common/static-routing.c index 241ff3027..32704dd14 100644 --- a/apps/rest-common/static-routing.c +++ b/apps/rest-common/static-routing.c @@ -37,33 +37,28 @@ void configure_routing(void) { PRINTF("configure_routing\n"); - if(node_id < 10) //COOJA - { - //Go to desktop machine over border router - ADD_ROUTE(DESKTOP_MACHINE_ID,COOJA_BORDER_ROUTER_ID); - } - else //SKY - { - if(node_id < 20) //First hops (ids between 10-20) - { - //Go to desktop machine over border router + if (node_id < 10) { /*COOJA*/ + /*Go to desktop machine over border router*/ + ADD_ROUTE(DESKTOP_MACHINE_ID, COOJA_BORDER_ROUTER_ID); + } else { /*SKY*/ + if (node_id < 20) { /*First hops (ids between 10-20)*/ + /*Go to desktop machine over border router*/ ADD_ROUTE(DESKTOP_MACHINE_ID, BORDER_ROUTER_ID); } - switch(node_id) - { + switch(node_id) { case 12: - ADD_ROUTE(22, 22); //Go to next hop over the local address of next hop + ADD_ROUTE(22, 22); /*Go to next hop over the local address of next hop*/ break; case 13: - ADD_ROUTE(23, 23); //Go to next hop over the local address of next hop + ADD_ROUTE(23, 23); /*Go to next hop over the local address of next hop*/ break; case 22: - ADD_ROUTE(0, 12); //Go to desktop machine over the corresponding first hop + ADD_ROUTE(0, 12); /*Go to desktop machine over the corresponding first hop*/ break; case 23: - ADD_ROUTE(0, 13); //Go to desktop machine over the corresponding first hop + ADD_ROUTE(0, 13); /*Go to desktop machine over the corresponding first hop*/ break; default: break; diff --git a/apps/rest-common/static-routing.h b/apps/rest-common/static-routing.h index d08304545..37479e4d2 100644 --- a/apps/rest-common/static-routing.h +++ b/apps/rest-common/static-routing.h @@ -10,11 +10,11 @@ #define NODE_IP(nodeid,type,ipaddr) NODE_##nodeid##_##type(ipaddr) -//desktop machine +/*desktop machine*/ #define DESKTOP_MACHINE_ID 0 #define NODE_0_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0x0001) -//Cooja Nodes +/*Cooja Nodes*/ #define COOJA_BORDER_ROUTER_ID 1 #define NODE_1_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7401, 0x0001, 0x0101) #define NODE_1_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7401, 0x0001, 0x0101) @@ -25,19 +25,19 @@ #define NODE_6_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7406, 0x0006, 0x0606) #define NODE_6_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7406, 0x0006, 0x0606) -//nodes +/*real nodes*/ #define BORDER_ROUTER_ID 11 #define NODE_11_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xd5f1) #define NODE_11_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xd5f1) -#define NODE_12_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xc0f6) -#define NODE_12_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xc0f6) +#define NODE_12_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x1160, 0xf95a) +#define NODE_12_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x1160, 0xf95a) #define NODE_13_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x3575) #define NODE_13_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x3575) -#define NODE_22_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x1160, 0xf95a) -#define NODE_22_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x1160, 0xf95a) +#define NODE_22_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xc0f6) +#define NODE_22_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xc0f6) #define NODE_23_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x0d5a) #define NODE_23_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x0d5a)